Polygone mit litecanvas

Polygone mit litecanvas

litecanvas ist eine kleine aber feine 2D-Engine in JavaScript. Ich wollte Vektor-Grafiken (SVG) damit darstellen können. Doch so einfach ist das nun auch wieder nicht.

Der Fokus von litecanvas liegt augenscheinlich auf einer Pixel-basierten Darstellung. Damit erstellte Dinge haben so einen gemütlichen Retro-Charme.

In litecanvas existieren auch eingebaute Funktionen zum Zeichnen von einfachen geometrischen Formen, Polygone sind jedoch nicht mit dabei. Also ran an die Sache!

Polygone zeichnen

Die Darstellung in litecanvas erfolgt über den JavaScript canvas-Kontext. Es stehen also alle gängigen Funktionalitäten in diesem Zusammenhang zur Verfügung.

Das Rad muss hier für mich nicht neu erfunden werden, da andere Menschen bereits Polygone mit HTML5 canvas darstellen wollten. Im Netz fand ich dazu auf stackoverflow den Beitrag "How to draw polygons on an HTML5 canvas?" und darin die Lösung: .lineTo(x, y).

Es wird ein Pfad geöffnet und sich im Polygon von Punkt zu Punkt gehangelt. Am Ende wird der Pfad geschlossen und fertig ist die Laube. Der Code dazu könnte so aussehen:

ctx.beginPath();
ctx.moveTo(polygon[0], polygon[1]);
for(let item=2; item < polygon.length-1; item+=2){
    ctx.lineTo( polygon[item], polygon[item+1] )
} 
ctx.closePath();

Koordinaten-Punkte erhalten

Wie erhält man nun die Koordinaten-Punkte eines Polygons aus einem Grafik-Vektor?
Im besten Fall liefert ein SVG bereits Punktwerte wie <polygon points="..." />. Leider ist das nicht immer der Fall. Oft sind in SVGs Pfad-Kommandos zu finden. Sowas wie <path d="M143.44,100.78v-26.4l.58..." /> - da sieht man erst einmal alt aus.

Aber auch hier hilft wieder die Informationstauschbörse stackoverflow mit dem Beitrag "Converting svg path to polygon in javascript" - der ausführlichst erklärt, wie man zum gewünschten Ziel kommt, und sogar 1A-Code-Beispiele liefert!

Alles richtig miteinander verschraubt, können nun SVG-Pfad-Definitionen in Polygon-Koordinaten-Punkte umgewandelt werden. Diese sind dann im canvas-Kontext zu setzen und zu verbinden.

Keine Bézierkurven und Bögen

Der Nachteil an der genannten Lösung ist, dass keine Bézierkurven oder Abschnitte mit Bogen-Kommandos dargestellt werden können. Aber auch dafür gibt es eine Lösung im bereit erwähnten stackoverflow Beitrag "Converting svg path to polygon in javascript" - auf die ich hier jedoch nicht weiter eingehe.

Umsetzung in litecanvas

Ich verwende ein paar Plugins für litecanvas, um mir die Umsetzung zu Vereinfachen.

Die @litecanvas/utils liefern eine "Actor"-Komponente, mit der man ein Objekt in der Spiel-Engine unkompliziert handhaben kann. Hierzu wird mit paint() ein Sprite definiert, das die Darstellungsinformation beinhaltet. Die Funktion kann ein callback verabreiten, in dem der canvas-Kontext manipuliert werden kann. Und genau da setze ich an!

playerSprite = paint(
  200, // width 
  200, // height
  function (_ctx) { // callback
    cls(0) 
    drawPolygon(_ctx,      
      svg2points('M143.44,100.78v-26.4l.58...')      
    )
    fill(4); // fill color from litecanvas palette (4: red) for the _ctx polygon
  }, { scale: 4 })

Das Objekt mit den Dimensionen 200x200 (BxH) wird auf einen dunklen Hintergrund (cls(0)) gezeichnet, der canvas-Kontext _ctx wird der Funktion drawPolygon() übergeben. Zum Abschluss wird das Polygon mit einer Farbe ausgefüllt (fill(4)) und um das vierfache vergrößert (scale: 4.)

Die Funktion drawPolygon() ist unspektakulär und setzt nur die zuvor gewonnenen Erkenntnisse um:

function drawPolygon(_ctx, polygonPointsString) {
  let polygonPoints = polygonPointsString.split(' ')  
  _ctx.beginPath();
  _ctx.moveTo(polygonPoints[0], polygonPoints[1]);
  for (let item = 2; item < polygonPoints.length - 1; item += 2) {
    _ctx.lineTo(polygonPoints[item], polygonPoints[item + 1])
  }
  _ctx.closePath();
}

Der Zauber liegt in der svg2points()-Funktion (svg.js), die aus den SVG-Kommandos Polygon-Koordinatenpunkte erstellt.

Fertig kann das alles dann vielleicht so aussehen: https://tools.uplegger.eu/display.litecanvas-polygon/

Ausblick

Für zukünftige Projekte mit litecanvas habe ich so eine gute Ausgangsbasis, um Vektor-Grafiken für die Darstellung zu verwenden.