Based on this answer, how can I get a live stream of the circle's X & Y coordinates while the transition is occurring?
2 Answers
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 MutationRecord
s 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.

- 1
- 1

- 21,179
- 13
- 61
- 84
-
1That'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
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>

- 106,305
- 20
- 172
- 230
-
1I 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