使用 d3 链接(同步)依赖转换

Chaining (syncing) dependant transitions using d3

我正在编写一个显示值的小部件,该小部件能够在需要时为新值设置动画。数字显示的一部分是显示符号的能力。例如百分号(%).

我已经能够使用 d3 和颜色正确编码转换。该值完美运行。符号颜色的过渡有效,但符号位置的过渡不同步。

我的示例代码演示了随机值变化。但是symbol的位置总是针对前一个随机值,而不是当前值。

JSFiddle 的问题在这里:https://jsfiddle.net/metalskin/ektvL7kj/

代码如下:

<!doctype html>
<html style="height: 100%">
<head>
    <meta charset="UTF-8">
    <title>Test Arc Graph</title>
    <style>
      body {
        width: 100%;
        height: 100%;
      }
      .mainDiv {
        width: 100%;
        height: 25%;
        display: block; 
        overflow: hidden;
      }
      .widget {
        width: 25%;
        height: 100%;
        float: left;
      }
      #numWidget {
        width: 100%;
        height: 100%;
      }
    </style>    
</head>
<body>
  <div class="mainDiv">
    <div id="widgetDiv" class="widget" />
  </div>
  <script type="text/javascript" src="js/d3.min.js"></script>
  <script>

    var value = setValue(0, 0, false);

    var svg = d3.select("#widgetDiv").append("svg")
      .attr("id", "numWidget")
      .attr("viewBox", "0 0 100 100")
      .attr("perserveAspectRatio", "meet")
      .append("g");

    var textInst = svg.append("text")
      .attr("id", "numValue")
      .attr("dx", 50)
      .attr("dy", 50)
      .text(value)
      .attr("text-anchor", "middle")
      .attr("dominant-baseline", "central")
      .attr("font-family", "sans-serif")
      .style("font-weight", "bold")
      .style("font-size", "3em")
      .attr("fill", determineForegroundColor(value));

    var symbolInst = svg.append("text")
      .attr("id", "numSymbol")
      .attr("dx", 51 + ( textInst.node().getBBox().width / 2))
      .attr("dy", 53)
      .text("%")
      .attr("text-anchor", "begin")
      .attr("baseline-shift", "super")
      .attr("font-family", "sans-serif")
      .style("font-weight", "bold")
      .style("font-size", "1em")
      .attr("fill", determineForegroundColor(value));

    setInterval(function() {
      var min = -120;
      var max = 120;
      // calc a int random value between min and max
      var newValue = Math.floor(Math.random() * (max - min)) + min;
      value = setValue(value, newValue, true, textInst, symbolInst);
    }, 1500);

    function determineForegroundColor(val) {
      if(val <= 80) {
        return "rgb(100,100,100)";
      } else if(val >= 100) {
        return "rgb(200,50,50)";
      }

      return "rgb(200,200,50)";
    }

    function setValue(oldValue, newValue, redraw, textValueInst, symbolInst) {
      var format = d3.format("f");

      if(redraw) {
        (function(replacementValue, textInst) {
          textInst.transition()
            .duration(750)
            .ease('linear')
            .style("fill", determineForegroundColor())
            .tween('text', function() {
              var ip = d3.interpolate(oldValue, replacementValue);
              return function(t) {
                this.textContent = format(ip(t));
              };
            })
//          .each(function() {
//              d3.select(this);
//              symbolInst
//                .style("fill", determineForegroundColor())
//                .attr("dx", 51 + ( textInst.node().getBBox().width / 2));
//          })
          ;

          symbolInst.transition()
            .duration(750)
            .ease('linear')
            .style("fill", determineForegroundColor())
            .attr("dx", 51 + ( textInst.node().getBBox().width / 2));
        })(newValue, textValueInst);
      }

      return newValue; 
    };    

  </script>  
</body>
</html>

注释掉的代码是尝试使用each。当取消注释并且注释掉紧随其后的转换时,行为不会改变。我想通过使用 each 我会在过渡期间得到一个 event ,这样我就可以根据值文本组件的当前值来偏移符号。我发现一些建议做 d3.select(this) 的 doco,但我无法弄清楚问题是什么。

我怀疑使用 each 是正确的方法,只是找不到与我正在做的事情相对应的关于如何使用它的示例或讨论。

您可以在 tween 函数中对文本元素的过渡和偏移 % 符号进行分组。

textInst.transition()
  .duration(750)
  .ease('linear')
  .style("fill", determineForegroundColor())
  .tween('text', function() {
    var ip = d3.interpolate(oldValue, replacementValue);
    return function(t) {                
      this.textContent = format(ip(t));
      symbolInst
        .style("fill", determineForegroundColor())
        .attr("dx", 51 + ( textInst.node().getBBox().width / 2));
    };
  });

这是你的updated fiddle