Animation Loop
Let us suppose that you want to animate a result through time - typically evolving even when the user doesn't interact directly with it. Animation consists in repetitively calling a function that print/compute/draws the currently visualized results. Such repetition is called an animation loop.
Each static view of a single call from an animation loop is called a Frame. The animation loop should be able to update and draw the result at least 25 times per seconds in order to have the feeling of a continuous animation. The number of drawing per seconds is usually called Frames Per Seconds, or fps. A continous animation should therefore run, at least, at 25fps, or in order words, the computation of each frame should not exceed 40ms.
Our screen have typically a refreshing rate of about 60fps. It is therefore useless to draw the results more often.
requestAnimationFrame
JavaScript proposes the built-in function requestAnimationFrame allowing to handle an animation loop in calling itself repetitively.
requestAnimationFrame takes as argument a user defined function. This function is called automatically as soon as the system is ready, and synchronize to the refreshing rate of your system.
- The user-defined function receives automatically the current amount of time elapsed since the beginning of the loop as parameter (at a precision of 1ms).
Create an empty screen program with the following JS code
requestAnimationFrame( frame ) function frame(currentTime) { console.log(currentTime); requestAnimationFrame( frame ) }
- - Observe the printed value on the console. This value indicates the currentTime elapsed since the beginning of the loop (in ms).
- - At the opposite of a simple loop, requestAnimationFrame automatically handle the synchronisation with the system, ensuring that your system is ready to draw the next frame before doing it.
Example of animation
Consider this simple example of an animation loop generated using requestAnimationFrame. HTML:<body> <div class="box"></div> </body>
.box { position: fixed; width: 100px; height: 100px; background-color: red; }
"use strict"; const boxElement = document.querySelector(".box"); let leftPos = 0; requestAnimationFrame( animationLoop ) // This function is continuously called by requestAnimationFrame function animationLoop(currentTime) { boxElement.style.left = `${leftPos}px`; leftPos = leftPos+1; if(currentTime>2000) // after the webpage run 2s { boxElement.style.backgroundColor = "green"; } if(currentTime>4000) // after the webpage run 4s { boxElement.style.backgroundColor = "yellow"; boxElement.style.width = "200px"; boxElement.textContent = "Animated in JavaScript!"; } requestAnimationFrame( animationLoop ) }
Interaction and animation
Let us consider we want to model the following behavior, where a disc appears when and where the user click, and then falls down.
[Corresponding Webpage]Let us first start with a single disc.
Create the following code making a disc appearing at the position of the user click (no animation yet).
HTML<body> <div class="circle"></div> </body>
.circle { background-color:cyan; width: 100px; height: 100px; position: fixed; border-radius: 50%; }
const radius = 50; // Radius of the circle let y = 0; // height (/vertical) of the circle within the viewport let circleElement = document.querySelector('.circle'); main(); function main() { document.addEventListener('click', createCircle); } function createCircle(event) { const x = event.clientX; y = event.clientY; circleElement.style.top = `${y-radius}px`; circleElement.style.left = `${x-radius}px`; }
Create an animation in making the y value increasing from a constant value at each frame. Then applying this new y value to the style of circleElement. (Note that your disc will instantaneously translate to a new position when the user clicks.)
Extend your code in handling an arbitrary number of discs. A new disc should appear for each user click.
Hints :- - You can use an array, initialy empty, to store the disc elements, and their y position.
- - Every time the user click, a new disc is created and inserted in the array and in the DOM.
- - At every frame, all the y position of all the discs are updated.
- Extension: Delete discs that are outside of the viewport (that you cannot see anymore) to limit the size of your DOM and the array storing all the elements.