{
const svg = d3.create('svg')
.attr('width', 900)
.attr('height', 500)
const data = d3.range(10).map(() => ({
x: Math.random() * 900,
y: Math.random() * 500
}))
const line = d3.line()
.x(d => d.x)
.y(d => d.y)
.curve(d3.curveBasis)
const path = svg
.append('path')
.datum( data )
.attr('d', line)
.style('stroke', 'black')
.style('stroke-width', 2)
.style('fill', 'transparent')
while(true) {
const length = path.node().getTotalLength(),
int = d3.interpolate(0, length),
x = (t) => path.node().getPointAtLength(int(t)).x,
y = (t) => path.node().getPointAtLength(int(t)).y
svg.selectAll('circle')
.data([ data[0] ])
.join('circle')
.attr('cx', d => d.x)
.attr('cy', d => d.y)
.style('fill', d3.interpolateRainbow(0))
.style('stroke', 'black')
.attr('r', 20)
.transition().delay(500).duration(10000)
.attrTween('cx', () => x )
.attrTween('cy', () => y )
.styleTween('fill', () => d3.interpolateRainbow )
yield svg.node()
await Promises.tick(12000)
}
}