Javascript Web Animation API – finish, cancel

Web Animation API finish, cancel

Das Web Animation API kann mittels Animation.onfinish feststellen, dass eine Animationen vollständig durchgeführt oder ob die Animation gecancelt wurde.

Javascript Web Animation Api: onfinish, oncancel

An jeder Stelle der Animation können aktuelle Werte der Animation abgefragt werden, um Verhalten zu ändern und auf das Verhalten anderer Elemente zu reagieren.

Genauso wie bei einer CSS-Animation wird ein animiertes Element wie ein absolut positioniertes Element behandelt und hat keinen Einfluß auf vorangehende oder folgende Elemente. Die CSS-Stile, die von der Animation manipuliert wurden, tauchen anders als bei den klassischen Animationstechniken im DOM nicht auf.

const elem = document.querySelector("#circle");
let currentAnimation;

function move (transformStart, transformEnd) {
	console.log (transformStart)
	console.log (transformEnd)
	currentAnimation = elem.animate (
		[
			{ transform: transformStart },
			{ transform: transformEnd }
		],
		{
			duration: 2000,
			fill: "forwards"
		}
	)
}

function shiftLeft() {
	move ("translateX(400px)", "translateX(0)")
}

function shiftRight() {
	move ("translateX(0)", "translateX(400px)")
}

Wenn die Rechts- / Links-Buttons schnell nacheinander gedrückt werden, sehen wir, dass die jeweils andere Richtung nicht sofort an Ort und Stelle ausgeführt wird, sondern erst an den offiziellen Startpunkt springt. Was da tatsächlich passiert, kann in der Firefox-Console unter Animationen beobachtet werden.

firefox-animation-console

pause() und cancel()

Ein vorgelagertes Pausieren kann dieses unerwünschte Verhalten beenden. getComputedStyle(elem) liefert die aktuellen CSS-Stile des animierten Elements. Der neue Startpunkt kommt vom Stil transform des Keyframes. Erst dann wird die Animation gecancelt (wobei der Browser die Ressourcen freigibt) und die neue Animation gestartet.

Und noch ein Einwand: Wenn die Animation z.B. nach der halben Laufzeit (~1000 ms) beendet wird, läuft die gegenläufige Animation für die volle Dauer und das Element bewegt sich langsamer. currentAnimation.effect.getComputedTiming() liefert die neuen Ausgangswerte und die neue Dauer berechnet sich mit

duration = activeDuration - progress * activeDuration
const elem = document.querySelector("#circle");
let currentAnimation;

function move (transformEnd) {
	currentAnimation?.pause();
	let transformStart = getComputedStyle (elem).transform;
	
	let duration = 2000;
	if (currentAnimation) {
		const timing = currentAnimation.effect.getComputedTiming();
		const activeDuration = timing.activeDuration;
		const activeProgress = timing.progress;
		duration -= activeDuration - activeProgress * activeDuration;
	}
	currentAnimation?.cancel();
	
	currentAnimation = elem.animate (
		[
			{ transform: transformStart },
			{ transform: transformEnd }
		],
		{
			duration: duration,
			fill: "forwards"
		}
	)
}

function shiftLeft() {
	move ("translateX(0)")
}

function shiftRight() {
	move ("translateX(400px)")
}

finished.then – Animation gelaufen, dann nächste Animation

animate().finished gibt ein Promise zurück, das auslöst, wenn die Animation abgespielt wurde.

<div class="canvas">
	<div id="rad"></div>
</div>

Die folgende Animation läuft in vier Phasen ab: Die Transformation von links nach rechts, nach unten, zurück nach links und nach oben zum Anfang.

function rundum () {
	const ani = rad.animate ( kfLeftRight,timing1).finished
		.then (() => { rad.animate (kfRightDown,timing2).finished
		.then (() => { rad.animate (kfRightLeft,timing1).finished
		.then (() => { rad.animate (kfLeftUp,timing2).finished
		.then (() => { rundum() })
			})
		})
	})
}

rundum();

kfLeftRight, kfRightDown, kfRightLeft und kfLeftUp sind die Arrays der Keyframes, timing1 und timing2 die Optionen.

In diesem Beispiel wird nur ein Element (rad) animiert. Animation mit mehreren Elementen mit finished.then() synchronisieren.

finish()

Das Javascript Web Animation Api bietet mehrere Optionen, um das Ende einer Animation festzustellen.

currentAnimation.onfinish = () => console.log("Animation beendet");
		// oder mit Promise
currentAnimation.finished.then(() => console.log("Animation beendet"));

Das Promise löst eine Fehlermeldung aus, die abgehandelt werden muss.

currentAnimation.finished 
	.then (() => console.log ("Animation beendet"))
	.catch ( error => console.log ("Animation gecancelt", error));

		//Und natürlich können wir async/await benutzen

try {
	await currentAnimation.finished;
} catch (error) {
	console.log ("Animation gecancelt", error);
}