|
| 1 | +import { css, customElement, html, LitElement, property } from 'lit-element'; |
| 2 | +import { ElementPin } from '.'; |
| 3 | +import { GND, VCC } from './pin'; |
| 4 | + |
| 5 | +@customElement('wokwi-ky-040') |
| 6 | +export class KY040Element extends LitElement { |
| 7 | + @property() angle = 0; |
| 8 | + @property() stepSize = 18; |
| 9 | + @property() private pressed = false; |
| 10 | + |
| 11 | + static get styles() { |
| 12 | + return css` |
| 13 | + svg { |
| 14 | + user-select: none; |
| 15 | + } |
| 16 | +
|
| 17 | + .arrow { |
| 18 | + cursor: pointer; |
| 19 | + } |
| 20 | +
|
| 21 | + svg:hover .arrow { |
| 22 | + fill: #666; |
| 23 | + stroke: #666; |
| 24 | + stroke-width: 1.5px; |
| 25 | + transition: stroke-width 0.3s; |
| 26 | + } |
| 27 | +
|
| 28 | + svg:hover .arrow:hover { |
| 29 | + fill: black; |
| 30 | + } |
| 31 | +
|
| 32 | + svg:hover .handle:hover { |
| 33 | + stroke: #ccc; |
| 34 | + stroke-width: 1.5px; |
| 35 | + transition: stroke-width 0.3s; |
| 36 | + } |
| 37 | +
|
| 38 | + svg:hover .handle.active { |
| 39 | + fill: white; |
| 40 | + stroke: white; |
| 41 | + stroke-width: 1.5px; |
| 42 | + transition: stroke-width 0.3s; |
| 43 | + } |
| 44 | +
|
| 45 | + .handle { |
| 46 | + cursor: pointer; |
| 47 | + } |
| 48 | + `; |
| 49 | + } |
| 50 | + |
| 51 | + readonly pinInfo: ElementPin[] = [ |
| 52 | + { name: 'CLK', y: 7.9, x: 116, number: 1, signals: [] }, |
| 53 | + { name: 'DT', y: 17.4, x: 116, number: 2, signals: [] }, |
| 54 | + { name: 'SW', y: 27, x: 116, number: 3, signals: [] }, |
| 55 | + { name: 'VCC', y: 36.3, x: 116, number: 4, signals: [VCC()] }, |
| 56 | + { name: 'GND', y: 45.5, x: 116, number: 5, signals: [GND()] }, |
| 57 | + ]; |
| 58 | + |
| 59 | + render() { |
| 60 | + return html` |
| 61 | + <svg |
| 62 | + width="30.815mm" |
| 63 | + height="18.63mm" |
| 64 | + version="1.1" |
| 65 | + viewBox="0 0 116 70.4" |
| 66 | + xmlns="http://www.w3.org/2000/svg" |
| 67 | + xmlns:xlink="http://www.w3.org/1999/xlink" |
| 68 | + > |
| 69 | + <defs> |
| 70 | + <linearGradient |
| 71 | + id="a" |
| 72 | + x1="158" |
| 73 | + x2="170" |
| 74 | + y1="86.5" |
| 75 | + y2="86.5" |
| 76 | + gradientTransform="translate(-75.1 -60.1)" |
| 77 | + gradientUnits="userSpaceOnUse" |
| 78 | + > |
| 79 | + <stop stop-color="#4d4d4d" offset="0" /> |
| 80 | + <stop stop-color="#4d4d4d" stop-opacity="0" offset="1" /> |
| 81 | + </linearGradient> |
| 82 | + </defs> |
| 83 | +
|
| 84 | + <!-- Board --> |
| 85 | + <path |
| 86 | + d="m0 0v70.4h99v-70.4zm18 56.5a6.5 6.5 0 0 1 6.5 6.5 6.5 6.5 0 0 1-6.5 6.5 6.5 6.5 0 0 1-6.5-6.5 6.5 6.5 0 0 1 6.5-6.5zm63.8 0.213a6.5 6.5 0 0 1 6.5 6.5 6.5 6.5 0 0 1-6.5 6.5 6.5 6.5 0 0 1-6.5-6.5 6.5 6.5 0 0 1 6.5-6.5z" |
| 87 | + fill="#1a1a1a" |
| 88 | + fill-rule="evenodd" |
| 89 | + /> |
| 90 | +
|
| 91 | + <!-- Rotator --> |
| 92 | + <g fill="#ccc" fill-rule="evenodd"> |
| 93 | + <rect x="9.05" y="17.4" width="6.95" height="2.47" rx=".756" /> |
| 94 | + <rect x="9.15" y="26.5" width="6.95" height="2.47" rx=".756" /> |
| 95 | + <rect x="9.05" y="36.1" width="6.95" height="2.47" rx=".756" /> |
| 96 | + </g> |
| 97 | +
|
| 98 | + <g tabindex="0" @keydown=${this.keydown} @keyup=${this.keyup}> |
| 99 | + <rect |
| 100 | + x="12.2" |
| 101 | + y="8.05" |
| 102 | + width="48.4" |
| 103 | + height="41" |
| 104 | + rx="7.12" |
| 105 | + fill="#e6e6e6" |
| 106 | + fill-rule="evenodd" |
| 107 | + /> |
| 108 | + <g> |
| 109 | + <g fill-rule="evenodd"> |
| 110 | + <circle cx="36.6" cy="28.5" r="13.5" fill="#666" /> |
| 111 | + <rect x="32.5" y="7.87" width="7.42" height="41.5" fill="#666" /> |
| 112 | +
|
| 113 | + <!-- handle --> |
| 114 | + <path |
| 115 | + transform="rotate(${this.angle}, 36.244, 28.5)" |
| 116 | + d="m36.3 21.4a7.03 7.14 0 0 |
| 117 | + 0-3.74 1.1v12.1a7.03 7.14 0 0 0 3.74 1.1 7.03 7.14 0 0 0 7.03-7.14 7.03 7.14 0 0 |
| 118 | + 0-7.03-7.14z" |
| 119 | + fill="#ccc" |
| 120 | + stroke="#060606" |
| 121 | + stroke-width=".3" |
| 122 | + class="handle ${this.pressed ? 'active' : ''}" |
| 123 | + @mousedown=${this.press} |
| 124 | + @mouseup=${this.release} |
| 125 | + /> |
| 126 | + </g> |
| 127 | +
|
| 128 | + <!-- Counter Clockwise Arrow --> |
| 129 | + <path |
| 130 | + d="m21 44.5c-5.17-1.78-7.55-5.53-6.6-11.2 0.0662-0.327 0.107-0.938 0.272-1.06 0.204-0.137 0.312-0.116 0.39-0.1 0.0775 0.0152 0.139 0.0274 0.189 0.102 0.846 3.81 3.13 6.84 6.57 7.59 0.304-0.787 0.461-3.32 0.826-3.24 0.428 0.0848 4.31 5.73 4.93 6.65-0.978 0.839-6.07 4.44-6.95 4.28 0 0 0.206-2.19 0.362-2.96z" |
| 131 | + fill="#b3b3b3" |
| 132 | + stroke="#000" |
| 133 | + stroke-width=".0625px" |
| 134 | + class="arrow" |
| 135 | + @click=${this.counterClockwiseClick} |
| 136 | + /> |
| 137 | +
|
| 138 | + <!-- Clockwise Arrow --> |
| 139 | + <path |
| 140 | + d="m21.2 12.1c-5.17 1.78-7.55 5.53-6.6 11.2 0.0662 0.327 0.107 0.938 0.272 1.06 0.204 0.137 0.312 0.116 0.39 0.1 0.0775-0.0152 0.139-0.0274 0.189-0.102 0.846-3.81 3.13-6.84 6.57-7.59 0.304 0.787 0.461 3.32 0.826 3.24 0.428-0.0848 4.31-5.73 4.93-6.65-0.978-0.839-6.07-4.44-6.95-4.28 0 0 0.206 2.19 0.362 2.96z" |
| 141 | + fill="#b3b3b3" |
| 142 | + stroke="#022" |
| 143 | + stroke-width=".0625px" |
| 144 | + class="arrow" |
| 145 | + @click=${this.clockwiseClick} |
| 146 | + /> |
| 147 | + </g> |
| 148 | + </g> |
| 149 | +
|
| 150 | + <!-- Chip Pins --> |
| 151 | + <rect |
| 152 | + x="83" |
| 153 | + y="1.72" |
| 154 | + width="10.9" |
| 155 | + height="49.2" |
| 156 | + fill="url(#a)" |
| 157 | + fill-rule="evenodd" |
| 158 | + opacity=".65" |
| 159 | + stroke="#fff" |
| 160 | + stroke-width="1.16" |
| 161 | + /> |
| 162 | + <g fill="#ccc" fill-rule="evenodd"> |
| 163 | + <rect x="86.9" y="6.54" width="28.9" height="2.47" rx=".877" /> |
| 164 | + <rect x="86.8" y="15.9" width="28.9" height="2.47" rx=".877" /> |
| 165 | + <rect x="87.1" y="25.6" width="28.9" height="2.47" rx=".877" /> |
| 166 | + <rect x="87.1" y="34.9" width="28.9" height="2.47" rx=".877" /> |
| 167 | + <rect x="87.6" y="44.1" width="28.9" height="2.47" rx=".877" /> |
| 168 | + </g> |
| 169 | + <g fill="#ffffff" font-family="sans-serif" letter-spacing="0px" word-spacing="0px"> |
| 170 | + <text x="65.55" y="12.13" font-size="7.29px" fill="#ffffff" stroke-width=".182">CLK</text> |
| 171 | + <text x="65.02" y="21.93" font-size="7.44px" fill="#ffffff">DT</text> |
| 172 | + <text x="65.29" y="31.26" font-size="7.54px" fill="#ffffff">SW</text> |
| 173 | + <text x="70.42" y="39.99" font-size="6.82px" fill="#ffffff">+</text> |
| 174 | + <text x="64.31" y="49.74" font-size="7.59px" fill="#ffffff">GND</text> |
| 175 | + </g> |
| 176 | + </svg> |
| 177 | + `; |
| 178 | + } |
| 179 | + |
| 180 | + private clockwiseClick() { |
| 181 | + this.angle = (this.angle + this.stepSize) % 360; |
| 182 | + this.dispatchEvent(new InputEvent('rotate-cw')); |
| 183 | + } |
| 184 | + |
| 185 | + private counterClockwiseClick() { |
| 186 | + this.angle = (this.angle - this.stepSize + 360) % 360; |
| 187 | + this.dispatchEvent(new InputEvent('rotate-ccw')); |
| 188 | + } |
| 189 | + |
| 190 | + private press() { |
| 191 | + if (!this.pressed) { |
| 192 | + this.dispatchEvent(new InputEvent('button-press')); |
| 193 | + this.pressed = true; |
| 194 | + } |
| 195 | + } |
| 196 | + |
| 197 | + private release() { |
| 198 | + this.dispatchEvent(new InputEvent('button-release')); |
| 199 | + this.pressed = false; |
| 200 | + } |
| 201 | + |
| 202 | + private keydown(e: KeyboardEvent) { |
| 203 | + switch (e.key) { |
| 204 | + case 'ArrowUp': |
| 205 | + case 'ArrowRight': |
| 206 | + this.clockwiseClick(); |
| 207 | + e.preventDefault(); |
| 208 | + break; |
| 209 | + |
| 210 | + case 'ArrowDown': |
| 211 | + case 'ArrowLeft': |
| 212 | + this.counterClockwiseClick(); |
| 213 | + e.preventDefault(); |
| 214 | + break; |
| 215 | + |
| 216 | + case ' ': |
| 217 | + this.press(); |
| 218 | + e.preventDefault(); |
| 219 | + break; |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + private keyup(e: KeyboardEvent) { |
| 224 | + switch (e.key) { |
| 225 | + case ' ': |
| 226 | + e.preventDefault(); |
| 227 | + this.release(); |
| 228 | + break; |
| 229 | + } |
| 230 | + } |
| 231 | +} |
0 commit comments