Canvas vs CSS-Transformationen und Inkscape/Illustrator
Die Zeichnungen im Canvas sind keine Objekte, sondern bestehen aus einer Schicht von Pixeln, die sofort mit dem Canvas verschmelzen – ein digitales Ölbild. Transformationen wie rotate, scale und transform müssen vor dem Zeichnen einer Form angewendet werden, erst dann wird die Form auf dem Canvas aufgetragen.
In Grafikprogrammen wie Adobe Illustrator oder Inkscape drehen wir Elemente um ihren Mittelpunkt. Eine Form in einem Canvas hingegen wird nicht um ihren Mittelpunkt gedreht, sondern um den Nullpunkt des Canvas oben links. In der Animation verschwindet die Form, bis sie wieder im sichtbaren Viewport des Canvas erscheint.
ctx.rotate(radianAngle); ctx.beginPath(); ctx.fillStyle = "red"; ctx.rect(60,60,30,50); ctx.fill();
Wer von CSS-Transformationen und Grafikprogrammen kommt, muss beim HTML-Canvas neue Verhalten lernen:
- Nicht die Zeichnung, sondern der Context wird rotiert – vorübergehend.
- Die Zeichnung ist kein Objekt, sondern der Canvas besteht aus nur einer Schicht von Pixeln.
- Rotiert wird nicht mit Grad-Angaben, sondern in Radiant.
Canvas-Rotation um den Nullpunkt: rotate ()
Eine Transformation bewegt keine Elemente wie Transformationen in Inkscape, Illustrator oder CSS-Transformationen, sondern die Transformation ändert das Koordinatensystem.
Ohne weitere Angaben rotiert ctx.rotate() die Form um den Nullpunkt des Canvas oben links.
Der Effekt der Rotation ist nur im Canvas sichtbar. Das Canvas ist sozusagen ein Fenster zum vierten Quadranten eines Kreises. Die Diagonale des Canvas ist der Durchmesser dieses Kreises.
Context translate () / Context rotate ()
Damit eine Form im Canvas um einen selbstbestimmten Punkt rotiert, wird der Nullpunkt des Koordinatensystems mit translate (newX,newY) verschoben. Im Beispiel des roten Rechtecks oben auf den Mittelpunkt des Rechtecks.
…
const ctx = canvas.getContext("2d");
ctx.rect(60, 40, 30, 50);
ctx.fillStyle = "green";
ctx.fill();
… const ctx = canvas.getContext("2d"); ctx.translate(60,40); // versetzt den Nullpunkt ctx.rect(0, 0, 30, 50); ctx.fillStyle = "red"; ctx.fill();
Vor der Transformation und Rotation speichert ctx.save() den Zustand des Context. Am Ende stellt ctx.restore () der Original-Kontext vor der Transformation und Rotation wieder her.
ctx.save(); ctx.translate(75,65); ctx.rotate(radianAngle); ctx.beginPath(); ctx.fillStyle = "red"; ctx.rect(-15,-25,30,50); ctx.fill(); ctx.restore();
Context löschen: clearRect
In einer Zeichnung mit SVG oder bei DOM-Elementen in einem HTML-Dokument bleibt ein Element bei Transformationen wie Rotation oder Skalieren erhalten und kann zu jeder Zeit weiter oder erneut transformiert werden.
Aktionen auf dem Canvas hingegen erzeugen keine Elemente, sondern Pixel. Die Form auf dem Canvas ist kein eigenständiges Element wie ein Rechteck im Illustrationsprogramm oder in SVG, sondern die Form verschmilzt sofort nach der fill-Anweisung mit dem Canvas und wird als Form vergessen.
Wenn der Canvas vor dem Aufruf von ctx.rotate() nicht gelöscht wird, bleibt die Zeichnung stehen und wird durch die Rotation überlagert. Obendrein akkumulieren Transformationen – jeder Rotation geht von der letzten Transformation aus.
Der Context wird mit clearRect () vor jedem Frame der Animation gelöscht und neu mit den veränderten Koordinaten gezeichnet.
Context löschen und das orange Rechteck wieder an derselben Stelle zeichnen
ctx.clearRect(0,0,canvas.width,canvas.height); ctx.beginPath(); ctx.fillStyle = "orange"; ctx.rect(30,30,30,50); ctx.fill(); ctx.save();
Context versetzen mit translate, rotieren mit rotate und das rote Rechteck zeichnen
ctx.translate(150,100); // Nullpunkt auf den Mittelpunkt des Canvas setzen ctx.rotate(radianAngle); ctx.beginPath(); ctx.fillStyle = "red"; ctx.lineStyle = "#000"; ctx.rect(30,30,30,50); ctx.fill(); ctx.stroke();
Am Ende des Frames den Context wieder zurücksetzen
ctx.restore();
Canvas Rotation und Animation
Der Kontext des Canvas rotiert nicht mit der üblichen Angabe in 0 bis 360°, sondern die Rotation wird in Radiant angegeben (siehe auch Javascript Zeichnen und Animieren mit dem HTML Canvas-Element).
oder
let canvas = document.getElementById("canvas-animate"); let ctx = canvas.getContext("2d"); let p1 = {x:60,y:40}; // Ecke oben links let p2 = {x:90,y:70}; // Ecke unten rechts let dx = p2.x-p1.x; let dy = p2.y-p1.y; let length = Math.sqrt(dx*dx+dy*dy); let angle = Math.atan2(dy,dx); draw(angle); requestAnimationFrame(animate); function animate(time){ // Animieren mit requestAnimationFrame requestAnimationFrame(animate); draw(angle); angle += Math.PI/60; } function draw(radianAngle){ // Bei jedem Frame den Context vollständig löschen ctx.clearRect(0,0,canvas.width,canvas.height); ctx.beginPath(); ctx.fillStyle = "orange"; // Orange bleibt stehen ctx.rect(p1.x,p1.y,30,50); ctx.fill(); ctx.save(); // Context speichern // Nullpunkt auf die Mitte des Canvas ctx.translate(canvas.width/2,canvas.height/2); ctx.rotate(radianAngle); ctx.beginPath(); ctx.fillStyle = "red"; ctx.rect(-15,-25,30,50); ctx.fill(); ctx.restore(); // Content wiederherstellen }
Aber im Grunde genommen reicht es nicht, nur den sichtbaren Bereich des Canvas zu löschen – die Pixel, die bei der Rotation des Bildes entstanden sind, liegen auch innerhalb des sichtbaren Quadranten IV.