Hi,
I am drawing a series of paths, which can change over time.
I'd like to do two things:
b) animate the path transitioning, so if it changes from [a, b, c, d] to [a, b, e, f, d] this animates the bundle
I can do a) with:
var svg_line = d3.svg.line()
.x(path_x)
.y(path_y)
.interpolate("cardinal")
.tension(0.7)
;
trace_path = g_traces.selectAll(".trace_path")
.data(pathinfo, function(path) {
return _.first(path) + "_" + _.last(path);;
})
var path_total_length = function(d) {
return d.node().getTotalLength()
}
trace_path.enter().append("svg:path")
.attr("d", svg_line)
.attr("class", "trace_path")
.style("stroke-width", 7)
.style("stroke", "rgb(207,120,33)")
.style("fill", "none")
.attr("stroke-dasharray", function(d) {
return path_total_length(d3.select(this)) + " " + path_total_length(d3.select(this))})
.attr("stroke-dashoffset", function(d) {
return path_total_length(d3.select(this))})
trace_path
.attr("d", svg_line)
.transition()
.style("stroke", "rgb(25,52,65)")
.attr("d", svg_line)
.attr("stroke-dasharray", function(d) {
return path_total_length(d3.select(this)) + " " + path_total_length(d3.select(this))})
.ease("linear")
.attr("stroke-dashoffset", 0)
.duration(1000)
and I can do b) by making the path only inside the transition:
trace_path
.transition()
.style("stroke", "rgb(25,52,65)")
.attr("d", svg_line)
.attr("stroke-dasharray", function(d) {
return path_total_length(d3.select(this)) + " " + path_total_length(d3.select(this))})
.ease("linear")
.attr("stroke-dashoffset", 0)
.duration(1000)
instead of
trace_path
.attr("d", svg_line)
.transition()
.style("stroke", "rgb(25,52,65)")
.attr("d", svg_line)
.attr("stroke-dasharray", function(d) {
return path_total_length(d3.select(this)) + " " + path_total_length(d3.select(this))})
.ease("linear")
.attr("stroke-dashoffset", 0)
.duration(1000)
.transition()
.attr("marker-end", "url(#link_edge)")
The problem with approach b) is that if the path becomes longer, then the stroke is too short.
The problem looks to be in
return path_total_length(d3.select(this)) + " " + path_total_length(d3.select(this))})
where the d.node().getTotalLength() function doesn't get the new length. It looks like having the line animation interpolated means that the d.node().getTotalLength() function lags behind by one update.
If I send a new batch of paths, then the getTotalLength function returns the right value.
So it appears that there is a race condition somewhere, possibly due to the transition().
Is there somewhere that I can get the getTotalLength of the path once it has transitioned? I tried chaining, by putting another transition after the first one:
.transition()
.style("stroke", "rgb(25,52,65)")
.attr("d", svg_line)
.attr("stroke-dasharray", function(d) {
return path_total_length(d3.select(this)) + " " + path_total_length(d3.select(this))})
.ease("linear")
.attr("stroke-dashoffset", 0)
.duration(1000)
.transition()
.attr("stroke-dasharray", function(d) {
return path_total_length(d3.select(this)) + " " + path_total_length(d3.select(this))})
.duration(100)
But it still only gets the old length.
Thanks
Simo