{
const w = width;
const h = height*2;
const color = d3.scaleOrdinal(d3.schemeTableau10);
const svg = d3.create("svg").attr("viewBox", [0, 0, w, h]),
link = svg
.selectAll(".link")
.data(graph.links)
.join("line")
.classed("link", true),
node = svg
.selectAll(".node")
.data(graph.nodes)
.join("circle")
.attr("r", 5)
.style("fill", d => color(d.type))
.classed("node", true)
.classed("fixed", d => d.fx !== undefined);
let linkLabel = svg
.selectAll(".link-label")
.data(graph.links)
.join("text")
.text(d => d.type)
.classed('link-label', true)
let nodeLabel = svg
.selectAll(".node-label")
.data(graph.nodes)
.join("text")
.text(d => `${d.id} (${d.type})`)
.classed('node-label', true)
yield svg.node();
const simulation = d3
.forceSimulation()
.nodes(graph.nodes)
.force("charge", d3.forceManyBody().strength(-5))
.force("center", d3.forceCenter(w/2, h/2).strength(0.1))
.force("link", d3.forceLink(graph.links).distance(40))
.on("tick", tick);
const drag = d3
.drag()
.on("start", dragstart)
.on("drag", dragged);
nodeLabel.call(drag).on("click", click);
function tick() {
link
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y);
node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
nodeLabel
.attr("x", d => d.x)
.attr("y", d => d.y);
linkLabel
.attr("x", d => (d.source.x + d.target.x) / 2)
.attr("y", d => (d.source.y + d.target.y) / 2)
}
function click(event, d) {
delete d.fx;
delete d.fy;
simulation.alpha(1).restart();
}
function dragstart() {
}
function dragged(event, d) {
d.fx = clamp(event.x, 0, width);
d.fy = clamp(event.y, 0, height);
simulation.alpha(1).restart();
}
}