折线图的“输入"选择可以动画吗? [英] Can the 'enter' selection for a line graph be animated?

查看:106
本文介绍了折线图的“输入"选择可以动画吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个折线图,可以很好地更新.直到有新数据输入问题.届时,更新"选择会按照动画效果向下移动,但新数据则不会.

I have a line graph that updates very nicely. Until new data enters the question. At that point the 'update' selection animates down as it should but the new data doesn't.

很难解释发生了什么,但是gif值一千个单词(观察它在向下过渡时的情况):

It's hard to explain what's happening, but a gif is worth a thousand words (watch when it transitions down):

我已经使用update和render方法将图形包装在一个类中.这是我编写的render方法.

I've wrapped the graph in a class with an update and render method. Here's the render method I wrote.

render(){
    // Update both Axes
    this.xAxis.transition()
        .call( d3.axisBottom( this.xScale ) );
    this.yAxis.transition()
        .call( this.createYAxis );

    // Exit
    this.line.exit().remove();

    // Enter
    this.line
      .enter().append( 'path' )
        .attr( 'class', 'valueLine' )
        .transition()
        .attr( 'd', this.valueLine );

    // Update
    this.line.transition().attr( 'd', this.valueLine );

    // Allows method chaining
    return this;
}

为什么新"数据没有动画?

Why doesn't the 'new' data animate in?

推荐答案

简短答案

是的,但是您必须定义d属性的起始值.

从起始值到目标值的转换.现在,在输入"选择中,d属性没有起始值(即,在transition()之前):

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

因此,该路径的d属性为null(有关此在此答案中的更多信息)

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

让我们看看:

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>

使用相同的代码,设置d属性:

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>

回到您的问题:

您不能将d属性从null转换为您的字符串.不可能.不过,有一些可能的解决方法.

You cannot transition the d attribute from null to your string. It's impossible. There are some possible workarounds, though.

其中之一是在过渡之前创建默认的d属性.例如:

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>

但这是一个可怕的转变!问题在于初始d属性的点太少.因此,字符串插值器无法创建我们希望的插值.

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.

因此,我们可以使用自定义函数,例如Mike Bostock的.这是演示:

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>

这篇关于折线图的“输入"选择可以动画吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