I have a rectangle that is animated using .transition()
and it takes 5 seconds (.duration(5000)
). I want to know if there is any way to specify a percentage under those 5 seconds, so the animation is executed from that percentage on.
For example, with a duration of 5 seconds, if I specify a value of 50%
, I would like the animation to start from the values corresponding to 2.5 seconds (50% of 5). Is that possible?
This is my code:
d3.select("#visualization").append('svg');
var vis = d3.select("svg").attr("width", 800).attr("height", 614).style("border", "1px solid red");
var rectangle = vis.append("rect").attr("width", 100).attr("height", 70).attr("x", 0).attr("y", 50);
rectangle
.transition()
.duration(5000)
.attr("x", 250)
.attr("width", 100)
.attr("height", 100)
.attr("opacity", 0.5)
.attr("fill", "red");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<div id="visualization"></div>
For a linear easing, just change the duration and pass your own ease
function, which can be as simple as:
const percentage = 0.5;//here, a value between 0 and 1
selection.transition()
.duration(5000 * (1 - percentage))
.ease(t => percentage + t * (1 - percentage))
//etc...
If you have another easing, pass the modified t
value to it. For instance, using d3.easeCubic
:
.ease(t => d3.easeCubic(percentage + t * (1 - percentage)))
The logic here is simple: as the API explains, "for each frame that a transition is active, it invokes its tweens with an eased t-value ranging from 0 to 1". Therefore, our function just makes the transition starting at the eased value of percentage
and the t
value, going from 0 to 1, is used to indicate the fraction of the amount remaining (1 - percentage
) that must be added. When t = 1
the whole expression percentage + t * (1 - percentage)
equals 1.
Here are the demos. First, your regular transition:
const vis = d3.select("body").append('svg').attr("width", 800).attr("height", 614).style("border", "1px solid red");
var rectangle = vis.append("rect").attr("width", 100).attr("height", 70).attr("x", 0).attr("y", 50);
rectangle
.transition()
.duration(5000)
.attr("x", 250)
.attr("width", 100)
.attr("height", 100)
.style("opacity", 0.5)
.attr("fill", "red");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Now using percentage = 0.5
, everything (positions, opacity etc...) starts at 50% of your original transition:
const vis = d3.select("body").append('svg').attr("width", 800).attr("height", 614).style("border", "1px solid red");
var rectangle = vis.append("rect").attr("width", 100).attr("height", 70).attr("x", 0).attr("y", 50);
const percentage = 0.5;
rectangle
.transition()
.duration(5000 * (1 - percentage))
.ease(t => d3.easeCubic(percentage + t * (1 - percentage)))
.attr("x", 250)
.attr("width", 100)
.attr("height", 100)
.style("opacity", 0.5)
.attr("fill", "red");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
Finally, with percentage = 0.8
. Because this is a cubic easing, the opacity/movement are almost ending:
const vis = d3.select("body").append('svg').attr("width", 800).attr("height", 614).style("border", "1px solid red");
var rectangle = vis.append("rect").attr("width", 100).attr("height", 70).attr("x", 0).attr("y", 50);
const percentage = 0.8;
rectangle
.transition()
.duration(5000 * (1 - percentage))
.ease(t => d3.easeCubic(percentage + t * (1 - percentage)))
.attr("x", 250)
.attr("width", 100)
.attr("height", 100)
.style("opacity", 0.5)
.attr("fill", "red");
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
PS: not related, use style
instead of attr
for setting styles. You'll see that, in your specific case, it makes a huge difference.
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