chart = {
replay;
const svg = d3.create('svg')
.attr('viewBox', [0, 0, width, height]);
svg.append('g').call(xAxis);
svg.selectAll('.line-decade')
.data(x.ticks())
.join('line')
.attr('class', 'line-decade')
.attr('x1', d => x(d))
.attr('x2', d => x(d))
.attr('y1', 10)
.attr('y2', height - margin.top)
.attr('stroke-width', 1)
.attr('stroke', 'lightgray');
svg.selectAll('.label-family')
.data(families)
.join('text')
.attr('class', 'label-family')
.attr('x', 0)
.attr('y', d => y(d))
.attr('alignment-baseline', 'middle')
.text(d => d);
const simulation = d3.forceSimulation(data)
.force('x', d3.forceX((d) => x(d.date)).strength(5))
.force('y', d3.forceY((d) => y(d.family)))
.force('collide', d3.forceCollide(radius + padding))
.stop();
svg.selectAll('circle')
.data(data)
.join('circle')
.attr('cx', (d) => x(d.date))
.attr('cy', (d) => y(d.family))
.attr('r', radius)
.attr('fill', (d) => color(d.family))
.append('title')
.text(d => `${d.party} in ${d.country} (${d.date.getFullYear()})`);
for(let i = 0; i<120; i++) {
simulation.tick();
svg.selectAll('circle')
.data(data)
.transition()
.duration(1200)
.ease(d3.easeLinear)
.attr('cx', (d) => d.x)
.attr('cy', (d) => d.y);
yield svg.node();
}
}