Как определить, что анимация закончилась?
Речь о 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, время: 19:19. |