CSS, HTML und Javascript mit {stil}

Javascript API für HTML5 Canvas

elseif

HTML5 canvas mit seinen Javascript-Funktionen ist neben SVG einer der beiden designierten Nachfolger von Adobe Flash im Web und in Web-Applications.

Das HTML-Canvas-Element ist erst einmal nur eine leere Box. Erst Javascript füllt das canvas mit Formen, Farben und Verläufen und animiert den Inhalt.

Javascript für canvas ist Hardware-beschleunigt und vor allem für schnelle Animationen und Spiele bestimmt. Die einzelnen Frames oder die Pixel eines im Canvas erzeugten Bildes lassen sich als PNG-Bild speichern.

<canvas id="myCanvas" width="600" height="200"> </canvas>

Javascript canvas ist auch Bestandteil von ePub3, dem Standard für eBooks.

Canvas Attribute und Funktionen

Javascript kann die HTML-Attribute des canvas-Tags programmatisch ändern – nicht anders als bei jedem HTML-Element. Das canvas-Tag ist Teil des DOMs – nicht aber sein Inhalt. Der Inhalt des canvas-Tags besteht aus Pixeln.

Attribute/FunktionenBeschreibung
widthBreite des canvas in Pixeln (default: 300)
heightHöhe des canvas in Pixeln (default: 150)
toDataURL(type)Wandelt den Inhalt des canvas in ein statisches Bild um (image/png ist der Standard, den jeder Browser unterstützen muss)
getContext(ctxID)Der Zeichen-Kontext des canvas-Elements

Anwendungen von Javascript canvas sind wahre Monster an Code: Ganz schön viel Arbeit.

Eine Javascript-Library für canvas vereinfacht die Programmierung: calebevans.me/projects/jcanvas

KineticJS ist ein Framework, das die Programmierung von Bewegung, Übergänge, Ebenen, Filter und Ereignissen vereinfacht.

Canvas und Context

Javascript greift in drei Schritten auf den canvas zu:

  1. Einen Verweis auf das canvas-Element erzeugen
    var canvas = document.getElementById('canvas');
  2. Den Zeichen-Zustand oder context setzen
    var ctx = canvas.getContext("2d");
  3. Ein Element (Form, Pfad, …) zeichnen
var canvas = document.getElementById('canvas');
if (canvas && canvas.getContext) {
   var ctx = canvas.getContext("2d");
   if (ctx) {
      ctx.fillStyle = "#9FC0D0";
      ctx.fillRect(0,0,ctx.canvas.width, ctx.canvas.height);
                    ^         ^                 ^
                    |         |                 |
                    |         |                 Höhe der Füllung
                    |         Breite der Füllung
                    Ursprung des Canvas
    }
}
yx0,0width, height
Bevor Javascript die canvas-Fläche füllt, ist ein canvas schwarz und transparent.

Canvas kennt keinerlei Objekte – Javascript sieht den Inhalt eines Canvas nur als eine Serie von Pixeln.

Canvas Context

Jeder Context enthält einen Zustand – den Kontext der Zeichenfläche.

Eigenschaften des contextBeschreibung
fillStyleStil der Füllung: CSS-Farbe, Verlauf (Gradient), Muster (Pattern)
strokeStyleStil der Kontur: CSS-Farbe, Verlauf (Gradient), Muster (Pattern)
lineWidthBreite der Kontur (default: 1)

Der Zustand kann vom Script gespeichert und später wieder aktiviert werden: So entsteht eine History oder ein Protokoll des Zeichnungszustands. Die Zustände können in einem Stack gespeichert und später wieder abgerufen werden.

Der Drawing State verwaltet Eigenschaften des Canvas:

  • aktueller Wert von lineWidth, strokeStyle, fillStyle, lineCap usw.
  • aktuelle Transformations-Matrix
  • aktueller Clipping-Bereich
RectanglesLinesArcsPath
Colors/StylesBézier CurvesQuadratic CurvesText
CompositingPatternsGradientsShadows
Clipping Paths
TransformsImagesVideoRaw Pixels
Der Drawing State konserviert nicht die Zeichnung, sondern Breite und Farbe von Konturen und die Füllung von Objekten!

