如何使用补间功能更新d3.js中的文本内容?

时间:2017-05-24 01:30:27

标签: javascript d3.js tween

我正在尝试在点击时更新我的​​文本元素,就像输入一样。当我单击文本时,它应该从数据数组中拉出下一个文本元素并逐个字符地打印直到完成,但是没有任何反应。尽管没有错误。下面附有代码。

    var data = [
        "Hello",
        "World!",
        "What's up?"
       ];
    var i = 0;
    var body = d3.select("body");
    var element = body.append("svg");

   element.append("text")
       .data(data)
       .text(function(d) {return d})
       .attr("x", 150)
       .attr("y", 75)
       .attr("text-anchor", "middle")
       .attr("fill", "white")
           .on("click", function() {
               d3.select(this).transition()
                  .duration(5000)
                  .ease(d3.easeLinear)
                  .tween("text", function () {
                      var newText = data[i];
                      var textLength = newText.length;
                      return function (t) {
                          this.textContent = newText.slice(0, Math.round(t * textLength));
              };
          });

      //wrap around function for the data
      i = (i + 1) % data.length;
    });

1 个答案:

答案 0 :(得分:4)

更新的答案:

D3 version 5.8.0引入了一项重大变化:

  

补间功能现在可以使用this来引用当前节点。

因此,使用D3 v5.8.0或更高版本,您的代码就可以>。

旧答案(对于早于v5.8.0的版本):

问题只是最内层函数中this的含义。

与大多数D3方法一样,this是当前的DOM元素。对于transition.tween,它并没有什么不同:

  

当转换开始时,将为每个所选元素评估值函数,按顺序传递当前数据d和索引i,并将this上下文作为当前DOM元素。 (强调我的)

但是,在内部函数中,this只是window

最简单的解决方案是在外部函数中使用var self = this

.tween("text", function() {
    var self = this;
    var newText = data[i];
    var textLength = newText.length;
    return function(t) {
        self.textContent = newText.slice(0, Math.round(t * textLength));
    };
});

这是您更新的代码:



var data = [
  "Hello",
  "World!",
  "What's up?"
];
var i = 0;
var body = d3.select("body");
var element = body.append("svg");

element.append("text")
  .data(data)
  .text(function(d) {
    return d
  })
  .attr("x", 150)
  .attr("y", 75)
  .attr("text-anchor", "middle")
  .on("click", function() {
    d3.select(this).transition()
      .duration(5000)
      .ease(d3.easeLinear)
      .tween("text", function() {
        var self = this;
        var newText = data[i];
        var textLength = newText.length;
        return function(t) {
          self.textContent = newText.slice(0, Math.round(t * textLength));
        };
      });

    //wrap around function for the data
    i = (i + 1) % data.length;
  });

<script src="https://d3js.org/d3.v4.min.js"></script>
&#13;
&#13;
&#13;