chart = {
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.attr("stroke-width", 2);
var simulation = d3.forceSimulation()
.force('link', d3.forceLink(links).strength(.5).distance(20))
.force('charge', d3.forceManyBody())
.force("collide", d3.forceCollide(10))
.force('x', d3.forceX( ).x( d => width/2 ).strength(.05))
.force('y', d3.forceY( ).y( d => height/2 ).strength(.05))
.force('center', d3.forceCenter(width / 2, height / 2));
simulation.nodes(nodes).on('tick', update)
let voronoi = d3.Delaunay
.from(nodes, d => d.x, d => d.y)
.voronoi([0, 0, width, height]);
const mesh = svg.append("path")
.attr("fill", "none")
.attr("d", voronoi.render());
const cell = svg.append("g")
.attr("pointer-events", "all")
.selectAll("path")
.data(nodes)
.join("path")
.style("fill", d=>palette(color(d.group)))
.style("stroke", "#fff")
.style("stroke-width", 2)
.attr("d", (d, i) => voronoi.renderCell(i))
const circle = svg.append("g")
.selectAll("circle")
.data(nodes.filter(d=>(d.name.length>0)))
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.style("text-anchor","middle")
.attr("r", radius)
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended));
function update() {
voronoi = d3.Delaunay.from(nodes, d => d.x, d => d.y).voronoi([0, 0, width, height]);
circle
.attr("cx", d => d.x = Math.max(5, Math.min(width - radius, d.x)))
.attr("cy",d => d.y = Math.max(5, Math.min(height - radius, d.y)));
cell.attr("d", (d, i) => voronoi.renderCell(i));
mesh.attr("d", voronoi.render());
}
function dragstarted(d) {
if (!d3.event.active) simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d) {
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d,i) {
if (!d3.event.active) simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
return svg.node();
}