chart = {
replay;
const height = width;
const links = data.links.map(d => Object.create(d));
const nodes = data.nodes.map(d => Object.create(d));
const simulation = d3.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(-30))
.force("link", d3.forceLink(links).strength(1).distance(20).iterations(10))
.on("tick", ticked);
invalidation.then(() => simulation.stop());
const drag = d3.drag()
.subject(({x, y}) => simulation.find(x - width / 2, y - height / 2, 40))
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended);
const context = DOM.context2d(width, height);
function ticked() {
context.clearRect(0, 0, width, height);
context.save();
context.translate(width / 2, height / 2);
context.beginPath();
for (const d of links) {
context.moveTo(d.source.x, d.source.y);
context.lineTo(d.target.x, d.target.y);
}
context.strokeStyle = "#aaa";
context.stroke();
context.beginPath();
for (const d of nodes) {
context.moveTo(d.x + 3, d.y);
context.arc(d.x, d.y, 3, 0, 2 * Math.PI);
}
context.fill();
context.strokeStyle = "#fff";
context.stroke();
context.restore();
}
function dragstarted(event) {
if (!event.active) simulation.alphaTarget(0.3).restart();
event.subject.fx = event.subject.x;
event.subject.fy = event.subject.y;
}
function dragged(event) {
event.subject.fx = event.x;
event.subject.fy = event.y;
}
function dragended(event) {
if (!event.active) simulation.alphaTarget(0);
event.subject.fx = null;
event.subject.fy = null;
}
return d3.select(context.canvas).call(drag).node();
}