I am trying to run animations in order. Here is an example.
function rect1() {
d3.select("svg")
.append("rect")
.attr("id", "r1")
.attr("x", 300)
.attr("y", 100)
.attr("height", 0)
.attr("width", 0)
.transition()
.duration(1000)
.attr("height", 30)
.attr("width", 50);
}
function rect2() {
d3.select("svg")
.append("rect")
.attr("id", "r2")
.attr("x", 300)
.attr("y", 50)
.attr("height", 0)
.attr("width", 0)
.transition()
.duration(1000)
.attr("height", 30)
.attr("width", 50);
}
function highlightRect(id) {
d3.select(id)
.style("fill", "yellow")
}
So i want to create a function like this so i can run them in the order rect1(), rect2(), highlightRect() one after another (after each animation ends).
function startAnim (f1, f2, f3, f3a) {
f1();
f2();
f3(f3a);
}
startAnim(rect1, rect2, highlightRect, "#r1");
I have tried something like this but it gets messy when there are more animations.
// rect1
d3.select("svg")
.append("rect")
.attr("id", "r1")
.attr("x", 300)
.attr("y", 100)
.attr("height", 0)
.attr("width", 0)
.transition()
.duration(1000)
.attr("height", 30)
.attr("width", 50)
.on("end", () => {
// rect2
d3.select("svg")
.append("rect")
.attr("id", "r2")
.attr("x", 300)
.attr("y", 50)
.attr("height", 0)
.attr("width", 0)
.transition()
.duration(1000)
.attr("height", 30)
.attr("width", 50)
.on("end", ....);
});;
Might be an ignorant question can this be done with promises?
Thanks
Advertisement
Answer
Promisifying these would actually be pretty easy:
First we’ll make the functions return the object we’re chaining on.
function rect1() {
return d3.select("svg")
.append("rect")
.attr("id", "r1")
.attr("x", 300)
.attr("y", 100)
.attr("height", 0)
.attr("width", 0)
.transition()
.duration(1000)
.attr("height", 30)
.attr("width", 50);
}
function rect2() {
return d3.select("svg")
.append("rect")
.attr("id", "r2")
.attr("x", 300)
.attr("y", 50)
.attr("height", 0)
.attr("width", 0)
.transition()
.duration(1000)
.attr("height", 30)
.attr("width", 50);
}
function highlightRect(id) {
return d3.select(id)
.style("fill", "yellow")
}
Then we can use a generic higher order function to promisify those for us.
// Returns a promise that resolves after the given
// animation function finishes. Can optionally take args as a second parameter
// obviously this could just take a function and allow consumers
// to use anonymous functions for parameter-binding, but this function
// relies on the return value, so this is, maybe, slightly less easy to
// break on accident.
function runAnimation(fn, ...args) {
return new Promise(resolve => fn(...args).on("end", resolve));
}
Then chaining them is pretty easy:
runAnimation(rect1) .then(() => runAnimation(rect2)) .then(() => runAnimation(highlightRect, "#r1"))
Making a helper that takes an array of functions or something would be pretty easy here too.
Untested, but I think the general idea would work out.