Руководство по Web Animations API — Часть 2: Объект AnimationPlayer и управление временной шкалой

Перевод статьи Web Animations API Tutorial Part 2: The AnimationPlayer & Timeline Controls с сайта danielcwilson.com, опубликовано на css-live.ru с разрешения автора — Дэна Уилсона (твиттер — @dancwilson).

Это вторая часть из серии учебных статей про Web Animations API, который вот-вот появится в браузерах. Если у вас есть мысли/вопросы, вы заметили, что я неправильно истолковал спецификацию, или хотите обсудить со мной что-то конкретное в будущих статьях, то обращайтесь ко мне в Twitter, @dancwilson.

Теперь, когда мы знаем, как с помощью Web Animations API создать базовую анимацию, пришло время поговорить о состояниях, управлении, обратных вызовах и шкале времени.

Состояния проигрывания AnimationPlayer и управление им

Вызов возвращает element.animate() возвращается объект AnimationPlayer и анимация начинает проигрываться. Чтобы увидеть текущее состояние, можно обратиться к свойству playState (только для чтения), которое вернёт одну из пяти строк. Также текущее состояние анимации можно изменить, вызвав один из четырёх методов:

var player = element.animate(/* ... */);
console.log(player.playState); //"running"

player.pause(); //"paused"
player.play();  //"running"
player.cancel(); //"idle"... перейти к исходному состоянию
player.finish(); //"finished"... перейти к конечному состоянию

В дополнение к running, paused, idle и finished есть состояние проигрывания pending, которое происходит, когда команда проигрывания или паузы находится в режиме ожидания.

В следующем примере «Шагающие круги» показано шесть масштабируемых кругов. Чтобы увидеть в действии некоторые из вышеописанных состояний проигрывания, можете ставить анимацию каждого круга на паузу или воспроизведение.

Скорость воспроизведения

В предыдущем примере на CodePen есть ещё кнопка «2х», нажав которую, можно изменить скорость воспроизведения анимации на удвоенную. Это делается через свойство playbackRate, доступное для чтения и записи.

var player = element.animate(/* ... */);
console.log(player.playbackRate); //1

player.playbackRate = 2; ////двойная скорость. Для замедления скорости можно также применять десятичные дроби.

Обратный вызов при завершении

В CSS-переходах есть событие, которое обычно запускается после завершения перехода. Аналогично, AnimationPlayer позволяет указать функцию onfinish, когда либо анимация завершается, либо вызывается ранее рассмотренный метод finish(). Заметьте, что согласно спецификации, анимация не сможет завершиться, если ей установить бесконечное число итераций, равно как и анимация с playbackRate 0. В спецификации также заявлено наличие обратного вызова oncancel, и использование промисов, в добавок к этим обратным вызовам… которые будут весьма кстати (хотя пока они еще не реализованы)

В примере ниже используется onfinish для отображения некоторой статистики после завершения анимации (и он также любезно перетекает к обсуждению следующей темы про шкалу времени)

Шкала времени

У каждого объекта AnimationPlayer доступны для чтения и записи два свойства, связанных со временем — currentTime и startTime. Сосредоточимся пока на первом.

currentTime возвращает текущее положение анимации в миллисекундах. Максимальное значение вычисляется по формуле «задержка + (продолжительность * число итераций)», поэтому при бесконечных итерациях не бывает максимального значения.

var player = element.animate([
  {opacity: 1}, {opacity: 0}
], {
  duration: 1000,
  delay: 500,
  iterations: 3
});

player.onfinish = function() {
  console.log(player.currentTime); // 3500
};

От скорости воспроизведения зависит, насколько быстро анимация будет пробегать по шкале времени. Если скорость воспроизведения равна 10, то максимальный currentTime останется прежним, но при этом вы пройдёте шкалу времени в 10 раз быстрее. Это понятие также иллюстрируется в ранее рассмотренном примере «Обратный отсчёт времени».

Поскольку у currentTime есть возможность чтения/записи, можно воспользоваться этим для перехода к определённой точке на шкале времени. Это также позволяет синхронизировать две анимации, как показано в следующем примере.

Ещё одна опция: reverse()

Можно также обратить анимацию с помощью reverse(), который будет очень похож на play() (в частности, у него будет тот же самый playState), за исключением того, что с ним анимация проходит шкалу времени в обратном направлении. После завершения анимации currentTime будет равен 0.

Примечание: по состоянию на 31 июля 2015 reverse, кажется, не работает в полифилле, но у Chrome есть нативная поддержка. В отличии от других примеров, этот пример на CodePen работает только в Chrome.

В следующей серии…

Статья получилась немаленькой, но это было лишь первое знакомство с тем, что таит в себе эта спецификация. В следующей серии мы рассмотрим некоторые более продвинутые возможности.

Поглядите остальные статьи из этой серии:

P.S. Это тоже может быть интересно:

8

Комментарии

  1. Yura

    Ещё раз неустанно благодарю за этот курс статей )
    Хочу только обратить внимание , что всё таки есть нюанс в объекте AnimationPlayer.
    Я пробовал вынести этот объект с модуля где содержалась инициализация анимации, в прочем это у меня получилось, но в месте где я хотел прибегнуть к методу Animation.onfinish у меня возникли трудности : когда анимация «пробегала» метод Animation.onfinish я мог вызвать. Но когда фигура приобретала конечное положение вызвать этот метод у меня не получалось. Прибег к созданию другой анимации .

  2. Анатолий Борисов

    Попробовала в player.onfinish делать dispaly: none;
    Объект сразу исчезает без анимации.

    Как быть?

    1. SelenIT

      SelenIT

      Можно увидеть проблемный пример?

      1. Анатолий Борисов

        Пытался залить все на JSFiddle, но из-за лишних наворотов в путях к css бросил эту затею и залил на свой хостинг.

        По ссылке на объекте  «Sign up now» объект должен анимироваться и скрываться, чтобы показать другой объект вместо него.

        http://mydevelopersway.com/somestaff/loginregform/index_simple.html

        Почитав за сегодня еще статей, нашел рекомендации, что display: none с анимацией плохая затея.
        Думаю может использовать transform: translateZ  и скрыть за непрозрачным слоем?

        1. SelenIT

          SelenIT

          На мой взгляд, скрывать через translateZ — это всё же как-то слишком.

          У вас в примере обработчику onfinish присваивается не функция finishAnimate, а результат ее вызова, т.е. фактически функция вызывается и display:none присваивается еще в момент объявления анимации. Если делать это в функции-обработчике, всё должно быть нормально (пример на скорую руку: http://jsfiddle.net/qaw7esdm/).

          1. Анатолий Борисов

            Т.е. параметры в onfinish который является attribute EventHandler, который вроде как является частью  Animation interface (https://drafts.csswg.org/web-animations/#enumdef-animationplaystate) я смогу передать только через глобальные переменные?

            1. SelenIT

              SelenIT

              Не обязательно, можно через замыкание (достаточно обернуть содержимое функции finishAnimate в return function() { ... }).

              1. Анатолий Борисов

                До замыканий я еще не дорос (

                Сделал через глобальные переменные. Обновил код.

                Подключил полифилл. В IE 11 анимация начинает срабатывать со 2 или 3 раза.
                Точнее так: при первом раз почти не видно translateY, только изменение opacity.

                Что делать?

Оставить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Ваш E-mail не будет опубликован

Получать новые комментарии по электронной почте. Вы можете подписаться без комментирования.