2

I'm attempting to use the code found here as a jumping off point for a project. This code uses D3 to transition between two paths using a function called pathTween(), which is as follows:

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;
    };
  };
}

What has me baffled is that in this example, something in this block of code is giving the transition an ease-in-out sort of movement, and I want to change this to linear. I think it must be a D3 default in one of the functions used within pathTween(), unless I'm overlooking the part of pathTween() that would add that easing.

Anyone have an idea of what might be defaulting to ease-in-out and how to change it?

Thanks

Community
  • 1
  • 1
jrlars
  • 91
  • 8

1 Answers1

4

In a D3 v3.x transition,

The default easing function is "cubic-in-out".

This cubic-in-out easing...

... provides suitable slow-in slow-out animation.

Thus, if you want a linear easing, you just need to set it explicitly:

path.transition()
    .duration(2000)
    .ease("linear")//set the ease here
    .attrTween("d", pathTween(d1, 4))
    .each("end", function() { d3.select(this).call(transition, d1, d0); });

Here is the code with that easing: http://blockbuilder.org/anonymous/d0f28de24658467d48053ef6e39e8413

The same code in a S.O. snippet:

var width = 960,
    height = 500;

var svg = d3.select("body").append("svg")
    .attr("width", width)
    .attr("height", height);

var d0 = "M0,0c100,0 0,100 100,100c100,0 0,-100 100,-100",
    d1 = "M0,0c100,0 0,100 100,100c100,0 0,-100 100,-100c100,0 0,100 100,100";

svg.append("path")
    .attr("transform", "translate(180,150)scale(2,2)")
    .attr("d", d0)
    .call(transition, d0, d1);

function transition(path, d0, d1) {
  path.transition()
      .duration(2000)
      .ease("linear")
      .attrTween("d", pathTween(d1, 4))
      .each("end", function() { d3.select(this).call(transition, d1, d0); });
}

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;
    };
  };
}
path {
  fill: none;
  stroke: #000;
  stroke-width: 1.5px;
}
<script src="//d3js.org/d3.v3.min.js"></script>

EDIT: You said in the comments that you're using D3 v4.x. That being the case, you have a couple of changes:

path.transition()
    .duration(2000)
    .ease(d3.easeLinear)
    .attrTween("d", pathTween(d1, 4))
    .on("end", function() { d3.select(this).call(transition, d1, d0); });

They are: d3.easeLinear instead of "linear" and .on instead of .each.

Here is the blockbuilder: http://blockbuilder.org/GerardoFurtado/90f1d1040bcfd3b4172f3965efab2b37

Gerardo Furtado
  • 100,839
  • 9
  • 121
  • 171
  • Thanks for the response. While that code works great in your example, as soon as I try to implement it in an actual document I get the following error in the console: Uncaught Error at easeConstant (d3.js:3405) at Transition.transition_ease [as ease] (d3.js:3415) at transition (script.js:24) at Selection.selection_call [as call] (d3.js:1187) at HTMLDocument. (script.js:17) at j (jquery.min.js:2) at k (jquery.min.js:2) Any idea why this would be? – jrlars Jan 26 '17 at 02:44
  • 1
    What's the version of D3 you're using? Bostock's code uses v3.x. – Gerardo Furtado Jan 26 '17 at 02:56
  • Yep, just realized this has been either removed or changed. I guess I can change to v3, unless you happen to know what the .ease function has changed to? Thanks again for the help – jrlars Jan 26 '17 at 02:57