Drawing State ist keine History oder Protokoll, wie wir es z.B. von Photoshop kennen.

Javascript context.save() und context.restore() speichern einen Zeichen-Zustand bzw. aktivieren einen älteren Zustand, um den Zeichnungszustand wieder herzustellen.

Dieser Browser kann den Inhalt des CANAVS nicht darstellen.
sctx.strokeStyle = "darkblue";
sctx.fillStyle = "lightblue";
sctx.lineWidth = 10;
			
sctx.fillRect (25,25,100,125);
sctx.strokeRect (25,25,100,125); // Erstes Viereck gezeichnet
sctx.save();

Nachdem das erste Viereck gezeichnet ist, speichert sctx.save(); den Zustand von von strokeStyle, fillStyle und lineWidth (Blautöne). Mit »Weiter« wird ein neuer Zeichenzustand definiert:

sctx.strokeStyle = "darkred";
sctx.fillStyle = "lightred";
sctx.lineWidth = 4;
sctx.fillRect(175,25,100,125);
sctx.strokeRect(175,25,100,125);

Neue Elemente bekommen jetzt die aktuellen Einstellung von strokeStyle, fillStyle und lineWidth (Rottöne).

Der Klick auf Restore stellt den Zeichen-Context zurück auf den Zustand beim Aufruf von save().

Wenn jetzt ein weiteres Objekt gezeichnet wird, gilt wieder der initiale Zustand von strokeStyle, fillStyle und lineWidth (Blautöne und Breite der Kontur 10).

Canvas Arc: Kreise und Bögen

Wer mit Illustrator, Photoshop, SVG oder Inkscape Freisteller oder Grafiken erstellt, kennt Bezierkurven (die Feder in Photoshop). Pfade bestehen aus Linien, die an Knotenpunkte eine Biegung definieren und die von Knoten zu Knoten miteinander verbunden sind. Jeder Canvas kann immer nur einen aktiven Pfad haben.

Mit stroke() zeichnet Javascript die Kontur des Pfades; fill() füllt den Pfad im Canvas.

Bögen oder Arcs sind Teile eines Kreises:

                            +-- true, wenn der Bogen 
                            |   gegen den Uhrzeiger gezeichnet wird
arc (x,  y,  r,  sA,  eA,  aC)
     |   |   |    |   | 
     |   |   |    |   +-- Endwinkel
     |   |   |    | 
     |   |   |    +-- Anfänglicher Winkel
     |   |   |
     +---+   +-- Radius
       |
       Ursprung des Bogens
arc (x, y, r, sA, eA, aC) fügt dem aktuellen Pfad einen Bogen an Position (x,y) hinzu
arcTo (x1, y1, x2, y2, r) fügt dem aktuellen Pfad an der Position der Feder einen Bogen mit mit Radius r hinzu
closePath() schließt den aktuellen Zeichenpfad

Winkel für HTML5 Canvas werden als Radiant, nicht in Grad angegeben. Grad in Radiant umrechnen

var rad = (Math.PI / 180) * degrees;
360° = 2 π rad

1rad= 360° 2 π = 180° π 57,29577951°

= 2 π360 rad = π180rad 0,017453293 rad

(Google Chrome hat vergessen, wie man MathML-Formeln rendert – mal wieder zu Firefox oder Safari greifen.)

rad-zu-grad

Winkelangaben im Javascript canvas: Der erste Kreisbogen ist im Uhrzeigersinn (false), der zweite Kreisborgen gegen den Uhrzeigersinn (true).

if (canvas && canvas.getContext) {
    var ctx = canvas.getContext("2d");
    if (ctx) {  
        ctx.fillStyle = "hsla(68,80%,60%,0.3)";
        ctx.strokeStyle = "hsla(30,80%,60%,0.9)";
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.arc (150, 150, 100, (2)*Math.PI, (1/3)*Math.PI, false);
        ctx.stroke();
        ctx.lineTo(150, 150); ctx.stroke(); ctx.fill();
        ctx.closePath();ctx.stroke();

        ctx.beginPath();
        ctx.arc (450, 150, 100, (2)*Math.PI, (1/3)*Math.PI, true);
        …
    }
}

