Using the d3 graphics library, I can't seem to make paths draw slowly so they can be seen growing.
This site has a perfect example in the "Line Chart (Unrolling)" section, but no code is given for that section. Could someone please help me with the lines of D3 code that could make that happen?
When I try appending delay() or duration() such as in the following code snippet, the path still draws immediately, And all the SVG code after this segment fails to render.
var mpath = svg.append ('path');
mpath.attr ('d', 'M35 48 L22 48 L22 35 L22 22 L35 22 L35 35 L48 35 L48 48')
.attr ('fill', 'none')
.attr ('stroke', 'blue')
.duration (1000);
I believe the "D3 way" to do this is with a custom tween function. You can see a working implementation here: http://jsfiddle.net/nrabinowitz/XytnD/
This assumes that you have a generator called line
set up with d3.svg.line
to calculate the path:
// add element and transition in
var path = svg.append('path')
.attr('class', 'line')
.attr('d', line(data[0]))
.transition()
.duration(1000)
.attrTween('d', pathTween);
function pathTween() {
var interpolate = d3.scale.quantile()
.domain([0,1])
.range(d3.range(1, data.length + 1));
return function(t) {
return line(data.slice(0, interpolate(t)));
};
}
The pathTween
function here returns an interpolator that takes a given slice of the line, defined by how far we are through the transition, and updates the path accordingly.
It's worth noting, though, that I suspect you'd get better performance and a smoother animation by taking the easy route: put a white rectangle (if your background is simple) or a clipPath
(if your background is complex) over the line, and transition it over to the right to reveal the line underneath.
A common pattern when animating lines in svg is setting a stroke-dasharray
of the length of the path and then animate stroke-dashoffset
:
var totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", totalLength + " " + totalLength)
.attr("stroke-dashoffset", totalLength)
.transition()
.duration(2000)
.ease("linear")
.attr("stroke-dashoffset", 0);
You can see a demo here:
http://bl.ocks.org/4063326
Based on the post that you link to, I came up with the following example:
var i = 0,
svg = d3.select("#main");
String.prototype.repeat = function(times) {
return (new Array(times + 1)).join(this);
}
segments = [{x:35, y: 48}, {x: 22, y: 48}, {x: 22, y: 35}, {x: 34, y:35}, {x: 34, y:60}];
line = "M"+segments[0].x + " " + segments[0].y
new_line = line + (" L" + segments[0].x + " " + segments[0].y).repeat(segments.length);
var mpath = svg.append ('path').attr ('d',new_line )
.attr ('fill', 'none')
.attr ('stroke', 'blue')
for (i=0; i<segments.length; i++)
{
new_segment = " " + "L"+segments[i].x + " " + segments[i].y
new_line = line + new_segment.repeat(segments.length-i)
mpath.transition().attr('d',new_line).duration(1000).delay(i*1000);
line = line + new_segment
}
It is a bit ugly, but works. You can see it on jsFiddle