chart = {
replay;
const nodes = pack().leaves();
const simulation = d3.forceSimulation(nodes)
.force("x", d3.forceX(width / 2).strength(0.01))
.force("y", d3.forceY(height / 2).strength(0.01))
.force("cluster", forceCluster())
.force("collide", forceCollide());
const svg = d3.select(DOM.svg(width, height));
svg.attr("style","background-image:linear-gradient(darkgray, gray);");
var grads = svg.append("defs").selectAll("radialGradient")
.data(nodes)
.enter()
.append("radialGradient")
.attr("gradientUnits", "objectBoundingBox")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", "100%")
.attr("id", function(d, i) { return "grad" + i; });
grads.append("stop")
.attr("offset", "0%")
.style("stop-color", "white");
grads.append("stop")
.attr("offset", "100%")
.style("stop-color", function(d) { return color(d.data.group); });
const node = svg.append("g")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("style", "drop-shadow(16px 16px 10px black)")
.attr("fill", d => "url(#grad"+ d.index +")")
const text = svg.select("g").selectAll("text.label")
.data(nodes)
.enter().append("svg:text")
.attr("font-family", "Arial, Helvetica, sans-serif")
.attr("class", "label")
.attr("fill", "white")
.attr("font-size", "20px")
.attr("font-weight", "bold")
.attr("pointer-events", "none")
.attr("user-select", "none")
.attr("text-anchor", "middle")
.attr("x", d => d.x)
.attr("y", d => d.y)
.text(d => d.data.name)
svg.selectAll("circle").attr("style", "filter: drop-shadow(16px 16px 16px rgb(0 0 0 / 0.4));");
node.call(drag(simulation));
node.transition()
.delay((d, i) => Math.random() * 500)
.duration(750)
.attrTween("r", d => {
const i = d3.interpolate(0, d.r);
return t => d.r = i(t);
});
simulation.on("tick", () => {
node
.attr("cx", d => d.x)
.attr("cy", d => d.y);
text
.attr("x", d => d.x)
.attr("y", d => d.y);
});
invalidation.then(() => simulation.stop());
return svg.node();
}