Das waren schon immer Sie, Canvas2D.

Aaron Krajeski
Aaron Krajeski

In einer Welt voller Shader, 3D-Modelle und Filter ist Canvas2D vielleicht nicht das, was Sie suchen. Aber das sollte es! 30–40% der Webseiten enthalten ein <canvas>-Element und 98% aller Canvasse verwenden einen Canvas2D-Rendering-Kontext. Canvas2Ds finden sich in Autos, auf Kühlschränken und im Weltraum (wirklich!).

Zugegeben, die API ist in Bezug auf moderne 2D-Zeichnungen etwas in die Jahre gekommen. Zum Glück haben wir hart daran gearbeitet, neue Funktionen in Canvas2D zu implementieren, um CSS auf den neuesten Stand zu bringen, die Ergonomie zu optimieren und die Leistung zu verbessern.

Teil 1: CSS kennenlernen

CSS hat einige Zeichenbefehle, die in Canvas2D schmerzlich fehlen. Der neuen API wurden einige der am häufigsten gewünschten Funktionen hinzugefügt:

Rechteckiges Rechteck

Abgerundete Rechtecke: der Eckpfeiler des Internets, der Computertechnologie und fast der gesamten Zivilisation.

Im Ernst: Abgerundete Rechtecke sind äußerst nützlich: als Schaltflächen, Chatblasen, Thumbnails, Sprechblasen usw. In Canvas2D war es immer möglich, ein abgerundetes Rechteck zu erstellen. Bisher war es ein bisschen chaotisch:

const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
ctx.fillStyle = 'magenta';

const top = 10;
const left = 10;
const width = 200;
const height = 100;
const radius = 20;

ctx.beginPath();
ctx.moveTo(left + radius, top);
ctx.lineTo(left + width - radius, top);
ctx.arcTo(left + width, top, left + width, top + radius, radius);
ctx.lineTo(left + width, top + height - radius);
ctx.arcTo(left + width, top + height, left + width - radius, top + height, radius);
ctx.lineTo(left + radius, top + height);
ctx.arcTo(left, top + height, left, top + height - radius, radius);
ctx.lineTo(left, top + radius);
ctx.arcTo(left, top, left + radius, top, radius);
ctx.stroke();

All dies war notwendig für ein einfaches, einfaches abgerundetes Rechteck:

Ein abgerundetes Rechteck.

Die neue API bietet die Methode roundRect().

ctx.roundRect(upper, left, width, height, borderRadius);

Der obige Text kann also vollständig ersetzt werden durch:

ctx.roundRect(10, 10, 200, 100, 20);

Die Methode ctx.roundRect() akzeptiert auch ein Array mit bis zu vier Zahlen für das Argument borderRadius. Mit diesen Radien werden die vier Ecken des abgerundeten Rechtecks auf die gleiche Weise gesteuert wie bei CSS. Beispiel:

ctx.roundRect(10, 10, 200, 100, [15, 50, 30]);

Demo ansehen

Konischer Verlauf

Sie haben schon lineare Farbverläufe gesehen:

const gradient = ctx.createLinearGradient(0, 0, 200, 100);
gradient.addColorStop(0, 'blue');
gradient.addColorStop(0.5, 'magenta');
gradient.addColorStop(1, 'white');
ctx.fillStyle = gradient;
ctx.fillRect(10, 10, 200, 100);

Ein linearer Farbverlauf.

Radiale Farbverläufe:

const radialGradient = ctx.createRadialGradient(150, 75, 10, 150, 75, 70);
radialGradient.addColorStop(0, 'white');
radialGradient.addColorStop(0.5, 'magenta');
radialGradient.addColorStop(1, 'lightblue');

ctx.fillStyle = radialGradient;
ctx.fillRect(0, 0, canvas.width, canvas.height);

Radialer Farbverlauf

Aber wie wäre es mit einem schönen konischen Farbverlauf?

const grad = ctx.createConicGradient(0, 100, 100);

grad.addColorStop(0, 'red');
grad.addColorStop(0.25, 'orange');
grad.addColorStop(0.5, 'yellow');
grad.addColorStop(0.75, 'green');
grad.addColorStop(1, 'blue');

ctx.fillStyle = grad;
ctx.fillRect(0, 0, 200, 200);

Ein konischer Farbverlauf.

Textmodifikatoren

Die Text-Rendering-Funktionen von Canvas2D waren bisher sehr schlecht. Chrome hat dem Canvas2D-Text-Rendering mehrere neue Attribute hinzugefügt:

Diese Attribute stimmen alle mit ihren CSS-Entsprechungen mit denselben Namen überein.

Teil 2: Ergonomische Anpassungen

Bisher waren einige Dinge mit Canvas2D möglich, aber unnötig kompliziert zu implementieren. Hier sind einige Verbesserungen für JavaScript-Entwickler, die Canvas2D verwenden möchten:

Kontext zurücksetzen

Um das Löschen eines Canvas zu veranschaulichen, habe ich eine kleine Funktion zum Zeichnen eines Retro-Musters geschrieben:

