ecljs
Version:
electric circuits library
185 lines (184 loc) • 6.29 kB
JavaScript
import { isFn, obj } from 'dabbjs/dist/lib/dab';
import { extend } from 'dabbjs/dist/lib/misc';
import { tCl, attr, tag } from 'dabbjs/dist/lib/dom';
import { ItemBase } from './itemsBase';
//ItemBoard->Wire
export class ItemBoard extends ItemBase {
get onProp() { return this.$.onProp; }
get selected() { return this.$.selected; }
get bonds() { return this.container.itemBonds(this); }
get dir() { return this.$.dir; }
constructor(container, options) {
super(options);
this.container = container;
if (!container)
throw new Error(`missing container`);
//create getter/setters for every property, so type=="size" or "point" don't need to parse always
//and later save it along the .xml file for custom values
this.$.props = obj(this.base.props);
attr(this.g, {
id: this.id,
"svg-comp": this.base.type,
});
this.g.innerHTML = this.base.data;
//this still doesn't work to get all overridable properties ¿?
//properties still cannot access super value
//(<any>this.$).$elected = dab.propDescriptor(this, "selected");
}
select(value) {
if (this.selected != value) {
//set new value
this.$.selected = value;
//add class if selected, otherwise removes it
tCl(this.g, "selected", this.selected);
//trigger property changed if applicable
this.onProp && this.onProp({
id: `#${this.id}`,
code: 3 // "selected" code: 3
});
}
return this;
}
valid(node) { return node >= 0 && node < this.count; }
//this returns true for an EC, and any Wire node and that it is not a start|end bonded node
highlightable(node) { return this.valid(node); }
move(x, y) {
super.move(x, y);
//trigger property changed if applicable
this.onProp && this.onProp({
id: `#${this.id}`,
code: 2 // "move" code: 2
});
return this.refresh();
}
/**
* @description detects a point over a node
* @param p point to check for component node
* @param _ln 1-based line number, for EC it's discarded
*/
over(p, _ln) {
for (let i = 0, len = this.count; i < len; i++) {
let node = this.node(i);
//radius 5 => 5^2 = 25
if ((Math.pow((p.x) - node.x, 2) + Math.pow((p.y) - node.y, 2)) <= ItemBoard.nodeArea)
return i;
}
return -1;
}
/**
* @description refreshes all bonded components to this node
* @param node 0-base node
*/
nodeRefresh(node) {
let bond = this.container.nodeBonds(this, node), p = this.node(node);
p && bond && bond.to.forEach((d) => {
let ic = this.container.get(d.id);
ic && ic.setNode(d.ndx, p);
});
return this;
}
/**
* @description sets node new location. Only works for Wire
* @param _node 0-base node
* @param _p new location
*/
setNode(_node, _p) { return this; }
setOnProp(value) {
isFn(value) && (this.$.onProp = value);
return this;
}
/**
* @description returns true if there's at least one node highlighted.
*/
get isHighlighted() { return this.g.querySelector(`circle[svg-type="node"]`) != null; }
/**
* @description returns highlighted status of a node, or sets it's status
* @param node 0-based node
* @param value undefined: returns Highlighter; true: highlights; false: removes highlight
* @returns Highlighter for get if exists & set to true; otherwise undefined
*/
highlighted(node, value) {
let circleNode = getNode(this.g, node);
if (value === undefined) {
return circleNode != null;
}
if (value === false) {
//remove if exists, otherwise do nothing, it doesn't exists
circleNode && this.g.removeChild(circleNode);
}
else {
if (!this.highlightable(node) || circleNode)
return false;
//value == true, and it doesn't exists, create and return
//some bug, it's not deleted
let pin = this.node(node, true), attributes = {
"svg-type": this.$.hlNode,
cx: pin.x,
cy: pin.y,
r: this.$.hlRadius
};
attributes[this.$.hlNode] = node;
circleNode = tag("circle", "", attributes);
this.g.appendChild(circleNode);
}
return;
}
/**
* @description show/hide all node highlighted
* @param value true shows all nodes highlighted, false removes all highlights
*/
highlight(value) {
for (let node = 0, count = this.count; node < count; node++)
this.highlighted(node, value);
}
/**
* @description removes all highlights except for this node
* @param node 0-base node
*/
highlightThis(node) {
for (let n = 0, count = this.count; n < count; n++)
(n != node)
&& this.highlighted(n, false);
}
/**
* @description refreshes the node highlight position, useful for wire node draggings
* @param node 0-base node
*/
refreshHighlight(node) {
let circleNode = getNode(this.g, node), pin = this.node(node, true);
if (!circleNode)
return false;
attr(circleNode, {
cx: pin.x,
cy: pin.y,
});
return true;
}
/**
* removes this board component from then board
*/
remove() {
this.highlight(false);
super.remove();
}
prop(name) {
return this.$.props[name];
}
/**
* @description returns all custom properties of this component
*/
get props() { return this.$.props; }
defaults() {
return extend(super.defaults(), {
selected: false,
onProp: void 0,
dir: false,
hlNode: "node",
hlRadius: 5
});
}
}
ItemBoard.nodeArea = 81;
function getNode(g, n) {
return g.querySelector(`circle[svg-type="node"][node="${n}"]`);
}