0

Based on this answer, how can I get a live stream of the circle's X & Y coordinates while the transition is occurring?

Community
  • 1
  • 1
lfkwtz
  • 1,007
  • 2
  • 11
  • 25

2 Answers2

3

You could use the standard MutationObserver interface to listen for changes to the DOM. The MutationObserver constructor is provided a callback which will be called with an array of MutationRecords containing detailed information about the changes which occured. After creating an observer instance you can register it to changes to a particular node, e.g. your circle, and filter the attribute changes you are interested in, say cx and cy, by providing this configuration to the call to .observe() which will start the listener.

// Create a new MutationObserver.
// This one just logs changes to attributes.
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(m) {
    console.log(
      m.attributeName + 
      " -- old:" + m.oldValue +
      ", new: " + m.target.getAttribute(m.attributeName));
  });
});

// Start observing the circle node and listen for changes to attributes cx and cy
// while recording old values.
var config = {
  attributes: true,
  attributeOldValue: true,
  attributeFilter: ["cx","cy"]
};

observer.observe(circle.node(), config);

Given the JSFiddle you linked to, a working example might look like this:

var svg = d3.select("body")
    .append("svg")
    .attr("width", 200)
    .attr("height", 200);

var circle = svg.append("circle")
 .attr("id", "circ")
    .attr("cx", Math.random() * 200)
    .attr("cy", Math.random() * 200)
    .attr("r", 10 + "px")
    .transition().each("end", function () {
      myTransf();
  });

var d = d3.select("div");
function myTransf() {
    d3.select("#circ").transition().duration(500)
        .attr("cx", Math.random() * 200) // change this to random 2px 
     .attr("cy", Math.random() * 200) // change this to random 2px
        .each("end", function () {
        myTransf();
    });
}

// Create a new MutationObserver.
// This one just logs changes to attributes.
var observer = new MutationObserver(function(mutations) {
  mutations.forEach(function(m) {
    console.log(
      m.attributeName + 
      " -- old:" + m.oldValue +
      ", new: " + m.target.getAttribute(m.attributeName));
  });
});

// Start observing the circle node and listen for changes to attributes cx and cy
// while recording old values.
var config = {
  attributes: true,
  attributeOldValue: true,
  attributeFilter: ["cx","cy"]
};

observer.observe(circle.node(), config);

// Stop observing once you are done
setTimeout(function() {
  observer.disconnect();
}, 5000);
<script src="http://d3js.org/d3.v3.js"></script>

If you need to support IE <11, though, you are out of luck and need to resort to some other solution like the one proposed by Mark.

Community
  • 1
  • 1
altocumulus
  • 21,179
  • 13
  • 61
  • 84
  • 1
    That's a very cool approach. It allows you to leverage the built-in magic of `d3`s transition will still hooking each iteration. +1 – Mark Sep 17 '16 at 20:56
2

You'd have to take control of the transition and write a custom tween function. This way you control each animation step. Here's some runnable code replacing the attrTween magic in your example with a custom tween.

var svg = d3.select("body")
    .append("svg")
    .attr("width", 200)
    .attr("height", 200);

var circle = svg.append("circle")
  .attr("id", "circ")
    .attr("cx", Math.random() * 200)
    .attr("cy", Math.random() * 200)
    .attr("r", 10 + "px");
    
myTransf();

function myTransf() {
    circle.transition()
     .duration(500)
      .each("end", function () {
          myTransf();
      })
      .tween("move", function() {
        var self = d3.select(this),
            x = d3.interpolate(+self.attr('cx'), Math.random() * 200),
            y = d3.interpolate(+self.attr('cy'), Math.random() * 200);
        return function(t) {
          var cx = x(t),
              cy = y(t);
          self.attr("cx", cx);
          self.attr("cy", cy);
        };
      });
}
svg {
    border:1px solid #ccc;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
Mark
  • 106,305
  • 20
  • 172
  • 230
  • 1
    I came up with an [alternative](http://stackoverflow.com/a/39551543/4235784) to your approach and, because I like your contributions, I'd really appreciate you having a look into it. – altocumulus Sep 17 '16 at 20:46
  • Thanks to the both of you. I utilized the tween function, but I'll have to look into MutationObserver further now for future uses. – lfkwtz Sep 19 '16 at 16:16