chart = {
const nodes = data.children.sort((a, b) => (a.color > b.color ? 1 : -1));
const simulation = d3
.forceSimulation(nodes)
.force("charge", d3.forceManyBody().strength(100))
.force("manyBody", d3.forceManyBody().strength(30))
.force('x', d3.forceX().strength((0.3 * 100) / width))
.force('y', d3.forceY().strength((0.3 * 100) / height))
.force("center", d3.forceCenter().strength(0.01))
.force('collision', d3.forceCollide().radius(90))
.velocityDecay(.6)
.alphaDecay(1 - Math.pow(0.001, 1 / 600));
const svg = d3
.create("svg")
.attr("width", width)
.attr("height", height)
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr("class", "root");
const main = svg.append("g").attr("class", "main");
svg.on("click", (e, d) => zoomTo(main));
const zoom = d3
.zoom()
.scaleExtent([0.2, 6])
.on("zoom", event => {
const { transform } = event;
main.attr("transform", transform);
});
svg.call(zoom);
const node = main
.selectAll("g")
.data(nodes)
.join("g")
.call(drag(simulation))
.on("click", (event, d) => {
event.stopPropagation();
zoomTo(event, d);
});
node
.append("circle")
.attr('r', "80")
.attr("class", d => {
const depthClass = 'depth0';
const colorClass = d.color;
return `${depthClass} ${colorClass} clickable`;
});
const clusters = node.append('g').each((d, idx, elements) => {
const self = d3.select(elements[idx]);
const pack = drawPacks(self, d, { width: 160, height: 160 });
d.children = pack.children;
d.data = pack.data;
d.depth = 0;
});
node
.append("circle")
.attr('r', "85")
.attr('class', d => {
const colorClass = d.color;
return `outline ${colorClass}`;
});
node
.append("text")
.attr('class', 'text')
.text(d => d.name);
simulation.on("tick", () => {
node.attr("transform", d => `translate(${d.x}, ${d.y})`);
});
svg
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("fill", "red")
.attr("r", 10);
main
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("fill", "Green")
.attr("r", 10);
service.svg = svg;
service.zoom = zoom;
service.clusters = clusters;
service.main = main;
return svg.node();
}