Random-Point Line Transition

360 views
Skip to first unread message

matt sacks

unread,
Jun 6, 2012, 7:45:06 PM6/6/12
to d3...@googlegroups.com
This has probably been asked and answered sometime before, but I honestly couldn't find anything asking something quite like this question.

To start, yes - I have seen the Line Transition demo and the explanations that follow it. What I'm trying to accomplish is slightly different, instead of animating the line to the left and continuously updating it with one data point per interval, I'm trying to update the entire line with either more or less points. Looking for something like:

M x0, y0 L x1, y1 L x2, y2 L x3, y3 
   ↓   ↓    ↓   ↓    ↓   ↓    ↓   
M x0, y1 L x1, y2 L x2, ... L xn, yn

That is - from the line of it's old number of points to the new line of greater than (or less than) points without causing quirkiness in the animation. This is difficult because I'd need to re-draw the line (as it is) with the same number of points as the new data but interpolating between each point so that it renders exactly the same as before.

I can't quite think of some way to accomplish this with that approach, but maybe there's a different and better way?

A demonstration of this behavior using the standard

   .transition()
   .duration(n)
   .attr('d', line);

can be viewed here. I use attrTween() in my example because I think that there may be a way of using d3.interpolate() to create this animation, but I'm demonstrating how .attr() would use the same format.

Thanks,
matt

matt sacks

unread,
Jun 6, 2012, 11:02:22 PM6/6/12
to d3...@googlegroups.com
Created a comparison between a normal point distribution at this bl.ocks.org link.

Mike Bostock

unread,
Jun 10, 2012, 9:21:47 AM6/10/12
to d3...@googlegroups.com
To transition from an 8-point line to a 15-point line, you could
resample the original 8-point line to have 15 control points (while
retaining the same shape). For example, you can use De Casteljau's
algorithm to split Bézier curves at arbitrary points. You can resample
the original line to have control points at the same
distance-along-the-curve as the control points in the destination
line. Once you've got two 15-point lines, you can then use normal
interpolation to animate the transition.

Mike

matt sacks

unread,
Jun 10, 2012, 11:28:59 AM6/10/12
to d3...@googlegroups.com
Hi Mike - thanks for taking the time to review and answer my question.

The trouble I'm having is conceptualizing how to re-sample the original line with the new amount of points. I've thought about this a lot and it seems pretty difficult to accomplish given that the points need to be placed such that the line doesn't alter from it's original value.

So I took a look at the Wikipedia page on De Casteljau's algorithm and I'm not quite sure how to write an interpolator in d3 to mimic that formula (to be honest I don't know what Bi represents there, though Pi makes complete sense).

I remembered that Jason Davies wrote an animated Bezier curve example in d3 and decided to take a look at the source. On L103 of animated-bezier.js, the function interpolate gets called via getLevels which is called on each point in the update function for returning the new data points. I don't know if that interpolation was written before d3.interpolate or if d3.interpolate could be used instead, as my experience with that method is pretty minimal besides attrTweening.

Was hoping maybe you could dive deeper and help gist up an example [just a fork from this] of this interpolator using De Casteljau's algorithm, or maybe point me in a direction that could help with the javascript implementation.

Thanks again,
matt

Mike Bostock

unread,
Oct 19, 2012, 2:56:11 AM10/19/12
to d3...@googlegroups.com
Resurrecting an ancient thread here, but here's a solution that
requires almost no math and instead relies on SVG's getPointAtLength
feature to implement a custom path tween. The two paths are sampled
uniformly and converted into polylines temporarily during the
transition:

http://bl.ocks.org/3916621

Mike

marc fawzi

unread,
Oct 19, 2012, 11:26:59 AM10/19/12
to d3...@googlegroups.com
Hi Mike,

What does it mean to put the setAttribute then coma then the path inside parentheses?

(path1.setAttribute("d", d1), path1).getTotalLength()

Is that shorthand for something? Sorry first time seeing come this syntax

Tore Nauta

unread,
Oct 19, 2012, 12:47:48 PM10/19/12
to d3...@googlegroups.com

matt sacks

unread,
Oct 19, 2012, 12:50:51 PM10/19/12
to d3...@googlegroups.com
This is wonderful - thanks Mike! I'll see about wrapping this up in a d3-plugin (for transitioning <path> elements) later.

I'm not quite sure I follow where the polyline conversion takes place. Reading through the pathTween function, it looks like you return new structure for the line manually (by joining each point in the line with "L") while iterating through the data array - but I don't see anything about a polyline.

Mike Bostock

unread,
Oct 19, 2012, 12:53:37 PM10/19/12
to d3...@googlegroups.com
> I'm not quite sure I follow where the polyline conversion takes place.

I just meant that the path data is represented using line segments
("L") rather than whatever the original version is (e.g., "C"). It's
still a path element.

Mike

matt sacks

unread,
Oct 19, 2012, 12:59:09 PM10/19/12
to d3...@googlegroups.com
Makes sense, as anything else would probably result in the initial problem.

So stoked to have this!

marc fawzi

unread,
Oct 19, 2012, 1:09:08 PM10/19/12
to d3...@googlegroups.com
Thanks Tore.

I've not come across it till now, in 2 years of working with JS 

D3 code certainly uses all the Good Parts ;)

marc fawzi

unread,
Oct 19, 2012, 1:13:13 PM10/19/12
to d3...@googlegroups.com
"for (var i = 0, j = 9; i <= 9; i++, j--)"

i've used stuff like that for sure, but didn't realize that "the comma operator evaluates both of its operands (from left to right) and returns the value of the second operand."

Say what! that's insanely obscure, but aslo pretty and useful.
Reply all
Reply to author
Forward
0 new messages