142 lines
4.6 KiB
TypeScript
142 lines
4.6 KiB
TypeScript
// 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 <https://www.gnu.org/licenses/>.
|
|
|
|
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<boolean | null> = [];
|
|
private b: Array<boolean | null> = [];
|
|
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;
|
|
}
|
|
}
|