-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathseventrees.js
122 lines (98 loc) · 3.89 KB
/
seventrees.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
const renderParams = {
r: 7,
marginY: 25,
marginX: 25
}
class TreeControl {
constructor(parent, color) {
this.parent = parent;
this.color = color;
this._tree = leaf();
this.onTreeChange = new CustomEvent('onTreeChange');
}
get tree() { return this._tree; }
set tree(newTree) {
this._tree = newTree;
this.render();
}
render() {
if (this.transform) this.parent.removeChild(this.transform);
this.transform = document.createElementNS("http://www.w3.org/2000/svg", "g");
this.parent.appendChild(this.transform);
let meas = TreeControl.measure(this.tree);
//let dim = this.parent.getBoundingClientRect();
this.transform.setAttribute(
"transform",
`translate(${renderParams.marginX/2},${meas.right + renderParams.marginX}) rotate(270)`
);
this.renderTree(this.tree, '', 0, 0);
this.parent.style.width = `${meas.height + renderParams.marginY}px`;
this.parent.style.height = `${meas.width + 2*renderParams.marginX}px`;
}
renderTree(tree, path, cx, cy) {
if (tree.isLeaf) {
this.renderNode(tree, path, cx, cy);
}
else {
// measure the subtrees
let measl = TreeControl.measure(tree.left);
let cxl = cx - measl.right - renderParams.marginX/2;
let cyl = cy + renderParams.marginY;
let measr = TreeControl.measure(tree.right);
let cxr = cx + measr.left + renderParams.marginX/2;
let cyr = cy + renderParams.marginY;
// render in the right order ... important: lines in the background
this.renderLine(cx, cy, cxl, cyl);
this.renderLine(cx, cy, cxr, cyr);
// then recurse
this.renderTree(tree.left, path + 'l', cxl, cyl);
this.renderTree(tree.right, path + 'r', cxr, cyr);
// then the node
this.renderNode(tree, path, cx, cy);
}
}
renderNode(tree, path, cx, cy) {
let circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("cx", cx.toString());
circle.setAttribute("cy", cy.toString());
circle.setAttribute("r", renderParams.r);
//if (tree.color) {
circle.style.fill = tree.color;
//}
if (tree.isLeaf) {
circle.setAttribute("class", "leaf");
circle.addEventListener("click", () => {
this.tree = bud(this.tree, path, this.color);;
this.parent.dispatchEvent(this.onTreeChange);
});
}
else {
circle.setAttribute("class", "branch");
circle.addEventListener("click", () => {
this.tree = prune(this.tree, path);
this.parent.dispatchEvent(this.onTreeChange);
});
}
this.transform.appendChild(circle);
}
renderLine(x1, y1, x2, y2) {
let line = document.createElementNS("http://www.w3.org/2000/svg", "line");
line.setAttribute("x1", x1.toString());
line.setAttribute("y1", y1.toString());
line.setAttribute("x2", x2.toString());
line.setAttribute("y2", y2.toString());
line.setAttribute("class", "edge");
this.transform.appendChild(line);
}
static measure(tree) {
if (tree.isLeaf) return { left: 0, right: 0, width: 0, height: 0 }
let measLeft = TreeControl.measure(tree.left);
let measRight = TreeControl.measure(tree.right);
return {
left: measLeft.width + renderParams.marginX/2,
right: measRight.width + renderParams.marginX/2,
width: measLeft.width + measRight.width + renderParams.marginX,
height: renderParams.marginY + Math.max(measLeft.height, measRight.height)
}
}
}