Reputation: 122052
Suppose I have an arbitrary path drawn with d3
var points = [0, 4, 4, 4, 8, 8, 4, 4, 4, 8, 4, 4, 4, 4, 0];
var svg = d3.select('svg');
var line = d3.svg.line()
.y(function(d) { return 10*d})
.x(function(d, t) { return t*20 })
.interpolate('cubic');
svg.append('path')
.attr('d', line(points))
.attr('stroke', 'black')
.attr('stroke-width', 2)
.attr('fill', 'none')
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.min.js"></script>
<svg style="width: 100%; height: 100%; outline: 1px solid green;"></svg>
I want to animate the path drawing out slowly. I understand how to do it from beginning to end but in my case I want to start at an arbitrary point on the line and draw outward at the same rate in both direction. I can't quite figure out how to do this.
I can utilize attrTween
and take slices of the array varying by time, but if I do that, the line shifts since I don't know how to set the horizontal offset correctly at each step.
Upvotes: 3
Views: 936
Reputation: 25157
Hopefully you're working with the second answer on the page you linked to (the one by @duopixel), because that's a much better way. If so, then you can make the line start drawing from the middle if you slightly modify the attributes:
var points = [0, 4, 4, 4, 8, 8, 4, 4, 4, 8, 4, 4, 4, 4, 0];
var svg = d3.select('svg');
var line = d3.svg.line()
.y(function(d) { return 10*d})
.x(function(d, t) { return t*20 })
.interpolate('cubic');
var path = svg.append('path')
.attr('d', line(points))
.attr('stroke', 'black')
.attr('stroke-width', 2)
.attr('fill', 'none');
totalLength = path.node().getTotalLength();
path
.attr("stroke-dasharray", '0 ' + totalLength)
.attr("stroke-dashoffset", totalLength/2)
.transition()
.duration(2000)
.attr("stroke-dasharray", totalLength + ' 0')
.attr("stroke-dashoffset", totalLength);
<script src="//cdnjs.cloudflare.com/ajax/libs/d3/3.4.13/d3.min.js"></script>
<svg style="width: 100%; height: 100%; outline: 1px solid green;"></svg>
First, consider the original, common scenario of animating the drawing of a path from its start to its end. If l
is the length of the path (obtained by path.node().getTotalLength()
) then setting the path's stroke-dasharray
to l + ' ' + l
makes the dash and the gap between it and the next dash both equal to l
. Under these conditions, the path would appear solid, because the dash length being l
"pushes" the gap past the end of the path. By setting stroke-dashoffset
to l
, the above scenario is reversed — the path is entirely a gap (hence invisible) and the dash falls off the path. By transitioning between these 2 states (from one with offset to one without offset), we get a gradual drawing of a line.
Now, to animate from the middle, the dash is defined with length 0
and the gap has a length l
. So now the line is also completely invisible, due to the 0-length dash and the l
-length gap . Setting stroke-dashoffset
to l/2
moves this 0-length dash halfway down the path. That's the animation starting state. The end state is the reverse dasharray
where gap is 0 and dash-length is l
, which renders the line completely solid. To properly transition between these states, we also need to set the end state's stroke-dashoffset
to l
. That was something I figured out experimentally, and I'm not sure exactly how to explain it in words. But it works....
Upvotes: 7