score:3

Accepted answer

short answer

yes, but you have to define the starting value for the d attribute.

long answer

a transition goes from a starting value to a target value. right now, in your "enter" selection, you have no starting value (that is, before transition()) for the d attribute:

// enter
this.line
    .enter().append( 'path' )
    .attr( 'class', 'valueline' )
    .transition()//no 'd' attribute before this line
    .attr( 'd', this.valueline );

therefore, the d attribute for that path is null (read more about this in this answer).

let's see it:

var data = [10, 180, 30, 60, 190, 180, 50, 110, 40, 90, 90];
var svg = d3.select("svg");
var linegenerator = d3.line()
  .y(function(d) {
    return d
  })
  .x(function(d, i) {
    return i * 60
  });
var path = svg.selectall(null)
  .data([data])
  .enter()
  .append("path");
  
console.log(path.attr("d"))
path {
  fill: none;
  stroke-width: 2px;
  stroke: teal;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="200"></svg>

here the same code, setting the d attribute:

var data = [10, 180, 30, 60, 190, 180, 50, 110, 40, 90, 90];
var svg = d3.select("svg");
var linegenerator = d3.line()
  .y(function(d) {
    return d
  })
  .x(function(d, i) {
    return i * 60
  });
var path = svg.selectall(null)
  .data([data])
  .enter()
  .append("path")
  .attr("d", linegenerator);
path {
  fill: none;
  stroke-width: 2px;
  stroke: teal;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="200"></svg>

back to your question:

you cannot transition the d attribute from null to your string. it's impossible. there are some possible workarounds, though.

one of them is creating a default d attribute before the transition. for instance:

var data = [10, 180, 30, 60, 190, 180, 50, 110, 40, 90, 90];
var svg = d3.select("svg");
var linegenerator = d3.line()
  .y(function(d) {
    return d
  })
  .x(function(d, i) {
    return i * 60
  });
var path = svg.selectall(null)
  .data([data])
  .enter()
  .append("path")
  .attr("d", "m0,100 l600,100")
  .transition()
  .duration(2000)
  .attr("d", linegenerator);
path {
  fill: none;
  stroke-width: 2px;
  stroke: teal;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="200"></svg>

but that's a horrible transition! the problem is that the initial d attribute has too few points. because of that, the string interpolator cannot create the interpolation we wish.

so, we can use a custom function, like this one from mike bostock. here is the demo:

var data = [10, 180, 30, 60, 190, 180, 50, 110, 40, 90, 90];
var svg = d3.select("svg");
var linegenerator = d3.line()
  .y(function(d) {
    return d
  })
  .x(function(d, i) {
    return i * 60
  });
var path = svg.selectall(null)
  .data([data])
  .enter()
  .append("path")
  .attr("d", "m0,100 l600,100")
  .transition()
  .duration(2000)
  .attrtween("d", function(d) {
    return pathtween(linegenerator(d), 4, this)()
  });

function pathtween(d1, precision, self) {
  return function() {
    var path0 = self,
      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-width: 2px;
  stroke: teal;
}
<script src="https://d3js.org/d3.v4.min.js"></script>
<svg width="600" height="200"></svg>


Related Query

More Query from same tag