chart = {
let time_so_far = 0;
const svg = d3.create("svg")
.attr("viewBox", [0, 0, width+40, height+40]);
svg.append("g")
.attr("transform", "translate(" + 20 + "," + 20 + ")");
d3.select("#chart").style("width", (width + 20 + 20) + "px");
const circle = svg.append("g")
.selectAll("circle")
.data(nodes)
.join("circle")
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("fill", d => d.color);
circle.transition()
.delay((d, i) => i * 5)
.duration(800)
.attrTween("r", d => {
const i = d3.interpolate(0, d.r);
return t => d.r = i(t);
});
svg.selectAll('.grp')
.data(d3.keys(groups))
.join("text")
.attr("class", "grp")
.attr("text-anchor", "middle")
.attr("x", d => groups[d].x)
.attr("y", d => groups[d].y - 70)
.text(d => groups[d].fullname);
svg.selectAll('.grpcnt')
.data(d3.keys(groups))
.join("text")
.attr("class", "grpcnt")
.attr("text-anchor", "middle")
.attr("x", d => groups[d].x)
.attr("y", d => groups[d].y - 50)
.text(d => groups[d].cnt);
const simulation = d3.forceSimulation(nodes)
.force("x", d => d3.forceX(d.x))
.force("y", d => d3.forceY(d.y))
.force("cluster", forceCluster())
.force("collide", forceCollide())
.alpha(.09)
.alphaDecay(0);
simulation.on("tick", () => {
circle
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("fill", d => groups[d.group].color);
});
function timer() {
nodes.forEach(function (o, i) {
o.timeleft -= 1;
if (o.timeleft == 0 && o.istage < o.stages.length - 1) {
groups[o.group].cnt -= 1;
o.istage += 1;
o.group = o.stages[o.istage].grp;
o.timeleft = o.stages[o.istage].duration;
groups[o.group].cnt += 1;
}
});
time_so_far += 1;
d3.select("#timecount .cnt").text(time_so_far);
svg.selectAll('.grpcnt').text(d => groups[d].cnt);
d3.timeout(timer, 500);
}
d3.timeout(timer, 2000);
return svg.node()
}