draw90sPattern();

Ein Retromuster aus Dreiecken und Quadraten.

Sehr gut! Jetzt, da ich mit diesem Muster fertig bin, möchte ich den Canvas löschen und etwas anderes zeichnen. Wie löschen wir einen Canvas noch einmal? Oh ja! ctx.clearRect(), natürlich.

ctx.clearRect(0, 0, canvas.width, canvas.height);

Das hat nicht funktioniert. Oh ja! Ich muss zuerst die Transformation zurücksetzen:

ctx.resetTransform();
ctx.clearRect(0, 0, canvas.width, canvas.height);
Eine leere Leinwand.

Super! Eine schöne leere Leinwand. Zeichnen Sie jetzt eine schöne horizontale Linie:

ctx.moveTo(10, 10);
ctx.lineTo(canvas.width, 10);
ctx.stroke();

Eine horizontale und eine diagonale Linie.

Grrrr! Das stimmt nicht. 😡 Was macht diese zusätzliche Zeile hier? Und warum ist es rosa? Okay, sehen wir uns einfach mal StackOverflow an.

canvas.width = canvas.width;

Warum ist das so albern? Warum ist das so schwierig?

Das ist nicht mehr der Fall. Mit der neuen API haben wir die einfache, elegante, wunderschöne und bahnbrechende:

ctx.reset();

Tut mir leid, das hat so lange gedauert.

Filter

SVG-Filter sind eine Welt für sich. Wenn Sie mit SVG-Filtern noch nicht vertraut sind, empfehle ich Ihnen den Artikel The Art Of SVG Filters And Why It Is Awesome, in dem einige ihrer erstaunlichen Möglichkeiten gezeigt werden.

Für Canvas2D sind bereits SVG-Stilfilter verfügbar. Sie müssen den Filter nur als URL übergeben, die auf ein anderes SVG-Filterelement auf der Seite verweist:

<svg>
  <defs>
    <filter id="svgFilter">
      <feGaussianBlur in="SourceGraphic" stdDeviation="5" />
      <feConvolveMatrix kernelMatrix="-3 0 0 0 0.5 0 0 0 3" />
      <feColorMatrix type="hueRotate" values="90" />
    </filter>
  </defs>
</svg>
const canvas = document.createElement('canvas');
canvas.width = 500;
canvas.height = 400;
const ctx = canvas.getContext('2d');
document.body.appendChild(canvas);

ctx.filter = "url('#svgFilter')";
draw90sPattern(ctx);

Das stört unser Muster ziemlich:

Das Retro-Muster mit einem Weichzeichnereffekt.

Was aber, wenn Sie das oben Gesagte tun möchten, aber dabei in JavaScript bleiben und nicht mit Strings herumspielen möchten? Mit der neuen API ist dies möglich.

ctx.filter = new CanvasFilter([
  { filter: 'gaussianBlur', stdDeviation: 5 },
  {
    filter: 'convolveMatrix',
    kernelMatrix: [
      [-3, 0, 0],
      [0, 0.5, 0],
      [0, 0, 3],
    ],
  },
  { filter: 'colorMatrix', type: 'hueRotate', values: 90 },
]);

Ganz einfach. Probieren Sie es aus und spielen Sie mit den Parametern in der Demo hier.

Teil 3: Leistungsverbesserungen

Mit der neuen Canvas2D API wollten wir auch die Leistung nach Möglichkeit verbessern. Wir haben einige Funktionen hinzugefügt, um Entwicklern eine präzisere Kontrolle über ihre Websites und möglichst schnelle Framerates zu ermöglichen:

Häufig gelesen wird

Mit getImageData() können Sie Pixeldaten aus einem Canvas wieder lesen. Das kann sehr langsam gehen. Mit der neuen API können Sie einen Canvas explizit zum Zurücklesen kennzeichnen, z. B. für generative Effekte. So können Sie die Leistung optimieren und Canvas für eine größere Vielfalt von Anwendungsfällen flüssig halten. Diese Funktion ist schon seit einiger Zeit in Firefox verfügbar und wird jetzt endlich Teil der Canvas-Spezifikation.

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d', { willReadFrequently: true });

Kontextverlust

Lasst uns traurige Tabs wieder glücklich machen! Wenn einem Client der GPU-Speicher ausgeht oder ein anderes Unglück Ihre Leinwand trifft, können Sie jetzt einen Rückruf erhalten und bei Bedarf neu zeichnen:

const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');

canvas.addEventListener('contextlost', onContextLost);
canvas.addEventListener('contextrestored', redraw);

Wenn Sie mehr über Canvas-Kontext und -Verlust erfahren möchten, bietet die WHATWG eine gute Erklärung in ihrem Wiki.

Fazit

Ganz gleich, ob Sie Canvas2D zum ersten Mal verwenden, es seit Jahren nutzen oder seit Jahren vermeiden: Ich möchte Sie dazu anregen, sich Canvas noch einmal anzusehen. Es ist die API von nebenan, die schon immer da war.