Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In d3 is it possible to dynamically change where a path position starts for tweening?

Tags:

d3.js

glyph

to: clarify. Picture a circle. We start drawing the circle from a particular coordinate. Now lets draw the circle starting from another coordinate.

I am playing with path data derived from SVG glyphs and then using d3js tween to animate the change between the paths.

For this example, counting from 1 -> 9,0 and then repeating.

http://jsfiddle.net/chrisloughnane/HL2ET/

As you can see some of the transitions are not as nice as others. They draw a line that closes the path for the next path. (I'm guessing that) this happens when the start and end of the path are very far apart when the calculation for the new shape is made. When it works it's very nice.

Could anybody suggest a possible solution to the ugly lines?

CODE without path data

svg.append("path")
    .attr("transform", "translate(150,300)scale(.2,-.2)")
  .style("stroke", "red")
  .style("fill", "gray")
  .style("stroke-width", "9")
    .attr("d", d0)
    .call(transition, digits[0], digits[position]);

function transition(path, d0, d1) {
  position++;
  if(position==10)
  {
    position=0;
  }
  path.transition()
      .duration(2000)
      .attrTween("d", pathTween(d1, 4))
      .each("end", function() { d3.select(this).call(transition, d1, digits[position]); });
}

function pathTween(d1, precision) {
  return function() {
    var path0 = this,
        path1 = path0.cloneNode(),
        n0 = path0.getTotalLength(),
        n1 = (path1.setAttribute("d", d1), path1).getTotalLength();

    // Uniform sampling of distance based on specified precision.
    var distances = [0], i = 0, dt = precision / Math.max(n0, n1);
    while ((i += dt) < 1) distances.push(i);
    distances.push(1);

    // Compute point-interpolators at each distance.
    var points = distances.map(function(t) {
      var p0 = path0.getPointAtLength(t * n0),
          p1 = path1.getPointAtLength(t * n1);
      return d3.interpolate([p0.x, p0.y], [p1.x, p1.y]);
    });

    return function(t) {
      return t < 1 ? "M" + points.map(function(p) { return p(t); }).join("L") : d1;
    };
  };
}

Unfortunately it fails on chrome mobile too where as http://bl.ocks.org/mbostock/3081153 works fine.

The next step is to apply this effect to sentences.

like image 659
chris loughnane Avatar asked Nov 13 '22 05:11

chris loughnane


1 Answers

The difference between your example and that in Bostock's is that in his example there is a single continuous path that he tweens into another single continuous path.

Whereas, in your example, digits like 1, 2, 3, 5, 6, 7 can be drawn using single continuous path. But, in order to draw digits like 4, 6, 9 and 0 you need 2 paths- one on top of the other. And, for digit 8, you need to have 2 paths on top of an outer path.

So, my suggestion would be to keep 2 paths at all times atop the outer path that you are using at present & give them appropriate dimensions whenever any peculiar digit is to be shown.

Refer image for more details: enter image description here

like image 182
Vikram Deshmukh Avatar answered Dec 06 '22 03:12

Vikram Deshmukh