Nested Joins
by IPWright83
HTML
<svg width="800" height="800">
<g class="container" transform="translate(400, 400)"></g>
</svg>
JavaScript
const RADIUS = 50;
const data = [
["circle1", "circle2"],
["circle3", "circle4"],
["circle5", "circle6"],
["circle7", "circle8", "circle9"]
];
render = (data) => {
const join = d3
.select(".container")
.selectAll("g")
.data(data);
// Remove old groups
join
.exit()
.transition()
.duration(500)
.attr("transform", "scale(0)")
.remove();
// Create the new groups
const groups = join
.enter()
.append("g")
.attr("class", "outer");
// Add in the new circles
groups.append("circle")
.attr("r", 0)
.style("fill", "steelblue")
.transition()
.duration(500)
.attr("r", RADIUS);
// Merge the new groups with the existing groups
// and apply an appropriate translation
const innerJoin = groups
.merge(join)
.attr("transform", d => `translate(${d.x},${d.y})`)
.selectAll("circle.inner")
.data(d => d);
// Remove old small circles
innerJoin
.exit()
.transition()
.duration(500)
.attr("r", 0);
const newCircles = innerJoin
.enter()
.append("circle")
.attr("class", "inner")
.attr("r", 0)
.style("fill", "orange")
.attr("cy", -RADIUS - 5);
newCircles
.transition()
.duration(500)
.attr("r", 5);
newCircles.merge(join)
.attr("cx", (d, i) => 2 * i * 5);
}
const force = d3.forceSimulation()
.nodes(data)
.force("charge", d3.forceCollide().radius(100))
.on("tick", () => {
const container = d3.select(".container");
container
.selectAll(".outer")
.attr("transform", d => `translate(${d.x},${d.y})`);
});
render(data);
setTimeout(() => {
data.push([ "circle10", "circle11", "circle12", "circle13"]);
data[0].push("A");
data[0].push("B");
data[0].push("C");
...