Sichern und wiederherstellen von Canvas-Zuständen
Die Möglichkeiten mit Canvas-Elementen zu zeichnen beinhalten auch die Grafik zu animieren. Jedoch
ist die Animation zugleich auch nur über ein paar Umwege korrekt zu erreichen.
Die wohl größte Limitation bei der Animation ist es, dass sobald die "Shapes" gezeichnet sind,
bleiben sie so. Auch für die nächste Veränderung. Wenn wir also eine Shape bewegen wollen, müssen
wir sie
entfernen und erneut zeichnen und alles andere auch! Das kostet bei komplexen Bildern einiges an
Rechenzeit.
Das erneute Zeichnen können erleichtern, indem wir den Zustand des Canvas zwischenspeichern und
später erneut laden. Dazu nutzen wir folgenden Methoden:
ctx.save()
ctx.restore()
save() speichert, wie man vermuten kann, den aktuellen Zustand der Zeichnung. Zu einem Zustand
gehören sämtliche Einstellungen, wie z.B. fillStyle, globalAlpha usw.. restore()
hingegen stellt den gespeicherten Zustand wieder her. Save und Restore arbeiten wie auf einem Stack.
Das bedeutet, dass save() mehrmals ausgeführt werden kann und restore dann den auf dem Stack
obersten gespeicherten Zustand läd.
Prinzipien der Animation
Wollen wir nun unser Canvas mit Animationen belegen, gilt es folgende Schritte in der vorgebenen
Reihenfolge auszuführen.
- Clear the canvas
Wir müssen alle Elemente, die wir vorher gezeichnet haben, entfernen. Dazu eignet sich die
Methode clearRect().
- Save the canvas state
Sobald wir irgendwelche Einstellungen ändern, die den Zustand verändern, sollten wir den
Ausgangszustand gespeichert haben. Denn wir wollen bei jeder Animation den Ursprungszustand als
Ausgangsgrafik haben und jede Veränderung von da aus animieren.
- Draw animated shapes
Hier führen wir die eigentliche Animation bzw. das Rendering aus.
- Restore the canvas state
Wir stellen den gespeicherten Zustand wieder her, bevor wir ein neues Frame redern.
Kontrolle über die Animation
Das Timing, wann welches Frame gezeichnet wird, spielt bei Animationen eine besonders wichtige Rolle.
In der Regel sehen wir die Zeichnung eines Canvas dann, wenn das Skript, welches sie zeichnet,
zuende gelaufen ist. Das zum Beispiel macht es unmöglich eine Animation mit einer for-Schleife zu
animieren. Doch es gibt andere Wege den Zeitpunkt des Renderings zu kontrollieren.
setInterval(function, delay)
setTimeout(function, delay)
requestAnimationFrame(callback)
Die genannten drei Funktionen, die vom window-Objekt angeboten werden, erledigen diesen Job
ausreichend gut. setInterval() führt die übergebene Callback-Funktion im Abstand des
übergebenen Delays (in Millisekunden) aus. setTimeout() führt den übergebenen Callback nach
dem spezifizierten Delay aus. Und requestAnimationFrame() fordert den Browser auf für den
übergebenen Callback vor dem nächsten Repaint eine Animation auszuführen.
Nun folgt eine Beispielanimation, welche aus dem Mozilla
Developer Network entnommen ist. Sie demonstriert, wie sich mit verhältnismäßig wenig Code (<40
Zeilen) eine doch sehr ansehnliche Animation erstellen lässt.
Die resultierende Grafik ist ein kleines animiertes Sonnenystem
Der nachfolgende Code beschreibt die Animation des Sonnensystems:
var sun = new Image();
var moon = new Image();
var earth = new Image();
function init(){
sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
window.requestAnimationFrame(draw);
}
function draw() {
var ctx = document.getElementById('canvas').getContext('2d');
ctx.globalCompositeOperation = 'destination-over';
ctx.clearRect(0,0,300,300); // clear canvas
ctx.fillStyle = 'rgba(0,0,0,0.4)';
ctx.strokeStyle = 'rgba(0,153,255,0.4)';
ctx.save();
ctx.translate(150,150);
// Earth
var time = new Date();
ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
ctx.translate(105,0);
ctx.fillRect(0,-12,50,24); // Shadow
ctx.drawImage(earth,-12,-12);
// Moon
ctx.save();
ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
ctx.translate(0,28.5);
ctx.drawImage(moon,-3.5,-3.5);
ctx.restore();
ctx.restore();
ctx.beginPath();
ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit
ctx.stroke();
ctx.drawImage(sun,0,0,300,300);
window.requestAnimationFrame(draw);
}
init();
Bei weiterem Intresse an Canvas-Elementen kann ich die ausführlichen Ressourcen des Mozilla
Developer Network empfehlen. Diese dienten mir aus als Quelle für den Großteil den Inhalts dieser Seite.
Zurück zu Advanced