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.
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:
Get the source code here:
GitHub : Simple Spinner Animation
References: