Как определить, что анимация закончилась?
Речь о CSS свойстве animation.
Допустим, мы не успели поймать событие animationend, как тогда определить, что анимация элемента закончилась? Проверяем, что анимация не бесконечная computedStyle.animationIterationCount , ноcomputedStyle.animationPlayState так и продолжает возвращать значение running , даже если анимация уже прошла.Мы можем вычислить время анимации animationDelay + animationDuration * animationIterationCount , но не знаем, когда анимация запускалась.Есть идеи? |
Цитата:
или это чисто тема на рассуждение ? Цитата:
Цитата:
Если режим заполнения (overflow) анимации стоит "forwards" или "both" - значением вычисленного стиля элемента будет значение последнего (!) ключевого кадра. Если режим заполнения стоит "backwards" или "none" - значением вычисленного стиля будет значение, определённое НЕ из анимации - т.е. либо из каскадного стиля (вероятнее всего), либо из чего-нибудь другого. Последний ключевой кадр - это последний ключевой кадр (спс К.О.) Не помню, влияет ли на то, каким будет последний ключевой кадр, свойство iterationCount с нецелым значением (напр. "1.5" проиграет один проход и ещё половину следующего прохода) А вот animationDirection, установленное не в 'normal', обращает наоборот последний ключкадр через экстраполяцию. ... не помню всех деталей. всего лишь полгода прошло) |
Цитата:
Цитата:
Вообще хотелось бы универсальное решение, например, задачи: добавить класс элементу, если над этим элементом не происходит анимация, при условии, что раньше об этом элементе мы ничего не знали. Или хотя бы элементарное: вызвать callback, когда все анимации закончились. Я знаю, что из-за проблем с контролем CSS анимаций, например, в jQuery animate до сих пор никак не используются CSS transition и animation. Например, для transition можно посчитать время и запустить callback через setTimeout, как это сделано в плагине https://github.com/ai/transition-events Очень удобно, использовать метод addClass, возвращающий promise, которое fulfill'ется, когда все CSS переходы закончены: addClass(element, "trans").then(doSomething)если в качестве value будет передаваться элемент, можно строить такие очереди: addClass(document.query(".some"), "trans1").then(function (element) { doSomething1(); return addClass(element, "trans2"); }).then(function (element) { doSomething2(); return addClass(element, "trans3"); }).then(function (element) { doSomething3(); });Для браузеров, не поддерживающих transition, сразу выполнять действия так, как будто transition-duration + transition-delay = 0 А вот с animation уже такое не прокатит. |
Цитата:
Цитата:
Цитата:
тут и для анимаций метод с таймаутом прокатит, если её не паузить через animation-play-state а узнать, закончился ли transition, не зная, когда он начался - опять таки, проверять по изменению свойств. API скудное у этих стандартов, да Цитата:
|
Цитата:
|
melky,
да не дочитал полностью сообщение Octane, и запостил.. |
Цитата:
Цитата:
Цитата:
В отличие от transition, animation может быть запущена хоть при загрузке старницы, действий никаких не требуется, время старта мы не знаем. Пауза ладно, фиг с ней, ее хотя бы можно отследить по значению свойства, проблема начинается даже в простом случае: .animated { animation: anim1 1s 1, anim2 3s 1; animation-delay: 0s, 5s; } В данном случае может сработать до 4х событий (2 раза animationstart и соответственно 2 animationend). Если анимации запускаются с разной задержкой, становится проблемно выполнить действия, когда все анимации над элементом закончатся. Даже распарсив в JavaScript свойство style.animationName и узнав количество анимаций, мы не уверены, что все анимации запустятся, браузер не известит об анимации свойства, которое и так уже находится в состоянии конечного кадра (хотя надо будет проверить, уверен что так работает для transition). Не понятно, когда и сколько событий нужно подождать, чтобы удостовериться, что анимация закончилась. Если кому интересно, наработки здесь: getTransitionTime и getFiniteAnimationTime, add|remove|toggleClass |
Octane, у событий анимаций есть особые свойства:
Цитата:
или я не понял, в чём проблема событий анимации :) |
elapsedTime для каждой отдельной анимации приходит, не понимаю, как это может помочь.
Давай напишем метод addClass→promise для следующего случая:<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>…</title> <style> .animated { position: fixed; top: 0; left: 50%; width: 20px; height: 20px; background: #f50; transition: top 5s, left 1s; } .move { top: 0; left: 0; } </style> </head> <body> <div class="animated"></div> <script> function parseFloats(string) { return string.split(",").map(function (string) { return parseFloat(string) || 0; }); } function calcTransitionTime(delay, duration) { var length = Math.max(duration.length, delay.length), i = 0, time, maxTime = 0; while (i < length) { time = (delay[i] || 0) + (duration[i] || 0); if (time > maxTime) { maxTime = time; } i++; } return Math.ceil(maxTime * 1000); } function getTransitionTime(style) { return calcTransitionTime( parseFloats(style.transitionDelay), parseFloats(style.transitionDuration) ); } function addClass(element, className) { return new Promise(function (resolve) { element.classList.add(className); var delay = getTransitionTime(getComputedStyle(element)); setTimeout(function () { resolve(element); }, delay); }); } window.onload = function () { var el = document.querySelector(".animated"); addClass(el, "move").then(function () { alert("done"); }); }; </script> </body> </html>http://learn.javascript.ru/play/mdqxkb Здесь сработает через 1 секунду только один transitionend , но максимальное время анимации 5 секунд. Браузер не будет ничего делать для свойства top , ни событий, ни reflow. Обещание будет ждать зря 4 секунды. Есть идеи, как определить, что анимация закончилась за 1 секунду?Изобретать свой CSS парсер как-то не хочется, потому что просто вытащить анимируемое свойство из document.styleSheets[i].cssRules[j].style[n] не получится, класс может быть «размазан» по куче cssRules .Тоже самое и с animation: <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>…</title> <style> .animated { position: fixed; top: 0; left: 50%; width: 20px; height: 20px; background: #f50; } .move { animation: move-top 5s, move-left 1s; animation-fill-mode: both; } @keyframes move-top { 100% { top: 0; } } @keyframes move-left { 100% { left: 0; } } </style> </head> <body> <div class="animated"></div> <script> function parseFloats(string) { return string.split(",").map(function (string) { return parseFloat(string) || 0; }); } function calcFiniteAnimationTime(delay, duration, count) { var length = Math.max(duration.length, delay.length, count.length), i = 0, time, maxTime = 0; while (i < length) { time = (delay[i] || 0) + (duration[i] || 0) * (count[i] || 0); if (time > maxTime) { maxTime = time; } i++; } return Math.ceil(maxTime * 1000); } function getFiniteAnimationTime(style) { return calcFiniteAnimationTime( parseFloats(style.animationDelay), parseFloats(style.animationDuration), parseFloats(style.animationIterationCount) ); } function addClass(element, className) { return new Promise(function (resolve) { element.classList.add(className); var delay = getFiniteAnimationTime(getComputedStyle(element)); setTimeout(function () { resolve(element); }, delay); }); } window.onload = function () { var el = document.querySelector(".animated"); addClass(el, "move").then(function () { alert("done"); }); }; </script> </body> </html>http://learn.javascript.ru/play/hOiFcb Произойдет только одна пара событий animationstart и animationend , анимация закончится за 1 секунду, но delay будет равен 5 сек. |
По анимациям глянь :
http://codepen.io/ColCh/full/jilgs Поизменяй animation-delay или вообще анимации в классе и увидишь, что всё ок а по переходам я сам не придумал, как эту фигню обойти. В моём недописанном движке transition вообще не используются за их ущербностью |
Часовой пояс GMT +3, время: 14:28. |