Reputation: 33
I am trying to create a simple plane animation along a spiral curve
However, I encountered issue when trying to delay the transition using d3's delay function, the animation does not seem to go correctly
So I have been contemplating using setTimeout to delay the triggering of the transition function, but could not seem to get it right. Could someone give me a suggestion?
Link to the fiddle. This includes the original transition without setTimeout or any .delay; v15 shows the error with using .delay; and v16 has what I have tried with setTimeout
This is my code for transitioning without setTimeout (which works fine without .delay)
function transitionThis(d,i) {
d3.select(this).transition()
.duration(3000)
//.delay(3000) //causes error in the animation
.ease("exp")
.each("start", function() { d3.select(this).style("opacity", "1"); })
.attrTween("transform", translateAlong(path.node()))
.styleTween("opacity", function () {return d3.interpolate("1", "0");});}
plane.each(transitionThis);
// Returns an attrTween for translating along the specified path element.
function translateAlong(path) {
var l = path.getTotalLength();
var t0 = 0;
return function(i) {
return function(t) {
var p0 = path.getPointAtLength(t0 * l);//previous point
var p = path.getPointAtLength(t * l);////current point
var angle = Math.atan2(p.y - p0.y, p.x - p0.x) * 180 / Math.PI;//angle for tangent
t0 = t;
return "translate(" + p.x + "," + p.y + ")scale(" + (0.2+t*4) + ")rotate(" + angle +"15"+")";
};
};
}
and this is my attempt at adding setTimeout
function transitionThis(d,i) {
d3.select(this).transition()
.duration(3000)
//.delay(3000) //causes error in the animation
.ease("exp")
.each("start", function() { d3.select(this).style("opacity", "1"); })
.attrTween("transform", translateAlong(path.node()))
.styleTween("opacity", function () {return d3.interpolate("1", "0");});
}
function delayedFlight() {
var tOut = setTimeout(transitionThis(),3000);
}
plane.each(delayedFlight);
Upvotes: 3
Views: 1544
Reputation: 25157
Here's what's happening: for some reason, adding .delay()
to the transition makes it so that every once in a while the interpolation function (the one that returns the transform value) gets called two times in a row with the same value of t
. For example, here's a subset of the output I got when I inserted console.log(t)
:
0.006692062648206693
0.006707542472169953
0.007238969233518517
0.007255714140926161
0.0077049430038543705
0.0077049430038543705 // <- same as previous
0.008568945153864268
0.008588766510821856
0.00899496468906235
0.00899496468906235 // <- same as previous
0.009529833123126597
0.00955187716946928
0.01107410052517391
0.011099716711945125
0.012516716837337842
I'm not why it happens, but technically it's not a bug, just a quirk. However, it causes a sort of bug with your interpolation function: When t0
and t
are equal, so are p0
and p
and as a result the computed angle
is 0 for those intermittent cases. And that's when you see the plane stutter – whenever its rotation is set to 0.
The easiest fix is to make it so that t0
and t
are never equal, which can be achieved by intercepting that condition and modifying t0
a bit. Like this:
// Happens every once in a while
if (t == t0) {
// Move t0 "back in time" a bit
t0 -= .00001;
}
It's not so pretty, but is probably still better than getting into setTimeouts....
Upvotes: 2