According to the documentation for transition.tween()
,
calling transition.tween(name, factory)
...
Registers a custom tween for the specified name. When the transition starts, the specified factory function will be invoked for each selected element in the transition, being passed that element's data (d) and index (i) as arguments, with the element as the context (
this
).
What is the purpose of having a named tween? Since .tween
needs a reference to a transition to be used, it seems unlikely that it would be useful for reusing the same tween on different transitions. As far as I can tell, this name has no purpose at all.
To illustrate my point, I recently used a custom transition.tween()
to transition the text
and path
elements within a group simultaneously. HERE is a link to the example. The relevant code is:
function groupTween(transition, newAngle) {
transition.tween("thisNameMeansNothing", function() {
var d = d3.select(this).datum();
var interpolate = d3.interpolate(d.endAngle, newAngle);
return function(t) {
d.endAngle = interpolate(t);
d3.select(this).select("path")
.attr("d", arc);
d3.select(this).select("text")
.attr("transform", function(d) { return "translate(" + arc.centroid(d) + ")"; })
.text(function(d) {return formatLabel(d.endAngle);});
};
});
}
The name is never used except in registering the tween function, but must be given as it is a required first argument to .tween()
.
Question
Can this name be referenced later? If so, how? Where is such a reference stored? Also, any examples of this being used in the wild would be greatly appreciated.
d3-transition. A transition is a selection-like interface for animating changes to the DOM. Instead of applying changes instantaneously, transitions smoothly interpolate the DOM from its current state to the desired target state over a given duration. To apply a transition, select elements, call selection.
attrTween('d',...) takes a single function that returns another function. You pass it a function that gets called with the current datum, index and current node as the parameters. This function should return the interpolation function which gets called with a time value.
Transitions can be chained together by adding multiple calls to . transition . Each transition takes it in turn to proceed. (When the first transition ends, the second one will start, and so on.)
This is a great question.
I suspect that the quick answer for why the name
parameter exists at all, is that all the other transition tweens are associated with some sort of name (e.g., of an attribute or style), and it was convenient for them to all work the same way.
The name is used in the background, in the tween objects that are set on each element. If you create a long enough transition, you can use your DOM inspector to see the changing DOM properties of each element. There will be something called __transition__
which stores an array with the information about the active transition on the element and any scheduled sub-transitions.
That transition information object is not the same as the transition selection that you create in your code. Instead, it contains the specific details required to calculate the transition for that particular element: the start time, duration, and the specific tween factory function that will be used to generate the tween for that element. For your custom tween, this is your function(d,i)
that will return the function(t)
, but there are similar functions created by all the standard transition methods.
Those tween functions are stored in that transition information object by name, and your custom tween is stored using the name you give it. Which means the one real effect of setting a name is that if you use the same name twice on the same transition, you'll over-write the first version:
http://fiddle.jshell.net/9gPrY/
pTrans
.style("color", "red")
.style("color", "green")
.tween("countdown", function(d,i){
var check;
return function(t){
this.textContent = percent(t);
if (!check && t > 0.1) {
console.log("That wasn't supposed to happen");
check = true;
}
};
})
.tween("countdown", function(d,i){
var check;
return function(t){
this.textContent = percent(t);
if (!check && t > 0.1) {
printTweens();
check = true;
}
};
});
The second color
style transition call cancels out the previous one, and the second countdown
tween likewise cancels out the first. Only two tween functions are printed out, one called style.color
and one called countdown
.
Now, I haven't done exhaustive testing, but that seems to be it.
So in a sense maybe this is a poor design, a bit of the internal guts of the library poking out into the API. But I suppose there could be cases where you would want to be able to over-write a tween function partway through, and having a name is useful. As Lars has discovered (see comments), the only practical use, beyond debugging, seems to be the ability to overwrite a tween factory function during the delay before a transition starts (approx 17ms if you haven't specified a longer delay).
It could have been designed as an optional parameter (e.g., .tween(function, [name])
), but that would be inconsistent with the pattern used for all the other API functions.
So, in general, just use the name as a way to make your code more readable by describing what your tween function does. Unless you're obsessed with minification, in which case use a random single character.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With