Advancing & Removal
Here we will allow the graphic to animate between titles and cover how to handle the remove function.
Dealing with Asynchronous Animations
To begin with, let's find a bug in our current graphic. If you run the play
function then the stop
function in quick succession, the animation will break. To solve this, we will utilize a new JS feature called Promises. Promises allow us to delay the the execution of code until an asynchronous function, or function that happens in parallel to our other code, completes. A more technical breakdown of asynchronous code can be found on MDN's. For now, we just need to know that our GSAP animation happens asynchronously so we want to wait until it completes to continue executing our code. Let's wrap our animateIn
function inside of a new Promise.
We will return the new Promise so we can chain multiple animation together. Our Animate In Promise will allow the next Promise to execute once the resolve
function is called. In this case, we resolve
the Promise when the timeline completes all it's animations. Let's wrap outanimateOut
function in a Promise as well.
Wrapping the animateOut
function in a Promise works the same was as the aniamteIn
function.
Running Animations in Succession
We are going to need a function that handles executing and waiting for our animations to complete. Right below our inner IIFE, or knock-off constructor function, let's add an executePlayOutCommand
function and a addPlayOutCommand
function.
The appPlayOutCommand
function will take a Promise as an argument and add it to an array of Promises to execute. We will need to store the array somewhere and we will also want to throttle the number of animations being ran in succession. The amount of throttling needed for each graphic will vary but, for our example, three animations in the queue should be plenty. Let's add an animationQueue
and animationThreshold
variables to out graphic.
We can now write the logic for how our animations will be executed in executePlayOutCommand
function and adding the Promise to our list in addPlayOutCommand
function.
The addPlayOutCommand
function simply takes our Promise and adds it to the list of commands to execute. Then if there is only the one command we just added, we will run it in executePlayOutCommand
. We will also log a warning when we meet the animation threshold. This will help with debugging errors. The executePlayOutCommand
function will then run the first Promise in the array and when it is complete, we will check for another Promise. If there is one, call the executePlayOutCommand
function again. This process will repeat until there are now more Promises.
Handling an Advance Command
Now that we are handling our asynchronous animations, let's take advantage of those Promises to create an advance animation. We will add the code to update the title and subtitle between the animateOut
and animateIn
functions by using a then
function. then
functions are chained onto Promises and represent the next portion of script to be run. Let's create our next
function and break it down.
We begin by checking which state the graphic is in. If we are in state 1
then we can simply play the graphic. Although the play
command should be used, we will give the graphics operators a bit of wiggle room. If the graphic is in state 2
we can advance it but, we need to check and see if there is some data to advance to. We check that by making sure the data
variable has a length greater than what currentStep
we are on. Remember, currentStep
is what title we are going to see once all the animations are complete. When we add the reset
function, this will become more important because we could advance, reset, then advance again in once animation queue before reaching our threshold. We would want to know that after all of that, if we run another next command, we will be out of titles.
If the data is an array and meets our currentStep
rule, we will increment the currentStep
variable and create a Promise chain that will animate out our graphic, change the data, increment the activeStep
, and then animate the graphic back in. Finally we call addPlayOutCommand
with our Promise chain to allow the graphic to run the advance animation with our other animations.
Removing the Graphic
Thankfully we do not have any clean up to do in our remove
function. This is typically where you would make any API calls or store some temporary data in local storage. Both of those concepts are for more advanced graphics but we would recommend reading MDN's page on Local Storage for more info. For now, we will just check if the graphic has been played and if so, run the stop
function. This will allow our graphic to gracefully animate off if remove
is called.
There is one additional trick we will use in our remove
function to make the code cleaner and that is async
and await
. async
and await
are used to make Promises act like synchronous functions. We tell the JS engine that a function contains some asynchronous code by labeling the function with async
. Then when we want to run a Promise and pause our code execution, we use await
. The example above states that the remove
function contains some asynchronous code and we want to stop the code execution when the animateOut
function runs. Any other code, if there was some, after the animateOut
function would then run.
Resources
Promises on MDN's website.
Async & Await on MDN's website.
Asynchronous overview on MDN's website.
Local Storage on MDN's website.
Last updated