Canvas Linien: Path

Ein Pfad im HTML5-Canvas beginnt mit beginPath() gefolgt von moveTo(x,y), um den Ausgangspunkt des Pfads zu setzen. lineTo(x,y) gibt die Koordinaten der folgenden Punkte und erzeugt jeweils eine Linie vom Ausgangspunkt zum neuen Endpunkt. Am Ende zeichnet stroke() die Kontur des Pfades.

ctx.beginPath();
ctx.moveTo(20, 180); // Feder zum Startpunkt
ctx.lineTo(40, 20); ctx.lineTo(140, 60); ctx.lineTo(180, 180);
ctx.stroke();

closePath() schließt den Pfad (2. Pfad, closePath wird vor stroke() aufgerufen) und erzeugt dabei eine Linie vom Ausgangspunkt zum initialen Startpunkt des Pfades.

ctx.beginPath();
ctx.moveTo(220, 180); // Feder zum Startpunkt
ctx.lineTo(240, 20); ctx.lineTo(340, 60); ctx.lineTo(380, 180);
ctx.closePath();
ctx.stroke();

Der Pfad im Canvas muss nicht geschlossen werden, um den Pfad zu füllen. Aber fill() wird vor stroke() aufgerufen.

ctx.beginPath();
ctx.moveTo(420, 180); // Feder zum Startpunkt
ctx.lineTo(440, 20); ctx.lineTo(540, 60); ctx.lineTo(580, 180);
ctx.fill();
ctx.stroke();

Der Stroke – die Umrandung von Flächen oder Linien – auf den Canvas ist immer eine solide Linie. Gepunktete oder gestrichtelte Linien (dashed oder dotted) sind für den Javascript Canvas nicht vorgesehen.

Bézierkurven und quadratische Kurven

  • Bézierkurven haben zwei Kontrollpunkte, um die Kurve festzulegen.
  • Quadratische Kurven haben einen Startpunkt und einen Kontrollpunkt am Endpunkt.
Pfad-AktionBeschreibung
bezierCurveTo(cx1, cy1, cx2, cy2, end1, end2)Zeichent eine Bézierlinie vom Ausgangspunkt der Feder mit zwei Kontrollpunkten an (cx1,cy1) und (cx2,cy2) am Endpunkt (end1,end2)
quadraticCurveTo(cx, cy, x, y)Zeichnet eine quadratische Kurve am Ausgangpunkt mit einem Kontrollpunkt (cx,cy) am Endpunkt (x,y)
ctx.beginPath();
ctx.moveTo(50,120);
ctx.bezierCurveTo(50,20,200,20,200,70);
ctx.stroke();

ctx.beginPath();
ctx.moveTo(220,120);
ctx.quadraticCurveTo(220,20,380,70);

Die hellgrauen Linien zeigen die Kontrollpunkte an.

Canvas: Text zeichnen

Ein Text, der mit Javascript in ein HTML5 Canvas gezeichnet wird, kann nicht durch CSS aufbereitet werden und ist für Screenreader und Suchmaschinen nicht lesbar. Text wird zu Pixeln wie jede andere Form.

Text-AktionenBeschreibung
fontSchrift festlegen – und zwar genauso wie mit CSS. Default Schriftgröße ist 10px
textAlignstart (default), end, left, right, center
textBaselinetop, hanging, middle, alphabetic, ideographic, bottom
fillText(txt, x, y, [maxW])Text als String rendern, wobei x, y nicht breiter als maxW werden dürfen
strokeText(txt, x, y, [maxW])Text als String rendern, wobei x, y nicht breiter als maxW werden dürfen
measureText(text)Gibt die Metrik der aktuellen Schrifteinstellung zurück
Dieser Browser kann kein HTML5-canvas-Element darstellen
// Text mit Kontur
var myString = "Text in einem Canvas ist nicht barrierefrei";
ctx.fillText(myString, 20,20);
ctx.font = "20px Verdana"
ctx.fillStyle = "#FFDFE0";
ctx.strokeStyle = "#CF9C9E";
ctx.fillText(theString, 20,160);						
ctx.strokeText(theString, 20,160);