How To Create Animation Effects In Javascript
JavaScript animations can handle things that CSS can't.
For instance, moving along a complex path, with a timing part unlike from Bezier curves, or an animation on a canvas.
Using setInterval
An animation tin can be implemented equally a sequence of frames – normally minor changes to HTML/CSS properties.
For case, changing way.left
from 0px
to 100px
moves the element. And if we increase it in setInterval
, changing by 2px
with a tiny delay, like fifty times per second, then it looks smooth. That'due south the aforementioned principle every bit in the movie house: 24 frames per second is plenty to make it look shine.
The pseudo-code tin can look similar this:
let timer = setInterval(office() { if (animation complete) clearInterval(timer); else increase style.left by 2px }, 20); // change by 2px every 20ms, about 50 frames per second
More complete case of the animation:
let start = Date.now(); // recall start time let timer = setInterval(function() { // how much time passed from the start? permit timePassed = Date.now() - start; if (timePassed >= 2000) { clearInterval(timer); // end the blitheness after two seconds render; } // depict the animation at the moment timePassed draw(timePassed); }, xx); // every bit timePassed goes from 0 to 2000 // left gets values from 0px to 400px function draw(timePassed) { train.style.left = timePassed / 5 + 'px'; }
Click for the demo:
<!DOCTYPE HTML> <html> <caput> <style> #train { position: relative; cursor: pointer; } </style> </head> <body> <img id="railroad train" src="https://js.cx/clipart/railroad train.gif"> <script> railroad train.onclick = function() { let start = Appointment.now(); let timer = setInterval(function() { permit timePassed = Engagement.at present() - start; train.style.left = timePassed / 5 + 'px'; if (timePassed > 2000) clearInterval(timer); }, xx); } </script> </body> </html>
Using requestAnimationFrame
Permit's imagine we take several animations running simultaneously.
If we run them separately, then even though each one has setInterval(..., 20)
, so the browser would have to repaint much more ofttimes than every 20ms
.
That'south because they take different starting time, so "every 20ms" differs between different animations. The intervals are not aligned. So we'll accept several independent runs within 20ms
.
In other words, this:
setInterval(function() { animate1(); animate2(); animate3(); }, 20)
…Is lighter than three independent calls:
setInterval(animate1, 20); // contained animations setInterval(animate2, 20); // in unlike places of the script setInterval(animate3, 20);
These several independent redraws should be grouped together, to make the redraw easier for the browser and hence load less CPU load and expect smoother.
There's one more thing to keep in listen. Sometimes CPU is overloaded, or there are other reasons to redraw less ofttimes (similar when the browser tab is subconscious), so nosotros actually shouldn't run it every 20ms
.
But how do we know about that in JavaScript? There's a specification Blitheness timing that provides the role requestAnimationFrame
. Information technology addresses all these bug and even more.
The syntax:
permit requestId = requestAnimationFrame(callback)
That schedules the callback
part to run in the closest fourth dimension when the browser wants to exercise blitheness.
If we do changes in elements in callback
then they volition be grouped together with other requestAnimationFrame
callbacks and with CSS animations. So there will be one geometry recalculation and repaint instead of many.
The returned value requestId
can be used to cancel the call:
// cancel the scheduled execution of callback cancelAnimationFrame(requestId);
The callback
gets one argument – the time passed from the beginning of the page load in milliseconds. This fourth dimension tin also exist obtained past calling performance.now().
Usually callback
runs very soon, unless the CPU is overloaded or the laptop battery is near discharged, or there's some other reason.
The code below shows the time betwixt kickoff 10 runs for requestAnimationFrame
. Commonly it'south 10-20ms:
<script> let prev = functioning.now(); let times = 0; requestAnimationFrame(part measure(time) { document.torso.insertAdjacentHTML("beforeEnd", Math.floor(fourth dimension - prev) + " "); prev = fourth dimension; if (times++ < 10) requestAnimationFrame(measure); }) </script>
Structured animation
At present we can make a more than universal animation function based on requestAnimationFrame
:
part animate({timing, describe, elapsing}) { let start = performance.now(); requestAnimationFrame(function breathing(time) { // timeFraction goes from 0 to i let timeFraction = (time - get-go) / duration; if (timeFraction > 1) timeFraction = 1; // calculate the current animation state let progress = timing(timeFraction) depict(progress); // draw it if (timeFraction < i) { requestAnimationFrame(breathing); } }); }
Function animate
accepts 3 parameters that essentially describes the animation:
-
duration
-
Total time of animation. Like,
thou
. -
timing(timeFraction)
-
Timing function, like CSS-holding
transition-timing-part
that gets the fraction of fourth dimension that passed (0
at start,1
at the end) and returns the animation completion (similary
on the Bezier bend).For case, a linear function means that the animation goes on uniformly with the same speed:
part linear(timeFraction) { return timeFraction; }
Its graph:
That'due south simply like
transition-timing-function: linear
. At that place are more interesting variants shown below. -
draw(progress)
-
The function that takes the blitheness completion country and draws it. The value
progress=0
denotes the beginning animation state, andprogress=1
– the end country.This is that function that actually draws out the blitheness.
It can move the chemical element:
role depict(progress) { railroad train.style.left = progress + 'px'; }
…Or do anything else, we tin animate annihilation, in any way.
Allow'due south animate the chemical element width
from 0
to 100%
using our part.
Click on the chemical element for the demo:
function animate({duration, draw, timing}) { let start = performance.now(); requestAnimationFrame(role animate(time) { permit timeFraction = (time - beginning) / duration; if (timeFraction > 1) timeFraction = 1; let progress = timing(timeFraction) draw(progress); if (timeFraction < i) { requestAnimationFrame(animate); } }); }
<!DOCTYPE HTML> <html> <head> <meta charset="utf-eight"> <manner> progress { width: 5%; } </mode> <script src="animate.js"></script> </head> <body> <progress id="elem"></progress> <script> elem.onclick = function() { animate({ duration: k, timing: function(timeFraction) { return timeFraction; }, draw: role(progress) { elem.manner.width = progress * 100 + '%'; } }); }; </script> </trunk> </html>
The code for it:
animate({ elapsing: 1000, timing(timeFraction) { return timeFraction; }, draw(progress) { elem.style.width = progress * 100 + '%'; } });
Unlike CSS animation, nosotros tin can make whatever timing function and any drawing role hither. The timing part is not limited by Bezier curves. And describe
can go across properties, create new elements for like fireworks animation or something.
Timing functions
Nosotros saw the simplest, linear timing role in a higher place.
Let's run into more than of them. We'll try movement animations with different timing functions to see how they work.
Ability of n
If we want to speed up the animation, we can use progress
in the ability n
.
For example, a parabolic curve:
function quad(timeFraction) { return Math.pow(timeFraction, 2) }
The graph:
Meet in action (click to activate):
…Or the cubic curve or even greater northward
. Increasing the power makes it speed up faster.
Hither's the graph for progress
in the power 5
:
In activity:
The arc
Function:
function circ(timeFraction) { return 1 - Math.sin(Math.acos(timeFraction)); }
The graph:
Back: bow shooting
This function does the "bow shooting". First nosotros "pull the bowstring", and then "shoot".
Unlike previous functions, it depends on an boosted parameter x
, the "elasticity coefficient". The distance of "bowstring pulling" is defined past it.
The code:
function back(ten, timeFraction) { render Math.pw(timeFraction, 2) * ((x + 1) * timeFraction - x) }
The graph for x = 1.5
:
For animation we use information technology with a specific value of ten
. Case for x = 1.5
:
Bounce
Imagine we are dropping a brawl. It falls down, so bounces back a few times and stops.
The bounce
function does the same, simply in the reverse order: "bouncing" starts immediately. It uses few special coefficients for that:
function bounce(timeFraction) { for (let a = 0, b = one; one; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / xi) { render -Math.pow((xi - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, ii) } } }
In action:
Elastic animation
One more "elastic" function that accepts an boosted parameter ten
for the "initial range".
role rubberband(ten, timeFraction) { return Math.pow(two, 10 * (timeFraction - 1)) * Math.cos(twenty * Math.PI * x / three * timeFraction) }
The graph for x=one.five
:
In activity for ten=1.5
:
Reversal: ease*
So we accept a collection of timing functions. Their straight application is called "easeIn".
Sometimes we need to bear witness the animation in the reverse guild. That's done with the "easeOut" transform.
easeOut
In the "easeOut" fashion the timing
function is put into a wrapper timingEaseOut
:
timingEaseOut(timeFraction) = one - timing(1 - timeFraction)
In other words, we have a "transform" function makeEaseOut
that takes a "regular" timing function and returns the wrapper around information technology:
// accepts a timing function, returns the transformed variant function makeEaseOut(timing) { return function(timeFraction) { render one - timing(1 - timeFraction); } }
For instance, we can have the bounce
function described above and apply information technology:
let bounceEaseOut = makeEaseOut(bounce);
Then the bounciness will exist non in the beginning, merely at the end of the blitheness. Looks even meliorate:
#brick { width: 40px; acme: 20px; groundwork: #EE6B47; position: relative; cursor: pointer; } #path { outline: 1px solid #E8C48E; width: 540px; height: 20px; }
<!DOCTYPE HTML> <html> <head> <meta charset="utf-viii"> <link rel="stylesheet" href="style.css"> <script src="https://js.cx/libs/animate.js"></script> </head> <body> <div id="path"> <div id="brick"></div> </div> <script> office makeEaseOut(timing) { return function(timeFraction) { render ane - timing(one - timeFraction); } } function bounce(timeFraction) { for (let a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (seven - 4 * a) / 11) { return -Math.prisoner of war((eleven - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2) } } } allow bounceEaseOut = makeEaseOut(bounce); brick.onclick = function() { animate({ duration: 3000, timing: bounceEaseOut, draw: function(progress) { brick.fashion.left = progress * 500 + 'px'; } }); }; </script> </torso> </html>
Here we can see how the transform changes the beliefs of the function:
If there's an blitheness result in the beginning, like bouncing – it will be shown at the end.
In the graph in a higher place the regular bounciness has the cherry-red colour, and the easeOut bounce is blue.
- Regular bounce – the object bounces at the bottom, then at the stop sharply jumps to the top.
- Afterward
easeOut
– it beginning jumps to the pinnacle, then bounces there.
easeInOut
Nosotros also tin bear witness the issue both in the beginning and the end of the blitheness. The transform is called "easeInOut".
Given the timing function, nosotros calculate the animation country like this:
if (timeFraction <= 0.5) { // start one-half of the blitheness render timing(ii * timeFraction) / ii; } else { // 2d one-half of the animation return (2 - timing(2 * (ane - timeFraction))) / 2; }
The wrapper code:
function makeEaseInOut(timing) { return function(timeFraction) { if (timeFraction < .5) render timing(2 * timeFraction) / ii; else return (2 - timing(2 * (1 - timeFraction))) / ii; } } bounceEaseInOut = makeEaseInOut(bounce);
In action, bounceEaseInOut
:
#brick { width: 40px; height: 20px; background: #EE6B47; position: relative; cursor: pointer; } #path { outline: 1px solid #E8C48E; width: 540px; height: 20px; }
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> <script src="https://js.cx/libs/animate.js"></script> </caput> <body> <div id="path"> <div id="brick"></div> </div> <script> function makeEaseInOut(timing) { render role(timeFraction) { if (timeFraction < .5) render timing(ii * timeFraction) / 2; else return (2 - timing(2 * (1 - timeFraction))) / ii; } } function bounciness(timeFraction) { for (permit a = 0, b = 1; 1; a += b, b /= 2) { if (timeFraction >= (7 - 4 * a) / xi) { return -Math.prisoner of war((11 - 6 * a - 11 * timeFraction) / four, 2) + Math.pow(b, two) } } } allow bounceEaseInOut = makeEaseInOut(bounce); brick.onclick = role() { animate({ duration: 3000, timing: bounceEaseInOut, depict: function(progress) { brick.style.left = progress * 500 + 'px'; } }); }; </script> </body> </html>
The "easeInOut" transform joins 2 graphs into one: easeIn
(regular) for the first one-half of the blitheness and easeOut
(reversed) – for the 2d part.
The effect is clearly seen if we compare the graphs of easeIn
, easeOut
and easeInOut
of the circ
timing function:
- Red is the regular variant of
circ
(easeIn
). - Green –
easeOut
. - Blue –
easeInOut
.
As nosotros can see, the graph of the first half of the animation is the scaled down easeIn
, and the second half is the scaled downward easeOut
. As a result, the animation starts and finishes with the same effect.
More interesting "draw"
Instead of moving the element we tin can practise something else. All we demand is to write the proper draw
.
Here'due south the animated "billowy" text typing:
textarea { display: block; edge: 1px solid #BBB; color: #444; font-size: 110%; } push { margin-top: 10px; }
<!DOCTYPE HTML> <html> <caput> <meta charset="utf-8"> <link rel="stylesheet" href="style.css"> <script src="https://js.cx/libs/animate.js"></script> </head> <body> <textarea id="textExample" rows="5" cols="threescore">He took his vorpal sword in hand: Long time the manxome foe he sought— So rested he past the Tumtum tree, And stood awhile in thought. </textarea> <button onclick="animateText(textExample)">Run the animated typing!</push> <script> function animateText(textArea) { let text = textArea.value; allow to = text.length, from = 0; breathing({ duration: 5000, timing: bounce, draw: function(progress) { let result = (to - from) * progress + from; textArea.value = text.substr(0, Math.ceil(result)) } }); } function bounce(timeFraction) { for (allow a = 0, b = 1; one; a += b, b /= two) { if (timeFraction >= (vii - four * a) / 11) { return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, ii) + Math.prisoner of war(b, 2) } } } </script> </body> </html>
Summary
For animations that CSS can't handle well, or those that need tight control, JavaScript can help. JavaScript animations should be implemented via requestAnimationFrame
. That built-in method allows to setup a callback function to run when the browser volition be preparing a repaint. Usually that'due south very soon, but the verbal time depends on the browser.
When a folio is in the background, there are no repaints at all, and then the callback won't run: the animation will be suspended and won't eat resources. That's great.
Hither's the helper animate
role to setup about animations:
role animate({timing, draw, elapsing}) { let start = performance.now(); requestAnimationFrame(function breathing(time) { // timeFraction goes from 0 to 1 let timeFraction = (time - get-go) / duration; if (timeFraction > i) timeFraction = 1; // summate the current animation state let progress = timing(timeFraction); depict(progress); // draw it if (timeFraction < 1) { requestAnimationFrame(animate); } }); }
Options:
-
duration
– the total animation time in ms. -
timing
– the function to calculate animation progress. Gets a time fraction from 0 to 1, returns the animation progress, usually from 0 to one. -
draw
– the office to depict the animation.
Surely we could improve it, add more than bells and whistles, simply JavaScript animations are not applied on a daily footing. They are used to exercise something interesting and not-standard. So yous'd want to add the features that you lot need when y'all need them.
JavaScript animations tin can apply any timing function. We covered a lot of examples and transformations to brand them even more versatile. Different CSS, nosotros are not limited to Bezier curves here.
The same is about describe
: we can animate anything, not only CSS properties.
Source: https://javascript.info/js-animation
Posted by: goodmancrooking1973.blogspot.com
0 Response to "How To Create Animation Effects In Javascript"
Post a Comment