logicsimulator/components/ledarray.ts

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;
}
}