Canvas Transformationen: rotate

Canvas Formen rotieren um einen Mittelpunkt

Das Rotieren einer Form im Canvas läuft vollkommen anders ab als in Grafikprogrammen, in CSS oder SVG, denn rotate () rotiert nicht die Form, sondern das Koordinatensystem des Canvas mit dem Nullpunkt oben links.

Obendrein besteht die Zeichnung aus einer Schicht von Pixeln, die sofort mit dem Canvas verschmelzen, und nicht aus Objekten. Transformationen wie rotate, scale und transform müssen vor dem Zeichnen einer Form angewendet werden, erst dann wird die Form normal auf dem Canvas aufgetragen.

Canvas vs CSS-Transformationen und SVG

Aus Bildbearbeitungsprogrammen wie Adobe Photoshop oder Präsentationsprogrammen wie Powerpoint sind wir daran gewöhnt, dass Elemente um ihren Mittelpunkt gedreht werden. 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, Grafikprogrammen oder SVG kommt, muss beim HTML Canvas neue Verhalten lernen:

  • Nicht die Form wird gedreht, sondern der Context.
  • Die Form ist kein Objekt, sondern der Canvas besteht aus nur einer Schicht von Pixeln
  • Rotiert wird nicht mit Grad-Angaben, sondern in Radiant

Rotieren um den Nullpunkt des Canvas: rotate ()

Eine Transformation bewegt keine Elemente wie Transformationen in SVG 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.

Quadrant I Quadrant II Quadrant III Quadrant IV CANVAS
Canvas ist immer der vierte Quadrant eines Kreis um den Nullpunkt. Nicht die Form auf dem Canvas wird gedreht – der Canvas ist nur die sichtbare Fläche für Pixel. Sobald die Pixel auf den Canvas gesetzt wurden, sind sie Teil des Canvas und kein selbstständiges Element wie eine Ebene in Photoshop oder ein Objekt in SVG.

CTX translate – Nullpunkt versetzen

Damit eine Form im Canvas um einen selbstbestimmten Punkt rotiert, wird der Nullpunkt des Koordinatensystems mit translate (newX,newY) verschoben. Im Beispiel des Rechtecks oben auf den Mittelpunkt des Rechtecks.

Diese Anweisungen führen zu den selben Ergebnissen:

          +-- dx – Abstand vom Nullpunkt
          |   +-- dy – Abstand vom Nullpunkt 
          |   |   +-- Breite
          |   |   |   +-- Höhe des Rechtecks
          |   |   |   |
ctx.rect(60, 40, 30, 50);
ctx.translate(60,40); // versetzt den Nullpunkt
ctx.rect(0, 0, 30, 50);

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 HTML5 Canvas).

2πrad = 360°

oder

1rad= 360° 2 π =180° π57,29578
var canvas = document.getElementById("canvas-animate");
let ctx = canvas.getContext("2d");

var p1 = {x:60,y:40}; // Ecke oben links
var p2 = {x:90,y:70}; // Ecke unten rechts
var dx = p2.x-p1.x;
var dy = p2.y-p1.y;
var length = Math.sqrt(dx*dx+dy*dy);
var 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 außerhalb des sichtbaren Quadranten IV.

CANVAS ROTATE