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.