D3 v4中的补间数字不再像v3那样有效了

时间:2017-08-23 06:14:11

标签: javascript d3.js

我试图弄清楚为什么我在D3版本4中的补间数字(向上或向下计数)不再起作用。

这是我的代码:

var pieText = svg4.append("text")
    .attr("class", "pieLabel")
    .attr("x", 0)
    .attr("y", 0)
    .text(0)
    .attr("dy", "0.2em")
    .style("font-size", 19)
    .style("fill", "#46596b")
    .attr("text-anchor", "middle");

d3.selectAll(".pieLabel").transition()
  .delay(500)
  .duration(1000)
  .tween("text", function(d) {
    var i = d3.interpolate(this.textContent, d.value);
    return function(t) {
      this.textContent = form(i(t));
    };
  });

console.log告诉我插值工作正常。 那变了什么?我该如何让它发挥作用?

感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

这里的问题只是内部函数中的this,它将不再像在v3中那样工作。

让我们证明一下。看看这里的控制台,使用D3 v3,this是DOM元素:



d3.select("p").transition()
  .tween("foo", function(d) {
    var i = d3.interpolate(0, 1);
    return function(t) {
      console.log(this)
    };
  });

<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
<script src="https://d3js.org/d3.v3.min.js"></script>
<p></p>
&#13;
&#13;
&#13;

现在使用D3 v4 ... this的相同代码段现在是window对象:

&#13;
&#13;
d3.select("p").transition()
  .tween("foo", function(d) {
    var i = d3.interpolate(0, 1);
    return function(t) {
      console.log(this)
    };
  });
&#13;
<script src="https://getfirebug.com/firebug-lite-debug.js"></script>
<script src="https://d3js.org/d3.v4.min.js"></script>
<p></p>
&#13;
&#13;
&#13;

解决方案:将外部函数中对this的引用保留为变量(传统上命名为self,但此处我将命名为node }):

d3.selectAll(".pieLabel").transition()
    .delay(500)
    .duration(1000)
    .tween("text", function(d) {
        var node = this;
        //keep a reference to 'this'
        var i = d3.interpolate(node.textContent, d.value);
        return function(t) {
            node.textContent = form(i(t));
            //use that reference in the inner function
        };
    });

以下是仅包含此更改的代码:

&#13;
&#13;
var widthpie = 250,
  heightpie = 300,
  radius = Math.min(widthpie, heightpie) / 2;

var data = [{
  antwort: "A",
  value: 0.5
}, {
  antwort: "B",
  value: 0.4
}];

var form = d3.format(",%");

var body4 = d3.select("#chart1");

var svg4 = body4.selectAll("svg.Pie")
  .data(data)
  .enter()
  .append("svg")
  .attr("width", widthpie)
  .attr("height", heightpie)
  .append("g")
  .attr("transform", "translate(" + widthpie / 2 + "," + heightpie / 2 + ")");

var pieText = svg4.append("text")
  .attr("class", "pieLabel")
  .attr("x", 0)
  .attr("y", 0)
  .text(0)
  .attr("dy", "0.2em")
  .style("font-size", 19)
  .style("fill", "#46596b")
  .attr("text-anchor", "middle");

d3.selectAll(".pieLabel").transition()
  .delay(500)
  .duration(1000)
  .tween("text", function(d) {
    var node = this;
    var i = d3.interpolate(node.textContent, d.value);
    return function(t) {
      node.textContent = form(i(t));
    };
  });
&#13;
<script src="https://d3js.org/d3.v4.min.js"></script>
<div id="chart1"></div>
&#13;
&#13;
&#13;

PS:我在片段中使用Firebug是因为S.O.代码段不能正确记录窗口对象。

答案 1 :(得分:2)

问题是由更改日志中未记录的更改引起的。 D3 v3 calls回调返回的内部函数在通过当前节点作为transition.tween()上下文的每个tick上传递给this

tweens[--n].call(node, e);

从v4开始,当内部函数为called时不再是这种情况:

tween[i].call(null, t);

null传递给该函数将被全局对象替换。在这种情况下,函数中的this不再指向当前元素,对于v3也是如此。 Gerardo已经在他的answer中提出了补救措施,甚至在第4版的documentation中也提出了建议:

transition.tween("attr.fill", function() {
  var node = this, i = d3.interpolateRgb(node.getAttribute("fill"), "blue");
  return function(t) {
    node.setAttribute("fill", i(t));
  };
});

因此,您需要一个闭包来保持对当前元素的引用,因为它在this提供的回调中被引用为transition.tween()

答案 2 :(得分:-2)

我复制这段代码我不知道在哪里,如果有人知道只是给予反抗。我使用它来添加转换到路径,我希望这给你一个想法

使用此附加过渡

.transition()
              .duration(2000)
              .attrTween("stroke-dasharray", tweenDash)

这个功能

function tweenDash() {
    return function(t) {
        var l = path.node().getTotalLength();
        interpolate = d3.interpolateString("0," + l, l + "," + l);

        //t is fraction of time 0-1 since transition began

        var p = path.node().getPointAtLength(t * l);

        return interpolate(t);
    }
}