如何使用 tween 函数更新 d3.js 中的文本内容?

J I*_*eza 2 javascript tween d3.js

我正在尝试在单击时更新我的​​文本元素以在输入时展开。当我单击文本时,它应该从数据数组中提取下一个文本元素并逐个字符地打印直到完成,但是,什么也没有发生。虽然没有抛出错误。下面附上代码。

    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;
    });
Run Code Online (Sandbox Code Playgroud)

Ger*_*ado 6

更新的答案:

D3 5.8.0 版引入了一个重要的变化:

现在可以使用 Tween 函数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));
    };
});
Run Code Online (Sandbox Code Playgroud)

这是您更新的代码:

.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));
    };
});
Run Code Online (Sandbox Code Playgroud)
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;
  });
Run Code Online (Sandbox Code Playgroud)