问题
I am trying to create an animation where circles are being animated on multiple paths.
I am able to get the animation I want for one of the paths but am not sure why the circles are only animating on that particular path, instead of being distributed according to the path they belong.
The full code can be found on my bl.ocks page: https://bl.ocks.org/JulienAssouline/4a11b54fc68c3255a85b31f34e171649
This is the main part of it
var path = svg.selectAll("path")
.data(data.filter(function(d){
return d.From > 2010
}))
.enter()
.append("path")
.style("stroke", "#832129")
.attr("class", "arc")
.attr("d", function(d){
var To_scale = xScale(d.experience),
From_scale = xScale(0),
y = yScale(0),
dx = To_scale - From_scale,
dy = y,
dr = Math.sqrt(dx * dx + dy * dy);
return "M" + From_scale + " " + y + " A 43 50 0 0 1 " + To_scale + " " + y;
})
.style("fill", "none")
.style("opacity", 0)
.call(transition)
.on("mouseover", function(d){
var thisClass = d3.select(this).attr("class")
d3.selectAll(".path").style("opacity", 0.1)
d3.select(this).style("stroke", "white").style("opacity", 1).style("stroke-width", 2)
})
.on("mouseout", function(d){
d3.select(this).style("stroke", "#832129").style("opacity", 1)
})
function transition(path){
path.each(function(PathItem, index){
d3.select(this).transition()
// .delay(index + 200)
.duration(index * 5 + 1000)
.on("start", function(){
d3.select(this).style("opacity", 1)
})
.attrTween("stroke-dasharray", tweenDash)
})
}
function tweenDash(){
var l = this.getTotalLength(),
i = d3.interpolateString("0," + l, l + "," + l)
return function(t){ return i(t); };
}
console.log(data[0])
var circle = svg.selectAll("circle")
.data(data.filter(function(d){
return d.From > 2010
}))
.enter()
.append("circle")
.attr("r", 5)
.attr("cx", function(d){
return xScale(d.experience)
})
.style("fill", "red")
.attr("transform", "translate(" + 0 + ")")
.style("opacity", 0)
transition_circles();
function transition_circles(){
circle.each(function(pathItem, index){
d3.select(this)
.transition()
.delay(index * 200)
.duration(index * 10 + 1000)
.on("start", function(){
d3.select(this).style("opacity", 1)
})
.on("end",function(){
d3.select(this).style("opacity", 0)
})
.attrTween("transform", translateAlong(path.node(), index))
})
}
function translateAlong(path, index){
var l = path.getTotalLength();
return function(d, i , a){
return function(t){
var p = path.getPointAtLength(t * l);
return "translate(" + p.x + "," + p.y + ")";
}
}
}
Basically, I followed this https://bl.ocks.org/mbostock/1705868 example to get the point-along-path interpolation, but am having trouble adapting it to get the same effect on multiple lines.
I also tried adding .attr("cx", function(d){ return d.experience}
to the circles but that didn't work.
回答1:
You're always passing the same path (the first one) to the translateAlong
function:
.attrTween("transform", translateAlong(path.node(), index))
//this is always the first path ---------^
You have to pass different paths to the translateAlong
function. There are different ways for doing that (I don't know which one you want), one of those is:
.attrTween("transform", translateAlong(path.nodes()[index], index))
In this approach, the indices of the circles go from 0 to the data array length minus 1. So, since path.nodes()
is an array of elements, it's selecting different ones by their indices.
Here is the updated bl.ocks: https://bl.ocks.org/anonymous/f54345ed04e1a66b7cff3ebeef271428/76fc9fbaeed5dfa867fdd57b24c6451346852568
PS: regarding optimisation, you don't need to draw several paths at the same position! Right now you have dozens of paths which are exactly the same. Just draw the different paths (in your case, only 3).
来源:https://stackoverflow.com/questions/47724173/animating-circles-along-multiple-paths