Pfade

April 2023
Die meisten Zeichenwerkzeuge bearbeiten einen Pfad (Path). Auf der Canvas zeigt sich ein Pfad allgemein gesprochen als Punkte, die miteinander verbunden sind. Da schließt nicht nur Linien, sondern auch Rundungen und Kreise ein.

Zwei unterschiedliche Kreise zeichnen

Wir platzieren linksseitig einen gefüllten Kreis (Farbe Schwarz ist voreingestellt) und rechtsseitig einen leeren Kreis mit einem breiten, grünen Rand. Sollte eigentlich kein Problem sein.
Ctx2d.arc(50, 50, 36, 0, 2 * Math.PI, false);
Ctx2d.fill(); // den ersten Kreis füllen

Ctx2d.arc(150, 70, 36, 0, 2 * Math.PI, false);
Ctx2d.strokeStyle = '#00cc00';
Ctx2d.lineWidth = 3;
Ctx2d.stroke(); // den zweiten grün umranden
Es fällt sofort eine Linie auf, die da nicht hingehört. Der Zeichenkontext versucht, alles zu einer einzigen Figur zu verbinden, wodurch der Begriff Pfad recht augenscheinlich wird.
Die nicht gewünschte Linie beginnt am Endpunkt des ersten Kreises und endet am Anfangspunkt des zweiten Kreises. In beiden Fällen liegen die Punkte bei null Grad aus Sicht der Kreise. Damit wäre die Führung der Linie klar.

Zeichenposition verschieben

Es gibt die Methode moveTo(x,y), die die aktuelle Zeichenposition verändert, ohne eine Linie zu zeichnen. Wir müssen nur die Zeichenposition genau auf den Anfangspunkt des zweiten Kreises richten.
Ctx2d.arc(50, 50, 36, 0, 2 * Math.PI, false);
Ctx2d.fill(); 
Ctx2d.moveTo(186,70);
Ctx2d.arc(150, 70, 36, 0, 2 * Math.PI, false);
Ctx2d.strokeStyle = '#00cc00';
Ctx2d.lineWidth = 3;
Ctx2d.stroke(); 
Das sieht schon deutlich besser aus, jedoch wird auch der erste Kreis gestroket.
Die Methode moveTo() verschiebt zwar die Zeichenposition, ohne etwas zu zeichnen, ist aber trotzdem Bestandteil des Pfades, der damit immer noch eine durchgängige Figur ist. Gestylt und gerendert wird immer der ganze Pfad.
In der Literatur ist die Rede vom "aktiven Pfad", wobei es immer nur einen aktiven Pfad geben kann. Sobald der Zeichenkontext eröffnet ist, gibt es automatisch einen aktiven Pfad. Bisher haben wir also nur einen Pfad bearbeitet.
Es gibt aber die Möglichkeit, den aktiven Pfad zu beenden und einen neuen Pfad zu eröffnen. Beides bewirkt die Methode beginPath(). Wir fügen beginPath() also nach dem Zeichnen des ersten Kreises ein.
Ctx2d.arc(50, 50, 36, 0, 2 * Math.PI, false);
Ctx2d.fill(); 
Ctx2d.beginPath();
Ctx2d.arc(150, 70, 36, 0, 2 * Math.PI, false);
Ctx2d.strokeStyle = '#00cc00';
Ctx2d.lineWidth = 3;
Ctx2d.stroke(); 
Und damit haben wir unser Ziel erreicht, es gibt keine unerwünschte Linie mehr, die wir mit moveTo() kaschieren müssten.
Es gibt auch die Methode closePath(), von der man denken könnte, dass sie einen aktiven Pfad beendet. Nein, das tut sie nicht! Beispiele dazu später.

Nochmal der Reihe nach

  • Wir zeichnen den ersten Kreis und füllen ihn.
    Ctx2d.arc(50, 50, 36, 0, 2 * Math.PI, false);
    Ctx2d.fill(); 
    Der Pfad ist noch aktiv, das heißt, wir könnten über den Zeichenkontext weitere Veränderungen treffen.
  • Wir schließen den aktiven Pfad.
    Ctx2d.beginPath();
    Jetzt ist der Pfad geschlossen, es gibt vom Zeichenkontext keinen Zugriff mehr auf den gefüllten Kreis. Es bleibt nur die Darstellung in der Canvas übrig.
    Es hat sich aber ein neuer aktiver Pfad eröffnet, der zwar noch leer, jedoch mit dem Zeichenkontext verbunden ist.
  • Wir zeichnen den zweiten Kreis.
    Ctx2d.arc(150, 70, 36, 0, 2 * Math.PI, false);
    Ctx2d.strokeStyle = '#00cc00';
    Ctx2d.lineWidth = 3;
    Ctx2d.stroke();
    Der Zeichenkontext ist mit dem neuen aktiven Pfad verbunden und sieht den ersten Kreis nicht mehr. Alle Einstellungen wirken sich nur auf den zweiten Kreis aus.
So könnten wir beliebig viele unabhängige Darstellungen auf unserer Canvas platzieren, schön getrennt durch beginPath().