[ Web Proxy ]
URL:
Viewing: https://learn.javascript.ru/js-animation [Back]  [Original]

JavaScript-
:
DanskEnglishEspaolFranaisIndonesiaItalianoTrkeOzbek
31 2024 .

JavaScript-

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';
}

, :

index.html
<!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-function linear. .

draw(progress)

, . progress=0 , , progress=1 .

, .

:

function draw(progress) {
  train.style.left = progress + 'px';
}

- . , .

, width 0 100%.

, :

animate.js
index.html
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);

, , . :

style.css
index.html
#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:

style.css
index.html
#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.

:

style.css
index.html
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-.

: 5

. , , :

.

, CSS- top position:absolute position:relative.

field.clientHeight. CSS- top , 0 field.clientHeight - ball.clientHeight.

, bounce easeOut.

:

let to = field.clientHeight - ball.clientHeight;

animate({
  duration: 2000,
  timing: makeEaseOut(bounce),
  draw(progress) {
    ball.style.top = to * progress + 'px'
  }
});

.

: 5

. :

. 100px.

.

. : elem.style.left.

: , , .

animate.

linear, makeEaseOut(quad) .

:

let height = field.clientHeight - ball.clientHeight;
let width = 100;

//  top ()
animate({
  duration: 2000,
  timing: makeEaseOut(bounce),
  draw: function(progress) {
    ball.style.top = height * progress + 'px'
  }
});

//  left ( )
animate({
  duration: 2000,
  timing: makeEaseOut(quad),
  draw: function(progress) {
    ball.style.left = width * progress + "px"
  }
});

.


Web Proxy Viewer  |  New URL  |  Original Page