Saturday, 20 June 2020

JS Animation for Beginners

Simple Spinner Animation


The Start and Stop Spinner app example given in MDN docs ( Go to example ) has one drawback. When you stop a spinner and restart it , the loader does not start spinning from the point where it was stopped. This is due to the usage of timestamp in the requestAnimationFrame callback or draw(). This  timestamp is  a DOMHighResTimeStamp  ~= performance.now() . In other words, This gives the current time. To be more precise, performane.now() gives the elapsed time since the document was loaded. This callback parameter will be of great use for many animation scenarios but it is not appropriate for this usecase. One will be expecting the spinner to start spinning from where it was paused. Take a look at what happens when you run the code given in MDN docs.


MDN-Spinner

Before you proceed, go through MDN docs to read about requestAnimationFrame here). In a nutshell , this is used to synchronize your paints to your screen's refresh rate. rAF is used to get the optimal 60fps.

The MDN sample code uses timestamp to calculate the rotateCount or the degree of rotation. We don't have control over this timestamp value. We cannot start and pause it. We click on the screen to pause the spinner  (say the timestamp value is 117.43 at this instant), we wait for a while and click on the screen again to resume the spinner . Now , the timestamp value is much greater than what it was when the spinner was paused (say the timestamp value is now 504.56). This difference is what we see getting reflected in the degree of rotation. Here's how i modified the code to fix this issue:

spinner.js:
 
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
const spinner = document.querySelector('div');
let isSpinning = true;
let rotateCount = 0;
let startTime = null;
let rAF;
let rotateCounter;


startRotateCounter = () =>{
    rotateCounter= setInterval(() => {rotateCount+=15}, 60)
}

document.body.addEventListener('click',() => {
    if(!isSpinning) {
        console.log("starting at:", rotateCount);
        startRotateCounter();
        draw();
        isSpinning = true;
    }
    else {
        cancelAnimationFrame(rAF);
        clearInterval(rotateCounter);
        console.log("stopping at:",rotateCount);
        isSpinning = false;
        
    }
});

let draw = () => {
    if (rotateCount > 359) {
        rotateCount %= 360;
   }

      spinner.style.transform =`rotate(${rotateCount}deg)`;
    
      rAF = requestAnimationFrame(draw);
}

startRotateCounter();
draw();

I used rotateCounter to control the degree of rotation of the spinner. rotateCount is incremented by 15 every 60 ms. You can control the speed of rotation by changing this increment value. You can play around with these two values and choose the values which suit your need.

Notice the smooth transition between pause and restart:


spinner



Get the source code here:





References:



No comments:

Post a Comment

JS Animation for Beginners

Simple Spinner Animation The Start and Stop Spinner app example given in MDN docs (  Go to example  ) has one drawback. When you s...