GSAP provides several easy-to-use methods to control the playback of your individual animations and timelines. In this section we'll add playback controls to the animation that we created in the prior lesson. I've created a starter page for this lesson here.
You'll notice that the starter page contains four buttons below the SVG - play, pause, reverse and restart, as well as range slider input that will be used later as a video scrub bar. I've created variables for all the UI elements:
1
2
3
4
5
6
// ui
const playButton = document.querySelector("#play");
const pauseButton = document.querySelector("#pause");
const reverseButton = document.querySelector("#reverse");
const restartButton = document.querySelector("#restart");
const scrubber = document.querySelector("#scrubber");
I've also changed the animation itself so that it only runs once by removing the repeat:-1 and yoyo:true properties;
1
theTween = gsap.timeline();
The playback controls are incredibly simple to use - all you need to do is call the tween's play(), pause(), reverse() or restart() method.
Let's create our methods in the starter codepen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function play(){
theTween.play();
}
function pause(){
if(theTween != null) theTween.pause();
}
function reverse(){
if(theTween != null) theTween.reverse();
}
function restart(){
if(theTween != null){
theTween.restart();
return;
}
theTween.play();
}
Let's hook these methods up to our buttons.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function initUI(){
playButton.addEventListener("click", play);
pauseButton.addEventListener("click", pause)
reverseButton.addEventListener("click", reverse);
restartButton.addEventListener("click", restart)
}
function play(){
theTween.play();
}
function pause(){
if(theTween != null) theTween.pause();
}
function reverse(){
if(theTween != null) theTween.reverse();
}
function restart(){
if(theTween != null){
theTween.restart();
return;
}
theTween.play();
}
Next we'll add a slider that will allow you to "scrub" through the animation. The slider will also act as an animation progress bar. This is the html for our slider.
1
2
3
4
<label>
<span id="slider-label">animation scrubber</span>
<input id="scrubber" type="range" value="0" min="0" max="1" step="0.01">
</label>
Note that GSAP measures the progress of it's animations with a value ranging from 0 to 1, so I've given the slider corresponding min and max amounts.
In order to create a progress bar/scrubber we'll need to know how long the animation is and the progress of the animation at any given time. Once we have those values, we'll be able to set the progress of the animation with our slider.
First let's create a variable to store our animation duration.
1
2
3
// tween variables
let theTween = null;
let animationDuration = 0;
We can set the value of animationDuration using the duration() method once we create our timeline.
theTween.duration();
1
2
3
4
5
6
7
8
function animate() {
theTween = gsap.timeline();
theTween
.fromTo(...
// tween code
);
animationDuration = theTween.duration();
}
GSAP allows you to pass a callback function to your tween that will execute every time the animation updates. We pass the callback to our tween using the vars object, which we've used previously to configure our repeat and yoyo values. The property we'll need to set is onUpdate, and we'll pass it a function called updateScrubber which we'll create in a second.
1
2
3
function animate() {
theTween = gsap.timeline({ onUpdate:updateScrubber});
// rest of our animate code
The updateScrubber() method will be used to update the slider position. In order to do so we'll need to know how much time has elapsed in the animation, and then devide that by the animationDuration. We'll then use that to set the value of our scrubber.
1
2
3
4
function updateScrubber(){
const val = theTween.time()/animationDuration;
scrubber.value = val;
}
Now let's add the scrub functionality. We'll need to add an "input" listener to the slider, get it's value, and then set our animation's progress accordingly. First let's update our initUI method by adding the input listener and setting out eventHandler.
1
2
3
4
5
6
7
8
function initUI() {
playButton.addEventListener("click", play);
pauseButton.addEventListener("click", pause);
reverseButton.addEventListener("click", reverse);
restartButton.addEventListener("click", restart);
// slider
scrubber.addEventListener("input", sliderInputHandler);
}
Now let's create the handler. We'll get the "seek time" for our animation by multiplying the scrubber value by the animation duration, then we'll set the animation to that time using the seek method.
someTween.seek(someTime);
1
2
3
4
function sliderInputHandler(){
const seekTime = scrubber.value * animationDuration;
theTween.seek(seekTime)
}
We don't want our scrubber "playhead" to move while we're scrubbing the animation, so we'll add some mouse event handlers to pause the animation every time the cursur mouses over the slider. We'll also add a handler to play the animation once the user mouses out. First we'll add the mouse events to the slider in our initUI method:
1
2
3
4
5
6
7
8
9
10
function initUI() {
playButton.addEventListener("click", play);
pauseButton.addEventListener("click", pause);
reverseButton.addEventListener("click", reverse);
restartButton.addEventListener("click", restart);
// slider
scrubber.addEventListener("input", sliderInputHandler);
scrubber.addEventListener("mouseover",sliderOverHandler);
scrubber.addEventListener("mouseout", sliderOutHandler);
}
Now let's create the handlers that pause/play the animation when the user mouses over/out of the slider:
1
2
3
4
5
6
function sliderOverHandler(){
theTween.pause();
};
function sliderOutHandler(){
theTween.play();
}
And that's it! Here's the final version on codepen.