From ceb957b0248e6a4bd39e680380710ba2108b505d Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Mon, 2 Apr 2018 15:37:23 -0700 Subject: [PATCH 1/3] Fixing default value for RGB --- libs/core/rgb.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/core/rgb.ts b/libs/core/rgb.ts index c629791..e52e77f 100644 --- a/libs/core/rgb.ts +++ b/libs/core/rgb.ts @@ -33,7 +33,7 @@ namespace rgb { /** * Make the on-board RGB LED show an RGB color (range 0-255 for r, g, b). - * @param rgb RGB color of the LED, eg: Colors.Red + * @param rgb RGB color of the LED, eg: 0xff0000 */ //% blockId="rgb_set_color" block="set rgb to %rgb=colorNumberPicker" //% weight=90 help="rgb/set-color" From 3650ce6f4113ed219985b3867fb547284d946766 Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Thu, 7 Mar 2019 17:20:41 -0800 Subject: [PATCH 2/3] First pass at RGB sticker support --- sim/ltcboard.ts | 3 ++ sim/state/rgb.ts | 67 ++++++++++++++++++++++++++ sim/visuals/ltc.ts | 53 ++++++++++++++------- sim/visuals/rgbsticker.ts | 99 +++++++++++++++++++++++++++++++++++++++ sim/visuals/rgbsvg.ts | 3 ++ 5 files changed, 209 insertions(+), 16 deletions(-) create mode 100644 sim/visuals/rgbsticker.ts create mode 100644 sim/visuals/rgbsvg.ts diff --git a/sim/ltcboard.ts b/sim/ltcboard.ts index 9806698..3b1ca52 100644 --- a/sim/ltcboard.ts +++ b/sim/ltcboard.ts @@ -60,6 +60,7 @@ namespace pxsim { serialState: LtcSerialState; // TODO: not singletons neopixelState: NeoPixelState; + rgbStickerState: RGBStickerState; constructor() { super() @@ -94,6 +95,8 @@ namespace pxsim { this.builtinPartVisuals["buttonpair"] = (xy: visuals.Coord) => visuals.mkBtnSvg(xy); this.builtinPartVisuals["neopixel"] = (xy: visuals.Coord) => visuals.mkNeoPixelPart(xy); + + this.rgbStickerState = new RGBStickerState(); } receiveMessage(msg: SimulatorMessage) { diff --git a/sim/state/rgb.ts b/sim/state/rgb.ts index 5b7ae88..9681dd7 100644 --- a/sim/state/rgb.ts +++ b/sim/state/rgb.ts @@ -10,4 +10,71 @@ namespace pxsim.rgb { led.updateBuffer(newColor, 0); runtime.queueDisplayUpdate(); } + + export function setRGBStickerLed(name: number, index: number, r: number, g: number, b: number): void { + const state = board().rgbStickerState; + state.setLED(name, index, r, g, b); + runtime.queueDisplayUpdate(); + } +} + +namespace pxsim { + export class RGBStickerState { + protected buffers: Uint8Array[] = []; + protected colors: Map = {}; + protected dirty: Map = {}; + + public setLED(pin: number, index: number, r: number, g: number, b: number) { + let buf = this.buffers[pin]; + + if (!buf) buf = new Uint8Array(60); + + const start = index * 3; + + buf[start] = g; + buf[start + 1] = r; + buf[start + 2] = b; + + this.updateBuffer(buf, pin); + } + + public getColors(pin: number): RGBW[] { + let outColors = this.colors[pin] || (this.colors[pin] = []); + if (this.dirty[pin]) { + let buf = this.buffers[pin] || (this.buffers[pin] = new Uint8Array([])); + this.readNeoPixelBuffer(buf, outColors, NeoPixelMode.RGB); + this.dirty[pin] = false; + } + return outColors; + } + + usedPins(): number[] { + const names: number[] = []; + this.buffers.filter((buf, index) => { + if (buf) names.push(index); + }) + return names; + } + + protected updateBuffer(buffer: Uint8Array, pin: number) { + this.buffers[pin] = buffer; + this.dirty[pin] = true; + } + + private readNeoPixelBuffer(inBuffer: Uint8Array, outColors: RGBW[], mode: NeoPixelMode) { + let buf = inBuffer; + let stride = mode === NeoPixelMode.RGBW ? 4 : 3; + let pixelCount = Math.floor(buf.length / stride); + for (let i = 0; i < pixelCount; i++) { + // NOTE: for whatever reason, NeoPixels pack GRB not RGB + let r = buf[i * stride + 1] + let g = buf[i * stride + 0] + let b = buf[i * stride + 2] + let w = 0; + if (stride === 4) + w = buf[i * stride + 3] + outColors[i] = [r, g, b, w] + } + } + } } \ No newline at end of file diff --git a/sim/visuals/ltc.ts b/sim/visuals/ltc.ts index f9211e8..b4fb5ba 100644 --- a/sim/visuals/ltc.ts +++ b/sim/visuals/ltc.ts @@ -243,31 +243,15 @@ namespace pxsim.visuals { private style: SVGStyleElement; private defs: SVGDefsElement; private g: SVGGElement; - - private logos: SVGElement[]; - private head: SVGGElement; private headInitialized = false; - private headText: SVGTextElement; - private display: SVGElement; - private buttons: SVGElement[]; - private buttonsOuter: SVGElement[]; - private buttonABText: SVGTextElement; private pins: SVGElement[]; - private pinLabels: SVGElement[]; private pinGradients: SVGLinearGradientElement[]; private pinTexts: SVGTextElement[]; - private ledsOuter: SVGElement[]; private leds: SVGRectElement[]; private rgbLed: SVGCircleElement; private systemLed: SVGCircleElement; - private antenna: SVGPolylineElement; - private lightLevelButton: SVGCircleElement; - private lightLevelGradient: SVGLinearGradientElement; - private lightLevelText: SVGTextElement; private thermometerGradient: SVGLinearGradientElement; private thermometer: SVGRectElement; private thermometerText: SVGTextElement; - private shakeButton: SVGCircleElement; - private shakeText: SVGTextElement; public board: pxsim.LtcBoard; private pinNmToCoord: Map = {}; @@ -277,6 +261,8 @@ namespace pxsim.visuals { private scopeTextNode2: SVGTextElement; private scopeTextNode3: SVGTextElement; + private ledStickers: RGBSticker[]; + constructor(public props: IBoardProps) { this.recordPinCoords(); this.buildDom(); @@ -345,6 +331,7 @@ namespace pxsim.visuals { this.updateTemperature(); this.updateRgbLed(); this.updateSerial(); + this.updateRGBStickers(); if (!runtime || runtime.dead) svg.addClass(this.element, "grayscale"); else svg.removeClass(this.element, "grayscale"); @@ -494,6 +481,34 @@ namespace pxsim.visuals { } } + private updateRGBStickers() { + const state = this.board.rgbStickerState; + state.usedPins().forEach(pin => { + let sticker = this.ledStickers[pin]; + if (!sticker) { + sticker = (this.ledStickers[pin] = new RGBSticker()); + this.g.appendChild(sticker.getSVG()); + svg.hydrate(this.element, { + "version": "1.0", + "viewBox": `0 0 230 250`, + "class": "sim", + "x": "112.5px", + "y": "0px", + "width": "100%", + "height": "100%" + }); + + sticker.moveTo(50, 140); + this.g.appendChild(sticker.createDataPath([20 + 24 * (pin + 1), 110])); + } + const colors = state.getColors(pin); + for (let i = 0; i < colors.length; i++) { + const color = colors[i]; + sticker.setLED(i, color) + } + }); + } + private updateSerial() { let state = this.board; if (!state || !state.serialState) return; @@ -663,6 +678,10 @@ namespace pxsim.visuals { svg.child(neopixelmerge, "feMergeNode", { in: "coloredBlur" }) svg.child(neopixelmerge, "feMergeNode", { in: "SourceGraphic" }) + let smallerNeopixelGlow = svg.child(this.defs, "filter", { id: "smallneopixelglow", x: "-200%", y: "-200%", width: "400%", height: "400%" }); + svg.child(smallerNeopixelGlow, "feGaussianBlur", { stdDeviation: "2", result: "coloredBlur" }); + smallerNeopixelGlow.appendChild(neopixelmerge.cloneNode(true)); + let ledglow = svg.child(this.defs, "filter", { id: "ledglow", x: "-200%", y: "-200%", width: "400%", height: "400%" }); svg.child(ledglow, "feGaussianBlur", { stdDeviation: "3", result: "coloredBlur" }); let ledglowmerge = svg.child(ledglow, "feMerge", {}); @@ -707,6 +726,8 @@ namespace pxsim.visuals { 133, 157 ].map(x => svg.child(this.g, "text", { class: "sim-text-pin no-drag", x: x + 7, y: 125, textAnchor: "middle" })); + + this.ledStickers = []; } private attachEvents() { diff --git a/sim/visuals/rgbsticker.ts b/sim/visuals/rgbsticker.ts new file mode 100644 index 0000000..0914d7a --- /dev/null +++ b/sim/visuals/rgbsticker.ts @@ -0,0 +1,99 @@ +namespace pxsim.visuals { + export class RGBSticker { + protected root: SVGSVGElement; + protected leds: SVGCircleElement[]; + + protected left: number; + protected top: number; + + constructor() { + this.root = pxsim.svg.parseString(RGB_STICKER_SVG); + this.leds = toArray(this.root.getElementsByTagName("circle")).reverse(); + } + + getSVG() { + return this.root; + } + + setLED(index: number, color: [number, number, number]) { + if (index >= this.leds.length) return; + const led = this.leds[index]; + + let hsl = visuals.rgbToHsl(color); + let [h, s, l] = hsl; + let lx = Math.max(l * 1.3, 85); + // at least 10% luminosity + l = l * 90 / 100 + 10; + led.style.stroke = `hsl(${h}, ${s}%, ${Math.min(l * 3, 75)}%)` + led.style.strokeWidth = "1.5"; + svg.fill(led, `hsl(${h}, ${s}%, ${lx}%)`) + svg.filter(led, `url(#smallneopixelglow)`); + } + + moveTo(left: number, top: number) { + this.root.setAttribute("x", left + ""); + this.root.setAttribute("y", top + ""); + this.left = left; + this.top = top; + } + + groundLocation(): [number, number] { + return [(this.left || 0) + 100, (this.top | 0) + 50]; + } + + powerLocation(): [number, number] { + return [(this.left || 0) + 100, (this.top | 0) + 20]; + } + + dataLocation(): [number, number] { + return [(this.left || 0) + 5, (this.top | 0) + 20]; + } + + createDataPath(pinLocation: [number, number]) { + const end = this.dataLocation(); + const bendY = pinLocation[1] + ((this.top - pinLocation[1]) / 2); + const path: [number, number][] = [ + pinLocation, + [pinLocation[0], bendY], + [this.left - 20, bendY], + [this.left - 20, end[1]], + end + ]; + return createCopperTapePath(path); + } + } + + export function createCopperTapePath(points: [number, number][]) { + const p: SVGPathElement = svg.elt("path") as SVGPathElement; + let d = `M ${points[0][0]} ${points[0][1]}` + for (let i = 1; i < points.length; i++) { + d += ` L ${points[i][0]} ${points[i][1]}` + } + // d += " z"; + + p.setAttribute("d", d); + p.setAttribute("stroke-width", "5px"); + p.setAttribute("stroke", "#ffd42a"); + p.setAttribute("fill", "none"); + + return p; + } + + function toArray(c: NodeListOf): U[] { + const res: U[] = []; + + for (let i = 0; i < c.length; i++) { + res.push(c.item(i)); + } + + return res; + } + + function translateX(point: [number, number], value: number): [number, number] { + return [point[0] + value, point[1]]; + } + + function translateY(point: [number, number], value: number): [number, number] { + return [point[0], point[1] + value]; + } +} \ No newline at end of file diff --git a/sim/visuals/rgbsvg.ts b/sim/visuals/rgbsvg.ts new file mode 100644 index 0000000..5144241 --- /dev/null +++ b/sim/visuals/rgbsvg.ts @@ -0,0 +1,3 @@ +namespace pxsim.visuals { + export const RGB_STICKER_SVG = `` +} \ No newline at end of file From 55053cdbc71506278a361486cf17971c4031bf91 Mon Sep 17 00:00:00 2001 From: Richard Knoll Date: Fri, 8 Mar 2019 15:05:06 -0800 Subject: [PATCH 3/3] More RGB SVG work --- libs/core/rgb.cpp | 15 +++ libs/core/rgb.ts | 20 ++++ libs/core/shims.d.ts | 11 +++ sim/state/rgb.ts | 9 +- sim/visuals/ltc.ts | 18 ++-- sim/visuals/rgb_single.svg | 1 + sim/visuals/rgbsticker.ts | 184 +++++++++++++++++++++++++++++-------- sim/visuals/rgbsvg.ts | 2 +- 8 files changed, 209 insertions(+), 51 deletions(-) create mode 100644 sim/visuals/rgb_single.svg diff --git a/libs/core/rgb.cpp b/libs/core/rgb.cpp index af9ba8b..e774ce3 100644 --- a/libs/core/rgb.cpp +++ b/libs/core/rgb.cpp @@ -34,4 +34,19 @@ namespace rgb { pixels[0].b = b; ledShow(LED_BUILTIN_RGB, pixels, 1); } + + /** + * Sets an RGB sticker led to a specific red, green, blue color. + * @param name the pin name + * @param index the lef index + * @param red the red color + * @param green the green color + * @param blue the blue color + */ + //% parts="rgbled" + void setRGBStickerLed(int name, int index, int r, int g, int b) { + if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) { + return; + } + } } \ No newline at end of file diff --git a/libs/core/rgb.ts b/libs/core/rgb.ts index e52e77f..86b3dc9 100644 --- a/libs/core/rgb.ts +++ b/libs/core/rgb.ts @@ -116,6 +116,26 @@ namespace rgb { return rgb(255 - wheelPos * 3, wheelPos * 3, 255); } + + /** + * Make an RGB sticker LED show an RGB color (range 0-255 for r, g, b). + * @param rgb RGB color of the LED, eg: 0xff0000 + */ + //% blockId="rgb_sticker_set_color" block="set rgb sticker on %pin| with index %index| to %rgb=colorNumberPicker" + //% weight=90 help="rgb/set-color" + export function setStickerColor(pin: DigitalPin, index: number, rgb: number) { + if (_brightness == undefined) { + _brightness = 20; + } + + rgb = fade(rgb, _brightness); + let red = unpackR(rgb); + let green = unpackG(rgb); + let blue = unpackB(rgb); + + setRGBStickerLed(pin, index, red, green, blue); + } + /** * Get the RGB value of a known color */ diff --git a/libs/core/shims.d.ts b/libs/core/shims.d.ts index b906f15..5ee964d 100644 --- a/libs/core/shims.d.ts +++ b/libs/core/shims.d.ts @@ -107,6 +107,17 @@ declare namespace rgb { */ //% parts="rgbled" shim=rgb::setRGBLed function setRGBLed(r: int32, g: int32, b: int32): void; + + /** + * Sets an RGB sticker led to a specific red, green, blue color. + * @param name the pin name + * @param index the lef index + * @param red the red color + * @param green the green color + * @param blue the blue color + */ + //% parts="rgbled" shim=rgb::setRGBStickerLed + function setRGBStickerLed(name: int32, index: int32, r: int32, g: int32, b: int32): void; } // Auto-generated. Do not edit. Really. diff --git a/sim/state/rgb.ts b/sim/state/rgb.ts index 9681dd7..18d595a 100644 --- a/sim/state/rgb.ts +++ b/sim/state/rgb.ts @@ -21,6 +21,7 @@ namespace pxsim.rgb { namespace pxsim { export class RGBStickerState { protected buffers: Uint8Array[] = []; + protected lengths: number[] = []; protected colors: Map = {}; protected dirty: Map = {}; @@ -35,6 +36,8 @@ namespace pxsim { buf[start + 1] = r; buf[start + 2] = b; + this.lengths[pin] = Math.max(this.lengths[pin] || 0, index + 1); + this.updateBuffer(buf, pin); } @@ -42,7 +45,7 @@ namespace pxsim { let outColors = this.colors[pin] || (this.colors[pin] = []); if (this.dirty[pin]) { let buf = this.buffers[pin] || (this.buffers[pin] = new Uint8Array([])); - this.readNeoPixelBuffer(buf, outColors, NeoPixelMode.RGB); + this.readNeoPixelBuffer(buf, outColors, NeoPixelMode.RGB, this.lengths[pin]); this.dirty[pin] = false; } return outColors; @@ -61,10 +64,10 @@ namespace pxsim { this.dirty[pin] = true; } - private readNeoPixelBuffer(inBuffer: Uint8Array, outColors: RGBW[], mode: NeoPixelMode) { + private readNeoPixelBuffer(inBuffer: Uint8Array, outColors: RGBW[], mode: NeoPixelMode, pixelCount = 0) { let buf = inBuffer; let stride = mode === NeoPixelMode.RGBW ? 4 : 3; - let pixelCount = Math.floor(buf.length / stride); + pixelCount = pixelCount || Math.floor(buf.length / stride); for (let i = 0; i < pixelCount; i++) { // NOTE: for whatever reason, NeoPixels pack GRB not RGB let r = buf[i * stride + 1] diff --git a/sim/visuals/ltc.ts b/sim/visuals/ltc.ts index b4fb5ba..c1ad160 100644 --- a/sim/visuals/ltc.ts +++ b/sim/visuals/ltc.ts @@ -261,7 +261,7 @@ namespace pxsim.visuals { private scopeTextNode2: SVGTextElement; private scopeTextNode3: SVGTextElement; - private ledStickers: RGBSticker[]; + private ledStickers: RGBStickerStrip[]; constructor(public props: IBoardProps) { this.recordPinCoords(); @@ -484,10 +484,10 @@ namespace pxsim.visuals { private updateRGBStickers() { const state = this.board.rgbStickerState; state.usedPins().forEach(pin => { - let sticker = this.ledStickers[pin]; - if (!sticker) { - sticker = (this.ledStickers[pin] = new RGBSticker()); - this.g.appendChild(sticker.getSVG()); + let rgbStrip = this.ledStickers[pin]; + if (!rgbStrip) { + rgbStrip = (this.ledStickers[pin] = new RGBStickerStrip()); + this.g.appendChild(rgbStrip.getSVG()); svg.hydrate(this.element, { "version": "1.0", "viewBox": `0 0 230 250`, @@ -498,13 +498,15 @@ namespace pxsim.visuals { "height": "100%" }); - sticker.moveTo(50, 140); - this.g.appendChild(sticker.createDataPath([20 + 24 * (pin + 1), 110])); + rgbStrip.moveTo(45, 140); + rgbStrip.setDataPinLocation([20 + 24 * (pin + 1), 110]) + rgbStrip.setGroundPinLocation([20, 110]) + rgbStrip.setPowerPinLocation([208, 110]) } const colors = state.getColors(pin); for (let i = 0; i < colors.length; i++) { const color = colors[i]; - sticker.setLED(i, color) + rgbStrip.setLED(i, color) } }); } diff --git a/sim/visuals/rgb_single.svg b/sim/visuals/rgb_single.svg new file mode 100644 index 0000000..cfb097c --- /dev/null +++ b/sim/visuals/rgb_single.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/sim/visuals/rgbsticker.ts b/sim/visuals/rgbsticker.ts index 0914d7a..394cffd 100644 --- a/sim/visuals/rgbsticker.ts +++ b/sim/visuals/rgbsticker.ts @@ -1,33 +1,31 @@ namespace pxsim.visuals { export class RGBSticker { protected root: SVGSVGElement; - protected leds: SVGCircleElement[]; + protected led: SVGCircleElement; protected left: number; protected top: number; constructor() { this.root = pxsim.svg.parseString(RGB_STICKER_SVG); - this.leds = toArray(this.root.getElementsByTagName("circle")).reverse(); + this.led = this.root.getElementsByTagName("circle").item(0); } getSVG() { return this.root; } - setLED(index: number, color: [number, number, number]) { - if (index >= this.leds.length) return; - const led = this.leds[index]; + setLED(color: [number, number, number]) { let hsl = visuals.rgbToHsl(color); let [h, s, l] = hsl; let lx = Math.max(l * 1.3, 85); // at least 10% luminosity l = l * 90 / 100 + 10; - led.style.stroke = `hsl(${h}, ${s}%, ${Math.min(l * 3, 75)}%)` - led.style.strokeWidth = "1.5"; - svg.fill(led, `hsl(${h}, ${s}%, ${lx}%)`) - svg.filter(led, `url(#smallneopixelglow)`); + this.led.style.stroke = `hsl(${h}, ${s}%, ${Math.min(l * 3, 75)}%)` + this.led.style.strokeWidth = "1.5"; + svg.fill(this.led, `hsl(${h}, ${s}%, ${lx}%)`) + svg.filter(this.led, `url(#smallneopixelglow)`); } moveTo(left: number, top: number) { @@ -36,40 +34,166 @@ namespace pxsim.visuals { this.left = left; this.top = top; } + } + + export class RGBStickerStrip { + protected stickers: RGBSticker[]; + protected root: SVGGElement; + + protected wireRoot: SVGGElement; + protected stickerRoot: SVGGElement; + + protected groundWire: SVGPathElement; + protected dataWire: SVGPathElement; + protected powerWire: SVGPathElement; + + protected left: number; + protected top: number; + + protected bottomSticker: SVGElement; + protected dataSourceLocation: [number, number]; + protected groundSourceLocation: [number, number]; + protected powerSourceLocation: [number, number]; + + get right() { + return (this.left || 0) + this.stickers.length * 25; + } + + constructor() { + this.stickers = []; + + this.root = svg.elt("g") as SVGGElement; + this.stickerRoot = svg.child(this.root, "g") as SVGGElement; + this.wireRoot = svg.child(this.root, "g") as SVGGElement; + } + + moveTo(left: number, top: number) { + this.left = left; + this.top = top; + + this.updateTransform(); + } + + getSVG() { + return this.root; + } + + setLED(index: number, color: [number, number, number]) { + let didGrow = false; + while (this.stickers.length < index + 1) { + const newSticker = new RGBSticker(); + this.stickerRoot.insertBefore(newSticker.getSVG(), this.bottomSticker); + newSticker.moveTo(25 * this.stickers.length, 0); + this.stickers.push(newSticker); + this.bottomSticker = newSticker.getSVG(); + didGrow = true; + } + + if (didGrow) { + this.updateAllPaths(); + } + + this.stickers[index].setLED(color); + } groundLocation(): [number, number] { - return [(this.left || 0) + 100, (this.top | 0) + 50]; + // The end of the ground copper tape path + return [this.right - 10, (this.top | 0) + 55]; } powerLocation(): [number, number] { - return [(this.left || 0) + 100, (this.top | 0) + 20]; + // The end of the power copper tape path + return [this.left + 5, (this.top | 0) + 35]; } dataLocation(): [number, number] { - return [(this.left || 0) + 5, (this.top | 0) + 20]; + // The end of the data copper tape path + return [this.right, (this.top | 0) + 20]; + } + + setDataPinLocation(point: [number, number]) { + this.dataSourceLocation = point; + this.updateDataPath(); + } + + setGroundPinLocation(point: [number, number]) { + this.groundSourceLocation = point; + this.updateGroundPath(); } - createDataPath(pinLocation: [number, number]) { + setPowerPinLocation(point: [number, number]) { + this.powerSourceLocation = point; + this.updatePowerPath(); + } + + protected updateAllPaths() { + this.updateDataPath(); + this.updateGroundPath(); + this.updatePowerPath(); + } + + protected updateGroundPath() { + if (!this.groundSourceLocation) return; + if (this.groundWire) this.wireRoot.removeChild(this.groundWire); + + const end = this.groundLocation(); + const path: [number, number][] = [ + this.groundSourceLocation, + [this.groundSourceLocation[0], end[1]], + end + ]; + + this.groundWire = createCopperTapePath(path); + this.wireRoot.appendChild(this.groundWire); + } + + protected updateDataPath() { + if (!this.dataSourceLocation) return; + if (this.dataWire) this.wireRoot.removeChild(this.dataWire); + const end = this.dataLocation(); - const bendY = pinLocation[1] + ((this.top - pinLocation[1]) / 2); + const bendY = this.dataSourceLocation[1] + ((this.top - this.dataSourceLocation[1]) / 2); const path: [number, number][] = [ - pinLocation, - [pinLocation[0], bendY], - [this.left - 20, bendY], - [this.left - 20, end[1]], + this.dataSourceLocation, + [this.dataSourceLocation[0], bendY], + [this.left - 10, bendY], + [this.left - 10, end[1]], end ]; - return createCopperTapePath(path); + + this.dataWire = createCopperTapePath(path); + this.wireRoot.appendChild(this.dataWire); + } + + protected updatePowerPath() { + if (!this.powerSourceLocation) return; + if (this.powerWire) this.wireRoot.removeChild(this.powerWire); + + const end = this.powerLocation(); + const bendY = this.powerSourceLocation[1] + ((this.top - this.powerSourceLocation[1]) / 2); + const path: [number, number][] = [ + this.powerSourceLocation, + [this.powerSourceLocation[0], bendY], + [this.right + 20, bendY], + [this.right + 20, end[1]], + end + ]; + + this.powerWire = createCopperTapePath(path); + this.wireRoot.appendChild(this.powerWire); + } + + protected updateTransform() { + this.stickerRoot.setAttribute("transform", `translate(${this.left} ${this.top})`) } } - export function createCopperTapePath(points: [number, number][]) { + function createCopperTapePath(points: [number, number][]) { const p: SVGPathElement = svg.elt("path") as SVGPathElement; let d = `M ${points[0][0]} ${points[0][1]}` for (let i = 1; i < points.length; i++) { d += ` L ${points[i][0]} ${points[i][1]}` } - // d += " z"; p.setAttribute("d", d); p.setAttribute("stroke-width", "5px"); @@ -78,22 +202,4 @@ namespace pxsim.visuals { return p; } - - function toArray(c: NodeListOf): U[] { - const res: U[] = []; - - for (let i = 0; i < c.length; i++) { - res.push(c.item(i)); - } - - return res; - } - - function translateX(point: [number, number], value: number): [number, number] { - return [point[0] + value, point[1]]; - } - - function translateY(point: [number, number], value: number): [number, number] { - return [point[0], point[1] + value]; - } } \ No newline at end of file diff --git a/sim/visuals/rgbsvg.ts b/sim/visuals/rgbsvg.ts index 5144241..7c36b12 100644 --- a/sim/visuals/rgbsvg.ts +++ b/sim/visuals/rgbsvg.ts @@ -1,3 +1,3 @@ namespace pxsim.visuals { - export const RGB_STICKER_SVG = `` + export const RGB_STICKER_SVG = `` } \ No newline at end of file