Animation controlled by JavaScript

Jijie Liu
4 min readNov 24, 2020
a sliding block controlled by mouse

Introduction

Nowadays, more and more animation is applied on Front-end. It’s interesting to understand how JavaScript controls the animation.

In this article, I will talk about:

  • what is the animation in the browser
  • how to build a timeline
  • how to build an animation
  • how to control a timeline (pause / resume)

Animation in browser

Animation is a method in which frames are manipulated to appear as moving images. In browser, we can write a function to move images, and call this function repeatedly to achieve animation.

There are 3 ways.

setInterval : It can repeatedly call a function or executes a code snippet, with a fixed time delay between each call.

Usually, the browser shows 60 frames per second. Therefore the interval is set as 16ms (16ms * 60 = 960 < 1000ms).

let timerId = setInterval(() => alert('tick'), 16);

setTimeout : a better way to achieve animation. It’s more flexible.

let timerId = setTimeout(function tick() {   
alert('tick');
timerId = setTimeout(tick, 16);
}, 16);

There are 2 advantages of setTimeout :

  1. Delay (16ms) can be controlled dynamically.
  2. Delay (16ms) is applied precisely.

To control the delay:

let delay = 16;
let timerId = setTimeout(function tick() {
alert('tick');
if (some-condition) delay += 16; // delay is updated
timerId = setTimeout(tick, delay);
}, delay);

setInterval fixes the interval as 16ms, regardless the time of executing the function. That means the real time between two function is less than 16ms. However, setTimeout ensures the interval is exactly 16ms.

(more details is presented here)

requestAnimationFrame: this function calculates the interval between frames automatically. I will use this one in this article.

let tick = () => { requestAnimationFrame(tick) };cancelAnimationFrame(tick); // cancel the tick animation

Timeline

Timeline is the class which controls the animation. Its attributes are:

  • tick & tickHandler : the functions which trigger the animation
  • timelineStart : the start time of the timeline (it’s NOT the start time of animation)
  • pauseStart & pausedTime : the start time of the pause & the duration of the pause in the timeline
  • animations : all the animation in the timeline. They are saved in a Set .
  • animationStart : the time of registration of each animation in timeline. They are saved in a Map . The key is animation , value is the time.

These attributes must be private. We don’t want they are changed by outside accidentally. Unfortunately, JavaScript doesn’t have the private keyword. But, we can useSymbol to create a private key since Symbol is unique. Even if two Symbol have the same name, they are different. For exemple, we create a private animations :

const ANIMATIONS = Symbol('animations');export class Timeline { 
constructor() { this[ANIMATIONS] = new Set(); }
}

Timeline has several methods:

  • start : start the timeline, and start the animation.
  • pause : note the pauseStart time, and cancel the current animation
  • resume : calculate the duration of pause, and start the animation
  • add : register an animation, and save the time of registration.

It’s easy to cancel the animation. Since I use requireAnimationFrame :

this[TICK_HANDLER] = requestAnimationFrame(this[TICK]);
cancelAnimationFrame(this[TICK_HANDLER]);

The tricky part is to start one. The tick function deals with it.

First, it marks the start time as now. Then, for each animation, we need to calculate the time of animation:

  • If the animation is registered before the timeline start, then the time of animation is now — timelineStart
  • If the animation is registered after the timeline start, then the time of animation is now — animationStart

Next, the pausedTime and animation delay should be removed.

Finally, this time is passed to the animation, and animation is executed.

Animation

In browser, the animation is created by CSS. In the exemple, sliding block controlled by mouse, the animation is controlled by transform

transform: translateX(20px)

That means move the block 20px right.

We need to create an Animation class. It receives the time of animation, and calculates the position of the block. The method receive(time) works on this.

Before presenting receive method, let’s see the attributes of Animation.

  • object & property : the CSS property of HTML element we want to control. In this example, it’s transform
  • template : the function that returns the value of property , for example, pos => `translateX(${pos})`
  • startValue & endValue & duration : these are the parameters of animation. Combine these value with time, the position of block can be calculated.
  • delay : the time of delay, used in timeline
  • timingfn : The timing function controls the effect of animation, such as linear, ease, ease-in, …

Well, receive(time) calculates the range of animation by endValue - startValue , and the progress of animation by timingFn(time/duration) . The template accept startValue + range * progress , and returns the position.

Timeline control

Since Timeline and Animation have been created, animation can be controlled now.

First, let’s set a simple HTML, create a block.

Next, in JavaScript file, I created a timeline and an animation. then, I bound it with mouseover and mouseout event. Finally, I launched the timeline and add the animation to it.

In fact, the timing function is Cubic Bezier Curve, and I used the existed codes.

Conclusion

In this article, I presented how to control the animation using JavaScript. The main idea is create a timeline, which can maintain several animation, and the animation can modify the CSS of HTML element. The most important part of this little project is how to calculate the position of HTML element with the animation time.

If you want to try it, don’t forget pack the files. You may need following setup.

npm initnpm install --save-dev webpack webpack-cli webpack-dev-servernpm install --save-dev babel-loader @babel/core @babel/preset-env

and, the webpack configuration:

Finally, run webpack serve , enjoy :)

--

--

Jijie Liu

Developer in Paris, interested in building small cool stuffs