// LED array component for the LogicSimulator // Copyright (C) 2022 Sascha Nitsch // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see . interface LEDArrayParam extends BaseComponentParam { color: string; count: number; direction: number; padding?: number; } // eslint-disable-next-line @typescript-eslint/no-unused-vars class LEDArray extends BaseComponent { private color: string; private count: number; private direction: number; private padding: number; private onColor: string; private offColor: string; private a: Array = []; private b: Array = []; private elements: SVGElement[] = []; constructor(simulator: Simulator, id: string, param: LEDArrayParam) { super(simulator, id, param); this.color = param.color; this.count = param.count; this.direction = param.direction; this.padding = param.padding ? param.padding : 20; switch (this.color) { case 'red': this.onColor = 'ffb9b9'; this.offColor = '990000'; break; default: this.onColor = 'ffffff'; this.offColor = '000000'; } let x = this.x; let y = this.y; for (let i = 0; i < this.count; ++i) { this.pins.set('a' + i, new TriState(this, x, y)); this.pins.set('b' + i, new TriState(this, x, y)); // move next element in given direction switch (this.direction) { case 8: // up y += this.padding; break; case 6: // right x += this.padding; break; case 2: // down y -= this.padding; break; case 4: // left x -= this.padding; break; } this.a[i] = null; this.b[i] = null; } } addGradient(canvas: SVGElement, type: string, color1: string, color2: string) { const grad = document.createElementNS('http://www.w3.org/2000/svg', 'radialGradient'); grad.id = 'radialGradient' + type + this.color; let stop = document.createElementNS('http://www.w3.org/2000/svg', 'stop'); stop.setAttribute('offset', '0.4'); stop.setAttribute('style', 'stop-color:#' + color1 + ';stop-opacity:1'); grad.appendChild(stop); stop = document.createElementNS('http://www.w3.org/2000/svg', 'stop'); stop.setAttribute('offset', '1'); stop.setAttribute('style', 'stop-color:#' + color2 + ';stop-opacity:1'); grad.appendChild(stop); canvas.appendChild(grad); } setup(parent: SVGElement) { super.doSetup('ledarray', parent); // color already registered? const canvas = parent.ownerSVGElement; if (canvas === null || this.element === null) return; const c = canvas.getElementById('radialGradientOff' + this.color); if (c === null) { this.addGradient(canvas, 'Off', this.offColor, this.offColor); this.addGradient(canvas, 'On', this.onColor, this.offColor); } const e = []; for (let i = 0; i < this.count; ++i) { super.doSetup('ledarray', canvas); e[i] = this.element; e[i].setAttribute('style', 'fill:url(#radialGradientOff' + this.color + ')'); // move next element in given direction switch (this.direction) { case 8: // up this.y += this.padding; break; case 6: // right this.x += this.padding; break; case 2: // down this.y -= this.padding; break; case 4: // left this.x -= this.padding; break; } } this.elements = e; } io() { for (let i = 0; i < this.count; ++i) { this.a[i] = this.tri(this.getPin('a' + i).getAndReset()); this.b[i] = this.tri(this.getPin('b' + i).getAndReset()); } } update(): boolean { for (let i = 0; i < this.count; ++i) { if (this.a[i] !== this.b[i] && this.a[i] !== null && this.b[i] !== null) { this.elements[i].setAttribute('style', 'fill:url(#radialGradientOn' + this.color + ')'); } else { this.elements[i].setAttribute('style', 'fill:url(#radialGradientOff' + this.color + ')'); } } return false; } }