@jbrowse/core
Version:
JBrowse 2 core libraries used by plugins
116 lines (115 loc) • 3.82 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
class SceneGraph {
constructor(name, left, top, width, height, data) {
this.name = name;
this.left = left;
this.top = top;
this.width = width;
this.height = height;
this.data = data;
this.children = new Map();
this.absoluteCache = { dirty: true };
}
addChild(nameOrSceneGraph, left, top, width, height, data) {
const child = nameOrSceneGraph instanceof SceneGraph
? nameOrSceneGraph
: new SceneGraph(nameOrSceneGraph, left, top, width, height, data);
if (!(child instanceof SceneGraph)) {
throw new TypeError('argument to addChild must be an array or a SceneGraph');
}
if (this.children.has(child.name)) {
throw new Error(`child named "${child.name}" already exists`);
}
child.parent = this;
const { left: childLeft, right: childRight, top: childTop, bottom: childBottom, } = child.absolute;
if (childLeft !== undefined &&
childRight !== undefined &&
childTop !== undefined &&
childBottom !== undefined) {
this.expand(childLeft, childRight, childTop, childBottom);
this.children.set(child.name, child);
}
return child;
}
getSubRecord(name) {
return this.children.get(name);
}
expand(newLeft, newRight, newTop, newBottom) {
const { left, right, top, bottom } = this.absolute;
if (left !== undefined && newLeft < left) {
const diff = left - newLeft;
this.width += diff;
this.left -= diff;
}
if (right !== undefined && newRight > right) {
this.width += newRight - right;
}
if (top !== undefined && newTop < top) {
const diff = top - newTop;
this.height += diff;
this.top -= diff;
}
if (bottom !== undefined && newBottom > bottom) {
this.height += newBottom - bottom;
}
if (this.parent) {
this.parent.expand(newLeft, newRight, newTop, newBottom);
}
this.absoluteCache.dirty = true;
}
get bottom() {
return this.top + this.height;
}
get right() {
return this.left + this.width;
}
walkParents(callback) {
if (this.parent) {
callback(this.parent);
this.parent.walkParents(callback);
}
}
walkChildren(callback) {
for (const sub of this.children.values()) {
callback(sub);
sub.walkChildren(callback);
}
}
get absolute() {
if (this.absoluteCache.dirty) {
let xOffset = 0;
let yOffset = 0;
this.walkParents((node) => {
xOffset += node.left;
yOffset += node.top;
});
this.absoluteCache = {
dirty: false,
left: this.left + xOffset,
right: this.right + xOffset,
top: this.top + yOffset,
bottom: this.bottom + yOffset,
width: this.width,
height: this.height,
};
}
return this.absoluteCache;
}
move(x, y) {
this.left += x;
this.top += y;
this.absoluteCache.dirty = true;
this.walkChildren(c => {
c.absoluteCache.dirty = true;
});
const { left, right, top, bottom } = this.absolute;
if (left !== undefined &&
right !== undefined &&
top !== undefined &&
bottom !== undefined) {
this.expand(left, right, top, bottom);
}
}
}
exports.default = SceneGraph;