canvas = {
const svg = d3.create("svg").attr("viewBox", [-10, -10, width, height]);
const root = new Node;
const nodes = [root];
const links = [];
tree(root);
let link = svg.append("g")
.attr("fill", "none")
.attr("stroke", "#000")
.selectAll(".link");
let node = svg.append("g")
.attr("stroke", "#fff")
.attr("stroke-width", 2)
.selectAll(".node");
const interval = d3.interval(() => {
if (nodes.length >= 500) return interval.stop();
const parent = nodes[Math.random() * nodes.length | 0];
const child = Object.assign(new Node, {parent, depth: parent.depth + 1});
if (parent.children) parent.children.push(child);
else parent.children = [child];
nodes.push(child);
links.push({source: parent, target: child});
tree(root);
node = node.data(nodes);
node = node.enter().append("circle")
.attr("class", "node")
.attr("r", 4)
.attr("cx", d => d.parent ? d.parent.px : d.px = d.x)
.attr("cy", d => d.parent ? d.parent.py : d.py = d.y)
.merge(node);
link = link.data(links);
link = link.enter().insert("path", ".node")
.attr("class", "link")
.attr("d", d => {
const o = {x: d.source.px, y: d.source.py};
return renderLink({source: o, target: o});
})
.merge(link);
const t = svg.transition()
.duration(duration);
link.transition(t)
.attr("d", renderLink);
node.transition(t)
.attr("cx", d => d.px = d.x)
.attr("cy", d => d.py = d.y);
}, duration);
invalidation.then(() => interval.stop());
return svg.node();
}