From aa521b90907a72851d1bd4ff46cfb09cd998e3e1 Mon Sep 17 00:00:00 2001 From: Ilya Kantor Date: Wed, 22 Mar 2017 11:35:49 +0300 Subject: [PATCH] ok --- .../1-animate-logo-css/solution.md | 9 +- .../solution.view/index.html | 8 +- .../1-animate-logo-css/source.view/index.html | 6 +- .../1-animate-logo-css/task.md | 13 +- .../2-animate-logo-bezier-css/solution.md | 8 +- .../solution.view/index.html | 8 +- .../2-animate-logo-bezier-css/task.md | 8 +- .../3-js-animation/1-animate-ball/solution.md | 13 +- .../1-animate-ball/solution.view/index.html | 4 +- .../1-animate-ball/source.view/index.html | 6 +- .../3-js-animation/1-animate-ball/task.md | 5 +- .../2-animate-ball-hops/solution.md | 13 +- .../2-animate-ball-hops/task.md | 8 +- 5-animation/3-js-animation/article.md | 285 ++++++++---------- .../3-js-animation/move-raf.view/index.html | 25 +- .../3-js-animation/text.view/index.html | 9 +- .../3-js-animation/width.view/index.html | 2 +- figures.sketch | Bin 14589952 -> 14589952 bytes 18 files changed, 194 insertions(+), 236 deletions(-) diff --git a/5-animation/2-css-animations/1-animate-logo-css/solution.md b/5-animation/2-css-animations/1-animate-logo-css/solution.md index 2687b05f..7aa7ca72 100644 --- a/5-animation/2-css-animations/1-animate-logo-css/solution.md +++ b/5-animation/2-css-animations/1-animate-logo-css/solution.md @@ -1,16 +1,17 @@ -CSS-код для анимации одновременно `width` и `height`: +CSS to animate both `width` and `height`: ```css -/* исходный класс */ +/* original class */ #flyjet { transition: all 3s; } -/* JS добавляет .growing *. + +/* JS adds .growing */ #flyjet.growing { width: 400px; height: 240px; } ``` -Небольшая тонкость с окончанием анимации. Соответствующее событие `transitionend` сработает два раза -- по одному для каждого свойства. Поэтому, если не предпринять дополнительных шагов, сообщение из обработчика может быть выведено 2 раза. +Please note that `transitionend` triggers two times -- once for every property. So if we don't perform an additional check then the message would show up 2 times. diff --git a/5-animation/2-css-animations/1-animate-logo-css/solution.view/index.html b/5-animation/2-css-animations/1-animate-logo-css/solution.view/index.html index 31488125..4e90e247 100644 --- a/5-animation/2-css-animations/1-animate-logo-css/solution.view/index.html +++ b/5-animation/2-css-animations/1-animate-logo-css/solution.view/index.html @@ -14,7 +14,7 @@ height: 24px; transition: all 3s; } - + #flyjet.growing { width: 400px; height: 240px; @@ -24,7 +24,7 @@ - + - \ No newline at end of file + diff --git a/5-animation/2-css-animations/2-animate-logo-bezier-css/task.md b/5-animation/2-css-animations/2-animate-logo-bezier-css/task.md index da9985fd..9e21f410 100644 --- a/5-animation/2-css-animations/2-animate-logo-bezier-css/task.md +++ b/5-animation/2-css-animations/2-animate-logo-bezier-css/task.md @@ -2,12 +2,12 @@ importance: 5 --- -# Анимировать самолёт с перелётом (CSS) +# Animate the flying plane (CSS) -Модифицируйте решение предыдущей задачи , чтобы в процессе анимации изображение выросло больше своего стандартного размера 400x240px ("выпрыгнуло"), а затем вернулось к нему. +Modify the solution of the previous task to make the plane grow more than it's original size 400x240px (jump out), and then return to that size. -Должно получиться как здесь (клик на картинку) +Here's how it should look (click on the plane): [iframe src="solution" height=350] -В качестве исходного документа возьмите решение предыдущей задачи. \ No newline at end of file +Take the solution of the previous task as the source. diff --git a/5-animation/3-js-animation/1-animate-ball/solution.md b/5-animation/3-js-animation/1-animate-ball/solution.md index c931b5de..3a9b8564 100644 --- a/5-animation/3-js-animation/1-animate-ball/solution.md +++ b/5-animation/3-js-animation/1-animate-ball/solution.md @@ -1,10 +1,12 @@ -В HTML/CSS, падение мяча можно отобразить изменением свойства `ball.style.top` от 0 и до значения, соответствующего нижнему положению. +To bounce we can use CSS property `top` and `position:absolute` for the ball inside the field with `position:relative`. -Нижняя граница элемента `field`, в котором находится мяч, имеет значение `field.clientHeight`. Но свойство `top` относится к верху мяча, поэтому оно меняется до `field.clientHeight - ball.clientHeight`. +The bottom coordinate of the field is `field.clientHeight`. But the `top` property gives coordinates for the top of the ball, the edge position is `field.clientHeight - ball.clientHeight`. -Для создания анимационного эффекта лучше всего подойдет функция `bounce` в режиме `easeOut`. +So we animate the `top` from `0` to `field.clientHeight - ball.clientHeight`. -Следующий код даст нам нужный результат: +Now to get the "bouncing" effect we can use the timing function `bounce` in `easeOut` mode. + +Here's the final code for the animation: ```js let to = field.clientHeight - ball.clientHeight; @@ -12,9 +14,8 @@ let to = field.clientHeight - ball.clientHeight; animate({ duration: 2000, timing: makeEaseOut(bounce), - draw: function(progress) { + draw(progress) { ball.style.top = to * progress + 'px' } }); ``` - diff --git a/5-animation/3-js-animation/1-animate-ball/solution.view/index.html b/5-animation/3-js-animation/1-animate-ball/solution.view/index.html index a29a9466..7e031e8d 100644 --- a/5-animation/3-js-animation/1-animate-ball/solution.view/index.html +++ b/5-animation/3-js-animation/1-animate-ball/solution.view/index.html @@ -35,7 +35,7 @@ animate({ duration: 2000, timing: makeEaseOut(bounce), - draw: function(progress) { + draw(progress) { ball.style.top = to * progress + 'px' } }); @@ -48,4 +48,4 @@ - \ No newline at end of file + diff --git a/5-animation/3-js-animation/1-animate-ball/source.view/index.html b/5-animation/3-js-animation/1-animate-ball/source.view/index.html index 7b527a44..4095fbea 100644 --- a/5-animation/3-js-animation/1-animate-ball/source.view/index.html +++ b/5-animation/3-js-animation/1-animate-ball/source.view/index.html @@ -2,7 +2,7 @@ - + @@ -10,10 +10,10 @@
- +
- \ No newline at end of file + diff --git a/5-animation/3-js-animation/1-animate-ball/task.md b/5-animation/3-js-animation/1-animate-ball/task.md index 28f1b1b6..903e8238 100644 --- a/5-animation/3-js-animation/1-animate-ball/task.md +++ b/5-animation/3-js-animation/1-animate-ball/task.md @@ -2,9 +2,8 @@ importance: 5 --- -# Анимируйте мяч +# Animate the bouncing ball -Сделайте так, чтобы мяч подпрыгивал. Кликните по мячу, чтобы увидеть, как это должно выглядеть. +Make a bouncing ball. Click to see how it should look: [iframe height=250 src="solution"] - diff --git a/5-animation/3-js-animation/2-animate-ball-hops/solution.md b/5-animation/3-js-animation/2-animate-ball-hops/solution.md index e13dbab9..d47387e3 100644 --- a/5-animation/3-js-animation/2-animate-ball-hops/solution.md +++ b/5-animation/3-js-animation/2-animate-ball-hops/solution.md @@ -1,17 +1,18 @@ -В задаче создаётся подпрыгивающий мяч. Нам нужно всего лишь добавить еще одну анимацию для `elem.style.left`. +In the task we had only one property to animate. Now we need one more: `elem.style.left`. -Горизонтальная координата меняется по другому закону, нежели вертикальная. Она не "подпрыгивает", а постоянно увеличивается, постепенно сдвигая мяч вправо. +The horizontal coordinate changes by another law: it does not "bounce", but gradually increases shifting the ball to the right. -Поэтому мы не можем добавить её в тот же `animate`, нужно делать отдельный. +We can write one more `animate` for it. -В качестве временной функции для перемещения вправо мы могли бы применить для неё `linear`, но тогда горизонтальное движение будет отставать от скачков мяча. Более красиво будет что-то типа `makeEaseOut(quad)`. +As the time function we could use `linear`, but something like `makeEaseOut(quad)` looks much better. -Код: +The code: ```js let height = field.clientHeight - ball.clientHeight; let width = 100; +// animate top (bouncing) animate({ duration: 2000, timing: makeEaseOut(bounce), @@ -20,6 +21,7 @@ animate({ } }); +// animate left (moving to the right) animate({ duration: 2000, timing: makeEaseOut(quad), @@ -28,4 +30,3 @@ animate({ } }); ``` - diff --git a/5-animation/3-js-animation/2-animate-ball-hops/task.md b/5-animation/3-js-animation/2-animate-ball-hops/task.md index 2727eda0..1134d192 100644 --- a/5-animation/3-js-animation/2-animate-ball-hops/task.md +++ b/5-animation/3-js-animation/2-animate-ball-hops/task.md @@ -2,12 +2,12 @@ importance: 5 --- -# Анимируйте падение мяча с отскоками вправо +# Animate the ball bouncing to the left -Заставьте мяч падать вправо. Кликните, чтобы увидеть в действии. +Make the ball bounce to the left. Like this: [iframe height=250 src="solution"] -Напишите код, который будет анимировать мяч. Дистанция вправо составляет `100px`. +Write the animation code. The distance to the right is `100px`. -В качестве исходного кода возьмите решение предыдущей задачи . \ No newline at end of file +Take the solution of the previous task as the source. diff --git a/5-animation/3-js-animation/article.md b/5-animation/3-js-animation/article.md index dc80e1fb..35d7f082 100644 --- a/5-animation/3-js-animation/article.md +++ b/5-animation/3-js-animation/article.md @@ -1,4 +1,4 @@ -# JavaScript animations [todo] +# JavaScript animations JavaScript animations can handle things that CSS can't. @@ -94,7 +94,7 @@ let requestId = requestAnimationFrame(callback) That schedules the `callback` function to run in the closest time when the browser wants to do animation. -If we do changes in elements in `callback` then they will be grouped together with other `requestAnimationFrame` callbacks and with CSS animations. So there will be one repaint instead of many. +If we do changes in elements in `callback` then they will 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: ```js @@ -102,11 +102,11 @@ The returned value `requestId` can be used to cancel the call: cancelAnimationFrame(requestId); ``` -The `callback` function получает один аргумент -- время, прошедшее с начала загрузки страницы, результат вызова [performance.now()](https://developer.mozilla.org/en-US/docs/Web/API/Performance/now). +The `callback` gets one argument -- the time passed from the beginning of the page load in microseconds. This time can also be obtained by calling [performance.now()](mdn:api/Performance/now). -Как правило, запуск `callback` происходит очень скоро. Если у процессора большая загрузка или батарея у ноутбука почти разряжена -- то пореже. +Usually `callback` runs very soon, unless the CPU is overloaded or the laptop battery is almost discharged, or there's another reason. -Если вы запустите этот код, то увидите промежутки между первыми 20 запусками `requestAnimationFrame`. Как правило, это 10-20 мс, но бывает и больше и меньше. Это оптимальная частота анимации с точки зрения браузера. +The code below shows the time between first 20 runs fo `requestAnimationFrame`. Usually it's 10-20ms: ```html run height=40 refresh ``` -Функция анимации на основе `requestAnimationFrame`: +## Structured animation + +Now we can make a more universal animation function based on `requestAnimationFrame`: ```js -// Рисует функция draw -// Продолжительность анимации duration -function animate(draw, duration) { +function animate({timing, draw, duration}) { + let start = performance.now(); requestAnimationFrame(function animate(time) { - // определить, сколько прошло времени с начала анимации - let timePassed = time - start; + // timeFraction goes from 0 to 1 + let timeFraction = (time - start) / duration; + if (timeFraction > 1) timeFraction = 1; - // возможно небольшое превышение времени, в этом случае зафиксировать конец - if (timePassed > duration) timePassed = duration; + // calculate the current animation state + let progress = timing(timeFraction) - // нарисовать состояние анимации в момент timePassed - draw(timePassed); + draw(progress); // draw it - // если время анимации не закончилось - запланировать ещё кадр - if (timePassed < duration) { + if (timeFraction < 1) { requestAnimationFrame(animate); } @@ -149,99 +149,75 @@ function animate(draw, duration) { } ``` -Использование для поезда: -```js -animate(function(timePassed) { - train.style.left = timePassed / 5 + 'px'; -}, 2000); -``` - -В действии: - -[codetabs src="move-raf"] - -## Структура анимации - -На основе `requestAnimationFrame` можно соорудить и гораздо более мощную, но в то же время простую функцию анимации. - -У анимации есть три основных параметра: +Function `animate` accepts 3 parameters that essentially describe the animation: `duration` -: Общее время, которое должна длиться анимация, в мс. Например, `1000`. +: Total time of animation. Like, `1000`. `timing(timeFraction)` -: Временная функция, которая, по аналогии с CSS-свойством `transition-timing-function`, будет по текущему времени вычислять состояние анимации. +: Timing function, like CSS-property `transition-timing-function` that takes gets the fraction of time that passed (`0` at start, `1` at the end) and returns the animation completion (like `y` on the Bezier curve). - Она получает на вход непрерывно возрастающее число `timeFraction` -- от `0` до `1`, где `0` означает самое начало анимации, а `1` -- её конец. + For instance, a linear function means that the animation goes on uniformly with the same speed: - Её результатом должно быть значение завершённости анимации, которому в CSS transitions на кривых Безье соответствует координата `y`. - - Также по аналогии с `transition-timing-function` должны соблюдаться условия: - -- timing(0) = 0 -- timing(1) = 1 - - ...То есть, анимация начинается в точке `(0,0)` -- нулевое время и нулевой прогресс и заканчивается в `(1, 1)` -- прошло полное время, и процесс завершён. - - Например, функция-прямая означает равномерное развитие процесса: ```js function linear(timeFraction) { return timeFraction; } ``` - Её график: -![](linear.png) + It's graph: + ![](linear.png) - Как видно, её график полностью совпадает с `transition-timing-function: linear`, и эффект абсолютно такой же. - - Есть и другие, более интересные варианты, мы рассмотрим их чуть позже. + That's just like `transition-timing-function: linear`. There are more interesting variants shown below. `draw(progress)` -: Функция, которая получает состояние завершённости анимации и рисует его. Значению `progress=0` соответствует начальная точка анимации, `progress=1` -- конечная. +: The function that takes the animation completion state and draws it. The value `progress=0` denotes the beginning animation state, and `progress=1` -- the end state. - Именно эта функция и осуществляет, собственно, анимацию. + This is that function that actually draws out the animation. - Например, может двигать элемент: + It can move the element: ```js function draw(progress) { train.style.left = progress + 'px'; } ``` - Возможны любые варианты, анимировать можно что угодно и как угодно. + ...Or do anything else, we can animate anything, in any way. -Анимируем ширину элемента `width` от `0` до `100%`, используя нашу функцию. -Кликните для демонстрации: +Let's animate the element `width` from `0` to `100%` using our function. + +Click for the demo: [codetabs height=60 src="width"] -Код для запуска анимации: +The code for it: ```js animate({ duration: 1000, - timing: function(timeFraction) { + timing(timeFraction) { return timeFraction; }, - draw: function(progress) { + draw(progress) { elem.style.width = progress * 100 + '%'; } }); ``` -## Временные функции +Unlike CSS animation, we can make any timing function and any drawing function here. The timing function is not limited by Bezier curves. And `draw` can go beyound properties, create new elements for like fireworks animation or something. -Выше мы видели самую простую, линейную временную функцию. +## Timing functions -Рассмотрим примеры анимации движения с использованием различных `timing`. +We saw the simplest, linear timing function above. -### В степени n +Let's see more of them. We'll try movement animations with different timing functions to see how they work. -Вот еще один простой случай -- `progress` в степени `n`. Частные случаи - квадратичная, кубическая функции и т.д. +### Power of n -Для квадратичной функции: +If we want to speed up the animation, we can use `progress` in the power `n`. + +For instance, a parabolic curve: ```js function quad(progress) { @@ -249,45 +225,47 @@ function quad(progress) { } ``` -**График квадратичной функции:** +The graph: ![](quad.png) -Пример для квадратичной функции (клик для просмотра): +See in action (click to activate): [iframe height=40 src="quad" link] -Увеличение степени влияет на ускорение. Например, график для 5-й степени: +...Or the cubic curve or event greater `n`. Increasing the power makes it speed up faster. + +Here's the graph for `progress` in the power `5`: ![](quint.png) -В действии: +In action: [iframe height=40 src="quint" link] -### Дуга +### The arc -Функция: +Function: ```js function circ(timeFraction) { - return 1 - Math.sin(Math.acos(timeFraction)) + return 1 - Math.sin(Math.acos(timeFraction)); } ``` -**График:** +The graph: ![](circ.png) [iframe height=40 src="circ" link] -### Back: стреляем из лука +### Back: bow shooting -Эта функция работает по принципу лука: сначала мы "натягиваем тетиву", а затем "стреляем". +This function does the "bow shooting". First we "pull the bowstring", and then "shoot". -В отличие от предыдущих функций, эта зависит от дополнительного параметра `x`, который является "коэффициентом упругости". Он определяет расстояние, на которое "оттягивается тетива". +Unlike previous functions, it depends on an additional parameter `x`, the "elasticity coefficient". The distance of "bowstring pulling" is defined by it. -Её код: +The code: ```js function back(x, timeFraction) { @@ -295,21 +273,19 @@ function back(x, timeFraction) { } ``` -**График для `x = 1.5`:** +**The graph for `x = 1.5`:** ![](back.png) -Пример для `x = 1.5`: +For animation we use it with a concrete value of `x`. Example for `x = 1.5`: [iframe height=40 src="back" link] -### Отскок bounce +### Bounce -Представьте, что мы отпускаем мяч, он падает на пол, несколько раз отскакивает и останавливается. +Imagine we are dropping a ball. It falls down, then bounces back a few times and stops. -Функция `bounce` делает то же самое, только наоборот: "подпрыгивание" начинается сразу. - -Эта функция немного сложнее предыдущих и использует специальные коэффициенты: +The `bounce` function does the same, but in the reverse order: "bouncing" starts immediately. It uses few special coefficients for that: ```js function bounce(timeFraction) { @@ -321,15 +297,13 @@ function bounce(timeFraction) { } ``` -Код взят из MooTools.FX.Transitions. Конечно же, есть и другие реализации `bounce`. - -Пример: +In action: [iframe height=40 src="bounce" link] -### Упругая анимация +### Elastic animation -Эта функция зависит от дополнительного параметра `x`, который определяет начальный диапазон. +One more "elastic" function that accepts an additional parameter `x` for the "initial range". ```js function elastic(x, timeFraction) { @@ -337,79 +311,74 @@ function elastic(x, timeFraction) { } ``` -**График для `x=1.5`:** +**The graph for `x=1.5`:** ![](elastic.png) -Пример для `x=1.5`: +In action for `x=1.5`: [iframe height=40 src="elastic" link] -## Реверсивные функции ease* +## Reversal: ease* -Итак, у нас есть коллекция временных функций. +So we have a collection of timing functions. Their direct application is called "easeIn". -Их прямое использование называется "easeIn". - -**Иногда нужно показать анимацию в обратном режиме. Преобразование функции, которое даёт такой эффект, называется "easeOut"**. +Sometimes we need to show the animation in the reverse order. That's done with the "easeOut" transform. ### easeOut -В режиме "easeOut", значение timing вычисляется по формуле: `timingEaseOut(timeFraction) = 1 - timing(1 - timeFraction)` - -Например, функция `bounce` в режиме "easeOut": +In the "easeOut" mode the `timing` function is put into a wrapper `timingEaseOut`: ```js -// обычный вариант -function bounce(timeFraction) { - for (let a = 0, b = 1, result; 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); - } - } -} +timingEaseOut(timeFraction) = 1 - timing(1 - timeFraction) +``` -// преобразователь в easeOut +In other words, we have a "transform" function `makeEaseOut` that takes a "regular" timing function and returns the wrapper around it: + +```js +// accepts a timing function, returns the transformed variant function makeEaseOut(timing) { return function(timeFraction) { return 1 - timing(1 - timeFraction); } } - -*!* -let bounceEaseOut = makeEaseOut(bounce); -*/!* ``` -Полный пример -- отскок в `bounceEaseOut` теперь не в начале, а в конце (и это куда красивее): +For instance, we can take the `bounce` function described above and apply it: + +```js +let bounceEaseOut = makeEaseOut(bounce); +``` + +Then the bounce will be not in the beginning, but at the end of the animation. Looks even better: [codetabs src="bounce-easeout"] -На этом графике видно, как преобразование `easeOut` изменяет поведение функции: +Here we can see how the transform changes the behavior of the function: ![](bounce-inout.png) -Если есть анимационный эффект, такой как подпрыгивание -- он будет показан в конце, а не в начале (или наоборот, в начале, а не в конце). +If there's an animation effect in the beginning, like bouncing -- it will be shown at the end. -Красным цветом обозначен обычный вариант, а синим -- `easeOut`. +In the graph above the regular bounce has the red color, and the easeOut bounce is blue. -- Обычно анимируемый объект сначала медленно скачет внизу, а затем, в конце, резко достигает верха.. -- А после `easeOut` -- он сначала прыгает наверх, а затем медленно скачет внизу. +- Regular bounce -- the object bounces at the bottom, then at the end sharply jumps to the top. +- After `easeOut` -- it first jumps to the top, then bounces there. ### easeInOut -А еще можно сделать так, чтобы показать эффект *и в начале и в конце* анимации. Соответствующее преобразование называется "easeInOut". +We also can show the effect both in the beginning and the end of the animation. The transform is called "easeInOut". -Его код выглядит так: +Given the timing function, we calculate the animation state like this: ```js -if (timeFraction <= 0.5) { // первая половина анимации) +if (timeFraction <= 0.5) { // first half of the animation return timing(2 * timeFraction) / 2; -} else { // вторая половина +} else { // second half of the animation return (2 - timing(2 * (1 - timeFraction))) / 2; } ``` -Код, который трансформирует `timing`: +The wrapper code: ```js function makeEaseInOut(timing) { @@ -424,60 +393,52 @@ function makeEaseInOut(timing) { bounceEaseInOut = makeEaseInOut(bounce); ``` -Пример с `bounceEaseInOut`: +In action, `bounceEaseInOut`: [codetabs src="bounce-easeinout"] -Трансформация "easeInOut" объединяет в себе два графика в один: `easeIn` для первой половины анимации и `easeOut` -- для второй. +The "easeInOut" transform joins two graphs into one: `easeIn` (regular) for the first half of the animation and `easeOut` (reversed) -- for the second part. -Это отлично видно, если посмотреть графики `easeIn`, `easeOut` и `easeInOut` на примере функции `circ`: +The effect is clearly seen if we compare the graphs of `easeIn`, `easeOut` and `easeInOut` of the `circ` timing function: ![](circ-ease.png) -- Красным цветом обозначен обычный вариант функции `circ`. -- Зелёным -- `easeOut`. -- Синим -- `easeInOut`. +- Red is the regular variantof `circ` (`easeIn`). +- Green -- `easeOut`. +- Blue -- `easeInOut`. -Как видно, график первой половины анимации представляет собой уменьшенный "easeIn", а второй -- уменьшенный "easeOut". В результате, анимация начинается и заканчивается одинаковым эффектом. +As we can see, the graph of the first half of the animation is the scaled down `easeIn`, and the second half is the scaled down `easeOut`. As a result, the animation starts and finishes with the same effect. -```summary -Процесс анимации полностью в ваших руках благодаря `timing`. Её можно сделать настолько реалистичной, насколько захочется. +## More interesting "draw" -Впрочем, исходя из практики, можно сказать, что варианты `timing`, описанные выше, покрывают 95% потребностей в анимации. -``` +Instead of moving the element we can do something else. All we need is to write the write `draw` -## Сложные варианты step +### Typing in the text -Анимировать можно все, что угодно. Вместо движения, как во всех предыдущих примерах, можно изменять любые CSS свойства... И не только! - -Достаточно лишь написать соответствующий `draw`. - -### Набор текста - -Можно, к примеру, анимировать набор текста в "скачущем" режиме: +Here's the animated "bouncing" text typing: [codetabs src="text"] -## Итого +## Summary -Анимация выполняется путём вызовов `requestAnimationFrame`. Для поддержки IE9- желательно подключить полифилл, который будет внутри использовать `setTimeout`. Это будет всё равно лучше, чем независимые `setInterval`. +JavaScript animation is implemented with the help of `requestAnimationFrame`. -Реализация анимации -- очень простая и вместе с тем гибкая: +The helper `animate` function: ```js -function animate(options) { +function animate({timing, draw, duration}) { let start = performance.now(); requestAnimationFrame(function animate(time) { - // timeFraction от 0 до 1 - let timeFraction = (time - start) / options.duration; + // timeFraction goes from 0 to 1 + let timeFraction = (time - start) / duration; if (timeFraction > 1) timeFraction = 1; - // текущее состояние анимации - let progress = options.timing(timeFraction) + // calculate the current animation state + let progress = timing(timeFraction); - options.draw(progress); + draw(progress); // draw it if (timeFraction < 1) { requestAnimationFrame(animate); @@ -487,20 +448,14 @@ function animate(options) { } ``` -Основные параметры: +Options: -- `duration` -- длительность анимации в мс. -- `timing` -- функция, которая определяет состояние анимации каждый кадр. Получает часть времени от 0 до 1, возвращает завершенность анимации от 0 до 1. -- `draw` -- функция, которая отрисовывает состояние анимации от 0 до 1. +- `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 1. +- `draw` -- the function to draw the animation. -Эту функцию можно улучшить, например добавить коллбэк `complete` для вызова в конце анимации. +Surely we could improve it, add more bells and whistles, but JavaScript animations are not applied on a daily basis. They are used to do something interesting and non-standard. So you'd want to add the features that you need when you need them. -Мы рассмотрели ряд примеров для `timing` и трансформации `easeOut`, `easeInOut`, которые позволяют их разнообразить. В отличие от CSS мы не ограничены кривыми Безье, можно реализовать всё, что угодно. +JavaScript animations can use any timing function. We covered a lot of examples and transformations to make them even more versatile. Unlike CSS, we are not limited to Bezier curves here. -Это же относится и к функции `draw`. - -Такая реализация анимации имеет три основных области применения: - -- Нестандартные задачи и требования, не укладывающиеся в рамки CSS. -- Поддержка IE9-. -- Графика, рисование на canvas. +The same is about `draw`: we can animate anything, not just CSS properties. diff --git a/5-animation/3-js-animation/move-raf.view/index.html b/5-animation/3-js-animation/move-raf.view/index.html index 9b1a4899..bf6e0f6e 100644 --- a/5-animation/3-js-animation/move-raf.view/index.html +++ b/5-animation/3-js-animation/move-raf.view/index.html @@ -12,33 +12,32 @@ - - +