Independently Moving Dots
This is a really interesting problem that has lots of interesting applications in visualization.
data = [
{ step: 1, x: 1, y: 1, guy: "A", speed: 0 },
{ step: 2, x: 2, y: 2, guy: "A", speed: 1000 },
{ step: 3, x: 4, y: 1, guy: "A", speed: 2000 },
{ step: 4, x: 7, y: 2, guy: "A", speed: 3000 },
{ step: 1, x: 1, y: 4, guy: "B", speed: 0 },
{ step: 2, x: 2, y: 3, guy: "B", speed: 4000 },
{ step: 3, x: 3, y: 3, guy: "B", speed: 5000 },
{ step: 4, x: 5, y: 4, guy: "B", speed: 4000 },
];
var g = d3.select("#figurecontainer")
.append("svg")
.attr("height", height)
.attr("width", width)
var line = d3.line()
.x(function (d) { return x(d.x); })
.y(function (d) { return y(d.y); })
.curve(d3.curveCardinal.tension(0));
data.forEach(function (d) {
d.guy = d.guy;
d.step = +d.step;
d.x = +d.x;
d.y = +d.y;
d.speed = +d.speed;
});
var pathData = d3.nest()
.key(function (d) { return d.guy; })
.entries(data);
x.domain([d3.min(data, function (d) { return d.x }) - 1,
d3.max(data, function (d) { return d.x }) + 1]);
y.domain([d3.min(data, function (d) { return d.y }) - 1,
d3.max(data, function (d) { return d.y }) + 1]);
g.selectAll(".dot")
.data(data)
.enter().append("circle")
.attr("cx", function (d) { return x(d.x); })
.attr("cy", function (d) { return y(d.y + 0.5); })
.transition()
.ease(d3.easeElastic)
.duration(2000)
.attr("cy", function (d) { return y(d.y); })
.attr("r", 6)
.style("fill", "pink")
//////////////////////////////////////////////////////////////////
var totalLengths = [];
pathData.forEach(function (d) {
eachGuy = d.values;
circle = g.append("circle")
.attr("transform", `translate(${x(eachGuy[0].x)}, ${y(eachGuy[0].y)})`)
.attr("r", 20)
.style("fill", 'blue')
.style("opacity", 0.1)
///////////// Add paths and segments
mypaths = g.append("path")
.style("stroke", "black")
.style("fill", "none")
.style("opacity", 0.3)
.attr("d", line(eachGuy))
.attr("class", "temppath")
totalLengths.push(mypaths.node().getTotalLength())
// For each segment of each line, need to find segment lengths
var mySegments = [];
for (j = 0; j < 3; j++) {
segments = g
.append("path")
.attr("d", function (d) {
return line(eachGuy.slice(j, (j + 2)))
})
mySegments.push(segments);
segments.each(function () {
eachGuy[0].seglength = 0;
eachGuy[j + 1].seglength = this.getTotalLength()
});
}
///////////// This is the animation portion
var transitionFrom = circle.transition()
.duration(eachGuy[1].speed)
.attrTween("transform", getPath(mySegments[0].node()));
for (i = 1; i < 3; i++) {
transitionFrom = transitionFrom.transition()
.duration(eachGuy[i + 1].speed)
.attrTween("transform", getPath(mySegments[i].node()))
}
function getPath(path) {
var l = path.getTotalLength();
return function () {
return function (t) {
var p = path.getPointAtLength(t * l);
return "translate(" + p.x + "," + p.y + ")";
};
};
};
});