JavaScript- , CSS.
, , , canvas-.
setInterval
, HTML/CSS-.
, style.left 0px 100px . setInterval, 2px , 50 , . , : 24 , .
:
let timer = setInterval(function() {
if (animation complete) clearInterval(timer);
else increase style.left by 2px
}, 20); // 2px 20ms, 50
:
let start = Date.now(); //
let timer = setInterval(function() {
// ?
let timePassed = Date.now() - start;
if (timePassed >= 2000) {
clearInterval(timer); // 2
return;
}
// timePassed,
draw(timePassed);
}, 20);
// timePassed 0 2000
// left 0px 400px
function draw(timePassed) {
train.style.left = timePassed / 5 + 'px';
}
, :
<!DOCTYPE HTML>
<html>
<head>
<style>
#train {
position: relative;
cursor: pointer;
}
</style>
</head>
<body>
<img id="train" src="https://js.cx/clipart/train.gif">
<script>
train.onclick = function() {
let start = Date.now();
let timer = setInterval(function() {
let timePassed = Date.now() - start;
train.style.left = timePassed / 5 + 'px';
if (timePassed > 2000) clearInterval(timer);
}, 20);
}
</script>
</body>
</html>requestAnimationFrame
, , .
setInterval(..., 20), , 20ms.
- , 20 . 20ms.
:
setInterval(function() {
animate1();
animate2();
animate3();
}, 20)
, :
setInterval(animate1, 20); //
setInterval(animate2, 20); //
setInterval(animate3, 20);
, , .
, : CPU (, ), 20ms.
JavaScript? Animation timing requestAnimationFrame, .
:
let requestId = requestAnimationFrame(callback)
callback , .
callback , requestAnimationFrame CSS-. , .
requestId :
// callback
cancelAnimationFrame(requestId);
callback . performance.now().
, callback , CPU , - .
10 requestAnimationFrame. 10-20 :
<script>
let prev = performance.now();
let times = 0;
requestAnimationFrame(function measure(time) {
document.body.insertAdjacentHTML("beforeEnd", Math.floor(time - prev) + " ");
prev = time;
if (times++ < 10) requestAnimationFrame(measure);
})
</script>
requestAnimationFrame:
function animate({timing, draw, duration}) {
let start = performance.now();
requestAnimationFrame(function animate(time) {
// timeFraction 0 1
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
//
let progress = timing(timeFraction);
draw(progress); //
if (timeFraction < 1) {
requestAnimationFrame(animate);
}
});
}
animate , :
duration-
. ,
1000. timing(timeFraction)-
, CSS-
transition-timing-function, (y) (0,1)., , :
function linear(timeFraction) { return timeFraction; }:
[]
transition-timing-functionlinear. . draw(progress)-
, .
progress=0, ,progress=1., .
:
function draw(progress) { train.style.left = progress + 'px'; }- . , .
, width 0 100%.
, :
function animate({duration, draw, timing}) {
let start = performance.now();
requestAnimationFrame(function animate(time) {
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
let progress = timing(timeFraction)
draw(progress);
if (timeFraction < 1) {
requestAnimationFrame(animate);
}
});
}<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<style>
progress {
width: 5%;
}
</style>
<script src="animate.js"></script>
</head>
<body>
<progress id="elem"></progress>
<script>
elem.onclick = function() {
animate({
duration: 1000,
timing: function(timeFraction) {
return timeFraction;
},
draw: function(progress) {
elem.style.width = progress * 100 + '%';
}
});
};
</script>
</body>
</html>:
animate({
duration: 1000,
timing(timeFraction) {
return timeFraction;
},
draw(progress) {
elem.style.width = progress * 100 + '%';
}
});
CSS-, . , draw , (, ).
.
. , .
n
, progress n.
, :
function quad(timeFraction) {
return Math.pow(timeFraction, 2)
}
:
( ):
, n. .
progress 5:
:
:
function circ(timeFraction) {
return 1 - Math.sin(Math.acos(timeFraction));
}
:
:
. , .
, x . .
:
function back(x, timeFraction) {
return Math.pow(timeFraction, 2) * ((x + 1) * timeFraction - x)
}
x = 1.5:
x . x 1.5:
, . , , .
bounce , : . :
function bounce(timeFraction) {
for (let a = 0, b = 1; 1; a += b, b /= 2) {
if (timeFraction >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2)
}
}
}
:
, x .
function elastic(x, timeFraction) {
return Math.pow(2, 10 * (timeFraction - 1)) * Math.cos(20 * Math.PI * x / 3 * timeFraction)
}
x=1.5:
[]
x=1.5:
: ease*
, . easeIn.
. , , easeOut.
easeOut
easeOut timing timingEaseOut:
timingEaseOut(timeFraction) = 1 - timing(1 - timeFraction)
, makeEaseOut, :
//
function makeEaseOut(timing) {
return function(timeFraction) {
return 1 - timing(1 - timeFraction);
}
}
, bounce :
let bounceEaseOut = makeEaseOut(bounce);
, , . :
#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>
</head>
<body>
<div id="path">
<div id="brick"></div>
</div>
<script>
function makeEaseOut(timing) {
return function(timeFraction) {
return 1 - timing(1 - timeFraction);
}
}
function bounce(timeFraction) {
for (let a = 0, b = 1; 1; a += b, b /= 2) {
if (timeFraction >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2)
}
}
}
let bounceEaseOut = makeEaseOut(bounce);
brick.onclick = function() {
animate({
duration: 3000,
timing: bounceEaseOut,
draw: function(progress) {
brick.style.left = progress * 500 + 'px';
}
});
};
</script>
</body>
</html>, :
, , , .
easeOut.
- , .
-
easeOut, .
easeInOut
. easeInOut.
, :
if (timeFraction <= 0.5) { //
return timing(2 * timeFraction) / 2;
} else { //
return (2 - timing(2 * (1 - timeFraction))) / 2;
}
-:
function makeEaseInOut(timing) {
return function(timeFraction) {
if (timeFraction < .5)
return timing(2 * timeFraction) / 2;
else
return (2 - timing(2 * (1 - timeFraction))) / 2;
}
}
bounceEaseInOut = makeEaseInOut(bounce);
, 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>
</head>
<body>
<div id="path">
<div id="brick"></div>
</div>
<script>
function makeEaseInOut(timing) {
return function(timeFraction) {
if (timeFraction < .5)
return timing(2 * timeFraction) / 2;
else
return (2 - timing(2 * (1 - timeFraction))) / 2;
}
}
function bounce(timeFraction) {
for (let a = 0, b = 1; 1; a += b, b /= 2) {
if (timeFraction >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2)
}
}
}
let bounceEaseInOut = makeEaseInOut(bounce);
brick.onclick = function() {
animate({
duration: 3000,
timing: bounceEaseInOut,
draw: function(progress) {
brick.style.left = progress * 500 + 'px';
}
});
};
</script>
</body>
</html> easeInOut : easeIn () easeOut () .
, easeIn, easeOut easeInOut circ:
-
circ(easeIn). -
easeOut. -
easeInOut.
, easeIn, easeOut. , .
draw
- . , draw.
:
textarea {
display: block;
border: 1px solid #BBB;
color: #444;
font-size: 110%;
}
button {
margin-top: 10px;
}<!DOCTYPE HTML>
<html>
<head>
<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="60"> , ,
y.
.
</textarea>
<button onclick="animateText(textExample)"> !</button>
<script>
function animateText(textArea) {
let text = textArea.value;
let to = text.length,
from = 0;
animate({
duration: 5000,
timing: bounce,
draw: function(progress) {
let result = (to - from) * progress + from;
textArea.value = text.slice(0, Math.ceil(result))
}
});
}
function bounce(timeFraction) {
for (let a = 0, b = 1; 1; a += b, b /= 2) {
if (timeFraction >= (7 - 4 * a) / 11) {
return -Math.pow((11 - 6 * a - 11 * timeFraction) / 4, 2) + Math.pow(b, 2)
}
}
}
</script>
</body>
</html>JavaScript , CSS . JavaScript- requestAnimationFrame. , , ( , ).
, , : . .
animate :
function animate({timing, draw, duration}) {
let start = performance.now();
requestAnimationFrame(function animate(time) {
// timeFraction 0 1
let timeFraction = (time - start) / duration;
if (timeFraction > 1) timeFraction = 1;
//
let progress = timing(timeFraction);
draw(progress); //
if (timeFraction < 1) {
requestAnimationFrame(animate);
}
});
}
:
duration.timing. 0 1, , 0 1.draw.
, . JavaScript- , - . , .
JavaScript- . , . CSS, .
draw: , CSS-.
<code>, —<pre>, 10 — (plnkr, JSBin, codepen)