title: Chaining (syncing) dependant transitions using d3
body: <p>I'm writing a widget that displays a value with the ability to animate to the new value when required. Part of the number display is the ability to display a symbol. For example the percentage symbol (%).</p>
  
  <p>I've been able to code the transitions correctly using d3 and color. The value works perfectly. The transition for the color of the symbol works, however the transition for the position of the symbol is out of sync. </p>
  
  <p>My example code demonstrates random value changes. But the position of the symbol is always for the previous random value, not the current value.</p>
  
  <p>JSFiddle of the problem is here: <a href="https://jsfiddle.net/metalskin/ektvL7kj/" rel="nofollow">https://jsfiddle.net/metalskin/ektvL7kj/</a></p>
  
  <p>The code is as follows:</p>
  
  <pre><code>&lt;!doctype html&gt;
  &lt;html style="height: 100%"&gt;
  &lt;head&gt;
      &lt;meta charset="UTF-8"&gt;
      &lt;title&gt;Test Arc Graph&lt;/title&gt;
      &lt;style&gt;
        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%;
        }
      &lt;/style&gt;    
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div class="mainDiv"&gt;
      &lt;div id="widgetDiv" class="widget" /&gt;
    &lt;/div&gt;
    &lt;script type="text/javascript" src="js/d3.min.js"&gt;&lt;/script&gt;
    &lt;script&gt;
  
      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 &lt;= 80) {
          return "rgb(100,100,100)";
        } else if(val &gt;= 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; 
      };    
  
    &lt;/script&gt;  
  &lt;/body&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>The commented out code is an attempt using <code>each</code>. When this is uncommented and the transition directly after is commented out, the behaviour doesn't change. I thought by using <code>each</code> I would get an <code>event</code> during the transition so I could offset the symbol based on the current value of the value text component. I found some doco that suggested doing a <code>d3.select(this)</code>, but I couldn't figure out what the problem was.</p>
  
  <p>I suspect that using <code>each</code> is the correct approach, just couldn't find an example or discussion on how to use it that corresponds to what I'm doing.</p>