|
| 1 | +import { customElement, html, LitElement, property } from 'lit-element'; |
| 2 | + |
| 3 | +@customElement('wokwi-neopixel') |
| 4 | +export class NeoPixelElement extends LitElement { |
| 5 | + @property() r = 0; |
| 6 | + @property() g = 0; |
| 7 | + @property() b = 0; |
| 8 | + |
| 9 | + render() { |
| 10 | + const { r, g, b } = this; |
| 11 | + const spotOpacity = (value: number) => (value > 0.001 ? 0.7 + value * 0.3 : 0); |
| 12 | + const maxOpacity = Math.max(r, g, b); |
| 13 | + const minOpacity = Math.min(r, g, b); |
| 14 | + const opacityDelta = maxOpacity - minOpacity; |
| 15 | + const multiplier = Math.max(1, 2 - opacityDelta * 20); |
| 16 | + const glowBase = 0.1 + Math.max(maxOpacity * 2 - opacityDelta * 5, 0); |
| 17 | + const glowColor = (value: number) => (value > 0.005 ? 0.1 + value * 0.9 : 0); |
| 18 | + const glowOpacity = (value: number) => (value > 0.005 ? glowBase + value * (1 - glowBase) : 0); |
| 19 | + const cssVal = (value: number) => |
| 20 | + maxOpacity ? Math.floor(Math.min(glowColor(value / maxOpacity) * multiplier, 1) * 255) : 255; |
| 21 | + const cssColor = `rgb(${cssVal(r)}, ${cssVal(g)}, ${cssVal(b)})`; |
| 22 | + const bkgWhite = |
| 23 | + 242 - |
| 24 | + (maxOpacity > 0.1 && opacityDelta < 0.2 |
| 25 | + ? Math.floor(maxOpacity * 50 * (1 - opacityDelta / 0.2)) |
| 26 | + : 0); |
| 27 | + const background = `rgb(${bkgWhite}, ${bkgWhite}, ${bkgWhite})`; |
| 28 | + return html` |
| 29 | + <svg |
| 30 | + width="5.6631mm" |
| 31 | + height="5mm" |
| 32 | + version="1.1" |
| 33 | + viewBox="0 0 5.6631 5" |
| 34 | + xmlns="http://www.w3.org/2000/svg" |
| 35 | + > |
| 36 | + <filter id="light1" x="-0.8" y="-0.8" height="2.8" width="2.8"> |
| 37 | + <feGaussianBlur stdDeviation="${Math.max(0.1, maxOpacity)}" /> |
| 38 | + </filter> |
| 39 | + <filter id="light2" x="-0.8" y="-0.8" height="2.2" width="2.8"> |
| 40 | + <feGaussianBlur stdDeviation="0.5" /> |
| 41 | + </filter> |
| 42 | + <rect x=".33308" y="0" width="5" height="5" fill="${background}" /> |
| 43 | + <rect x=".016709" y=".4279" width=".35114" height=".9" fill="#eaeaea" /> |
| 44 | + <rect x="0" y="3.6518" width=".35114" height=".9" fill="#eaeaea" /> |
| 45 | + <rect x="5.312" y="3.6351" width=".35114" height=".9" fill="#eaeaea" /> |
| 46 | + <rect x="5.312" y=".3945" width=".35114" height=".9" fill="#eaeaea" /> |
| 47 | + <circle cx="2.8331" cy="2.5" r="2.1" fill="#ddd" /> |
| 48 | + <circle cx="2.8331" cy="2.5" r="1.7325" fill="#e6e6e6" /> |
| 49 | + <g fill="#bfbfbf"> |
| 50 | + <path |
| 51 | + d="m4.3488 3.3308s-0.0889-0.087-0.0889-0.1341c0-0.047-6e-3 -1.1533-6e-3 -1.1533s-0.0591-0.1772-0.2008-0.1772c-0.14174 0-0.81501 0.012-0.81501 0.012s-0.24805 0.024-0.23624 0.3071c0.0118 0.2835 0.032 2.0345 0.032 2.0345 0.54707-0.046 1.0487-0.3494 1.3146-0.8888z" |
| 52 | + /> |
| 53 | + <path |
| 54 | + d="m4.34 1.6405h-1.0805s-0.24325 0.019-0.26204-0.2423l6e-3 -0.6241c0.57782 0.075 1.0332 0.3696 1.3366 0.8706z" |
| 55 | + /> |
| 56 | + <path |
| 57 | + d="m2.7778 2.6103-0.17127 0.124-0.8091-0.012c-0.17122-0.019-0.17062-0.2078-0.17062-0.2078-1e-3 -0.3746 1e-3 -0.2831-9e-3 -0.8122l-0.31248-0.018s0.43453-0.9216 1.4786-0.9174c-1.1e-4 0.6144-4e-3 1.2289-6e-3 1.8434z" |
| 58 | + /> |
| 59 | + <path |
| 60 | + d="m2.7808 3.0828-0.0915-0.095h-0.96857l-0.0915 0.1447-3e-3 0.1127c0 0.065-0.12108 0.08-0.12108 0.08h-0.20909c0.55906 0.9376 1.4867 0.9155 1.4867 0.9155 1e-3 -0.3845-2e-3 -0.7692-2e-3 -1.1537z" |
| 61 | + /> |
| 62 | + </g> |
| 63 | + <path |
| 64 | + d="m4.053 1.8619c-0.14174 0-0.81494 0.013-0.81494 0.013s-0.24797 0.024-0.23616 0.3084c3e-3 0.077 5e-3 0.3235 9e-3 0.5514h1.247c-2e-3 -0.33-4e-3 -0.6942-4e-3 -0.6942s-0.0593-0.1781-0.20102-0.1781z" |
| 65 | + fill="#666" |
| 66 | + /> |
| 67 | + <ellipse |
| 68 | + cx="2.5" |
| 69 | + cy="2.3" |
| 70 | + rx="0.3" |
| 71 | + ry="0.3" |
| 72 | + fill="red" |
| 73 | + opacity=${spotOpacity(r)} |
| 74 | + filter="url(#light1)" |
| 75 | + ></ellipse> |
| 76 | + <ellipse |
| 77 | + cx="3.5" |
| 78 | + cy="3.2" |
| 79 | + rx="0.3" |
| 80 | + ry="0.3" |
| 81 | + fill="green" |
| 82 | + opacity=${spotOpacity(g)} |
| 83 | + filter="url(#light1)" |
| 84 | + ></ellipse> |
| 85 | + <ellipse |
| 86 | + cx="3.3" |
| 87 | + cy="1.45" |
| 88 | + rx="0.3" |
| 89 | + ry="0.3" |
| 90 | + fill="blue" |
| 91 | + opacity=${spotOpacity(b)} |
| 92 | + filter="url(#light1)" |
| 93 | + ></ellipse> |
| 94 | + <ellipse |
| 95 | + cx="3" |
| 96 | + cy="2.5" |
| 97 | + rx="2.2" |
| 98 | + ry="2.2" |
| 99 | + opacity="${glowOpacity(maxOpacity)}" |
| 100 | + fill="${cssColor}" |
| 101 | + filter="url(#light2)" |
| 102 | + ></ellipse> |
| 103 | + </svg> |
| 104 | + `; |
| 105 | + } |
| 106 | +} |
0 commit comments