requestAnimationFrame vs setInterval
setTimeout und setInterval sind altgediente Techniken in der Animation mit Javascript. Sie verändert das animierte Element alle paar Millisekunden.
setInterval
function animate () {
// Berechnen
}
setInterval (animate, 1000);
setTimeout
function animate () {
setTimeout (animate, 500);
// Berechnen
}
animate();
setInterval() erwartet zwei Parameter oder Argumente: die Funktion, die bei jedem Schritt der Animation aufgerufen wird, und das Zeitinterval, in dem die Funktion für die Animation aufgerufen wird.
Aber setInterval() ist ineffizient. Wenn der Benutzer ein anderes Tab im Browser öffnet, läuft die Animation weiter. requestAnimationFrame ist effizienter.
requestAnimationFrame vs CSS-Animationen
CSS-Animationen sind mächtig, aber ihnen fehlen die Ereignisse, die eine Aktion starten oder beenden: CSS erkennt zwar ein Hovern mit der Maus, aber nicht das Touch des Fingers und Mausklicks nur auf wenigen Elementen (wie Radiobuttons). Auch bei komplexen Ketten (z.B. »starte Aktion, wenn eine andere Aktion abgelaufen ist«) bleibt CSS außen vor. Für Aktionen wie Stop, Pause und Resume eignet sich requestAnimationFrame besser.
Für komplexe Animationen haben wir heute auch das Web Animation Api, das eine CSS-ähnliche Notation nutzt, und den Start einer Aktion abhängig vom Zustand anderer Aktionen macht. Dennoch bleibt requestAnimationFrame die Wahl bei canvas-Animationen, denn im canvas-Element herrscht nicht das Document Object Model, sondern canvas basiert auf Pixeln.
Frame-Rate
Bei Animationen mit setTimeout oder setInterval kann das Script die aktuelle Frequenz der Frames nicht feststellen. requestAnimationFrame wird per Vorgabe 60 mal pro Sekunde aufgerufen – mehr ist selten nötig (oder besser: möglich), denn 60 Hz ist die Refresh-Rate der meisten Browser (oder Zeitrahmen von 16.7ms).
In Animationen mit requestAnimationFrame kann die Browser die Refresh-Rate reduzieren, wenn die Animation in einem Hintergrund-Tab läuft, um den Energieverbrauch zu senken.
requestAnimationFrame agiert anders als setInterval. Statt einen Timeout mit einer Verzögerung von 16.7ms in einer Schleife immer wieder aufzurufen, feuern die Browser ein Event, sobald das System wieder einen Frame rendern kann.
Syntax
Die Syntax von requestAnimationFrame() gleicht der Syntax von setTimeout(), da requestAnimationFrame wiederholt aufgerufen wird. Nur ein Timeout oder Interval wird nicht benötigt.
Wenn der Screen neu gerendert werden soll, wird requestAnimationFrame mit dem Name der Funktion aufgerufen, in der die Veränderungen und Berechnungen durchgeführt werden (aka Callback).
requestAnimationFrame(callback);
var iterationCount = 0; var repeater; function runlock () { easing = easeInQuad(iterationCount, 0, width, 300); lok.setAttribute ('style','left: ' + easing + 'px'); iterationCount++; if (iterationCount > 250) { cancelAnimationFrame(repeater); } else { repeater = requestAnimationFrame(runlock); } } runlock();
Die Lok läuft langsam an und wird schneller: Hier noch mit den Gleichungen von Robert Penners, die von Kipura für Javascript portiert wurden. Da ist das Javascript Web Animation Api weiter: Easing für Javascript Animationen.
requestAnimationFrame ist keine Schleife und kein Timer, sondern muss jedes Mal aufgerufen werden, wenn die Animation etwas ändert. Bis die Animation endet, muss requestionAnimationFrame immer wieder durch die Callback-Funktion aufgerufen werden.
Das ist also das »Skelett« der Animation:
function animate() { // Berechnen / Verändern = Animieren requestAnimationFrame(animate); } animate();
requestAnimationFrame mit Parametern
request Animation Frame wird mit einer Callback-Funktion aufgerufen. Wenn Parameter übergeben werden, kann die Callback Function auch eine anonyme Funktion sein, die wiederum die benötigten Parameter enthält.
function moveCurtain (curt, height) { easing = easeInOutQuart(step, height, -300, 90); step++; if (easing < 1) { cancelAnimationFrame (repeater); step = 0; } else { curt.setAttribute('height',easing); repeater = requestAnimationFrame (function () { moveCurtain (curt, easing); }); } }
function.bind() ist ein weiterer Mechanismus, um requestAnimationFrame mit Parametern aufzurufen. bind erzeugt eine neue Funktion, die this als ersten Parameter an bind() übergibt.
function move ( elem, timestamp) { // Berechne left und y elem.setAttribute("transform", "translate(" + left + " " + y +")"); requestAnimationFrame (move.bind (0,elem)); }; for (let i=0; i<waves.length; i++) { requestAnimationFrame(move.bind (0, waves[i])); }
Javascript animate () – Web Animation API
Mit animate () ist neben setTimeout, setInterval und requestAnimationFrame eine weitere Technik für Animationen auf den Plan getreten. Das Web Animation API mit animate() lehnt sich an CSS-Keyframes-Animationen an und eignet sich besonders für die Ablaufsteuerung von komplexen Objekten. requestAnimationFrame bleibt weiterhin die Basis für Canvas-Animationen.