Руководство по 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.
В следующей серии…
Статья получилась немаленькой, но это было лишь первое знакомство с тем, что таит в себе эта спецификация. В следующей серии мы рассмотрим некоторые более продвинутые возможности.
Поглядите остальные статьи из этой серии:
- Введение
- Часть 1: создание базовой анимации
- Часть 3: множественнные анимации
- Часть 4: групповые и последовательные эффекты
- Часть 5: траектории движений
- Заключение
- Полезные ссылки
P.S. Это тоже может быть интересно:
Ещё раз неустанно благодарю за этот курс статей )
Хочу только обратить внимание , что всё таки есть нюанс в объекте AnimationPlayer.
Я пробовал вынести этот объект с модуля где содержалась инициализация анимации, в прочем это у меня получилось, но в месте где я хотел прибегнуть к методу Animation.onfinish у меня возникли трудности : когда анимация «пробегала» метод Animation.onfinish я мог вызвать. Но когда фигура приобретала конечное положение вызвать этот метод у меня не получалось. Прибег к созданию другой анимации .
Попробовала в player.onfinish делать dispaly: none;
Объект сразу исчезает без анимации.
Как быть?
Можно увидеть проблемный пример?
Пытался залить все на JSFiddle, но из-за лишних наворотов в путях к css бросил эту затею и залил на свой хостинг.
По ссылке на объекте «Sign up now» объект должен анимироваться и скрываться, чтобы показать другой объект вместо него.
http://mydevelopersway.com/somestaff/loginregform/index_simple.html
Почитав за сегодня еще статей, нашел рекомендации, что display: none с анимацией плохая затея.
Думаю может использовать transform: translateZ и скрыть за непрозрачным слоем?
На мой взгляд, скрывать через
translateZ
— это всё же как-то слишком.У вас в примере обработчику
onfinish
присваивается не функцияfinishAnimate
, а результат ее вызова, т.е. фактически функция вызывается иdisplay:none
присваивается еще в момент объявления анимации. Если делать это в функции-обработчике, всё должно быть нормально (пример на скорую руку: http://jsfiddle.net/qaw7esdm/).Т.е. параметры в onfinish который является attribute EventHandler, который вроде как является частью Animation interface (https://drafts.csswg.org/web-animations/#enumdef-animationplaystate) я смогу передать только через глобальные переменные?
Не обязательно, можно через замыкание (достаточно обернуть содержимое функции
finishAnimate
вreturn function() { ... }
).До замыканий я еще не дорос (
Сделал через глобальные переменные. Обновил код.
Подключил полифилл. В IE 11 анимация начинает срабатывать со 2 или 3 раза.
Точнее так: при первом раз почти не видно translateY, только изменение opacity.
Что делать?