- 1 Einleitung
- 2 Referenz
- 2.1
HTMLCanvasElement
- 2.2
CanvasRenderingContext2D
- 2.2.1 Verweis zurück auf die Leinwand
- 2.2.2 Zustand
- 2.2.3 Transformationen
- 2.2.4 Compositing
- 2.2.5 Farben und Stile
- 2.2.6 Linienkappen und Verbindungen
- 2.2.7 Schatten
- 2.2.8 Einfache Formen (Rechtecke)
- 2.2.9 Komplexe Formen (Pfade)
- 2.2.9.1
beginPath()
- 2.2.9.2
closePath()
- 2.2.9.3
stroke()
- 2.2.9.4
fill()
- 2.2.9.5
lineTo (x, y)
- 2.2.9.6
moveTo (x, y)
- 2.2.9.7
rect (x, y, w, h)
- 2.2.9.8
quadraticCurveTo (cpx, cpy, x, y)
- 2.2.9.9
bezierCurveTo (cp1x, cp1y, cp2x, cp2y, x, y)
- 2.2.9.10
arc (x, y, r, start, end, anticlockwise)
- 2.2.9.11
arcTo (x1, y1, x2, y2, radius)
- 2.2.9.12
clip()
- 2.2.9.13
isPointInPath (x, y)
- 2.2.9.1
- 2.2.10 Text
- 2.2.11 Bilder zeichnen
- 2.2.12 Pixel Manipulation
- 2.1
- 3 Anhänge
Das in HTML5 eingeführte Canvas- Element ermöglicht die dynamische Generierung von Bitmap-Bildern mithilfe von JavaScript-Code.
Die Grundeinstellung ist etwas kompliziert, die beteiligten Objekte selbst sind schlecht gestaltet, was auch auf eine echte Abnahme der Entwicklung der Standards zurückzuführen ist . Es gibt aber auch eine Kombination von Gründen, die das Canvas-Element zum Lernen und Trainieren wert machen: Es ist das zukünftige Element für Grafiken und sogar Videos in HTML, es ist äußerst leistungsfähig und in Kombination mit seinem natürlichen Lebensraum einer vollständigen Skriptsprache flexibel und voll anpassbar an alle Bedürfnisse.
Die Schnittstellen der JavaScript-Objekte sind unübersichtlich, Aktionen werden nicht ordnungsgemäß getrennt und die Wirkung der Methoden hängt von ungewöhnlichen Nebenwirkungen und Eigenschafteneinstellungen ab. Diese Schnittstellen sind jedoch klein: Teil 2 des Inhaltsverzeichnisses bietet bereits eine vollständige Zusammenfassung und Übersicht. Diese Reduzierung auf weniger als 20 Eigenschaften und 35 Methoden macht die vollständigen Funktionen des Canvas-Elements überschaubar und verständlich. Mit Hintergrundkenntnissen in HTML, CSS und zumindest ein wenig JavaScript kann dieses Canvas-Handbuch möglicherweise sowohl als Einführung als auch als täglicher Arbeitsbegleiter dienen, der ausreicht, um das gesamte Thema zu beherrschen.
Dieses Handbuch besteht aus drei Teilen:
- 1. Einleitung
- Eine erste Bekanntschaft mit dem Canvas-Element, einfachen Beispielen und der Grundeinstellung.
- 2. Referenz
- Dieser größte Teil des Canvas-Handbuchs ist eine umfassende Referenz für die beiden wichtigsten beteiligten JavaScript-Objekte: 1. the
HTMLCanvasElement
und 2. theCanvasRenderingContext2D
. Stellen Sie sich diesen zweiten Teil als benutzerfreundliche Version des offiziellen [W3C] -Standards für das Canvas-Element vor. Die Eigenschaften und Methoden sind wie in der Referenzzusammenfassung dieses Dokuments angegeben strukturiert . - 3. Anhänge
- für einige Elemente von CSS , HTML5 Dateivorlagen und Notizen über zusätzliche Werkzeuge und Werkzeugbau .
Wenn Sie ein Anfänger sind, lesen Sie den ersten Teil und durchsuchen Sie dann den zweiten Teil nach den Dingen, die Sie benötigen.
- [HOME] 1
- für (die neueste Version von) diesem Text.
- [FORUM] 2
- ist eine interaktive Seite für Benutzer- und Autorenkommentare zu diesem Text und Thema.
Es gibt nette Online-Ressourcen, die mir die ersten Schritte beigebracht haben, insbesondere das Canvas-Tutorial des Mozilla Developer Network .
Dieses Handbuch selbst wurde in Markdown geschrieben und mithilfe des wunderbaren universellen Dokumentenkonverters Pandoc in HTML konvertiert. 3
1 Einleitung
1.1 Offizielle Standards
Dies sind die offiziellen Papiere, die das Canvas-Element beschreiben und definieren:
- [W3C] 4
- Das W3C ( World Wide Web Consortium ) definiert den HTML5-Standard. In diesem Abschnitt wird das Canvas-Element beschrieben.
- [WAS] 5
- ist der Abschnitt des Entwurfs der Spezifikation für Webanwendungen der WHATWG ( Arbeitsgruppe für Web-Hypertext-Anwendungstechnologie ), in dem das Canvas-Element ursprünglich standardisiert ist.
- [W3C / 2D] 6
- ist die W3C-Beschreibung des HTML Canvas 2D-Kontexts
1.2 Anforderungen: Ein Browser mit Unterstützung für HTML5 und JavaScript
Das Canvas-Element ist Teil von HTML5 . Wenn ein Browser zu alt ist oder nicht in der Lage ist, mit diesem relativ neuen Standard umzugehen, können Sie ihn überhaupt nicht verwenden.
Eine detaillierte Übersicht über die Browserunterstützung für HTML5 im Allgemeinen und das Canvas-Element im Besonderen finden Sie beispielsweise unter caniuse.com .
Darüber hinaus muss Ihr Browser in der Lage und berechtigt sein, JavaScript-Code auszuführen. Vor ein paar Jahren hatte JavaScript den Ruf, den Benutzer zu ärgern, und in vielen Konfigurationen war es standardmäßig ausgeschaltet. Aber all dies gehört der Vergangenheit an, ganz sicher, wenn Sie nicht alle Funktionen von HTML5 und insbesondere das Canvas-Element verpassen möchten.
Um diesen Text zu verstehen, stellen Sie sicher, dass Ihr Browser auf dem neuesten Stand und ordnungsgemäß konfiguriert ist (siehe das erste Beispiel als Test, um sicherzustellen, dass er ordnungsgemäß funktioniert). Alle Abbildungen und Beispiele werden nicht als <img>
Bilder eingefügt , sondern mit Canvas-Elementen.
1.3 Ein erstes Beispiel
Hier ist ein Beispiel für ein Leinwandbild, das eine "Hallo" -Nachricht in einem roten Feld zeigt: 7
Der Quellcode für dieses Bild lautet: 8
<canvas id="VeryFirstExampleCanvas" width=150 height=60>
GO AND UPDATE YOUR BROWSER BEFORE YOU READ ON!
</canvas>
<script>
var canvas = document.getElementById ('VeryFirstExampleCanvas'); // access the canvas object
var context = canvas.getContext ('2d'); // access the canvas context
context.fillStyle = 'red'; // set the color to 'red'
context.fillRect (0,0,150,60); // draw a red box on the whole of the canvas
context.fillStyle = 'yellow'; // set the color to 'yellow'
context.fillRect (5,5,140,50); // draw a yellow box inside the red one
context.fillStyle = 'red'; // set the color back to 'red'
context.font = '40pt Arial'; // define the CSS font for writing text
context.fillText ('Hello',10,50); // write the text 'Hello'
</script>
Dieses kleine Beispiel enthält bereits alle Grundzutaten und Schritte, die wir später immer wieder wiederholen werden. Jedes normale Leinwandbild besteht aus zwei Teilen des Codes:
Erstens gibt es den
<canvas>...</canvas>
Teil, der Teil der HTML-Datei an der Stelle ist, an der sich das Bild befinden soll.
Es hat die beiden Attribute fürwidth
undlength
, die die Größe des rechteckigen Bildes definieren, gemessen in Pixel. In diesem Beispiel ist es150
pixelweit und60
pixelhoch.
Der Text innerhalb des<canvas>...</canvas>
Tags ist nicht der "Inhalt" der Zeichenfläche, sondern nur eine sogenannte "Fallback" -Nachricht. Dies sollte der Benutzer sehen, wenn der Browser zu alt ist oder nicht in der Lage ist, mit Canvas-Elementen umzugehen.Der zweite Teil des Codes ist das JavaScript-Skript. In diesem Beispiel wird es direkt unter und innerhalb eines
<script>...</script>
Tags platziert. Tatsächlich ist der Speicherort dieses Codeteils jedoch ziemlich willkürlich und wird häufig in eine separate.js
Datei verschoben . Das Skript führt normalerweise drei Schritte aus:Laden Sie das HTML-
<canvas>
Tag in einHTMLCanvasElement
Objekt. Wir haben es in einer Variablen gespeichert, diecanvas
durch Aufrufen der ersten Zeile benannt wurdevar canvas = document.getElementById('VeryFirstExampleCanvas');
Das Bild wird nicht direkt im
HTMLCanvasElement
, sondern in seinem sogenannten Kontext erzeugt , einem internenCanvasRenderingContext2D
Objekt, das wir in einer anderen Variablen gespeichert haben, diecontext
durch Aufrufen der zweiten Zeile benannt wurdevar context = canvas.getContext('2d');
Jetzt ist alles so eingestellt, dass "Sachen gezeichnet" werden, indem Eigenschaften geändert und Methoden aufgerufen werden, nämlich:
context.fillStyle = 'red'; // set the color to 'red' context.fillRect (0,0,150,60); // draw a red box on the whole of the canvas context.fillStyle = 'yellow'; // set the color to 'yellow' context.fillRect (5,5,140,50); // draw a yellow box inside the red on context.fillStyle = 'red'; // set the color back to 'red' context.font = '40pt Arial'; // define the CSS font for writing text context.fillText ('Hello',10,50); // write the text 'Hello'
Der Kontext ist der Ort, an dem der Bildinhalt generiert wird und die Beschreibung seiner Eigenschaften und Methoden den größten Teil dieses Handbuchs ausmacht. Um jedoch mit dem Canvas-Element arbeiten zu können, müssen wir diese grundlegenden Schritte verstehen.
Lassen Sie uns die gleichen Schritte noch einmal ausführen. Diesmal erzeugen wir die Nationalflagge Frankreichs .
Der Quellcode lautet wie folgt:
<canvas id="LittleTricolour" width=120 height=90> Your browser still doesn't work! </canvas>
<script>
// First, get hold of the canvas object and its context
var tricolourCanvas = document.getElementById('LittleTricolour'); // access the canvas object
var tricolourCanvasContext = tricolourCanvas.getContext('2d'); // access the canvas context
// Now do the real drawings:
tricolourCanvasContext.fillStyle = '#0055A4'; // set the color to blue
tricolourCanvasContext.fillRect ( 0, 0, 40, 90); // draw a blue rectangle on the left
tricolourCanvasContext.fillStyle = '#FFFFFF'; // set the color to white
tricolourCanvasContext.fillRect (40, 0, 40, 90); // draw a white rectangle in the middle
tricolourCanvasContext.fillStyle = '#EF4135'; // set the color to red
tricolourCanvasContext.fillRect (80, 0, 40, 90); // draw a red rectangle on the right
</script>
Alle visuellen Bildelemente werden ausschließlich im Canvas-Kontext generiert und in der willkürlich benannten JavaScript-Variablen gespeichert tricolourCanvasContext
.
1.4 Grundeinstellung
Jedes Leinwandelement existiert in zwei Welten und zwei Formen:
das
<canvas>
Tag , dh die<canvas>...</canvas>
Struktur, die Teil des HTML-Codes istdas
HTMLCanvasElement
Objekt , das ein geeignetes JavaScript - Objekt ist und enthält eine weiteres sogenanntes Kontextobjekt, in dem die tatsächlichen Bildelemente erzeugt werden.
Diese doppelte Natur des HTML-Tags einerseits und des JavaScript-Objekts andererseits ist nicht spezifisch für das Canvas-Element, sondern wesentlich für das gesamte Design des DOM (Document Object Model) 9 , das die dynamische Bearbeitung eines Dokuments mittels ermöglicht JavaScript.
<canvas>
Tag
In gewisser Weise <canvas>
ähnelt das <img>
Tag dem Tag zum Anzeigen von Bildern. Zum Beispiel der Quellcode
<img src="horse.jpg" width=100 height=100 alt="SOMETHING GOES WRONG" style="border: solid 5pt orange"> </img>
generiert das folgende Bild in Ihrem Browser

Mit width
und stellen height
wir die Größe des Bildes ein. (Denken Sie daran, dass dies jeweils 100
eine Abkürzung für ist "100px"
.) Mit alt
bieten wir einen "alternativen" oder Fallback-Text an, der angezeigt wird, falls das Bild aus irgendeinem Grund nicht angezeigt werden kann. Das allgemeine style
Attribut für HTML-Elemente wird verwendet, um einige CSS-Attribute festzulegen. In diesem Fall wird ein orangefarbener Rand um das Bild gezogen. Und natürlich hätten wir das schließende </img>
Tag weglassen können .
Das <canvas>
Tag hat ähnliche Funktionen. Zum Beispiel diese Codezeile
<canvas width=100 height=100 style="border: solid 5pt orange"> SOMETHING GOES WRONG </canvas>
erscheint so
Wiederum width
und height
gesetzt sind dies tatsächlich die einzigen zwei eigenen Attribute des <canvas>
Tags. Das style
Attribut ist ein allgemeines Attribut für HTML-Elemente und legt erneut einen orangefarbenen Rahmen um die Zeichenfläche. Wenn wir dieses Attribut weggelassen hätten, könnten wir die Leinwand überhaupt nicht richtig sehen.
Anders als das alt
Attribut für das <img>
Tag befindet sich der Fallback-Inhalt für das <canvas>
nicht in einem Attribut, sondern befindet sich innerhalb der <canvas>...</canvas>
Tags.
Übrigens width
und height
kann tatsächlich weggelassen werden. In diesem Fall ist die Breite standardmäßig auf 300px
und die Höhe auf eingestellt 150px
. Zum Beispiel,
<canvas style="border: solid 5pt orange"> </canvas>
erscheint so
Das style
Attribut ist eine allgemeine Option für alle HTML-Tags, um einige CSS-Funktionen hinzuzufügen. Tatsächlich ist dies jedoch nicht der Ort, an dem der tatsächliche Bildinhalt eines Canvas-Elements gezeichnet wird. Dies geschieht im sogenannten Canvas- Kontext .
Der reale grafische Inhalt und die Bildelemente einer Leinwand befinden sich weder in Attributen noch zwischen dem <canvas>...</canvas>
Tag. Es ist überhaupt nicht in HTML oder CSS geschrieben. Stattdessen erfolgt dies im sogenannten Canvas- Kontext , auf den nur in JavaScript zugegriffen und dieser geändert werden kann.
Es gibt verschiedene Möglichkeiten, ein Leinwandbild auf dem Bildschirm anzuzeigen. Tatsächlich kann dies sogar vollständig in JavaScript erfolgen, ohne dass ein <canvas>
Tag erforderlich ist. Wir beabsichtigen jedoch nicht, zu tief in das JavaScript-DOM einzutauchen und stattdessen eine Standardmethode zu verbreiten, die in den meisten Fällen ausreichen sollte.
Die Standardmethode ist folgende: 10
In unserer HTML-Datei platzieren wir ein
<canvas>...</canvas>
Tag an der Stelle, an der das Leinwandbild erscheinen soll.Wir fügen ein
id
Attribut mit einem beliebigen Namen hinzu (in unserem FallmyCan
). Achten Sie darauf, nicht denselben Namen für mehr als ein Tag zu verwenden, dh geben Sie jeder anderen Zeichenfläche eine andere ID.Wir erhalten dann durch Aufrufen Zugriff auf das Canvas-Objekt, das das Canvas-Element im DOM darstellt
document.getElementById('myCan');
Dieses Objekt ist ein JavaScript-Objekt vom Typ
HTMLCanvasElement
. Standardmäßig legen wir einen Namen, in der Regelcanvas
(abermyCan
,canvasNo27
usw. ist ebenfalls möglich), auf dieses Objekt durch den Aufrufvar canvas = document.getElementById('myCan');
Auf diese Weise erhalten wir später im Skript einen einfachen Zugriff darauf.
Jetzt müssen wir durch Aufrufen zum 2d-Kontext dieses Canvas-Objekts gelangen
getContext('2d')
. Und wieder fügen wir ihm normalerweise sofort einen Namen hinzucontext
(andere Autoren bevorzugenctx
oder was auch immer). Dies ist also unsere nächste Codezeilevar context = canvas.getContext('2d');
Beachten Sie, dass wir stattdessen mit dieser Zeile das gleiche Ergebnis erzielt hätten:
var context = document.getElementById('myCan').getContext('2d');
Natürlich ist es viel bequemer, die
canvas
Variable als Handle für das Canvas-Objekt zu verwenden.Jetzt haben wir alles vorbereitet, um die echten Zeichnungen zu erstellen, indem wir den genannten 2D-Kontext ändern und hinzufügen
context
. Das bedeutet, entweder Kontexteigenschaften abzurufen oder festzulegen, wie wir es in getan habencontext.fillStyle = 'red';
oder Aufrufen von Kontextmethoden, wie von
context.fillRect(0,0,150,60);
Insgesamt ist dies also unsere Standardvorlage zum Generieren von Leinwandbildern, zumindest für den Moment:
<canvas id="MyCanvasNo123" width=150 height=75> </canvas>
<script>
var canvas = document.getElementById ('MyCanvasNo123');
var context = canvas.getContext ('2d');
// ...
// ... do stuff with the context ...
// ...
</script>
Wir verwenden diese Vorlage in diesem Text und in vielen Beispielen zeigen wir nur den "... do stuff with the context ..."
Teil, vorausgesetzt, Sie kennen die anderen Zeilen. In den meisten Beispielen funktioniert diese einfache Vorlage und ist ein ausreichender Ausgangspunkt für die Gestaltung Ihrer eigenen Beispieldateien und Gemälde.
Aber auf einer professionelleren Ebene und wenn die erzeugten Bilder komplexer werden, sollten Sie dieses Design ändern:
In größeren Projekten ist es üblich, Inhalt und Stil zu trennen, und das Skript sollte in einen bestimmten Abschnitt oder sogar in eine externe
js
Datei verschoben werden.Wenn das gesamte Projekt online ist und der Browser mehr als eine Datei herunterladen muss, können Verzögerungen dazu führen, dass Canvas-Elemente überhaupt nicht gerendert werden. Wenn Bilder oder andere Mediendateien betroffen sind, ist es natürlich wichtig sicherzustellen, dass die Skriptteile erst ausgeführt werden, nachdem der gesamte HTML-Code geladen wurde.
All diese Probleme werden im Abschnitt Vorlagen des Anhangs behandelt.
Übrigens gibt es andere Kontexttypen als den 2D-Kontext mit seinen CanvasRenderingContext2D
Objekten. Das [W3C] enthält einen Hinweis: Eine zukünftige Version dieser Spezifikation wird wahrscheinlich einen 3D-Kontext definieren (wahrscheinlich basierend auf der OpenGL ES-API). All dies liegt jedoch außerhalb des Rahmens dieses Textes und wird von den großen Browsern noch nicht allgemein unterstützt.
1,5 Punkte (x,y)
und die Leinwandkoordinaten
Jede Leinwand hat ein width
und ein height
, und standardmäßig sind dies 300
bzw. 150
Pixel. Dies bedeutet, dass die Leinwand in 300
Pixel in die horizontale oder x-Achse und 150
Pixel in die vertikale oder y-Achse unterteilt ist . Die x-Achse verläuft von links 0
nach rechts 300
, die y-Achse von oben 0
nach unten 150
. 11
Innerhalb dieses Koordinatensystems wird jeder Punkt auf der Leinwand durch das Zahlenpaar (x,y)
mit 0 ? x ? width
und genau definiert 0 ? y ? height
.
Beispielsweise wird der Punkt (200,25)
auf einer 300x150
Pixelgröße mit Standardgröße durch den roten Punkt 12 dargestellt
Da diese Position für den Leser jedoch schwer zu überprüfen ist, zeigen wir unten häufig ein Koordinatensystem oder ein Raster auf Leinwandbeispielen an. Der gleiche Punkt ist dann leicht zu finden:
Alle Punkte (x,y)
, die außerhalb des Bereichs von liegen 0 ? x ? width
und 0 ? y ? height
nicht angezeigt werden. Beispielsweise werden die Punkte (-60,50)
oder (500,500)
nicht in der vorherigen Zeichenfläche angezeigt. 13 Wenn (Teile von) Figuren die Ränder der Leinwand überschreiten, werden die überschüssigen Teile einfach abgeschnitten, wie bei der folgenden Scheibe mit Mittelpunkt (250,100)
und Radius 100
.
Wenn wir zeichnen, sagen wir die deutsche Flagge auf einem solchen Gitter
dann ist es einfacher, dem Code auf dem Bildergebnis zu folgen, nämlich: 14
context.fillStyle = '#000000'; // set the color to black ('#000000' is the same as 'black')
context.fillRect(0, 0,200,40); // draw a rectangle field with top left point at (0,0), 200 pixel wide and 40 pixel high
context.fillStyle = '#FF0000'; // set the color to red (which is '#FF0000' is CSS hexadecimal color notation)
context.fillRect(0,40,200,40); // draw same size (200x40 pixel) rectangle at (0,40)
context.fillStyle = '#FFCC00'; // set the color to gold
context.fillRect(0,80,200,40); // last rectangle with left top point at (0,80)
Tatsächlich können wir dem ein solches Raster hinzufügen, context
indem wir die context.addGrid()
Methode aufrufen. Dies kann sehr praktisch sein, wenn Sie Code schreiben. Sobald die gesamte Leinwand gezeichnet ist, können Sie diese Linie einfach wieder entfernen. Beachten Sie jedoch, dass dies addGrid()
keine Standardmethode des CanvasRenderingContext2D
Objekts ist! Wenn Sie es selbst verwenden möchten, müssen Sie die Implementierung aus dem Anhang in Ihre eigene Datei kopieren .
2 Referenz
2.1 HTMLCanvasElement
Das Canvas-Element wird in zwei Formen angegeben: als HTML-Tag und als JavaScript-Objekt . In dieser Referenz konzentrieren wir uns auf die JavaScript-Seite der Dinge. Der Vollständigkeit halber lassen Sie uns eine kurze Wiederholung der Grundeinstellung geben
<canvas>
Tag
In HTML5 hat ein <canvas>
Tag die allgemeine Form
<canvas id="...." width="..." height="...">
... fallback content ...
</canvas>
Tatsächlich hat das canvas
Element nur zwei eigene Attribute width
und height
. Beide sind optional. Wenn sie weggelassen werden , wird standardmäßig die Breite 300px
und die Höhe auf festgelegt 150px
.
Das ... fallback content ...
ist, was im Browser erscheint, der nicht HTML5-fähig ist. Da wir diese Situation hier nicht berücksichtigen müssen, verwenden wir dies nur als Standardformular für unsere Beispiele:
<canvas id="..." width="..." height="..."> </canvas>
Das id
Attribut ist nur ein allgemeines Attribut für das HTML-Element. Wir fügen es jedoch in den folgenden Beispielen hinzu, da es eine Standardmethode zum Abrufen des HTMLCanvasElement
Objekts in JavaScript bietet . Normalerweise machen wir so etwas
<canvas id="mycanvas" width=100 height=100> </canvas>
<script>
var canvas = document.getElementById ("mycanvas");
// ... now, we have the canvas element available and can manipulate it ...
</script>
Die canvas
Variable ist dann ein Handle für die HTMLCanvasElement
.
HTMLCanvasElement
Das JavaScript-Canvas-Objekt ist a HTMLCanvasElement
. Es hat:
zwei Eigenschaften, nämlich
zwei Methoden, nämlich
getContext()
das bietet Zugriff auf den Canvas-Kontext ,toDataURL()
Dadurch wird der gesamte Inhalt der angegebenen Zeichenfläche in Code für eine Bilddatei (PNG oder JPEG) übersetzt.
Das Canvas-Objekt ist ziemlich einfach, die tatsächlichen Zeichnungen und Bildelemente werden in seinem Kontext generiert . Im Allgemeinen und in diesem Handbuch betrachten wir nur eine Art von Kontext, nämlich den 2D-Kontext , der CanvasRenderingContext2D
im zweiten Teil dieser Referenz unter der Überschrift umfassend dokumentiert ist .
2.1.1 width
HTMLCanvasElement.width
speichert die Breite des Canvas-Elements, wie durch das
width
Attribut des<canvas>
Tags angegeben. Es ist jedoch auch möglich, diesen Wert zu ändern. Standardmäßig hat eine Leinwand eine300
Pixelbreite.
Platzieren Sie beispielsweise ein <canvas>
Tag mit nicht standardmäßiger Breite und Höhe und fügen Sie einen orangefarbenen Rand (über dessen style
Attribut) hinzu, damit dieser sichtbar ist. Dann fügen wir ein Skript hinzu, das diese Zeichenfläche verwendet, ihre width
und vorliest height
und das Ergebnis in die Zeichenfläche schreibt. Alle zusammen,
<canvas id="SizeReadingSample" width=456 height=123 style="border: 5pt solid orange"> </canvas>
<script>
var canvas = document.getElementById('SizeReadingSample');
var message = "This canvas is " + canvas.height + " pixel high and " + canvas.width + " pixel wide.";
var context = canvas.getContext('2d');
context.font = "20px Arial";
context.fillText (message, 15, 70);
</script>
ist der Code, der dieses Bild erzeugt
2.1.2 height
HTMLCanvasElement.height
speichert die Höhe des Canvas-Elements, wie durch das
height
Attribut des<canvas>
Tags angegeben, das150
standardmäßig ist.
Im vorherigen Beispiel haben wir das gesehen height
und width
sind lesbare Eigenschaften. Sie sind aber auch beschreibbar und wir können diese Werte dynamisch ändern.
Angenommen, wir haben eine <canvas>
Standardgröße, dh 300
Pixel breit und 150
hoch, und wir fügen ihr über ihr style
Attribut erneut einen orangefarbenen Rand hinzu , um ihre Form zu visualisieren.
<canvas id="SizeChangingSample" width=300 height=150 style="border: 5pt solid orange"> </canvas>
Dann fügen wir ein Skript hinzu, in dem wir die Größe der Zeichenfläche explizit ändern, indem wir beide width
und height
nur 30
Pixel festlegen, wie folgt:
var canvas = document.getElementById('SizeChangingSample');
canvas.width = 30;
canvas.height = 30;
Das Ergebnis ist in der Tat eine kleinere, verkleinerte Leinwand, nämlich:
2.1.3 getContext('2d')
HTMLCanvasElement.getContext (contextId)
Gibt den sogenannten Kontext zurück , dh ein Objekt, das eine API zum Zeichnen auf der Leinwand verfügbar macht. Derzeit wird nur das
CanvasRenderingContext2D
Objekt unterstützt, und dafürcontextId
ist das'2d'
. Das Ergebnis dieses Aufrufs ist,null
wenn die angegebene Kontext-ID nicht unterstützt wird.
Dieser Kontext , der in der Fortsetzung immer der 2D-Kontext sein wird, wird an die Leinwand angehängt und ist durch einen Aufruf von zugänglich canvas.getContext('2d')
. In diesem Kontext findet die gesamte Aktion statt. Es bietet die Schnittstelle für alle Zeichnungen, die der angegebenen Leinwand hinzugefügt wurden, und die Erläuterung des folgenden CanvasRenderingContext2D
Objekts ist daher der größte Teil dieses Handbuchs.
Das [W3C] -Dokument kündigt an, dass es in Zukunft wahrscheinlich einen '3d'
Kontext geben wird, der auf der OpenGL ES-API basiert.
2.1.4 toDataURL()
HTMLCanvasElement.toDataURL ()
HTMLCanvasElement.toDataURL (type,... )
Gibt eine
data:
URL für das Bild im Canvas zurück. Das erste optionaletype
Argument steuert den Typ des zurückzugebenden Bildes (z. B. PNG oder JPEG). Der Standardtyp ist'image/png'
für PNG- Bilder. Die anderen Argumente sind typspezifisch und steuern die Art und Weise, wie das Bild generiert wird.
Betrachten wir ein sehr kleines Leinwandbeispiel, beispielsweise ein rotes 20 x 20 Pixel großes Rechteck
generiert durch den folgenden Code
<canvas id="DataUrlSample" width=20 height=20></canvas>
<script>
var canvas = document.getElementById ('DataUrlSample');
var context = canvas.getContext ('2d');
context.fillStyle = 'red';
context.fillRect (0, 0, 20, 20);
</script>
Wir können jetzt die Zeichenfläche in eine PNG-Daten-URL konvertieren, indem wir Folgendes aufrufen:
var dataUrl = canvas.toDataURL();
und dataUrl
hält jetzt diese Zeichenfolge:
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAARzQklUCAgICHwIZIgAAAArSURBVDhPY/zPwABE1AOMowZSHJijYUhxEDKMhuFoGJIRAqPJhoxAQ9MCAEwCJ+021vhIAAAAAElFTkSuQmCC
Daten: Bild / PNG;
Wenn Sie diese Zeichenfolge kopieren und in das Adressfeld Ihres Browsers einfügen, sollte das Bild des roten Quadrats angezeigt werden.
Wir können auch zu einem konvertieren JPEG wie so
var dataUrl = canvas.toDataURL('image/jpeg');
und dann ist das Ergebnis diese Zeichenfolge:
data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAUABQDASIAAhEBAxEB/8QAFQABAQAAAAAAAAAAAAAAAAAAAAj/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/8QAFgEBAQEAAAAAAAAAAAAAAAAAAAcJ/8QAFBEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEQMRAD8AnQBDGqYAAAAAD//Z
Daten: image / JPEG; Base64, / 9j / 4AAQSkZJRgABAQAAAQABAAD / 2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD / 2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD / wAARCAAUABQDASIAAhEBAxEB / 8QAFQABAQAAAAAAAAAAAAAAAAAAAAj / xAAUEAEAAAAAAAAAAAAAAAAAAAAA / 8QAFgEBAQEAAAAAAAAAAAAAAAAAAAcJ / 8QAFBEBAAAAAAAAAAAAAAAAAAAAAP / aAAwDAQACEQMRAD8AnQBDGqYAAAAAD // Z
Sie können dies alles kopieren und in Ihrem Browser aufrufen, um das kleine rote Quadrat erneut zu erhalten.
Für eine bequemere Lösung können wir diese Zeilen an den vorherigen Code anhängen: 15
canvas.onclick = function () {
window.location = canvas.toDataURL('image/png');
};
Wenn wir dann auf die Leinwand klicken, öffnet der Browser die Daten-URL in das Adressfeld und zeigt so das Bild. Anschließend kann der Benutzer dieses Bild als PNG-Datei speichern.
2.2 CanvasRenderingContext2D
2.2.1 Verweis zurück auf die Leinwand
2.2.1.1 canvas
CanvasRenderingContext2D.canvas
verweist auf den
HTMLCanvasElement
gegebenen Kontext.
Angenommen, wir haben den folgenden Code:
<canvas id="ReferenceSample1" width=150 height=100 style="border: solid 5pt orange"> </canvas>
<script>
var context = document.getElementById('ReferenceSample1').getContext('2d');
context.canvas.width = 250; // reset the canvas width to 250
context.canvas.height = 50; // reset the canvas height to 50
</script>
Dies wird als Leinwand mit 250 x 50 Pixel angezeigt (sichtbar aufgrund des durchgehenden orangefarbenen 5-Punkt-Randes):
Die im <canvas>
Tag angegebene Originalgröße der Leinwand beträgt 150 x 100 Pixel. Die JavaScript-Variable context
enthält das CanvasRenderingContext2D
Objekt. Mit context.canvas
bekommen wir das HTMLCanvasElement
, was diesen Kontext enthält. Also mit context.canvas.width
und context.canvas.height
beziehen wir uns auf die Breite und Höhe dieser Leinwand.
Natürlich hätten wir genau das gleiche Bild erhalten mit:
<canvas id="ReferenceSample2" width=150 height=100 style="border: solid 5pt orange"> </canvas>
<script>
var canvas = document.getElementById('ReferenceSample2');
var context = canvas.getContext('2d');
canvas.width = 250;
canvas.height = 50;
</script>
Der Punkt hier war jedoch die Demonstration der Fähigkeit, aus seinem 2D-Kontext auf das Canvas-Objekt zu verweisen.
2.2.2 Zustand
Ein Zeichnungsstatus ist die Menge der aktuellen Einstellungen eines
CanvasRenderingContext2D
Objekts. Es enthält die aktuellen Stil - Werte (strokeStyle
undfillStyle
),globalAlpha
undglobalCompositeOperation
die Leitung (lineWidth
,lineCap
,lineJoin
,miterLimit
), Schatten (shadowOffsetX
,shadowOffsetY
,shadowBlur
,shadowColor
) und Texteinstellungen (font
,textAlign
,textBaseline
), den aktuellen Auswahlbereich und die aktuelle Transformationsmatrix .Jedes
CanvasRenderingContext2D
Objekt verwaltet einen Stapel von Zeichnungszuständen . Mitsave()
undrestore()
können Zeichnungszustände auf diesen Stapel verschoben und zu einem späteren Zeitpunkt wiederhergestellt werden.
Beachten Sie, dass der Zeichnungsstatus weder den aktuellen Pfad noch die Bitmaps enthält. So save()
und restore()
nicht speichern und ganze Leinwand Bilder wiederherstellen, dh gesamten Inhalt des gegebenen Kontextes. Verwenden Sie dazu ImageData
Objekte und die Methoden getImageData()
und putImageData()
(siehe Kapitel zur Pixelmanipulation ).
Angenommen, wir zeichnen 5 Figuren, von denen jede ein fillRect()
Rechteck mit zwei Textzeilen enthält strokeText()
:
Wie aus dem Bild ersichtlich ist, verwenden wir 3 verschiedene Stileinstellungen für die 5 Figuren, die als Zustände definiert sind :
- Zustand A mit einem linearen Farbverlauf
fillStyle
von oben rot nach unten grün und gelbstrokeStyle
. - Zustand B mit einem radialen Gradienten
fillStyle
, der von einem orangefarbenen Mittelstart zu einem äußeren grünen Endkreis und grün verläuftstrokeStyle
. - Zustand C mit dunkelgrau
fillStyle
und hellgraustrokeStyle
.
Wir könnten die vorherige Zeichenfläche generieren, indem wir die folgenden Schritte ausführen:
- Deklarieren Sie Zustand A und zeichnen Sie Abbildung 1 und 5
- Deklarieren Sie Zustand B und zeichnen Sie Abbildung 2 und 4
- deklarieren Sie Zustand C und zeichnen Sie Abbildung 3
Da wir jedoch die Verwendung von save()
und demonstrieren möchten restore()
, erstellen wir die Figuren in der angegebenen Reihenfolge:
- Setzen Sie Status A , zeichnen Sie Abbildung 1 und speichern Sie Status A auf dem Statusstapel
- Setzen Sie Status B , zeichnen Sie Abbildung 2 und speichern Sie Status B auf dem Statusstapel
- Setze Zustand C und zeichne Abbildung 3
- Überschreiben Sie Zustand C, indem Sie Zustand B vom Stapel wiederherstellen , und zeichnen Sie Abbildung 4
- Stellen Sie den Zustand A wieder her und zeichnen Sie Abbildung 5
Der vollständige Quellcode, der die Zeichenfläche tatsächlich generiert hat, lautet:
// Text style settings (these will be part of Start A, B, and C alike, because they do not change)
context.textAlign = 'center';
context.textBaseline = 'middle';
context.lineWidth = 2.0;
context.font = '25px Arial';
// Settings for State A
var verticalGrad = context.createLinearGradient (0,0,0,200);
verticalGrad.addColorStop (0,'red');
verticalGrad.addColorStop (1,'green');
context.fillStyle = verticalGrad;
context.strokeStyle = 'yellow';
// Draw Figure 1
context.fillRect (25,25,100,150);
context.strokeText ("Fig 1",75,50);
context.strokeText ("State A", 75,125);
// Save State A
context.save();
// Settings for State B
var radGrad = context.createRadialGradient (375,100,5, 375,100,200);
radGrad.addColorStop (0,'orange');
radGrad.addColorStop (1,'yellow');
context.fillStyle = radGrad;
context.strokeStyle = 'green';
// Draw Figure 2
context.fillRect (175,25,100,150);
context.strokeText ("Fig 2",225,50);
context.strokeText ("State B",225,125);
// Save State B
context.save();
// Settings for State C
context.fillStyle = '#888888';
context.strokeStyle = '#EEEEEE';
// Draw Figure 3
context.fillRect (325,25,100,150);
context.strokeText ("Fig 3",375,50);
context.strokeText ("State C",375,125);
// Pop State C and restore State B
context.restore();
// Draw Figure 4
context.fillRect (475,25,100,150);
context.strokeText ("Fig 4",525,50);
context.strokeText ("State B",525,125);
// Pop state B and restore state A
context.restore();
// Draw Figure 5
context.fillRect (625,25,100,150);
context.strokeText ("Fig 5",675,50);
context.strokeText ("State A",675,125);
2.2.2.1 save()
CanvasRenderingContext2D.save()
Schieben Sie den aktuellen Status auf den Statusstapel.
Eine Beispielanwendung finden Sie im vorherigen Arbeitsbereich.
2.2.2.2 restore()
CanvasRenderingContext2D.restore()
Entfernen Sie den obersten Status aus dem Statusstapel und stellen Sie so den vorherigen Status wieder her, der auf den Statusstapel verschoben wurde.
Ein Beispiel finden Sie auf der vorherigen Leinwand.
2.2.3 Transformationen
In der allgemeinen Geometrie verwandelt eine Transformation ein bestimmtes Objekt in ein anderes Objekt, behält jedoch seine Struktur bei. Dinge mögen deformiert erscheinen, aber sie werden nicht zerbrochen oder zerstört. Die absolute Position von Punkten kann sich ändern, aber die relativen Positionen bleiben erhalten, benachbarte Punkte sind nach der Transformation immer noch Nachbarn.
Drei spezielle Transformationen können mit speziellen Methoden im Canvas-Kontext aufgerufen werden:
scale()
Ändert die Größe der Leinwand, rotate()
dreht sie um den Ursprung und translate()
verschiebt sie an eine neue Position. Aber tatsächlich und anders als in den drei vorherigen Bildern vorgeschlagen, wird durch keine dieser Operationen die Leinwand als Objekt im Browserfenster verschoben, sondern ihr Koordinatensystem wird geändert. Im Folgenden zeigen wir anhand vieler Beispiele, was dies bedeutet.
Neben diesen drei speziellen Transformationen gibt es auch die allgemeinen transform()
und setTransform()
Methoden, die leistungsfähiger, aber auch schwieriger zu verstehen und anzuwenden sind. 16 Wir zeigen auch, dass jede Kombination von Transformationen (z. B. zuerst Skalierung, dann Rotation und schließlich wieder Skalierung) selbst eine Transformation ist und mit einem transform()
Aufruf ausgeführt werden kann. Umgekehrt bedeutet dies auch, dass wir eine komplexe Transformation in einfachere Schritte zerlegen können.
2.2.3.1 scale (x, y)
CanvasRenderingContext2D.scale (x, y)
Setzt den Breitenskalierungsfaktor auf
x
und den Höhenfaktor aufy
, sodass alle Größen der nachfolgend gezeichneten Objekte mit diesen Konstanten multipliziert werden.x
undy
sind (Gleitkomma-) Zahlen.
Bei einer Leinwand mit 200 x 200 Pixeln, die mit einem roten Rand und einem blauen Koordinatensystem (hier über dem roten Rand) dargestellt ist:
Wenn wir jetzt sagen scale(0.8,1.5)
, sagen wir , die horizontale x-Achse schrumpft um den Faktor 0.8
und die vertikale y-Achse erstreckt sich um den Faktor 1.5
. Das gleiche blaue Koordinatensystem auf dem roten Rand ist:
Das bedeutet, dass alle nach dem Aufruf von gezeichneten Bildelemente entsprechend scale(0.8,1.5)
kleiner und höher sind. Beachten Sie jedoch, dass sich die Größe der Zeichenfläche nicht geändert hat. Das Bild im Browser ist immer noch alles, was innerhalb des roten Randes liegt.
Nehmen wir noch einmal dieselbe Leinwand mit 200 x 200 Pixel (der rote Rand wird mit dem zusätzlichen Attribut style="border: solid 3pt red"
im <canvas>
Tag generiert ). Wir fügen der Leinwand einen grünen Kreis hinzu context
, was mit diesem Code gemacht wird
context.strokeStyle = 'green'; // set the color for the circle to 'green'
context.lineWidth = 5.0; // set the lineWidth for the circle to 5.0
context.beginPath(); // start a new path
context.arc (100,100,80,0,2*Math.PI); // a circle with center point (100,100) and radius 80
context.stroke(); // draw the path; in this case only the circle
Das Browserbild dieser Leinwand ist dies
Aber wenn wir dem vorherigen Code die Zeile voranstellen
context.scale (0.8, 1.5); // shrink the x-coordinates by 0.8, extend the y-coordinates by 1.5
dann wird das Bild dies sein
Die Breite wird um verringert 0.8
, die Höhe des Kreises um den Faktor erhöht 1.5
. Die Leinwand hat sich nicht in der Größe geändert, sie ist immer noch rechteckig mit 200 x 200 Pixel. Infolgedessen wird der Kreisteil, der den Leinwandrand überschreitet, abgeschnitten.
Zum Beispiel dieser Code
context.fillStyle = 'red';
context.strokeStyle = 'black';
context.font = '40px Arial';
// 1. draw a rectangle with text
context.fillRect (50, 50, 150, 40);
context.strokeText ('1. Hello', 55, 85);
// 2. scale and draw the same rectangle with text again
context.scale (0.8, 2);
context.fillRect (50, 50, 150, 40);
context.strokeText ('2. Hello', 55, 85);
// 3. scale once more, and make the same drawings
context.scale (0.8, 2);
context.fillRect (50, 50, 150, 40);
context.strokeText ('3. Hello', 55, 85);
erzeugt dieses Bild
Zuerst zeichnen wir durch Aufrufen ein Rechteck fillRect(50,50,150,40)
und fügen eine Nachricht mit ein strokeText('1. Hello',55,85)
. Dann skalieren wir x
nach 0.8
und y
nach 2
und nennen dasselbe fillRect(50,50,150,40)
noch einmal. Dieses zweite Rechteck wird eingefügt bei (0.8*50,2*50)
= (40,100)
, ist 0.8*150
= 120
Pixel breit und 2*40
= 80
Pixel hoch. Das zweite skalierte Rechteck entspricht also tatsächlich einem Aufruf von fillRect(40,100,120,80)
im ursprünglichen Koordinatensystem. Wenn wir jedoch die zweite Nachricht durch Aufrufen hinzufügen, erhalten strokeText('2. Hello',55,85)
wir auch eine skalierte Nachricht. Und dafür brauchen wir wirklich die scale()
Methode.
Wenn wir
scale(x,y)
mit einem Negativ aufrufenx
, wird das neue Koordinatensystem auf der y-Achse gespiegelt. Und wenny
negativ, wird das neue Koordinatensystem auf der x-Achse gespiegelt.
Angenommen, es gibt eine Leinwand mit 200 x 200 Pixeln (der rote Rahmen), dann scale(-1,1)
lautet das (blaue) Koordinatensystem nach einem Aufruf von :
Wenn wir diese 200x200 Pixel Leinwand nehmen, dann dieses Skript
context.scale (-1, 1);
context.fillStyle = 'green';
context.fillRect (-175, 70, 150, 60);
context.fillStyle = 'yellow';
context.fillRect (-170, 75, 140, 50);
context.fillStyle = 'green';
context.font = "40pt Arial";
context.fillText("Hello", -160, 120);
produziert dieses Bild:
Beachten Sie, dass die x-Koordinaten aller Punkte innerhalb der Leinwand jetzt negativ sind. Zum Beispiel platzieren wir den Text bei (-160,120)
und er läuft von rechts nach links.
Wenn wir dagegen aufrufen scale(1,-1)
, erhalten wir ein Bild, das auf der x-Achse gespiegelt ist:
2.2.3.2 rotate (angle)
CanvasRenderingContext2D.rotate (angle)
bewirkt eine
angle
Drehung aller nachfolgend gezeichneten Objekteangle
als (Gleitkomma-) Zahl.
Denken Sie daran, dass Winkel in diesem Zusammenhang immer im Bogenmaß statt im Grad definiert werden. Wenn Sie eine Gradrotation benötigen
d
, können Sie anrufenrotate (d * Math.PI / 180);
Angenommen, wir haben eine rot dargestellte Leinwand
Wenn wir aufrufen rotate(angle)
, werden alle nachfolgend gezeichneten Objekte angle
gemäß dem neuen blauen Koordinationssystem um das Gegebene gedreht . Beachten Sie jedoch, dass die gerenderte Leinwand im Browser immer noch die rote und nicht die gedrehte blaue Leinwand ist. Nur die Punkte, die innerhalb dieser blauen Leinwand liegen, sind sichtbar.
Betrachten wir genauer die Leinwandgröße mit Standardgröße (300 x 150 Pixel), die 15
durch Aufrufen um Grad gedreht wird rotate(15*Math.PI/180)
.
Dies ist ein Bild dieser Leinwand vor der Drehung mit einem gelben Gitter und den Kreuzungspunkten wie (50,50)
ausgeschrieben
Nach der 15
Gradumdrehung sieht das gleiche Gitter so aus
Zum Beispiel ist der Punkt (250,100)
verschwunden, weil er jetzt außerhalb der Leinwand liegt, während er (250,-50)
jetzt existiert.
Dieses Code-Snippet wendet zwei aufeinanderfolgende Umdrehungen an
context.fillStyle = 'red';
context.strokeStyle = 'black';
context.font = '40px Arial';
// 1. draw a rectangle with text
context.fillRect (100, 5, 150, 40);
context.strokeText ('1. Hello', 105, 40);
// 2. declare a rotation and draw the same rectangle with text again
context.rotate (30 * Math.PI / 180); // first rotation of 30 degree
context.fillRect (100, 5, 150, 40);
context.strokeText ('2. Hello', 105, 40);
// 3. declare the same rotation, once more, and make the same drawings
context.rotate (30 * Math.PI / 180); // second rotation of 30 degree
context.fillRect (100, 5, 150, 40);
context.strokeText ('3. Hello', 105, 40);
Das erzeugte Bild ist dies
Zuerst zeichnen wir das obere horizontale Rechteck mit einer "Hello"
Innenseite. Wir rotate
zeichnen dann um 30 Grad und zeichnen wieder das gleiche Rechteck und den gleichen Text. Beachten Sie, dass die Koordinaten gleich sind, d fillRect(100,5,100,40)
. H. Das zweite Rechteck wird unter dem ersten gedreht angezeigt. Wir machen dann eine zweite Drehung um 30 Grad, gefolgt von einer dritten Zeichnung des Rechtecks ??und des Textes. Dadurch wird das dritte Rechteck erzeugt, das nur zur Hälfte angezeigt wird, da sich die andere Hälfte bereits außerhalb der Leinwand befindet.
2.2.3.3 translate (x, y)
CanvasRenderingContext2D.translate (x, y)
Verschiebt den Ursprung der Leinwandpixel
x
nach rechts und diey
Pixel nach unten. Jedes neue Element nach dem Aufruf vontranslate(x,y)
wird gemäß diesen neuen Koordinaten hinzugefügt.
Angenommen, wir haben eine Leinwand mit einem 250x150
Pixel, die durch den roten Rahmen und das blaue Koordinatensystem darüber angezeigt wird
Nach einem Aufruf von translate (100,-50)
ist dies das neue Koordinatensystem
Im ursprünglichen Zustand und vor der Übersetzung hat die linke obere Ecke die Koordinaten (x,y)
=(0,0)
Nach der Übersetzung befindet sich die linke obere Ecke der Leinwand ad (-100,50)
Alles, was wir sagen (200,100)
, erscheint also vor, aber nicht mehr nach der Übersetzung.
Dieser Code-Ausschnitt
context.fillStyle = 'red';
context.strokeStyle = 'black';
context.font = '40px Arial';
// 1. draw the first red rectangle with text
context.fillRect (0,5,150,40);
context.strokeText ('1. Hello', 5, 40);
// 2. declare a translation and draw the same rectangle, again
context.translate(125,50); // first call of translate(125,50)
context.fillRect (0,5,150,40);
context.strokeText ('2. Hello', 5, 40);
// 3. declare the same translation, once more, and make the same drawings
context.translate(125,50); // second call of translate(125,50)
context.fillRect (0,5,150,40);
context.strokeText ('3.Hello', 5, 40);
erzeugt dieses Bild
Zuerst wird durch Aufrufen ein Rechteck gezeichnet fillRect(0,5,150,40)
und Text mit hinzugefügt strokeText('1. Hello',5,40)
. Dann translate(125,50)
wird aufgerufen und das gleiche Rechteck erneut mit gezeichnet fillRect(0,5,150,40)
. Da sich der Ursprung verschoben hat, wird dieses zweite Rechteck ebenfalls um 125 Pixel nach rechts und um 50 Pixel nach unten verschoben. Schließlich translate(125,50)
wird noch einmal aufgerufen, wodurch sich der Ursprung wieder bewegt. Und wenn das Rechteck auch wieder mit gezeichnet wird fillRect(0,5,150,40)
, erscheint rechts und unter den beiden vorherigen ein drittes Rechteck. Beachten Sie, dass der gesamte Inhalt außerhalb der Leinwand abgeschnitten ist und das dritte Rechteck nicht vollständig angezeigt wird.
2.2.3.4 transform (a, b, c, d, e, f)
CanvasRenderingContext2D.transform (a, b, c, d, e, f)
ist die allgemeine Methode zur Durchführung einer affinen Transformation. Jeder Punkt(x,y)
wird in den neuen Punkt umgewandelt(x',y')
, wo
x' = a*x + c*y + e
y' = b*x + d*y + f
Die Auswirkung der einzelnen Parameter auf das Ergebnis ist wie folgt:
Parameter | Bewirken |
---|---|
a |
skaliert horizontal (und spiegelt auf der y-Achse für negativ a ) |
b |
horizontal schief |
c |
Schrägstellung vertikal |
d |
skaliert vertikal (und Spiegel auf der x-Achse für negativ a ) |
e |
bewegt sich horizontal |
f |
vertikal bewegen |
Betrachten Sie eine Leinwand mit Standardgröße (dh 300 x 150 Pixel), die durch einen roten Rahmen mit einem blauen Koordinatengitter oben angegeben wird:
Nach einer Transformation von sagen
transform (0.5, 0.4, -0.2, 1.2, 200, 0)
Das neue Koordinatensystem ist dies
Und wenn wir diese Zeichenfläche context
vor und nach derselben Transformation füllen, indem wir diesen Code ausführen
// prepare the settings for color and font styles
context.fillStyle = 'red';
context.strokeStyle = 'black';
context.font = '40px Arial';
// 1. draw the first red rectangle with text
context.fillRect (0, 5, 150, 40);
context.strokeText ('1. Hello', 5, 40);
// 2. declare the translation and draw the same rectangle, again
context.transform (0.5, 0.4, -0.2, 1.2, 200, 0);
context.fillRect (0, 5, 150, 40);
context.strokeText ('2. Hello', 5, 40);
dann ist dies das resultierende Bild:
scale()
, rotate()
Und translate()
in Bezug auftransform()
transform()
zusammen mit dem ähnlichen setTransform()
ist die allgemeine Methode, um (affine) Transformationen durchzuführen. scale()
, rotate()
Und translate()
sind nur spezielle Versionen transform()
mit weniger Parametern. Die folgende Tabelle zeigt die genauen Implementierungen:
besondere Transformation |
gleiche Transformation in Bezug auf transform()
|
---|---|
scale(x,y)
|
transform (x, 0, 0, y, 0, 0)
|
rotate(angle)
|
transform (c, s, -s, c, 0, 0) wo c = Math.cos(angle) unds = Math.sin(angle)
|
translate(x,y)
|
transform (1, 0, 0, 1, x, y)
|
Also anstatt anzurufen sagen
context.scale (0.8, 1.5);
Den gleichen Effekt erzielen wir mit einem Aufruf von
context.transform (0.8, 0, 0, 1.5, 0, 0);
Bestimmte spezielle Rotationen sind diese:
Drehung |
bezüglich rotate()
|
gleiche Transformation in Bezug auf transform()
|
---|---|---|
90 Grad
|
rotate(Math.PI/2)
|
translate(0,1,-1,0,0,0)
|
180 Grad
|
rotate(Math.PI)
|
translate(-1,0,0,-1,0,0)
|
270 Grad
|
rotate(1.5*Math.PI)
|
translate(0,-1,1,0,0,0)
|
shear()
Transformation
Eine weitere spezielle Transformation, die in der CanvasRenderingContext2D
API nicht vordefiniert ist, ist
shear(x,y)
Das ist einfach eine Abkürzung 17 für
transform (1, y, x, 1, 0, 0)
Zum Beispiel,
shear(0.5,0)
ist diese Transformation:
shear(0,0.2)
ist
shear(0.5,0.2)
ist
2.2.3.5 setTransform (a, b, c, d, e, f)
CanvasRenderingContext2D.setTransform (a, b, c, d, e, f)
funktioniert wietransform()
, aber anstatt die aktuelle Transformation zu transformieren , wird sie bei der anfänglichen Identitätstransformation durchgeführt .
Anfänglich hat jeder Canvas-Kontext das anfängliche Koordinatensystem , wie in der Einführung beschrieben . Nach jeder Transformation wird dieses Koordinatensystem in ein neues aktuelles System geändert . Bei jedem tranform()
Aufruf wird dieses aktuelle System erneut transformiert. Ein Aufruf von setTransform()
transformiert jedoch nicht das aktuelle System, sondern beginnt mit dem ersten.
Im Standardjargon sprechen wir eher wieder von "Transformation" als von "Koordinatensystem", daher gibt es eine anfängliche Transformation (nämlich die Transformation der definierten Identität ) und eine aktuelle Transformation .
Beginnen wir noch einmal mit einem breiteren Blick darauf, wie alles miteinander verbunden und umgesetzt ist. Es könnte hilfreich oder hinderlich sein, die zugrunde liegende Mathematik zu erklären, daher haben wir dies als optionale Information in einen kleinen Exkurs und seine Fußnoten isoliert.
Exkurs: Die Algebra der (affinen) TransformationenEine Transformation
?
wird eindeutig bestimmt und repräsentiert 18 durch sechs numerische Parameter(a,b,c,d,e,f)
und definiert eine Funktion, dass die Punkte gegeben Karten(x,y)
an neue Punkte(x',y') = ?(x,y)
durch und wo das Mapping definiert istx' = a*x + c*y + e
undy' = b*x + d*y + f
.Wenn und zwei Transformationen sind, wird ihre Zusammensetzung als die Funktion definiert, die jeden Punkt dem neuen Punkt zuordnet . Es stellt sich heraus, dass die Kompositionsfunktion wieder eine genau definierte Transformation ist. Transformationen werden unter Komposition geschlossen.
?1
?2
?1??2
(x,y)
?2(?1(x,y))
?1??2
Genauer gesagt bedeutet dies, dass es auch bei Parametertupeln eine genau definierte Zusammensetzung gibt
?
. 19
If ist eine Darstellung für die Transformation und für und if(a1,b1,c1,d1,e1,f1)
?1
(a2,b2,c2,d2,e2,f2)
?2
(a1,b1,c1,d1,e1,f1) ? (a2,b2,c2,d2,e2,f2)
=(a3,b3,c3,d3,e3,f3)
dann ist die (einzigartige und genau definierte) Darstellung von .
(a3,b3,c3,d3,e3,f3)
?1??2
Die Identitätstransformation ist die Transformation
id
, die jeden Punkt(x,y)
auf sich selbst abbildetid(x,y)=(x,y)
. Dies impliziert sofort, dassid ? ?
=? ? id
=?
für jede Transformation?
.Es ist leicht zu überprüfen, ob die Parameterdarstellung von
id
gegeben ist durch(1,0,0,1,0,0)
.
Zu jedem Zeitpunkt, unmittelbar nach seiner Erstellung, verfügt der Canvas-Kontext über eine Eigenschaft, die als aktuelle Transformation bezeichnet wird . Hier kann es hilfreich sein, "aktuelles Koordinatensystem" anstelle von "aktuelle Transformation" zu lesen. Und das macht wirklich Sinn: Wenn die Zeichenfläche im Browser gerendert wird, werden die Bildkomponenten gemäß der angegebenen aktuellen Transformation oder dem angegebenen _Koordinatensystem im Zeichenbereich platziert.
Im [WHATWG] -Standard hatte jeder CanvasRenderingContext2d
diese aktuelle Transformation noch explizit als currentTransform
Eigenschaft verfügbar . 20 Im endgültigen Standard von [W3C] ist diese Eigenschaft jedoch verschwunden und nicht mehr zugänglich.
Das anfängliche Koordinatensystem, das zum Zeitpunkt der Kontexterstellung, ist dasjenige mit dem Ursprung (0,0)
am linken oberen Eckpunkt und der orthogonalen x- und y-Achse, wie in der Einleitung beschrieben . Die anfängliche Transformation ist tatsächlich die Identitätstransformation id
.
Jedes Mal, wenn eine neue Transformation ?'
wird durch einen im Skript ausgegeben transform()
Anruf (oder eine ihrer speziellen Versionen scale()
, rotate()
oder translate()
), die aktuelle Transformation ?
wird durch die neue aktuelle Transformation ersetzt ???'
. Und dieser Schritt wird nach jeder neuen Transformation wiederholt.
Und bei einem Aufruf von setTransform()
wird die aktuelle Transformation nicht auf ???'
, sondern auf die neue Transformation ?'
selbst gesetzt (wie sie durch die sechs Parameter des setTransform(a,b,c,d,e,f)
Aufrufs definiert ist).
Der [WHATWG] -Standard kannte auch eine resetTransform()
Methode, mit der die aktuelle Transformation explizit auf die Identität gesetzt wurde id
. Dies wurde jedoch wieder aus der endgültigen [W3C] -Version entfernt. Der gleiche Effekt eines resetTransform()
Anrufs kann natürlich auch mit einem setTransform(1,0,0,1,0,0)
Anruf erzielt werden , wodurch auch die aktuelle Transformation auf die Identität zurückgesetzt wird id
.
Angenommen, wir möchten "HALLO!" auf einer Leinwand, aber in einem vertikalen Textfeld, wie so
Ein ähnliches Problem ist folgendes: Wie drehen wir beispielsweise das Koordinatensystem einer Leinwand?
auf die linke Seite
Die Antwort auf das letztere Problem lautet: Drehen Sie zunächst 270
durch Aufrufen nach Gradrotate(1.5*Math.PI)
und zweitens, das Gitter nach unten bewegen , der x-Koordinatenachse , so daß (0,0)
an der linken unteren Ecke befindet, durch Aufrufen translate(-h,0)
, mit h
der Höhe der Leinwand ist, hier 150
.
Zurück zum ursprünglichen Problem des vertikalen Textes haben wir also eine 300x255
Pixel-Leinwand und rufen dann auf
context.rotate (1.5*Math.PI); // rotation of 270 degree
context.translate (-255,0); // move the coordinate system down along the x-axis by 255 pixel
was uns gibt
Wir zeichnen dann das Textfeld durch Aufrufen
context.fillStyle = 'red';
context.fillRect (0, 0, 255, 120);
context.fillStyle = 'yellow';
context.fillRect (5, 5, 245, 110);
context.fillStyle = 'red';
context.font = "50pt Arial";
context.lineWidth = 5.0;
context.fillText ("HELLO!", 10, 85);
so dass das vollständige Ergebnis wie erwartet ist:
Wir haben gerade eine Rotation und eine Übersetzung durchgeführt, können aber auch die beiden Transformationsschritte zu einem einzigen zusammenführen.
Erinnere dich daran
rotate(1.5*Math.PI)
ist das gleiche wietransform(c,s,-s,c,0,0)
mitc
=Math.cos(1.5*Math.PI)
=0
unds
=Math.sin(1.5*Math.PI)
=-1
. Mit anderen Worten wird eine Rotation nach270
Grad mit einemtransform(0,-1,1,0,0,0)
Anruf durchgeführt.translate(h,0)
ist das gleiche wietransform(1,0,0,1,h,0)
(0,-1,1,0,0,0) ? (1,0,0,1,h,0) = (0,-1,1,0,h,0)
Alles in allem bedeutet das das
context.rotate(1.5*Math.PI);
context.translate(h,0);
ist das gleiche wie
context.transform(0,-1,1,0,0,0);
context.transform(1,0,0,1,h,0);
und das hat den gleichen Effekt wie die Zusammensetzung
context.transform(0,-1,1,0,h,0);
Fahren wir mit dem vorherigen Beispiel des vertikalen Textfelds fort. Es war noch etwas Platz auf der Leinwand und wir werden dort ein Spiegelbild einfügen. Dies soll das Ergebnis sein:
Das Bild ist ein Spiegelbild, da das Pferd im Originalbild auf die andere Seite schaut:
In der Erklärung von haben scale()
wir bereits erwähnt, dass ein Spiegelbild auf der y-Achse durch einen scale(-1,1)
Aufruf erreicht werden kann. Wir lassen darauf einen translate(-w,0)
Aufruf folgen , wobei die Breite w
= ist 300
, so dass die Gesamttransformation 22 nun durch dieses Koordinatensystem gegeben ist
In diesem transformierten Canvas-Kontext fügen wir das Bild nun (0,0)
mit einer zugewiesenen Breite 180
und Höhe des 255
Pixels ein. Der Code ist dies
context.scale (-1, 1);
context.translate(-300,0);
var image = new Image();
image.src = "horse.jpg";
context.drawImage (image, 0, 0, 180, 255);
und dies ist das resultierende Browserbild
Inzwischen haben wir also den Code für die beiden Teile des endgültigen Bildes
Erstens gibt es links den Text, der von generiert wird
// 1. The vertical text box
// 1.a) Two transformations: first a rotation, then a translation
context.rotate (1.5 * Math.PI);
context.translate (-255,0);
// 1.b) The code for the text box
context.fillStyle = 'red';
context.fillRect (0, 0, 255, 120);
context.fillStyle = 'yellow';
context.fillRect (5, 5, 245, 110);
context.fillStyle = 'red';
context.font = "50pt Arial";
context.lineWidth = 5.0;
context.fillText ("HELLO!", 10, 85);
und dann ist da noch das Bild rechts, generiert von
// 2. The mirror image of the horse
// 2.a) Two transformations: first mirror at the y-axis, then a translation
context.scale (-1, 1);
context.translate (-300,0);
// 2.b) Insert the image
var image = new Image();
image.src = "horse.jpg";
context.drawImage (image, 0, 0, 180, 255);
Wenn wir jedoch beide Codefragmente addieren, erhalten wir dieses unerwartete Ergebnis:
Der Grund ist, dass die beiden Transformationen für das Bild für die beiden Transformationen für das Textfeld ausgeführt werden. Mit anderen Worten, ruft der transform()
, scale()
, rotate()
und translate()
die ändern aktuelle Transformation , die von der Standardanfang verschieden sein kann Identitätstransformation . Was wir vor dem zweiten Teil tun müssen, ist ein Zurücksetzen der aktuellen Transformation in die Identitätstransformation. Wie bereits erwähnt, musste das CanvasRenderingContext2D
Objekt resetTransform()
genau das tun. Im endgültigen Standard gibt es jedoch nur noch die setTransform()
Methode. Denken Sie daran, dass die Identitätstransformation durch die Parameter gegeben (1,0,0,1,0,0)
ist. setTransform(1,0,0,1,0,0)
Wenn Sie also aufrufen, werden die aktuellen Transformationsparameter zurückgesetzt. Der Code für die gesamte Leinwand ist gegeben durch
// 1. The vertical text box
// ...
// Reset the current transformation
context.setTransform (1,0,0,1,0,0);
// 2. The mirror image of the horse
// ...
2.2.4 Compositing
2.2.4.1 globalAlpha
CanvasRenderingContext2D.globalAlpha
bestimmt den aktuellen ?- Wert ( Alpha oder Transparenz ) für die Zeichnungen. Dieser ?-Wert ist eine Gleitkommazahl zwischen
0.0
(für vollständig transparent) und1.1
(für vollständig undurchsichtig). Der Standardwert ist1.0
, was bedeutet, dass alle gezeichneten Elemente überhaupt nicht transparent sind.
Lassen Sie uns den Effekt auf einer Leinwand mit vier Rechtecken demonstrieren, der durch die folgende Codevorlage generiert wird:
<canvas id="GlobalAlphaSample" width=470 height=180 style="border: solid 1pt blue"> </canvas>
<script>
var context = document.getElementById('GlobalAlphaSample').getContext('2d');
// 1. setting alpha
context.globalAlpha = "..."; // THIS IS THE IMPORTANT LINE!!!!!!!!!!!!!!!!!!!!
// 2. set the text style
context.font = '20px Arial'; context.strokeStyle = 'black';
// 3. draw the four rectangles
context.fillStyle = 'red'; context.fillRect( 10,10,150,100); context.strokeText('red', 20, 50);
context.fillStyle = 'green'; context.fillRect(110,30,150,100); context.strokeText('green', 120, 80);
context.fillStyle = 'yellow'; context.fillRect(210,50,150,100); context.strokeText('yellow',220,110);
context.fillStyle = 'blue'; context.fillRect(310,70,150,100); context.strokeText('blue', 320,140);
</script>
wobei wir jedes Mal einen anderen ?-Wert für das "..."
Teil einfügen .
Die Einstellung context.globalAlpha = 1.0
erzeugt Folgendes :
Natürlich ist dieser Wert 1.0
der Standardwert für ?, daher hätten wir die gesamte Codezeile weglassen und trotzdem das gleiche Ergebnis erzielen können.
Die Einstellung context.globalAlpha = 0.5
gibt uns jedoch jetzt Folgendes:
Und schließlich context.globalAlpha = 0.1
:
2.2.4.2 globalCompositeOperation
CanvasRenderingContext2D.globalCompositeOperation
legt fest, wie ein neues (" Quell ") Bild gegen ein vorhandenes (" Ziel ") Bild angezeigt wird. Mögliche Werte sind
source-over
,source-atop
,source-in
,source-out
,destination-over
,destination-atop
,destination-in
,destination-out
,xor
undcopy
. Standard istsource-over
. Unbekannte Werte werden ignoriert.
Angenommen, wir zeichnen zuerst ein orangefarbenes Quadrat und dann einen cyanfarbenen Kreis. In dieser zusammengesetzten Operation bezeichnen wir das bereits vorhandene Quadrat als Ziel , und der neue Kreis wird als Quelle der Komposition bezeichnet.
Wenn der Kreis mit dem Quadrat übereinstimmt, wird er standardmäßig über das Quadrat gelegt, dh als " Quelle über Ziel" oder " Quelle über Ziel" angezeigt "source-over"
. Wir können dieses Verhalten aber auch ändern und globalCompositeOperation
sagen "destination-over"
: In diesem Fall wird der Kreis unter dem Quadrat angezeigt, dh das Zielquadrat befindet sich über dem Quellkreis.
Die vorherige Zeichenfläche wurde mit diesem Code generiert:
<canvas id="GlobalCompositeSample" width=90 height=90 style="border: solid 1pt green"> </canvas>
<script>
var context = document.getElementById('GlobalCompositeSample').getContext('2d');
// 1. add the orange square
context.fillStyle = 'orange';
context.fillRect (0, 0, 60, 60);
// 2. set the globalCompositeOperation
context.globalCompositeOperation = "source-over";
// 3. add the cyan circle
context.fillStyle = 'cyan';
context.arc(54,54,36,0,2*Math.PI,false);
context.fill();
</script>
und wir erzeugen die Beispiele in der folgenden Tabelle im Wesentlichen durch Ersetzen "source-over"
durch den entsprechenden alternativen Wert.
"source-over" (Standard) Zeigt das Quellbild über dem Zielbild an. |
"source-atop" Zeigt die Quelle über dem Zielbild an. Der Teil des Quellbildes außerhalb des Zielbildes wird nicht angezeigt. |
"source-in" Zeigt die Quelle im Zielbild an, dh nur der Teil der Quelle innerhalb des Ziels wird angezeigt und das Ziel ist transparent. |
"source-out" Zeigt nur den Teil des Quellbilds an, der sich außerhalb des Ziels befindet und transparent gemacht wird. |
"destination-over" Zeigt das Ziel über dem Quellbild an. |
"destination-atop" Zeigt das Ziel über dem Quellbild an. Der Teil des Zielbilds, der sich außerhalb der Quelle befindet, wird nicht angezeigt. |
"destination-in" Zeigt nur den Teil des Ziels an, der sich im Quellbild befindet und transparent gemacht wird. |
"destination-out" Zeigt nur den Teil des Ziels an, der sich außerhalb des Quellbilds befindet und transparent gemacht wird. |
"lighter" Zeigt die Quelle zusammen mit dem Zielbild an, der überlappende Bereich wird heller. |
"copy" Ignoriert das Ziel und zeigt nur das Quellbild an. |
"xor" Es werden nur die Bereiche angezeigt, die ausschließlich entweder zum Ziel oder zur Quelle gehören. Überlappende Teile werden ignoriert. |
Im Gegensatz zum lighter
Wert werden auch einige frühere Browser unterstützt darker
. Dieser Wert ist jedoch nicht Teil der offiziellen Canvas-Spezifikation.
2.2.5 Farben und Stile
strokeStyle
und fillStyle
sind Kontexteigenschaften, die den Stilwert für den anschließend gezeichneten Strich bzw. die gefüllten Objekte enthalten.
Es gibt drei Arten möglicher Stilwerte: CSS-Farben , ( lineare oder radiale ) Verläufe und Muster .
Eine CSS-Farbe (siehe CSS-Farben unten) ist z. B. einer der Farbnamen (z. B. 'Grün' oder 'Aqua') oder eine hexadezimale Farbe (z
'#00FF00'
. B. ). Wenn die folgenden gefüllten Objekte grün sein sollen, setzen wir die Zeichenflächeneigenschaft mit saycontext.fillStyle = '#008000';
oder alternativ und mit demselben Effekt einen Farbnamen anstelle des hexadezimalen Farbwerts verwenden
context.fillStyle = 'green';
Ein Farbverlauf kann erstellt werden, um Farben zu definieren, die nicht konstant sind, sich jedoch im Bereich allmählich ändern. Wenn wir den Stil auf diese Weise festlegen möchten, müssen wir zuerst ein Objekt erstellen, das die undurchsichtige
CanvasGradient
Schnittstelle implementiert , mit der wir dieaddColorStop()
Methode aufrufen können . In unserem Skript müssen wir daher tunvar myNewGradient = context.createLinearGradient (...); // 1. create a linear gradient myNewGradient.addColorStop (...); // 2. set a color in the gradient vector field myNewGradient.addColorStop (...); // add yet another color; as many as you like context.fillStyle = myNewGradient; // 3. finally, let the gradient be new style from now on
Die gleiche Methode gilt für radiale anstelle von linearen Verläufen und für Striche anstelle von Füllstilen. Die Details sollten in den nachfolgenden Erläuterungen zu linearen und radialen Verläufen deutlich werden.
Ein Muster nimmt ein bestimmtes Bild auf und wiederholt es auf der gesamten Leinwand. Gezeichnete Objekte zeigen dann dieses Muster anstelle einer monochromen Farbe. Die entsprechende Methode, um dies zu erreichen, ist
createPattern (image, repetition)
2.2.5.1 strokeStyle
CanvasRenderingContext2D.strokeStyle
Enthält den Stilwert für Strichobjekte, bei dem es sich entweder um eine CSS-Farbe, einen Verlauf oder ein Muster handelt (wie in der Einführung erläutert ). Der Standardstilwert ist
'black'
.
Im folgenden Beispiel setzen wir zuerst den strokeStyle
Wert für die grüne Farbe.
<canvas id="StrokeStyleSample1" width=320 height=120> </canvas>
<script>
var context = document.getElementById('StrokeStyleSample1').getContext('2d');
// 1. set strokeStyle to a hexadecimal color value, namely '#008000' (same as 'green')
context.strokeStyle = '#008000';
// 2. draw a kind of half cirlce on the left
context.beginPath();
context.moveTo (60, 10);
context.lineTo (60, 110);
context.bezierCurveTo (0, 110, 0, 10, 60, 10);
context.stroke();
context.closePath();
// 3. draw a rectangle on the right top
context.strokeRect (80, 10, 230, 30);
// 4. set the text font and write 'Hello!' on the right bottom of the canvas
context.font = '60pt sans-serif';
context.strokeText ('Hello!', 80, 110);
</script>
Nachdem der strokeStyle
Wert eingestellt ist, werden alle Strichobjekten (gezeichnet mit stroke()
, strokeRect()
und strokeText()
) sind entsprechend gefärbt. Das vorherige Code-Snippet wird folgendermaßen dargestellt:
2.2.5.2 fillStyle
CanvasRenderingContext2D.fillStyle
Enthält den Stilwert für gefüllte Objekte. Wiederum (wie in der Einleitung erläutert ) sind mögliche Werte CSS-Farben, ein Farbverlauf oder ein Muster. Der Standardwert ist
'black'
.
Wie im vorherigen Beispiel setzen wir den fillStyle
Wert erneut auf einen grünen Farbwert.
<canvas id="FillStyleSample1" width=320 height=120> </canvas>
<script>
var context = document.getElementById('FillStyleSample1').getContext('2d');
// 1. set strokeStyle to a hexadecimal color value, namely '#008000' (same as 'green')
context.fillStyle = '#008000';
// 2. draw a kind of half cirlce on the left
context.beginPath();
context.moveTo (60, 10);
context.lineTo (60, 110);
context.bezierCurveTo (0, 110, 0, 10, 60, 10);
context.fill();
context.closePath();
// 3. draw a rectangle on the right top
context.fillRect (80, 10, 230, 30);
// 4. set the text font and write 'Hello!' on the right bottom of the canvas
context.font = '60pt sans-serif';
context.fillText ('Hello!', 80, 110);
</script>
Die gefüllten Objekte (gezeichnet in Schritt 2-4 mit fill()
, fillRect()
und fillText()
) erscheinen nun grün:
2.2.5.3 createLinearGradient (x0, y0, x1, y1)
undaddColorStop (pos, color)
CanvasRenderingContext2D.createLinearGradient (x0, y0, x1, y1)
Erstellt ein
CanvasGradient
Objekt, das einen linearen Verlauf definiert, der vom Startpunkt(x0,y0)
zum Endpunkt verläuft(x1,y1)
.
CanvasGradient.addColorStop (position, color)
weist dann ein
color
an der gegebenen zuposition
. Diesposition
ist ein Wert zwischen0.0
(Startpunkt des linearen Gradienten) und1.0
(Endpunkt). Dascolor
ist eine Zeichenfolge, die eine CSS-Farbe darstellt .Das
CanvasGradient
(mit hinzugefügten Farben) kann dann als Stilwert fürstrokeStyle
oder definiert werdenfillStyle
.
Ein typisches Beispiel für einen "Farbverlauf" -Farbstil ist ein Regenbogen, der seine Farbe allmählich ändert. Lassen Sie uns also einen linearen Verlauf erstellen, ihn benennen rainbowGradient
, einige Farben hinzufügen, diesen zuweisen fillStyle
und dann einen fillRect()
über die Größe der gesamten Leinwand zeichnen . Das resultierende Bild ist das folgende:
und das ursprüngliche Code-Snippet zum Erzeugen dieses Bildes ist gegeben durch
<canvas id="Rainbow1" width=600 height=100> </canvas>
<script>
var context = document.getElementById('Rainbow1').getContext('2d');
// 1. create the linear gradient
var rainbowGradient = context.createLinearGradient (100, 50, 500, 50);
// 2. add colors to the gradient
rainbowGradient.addColorStop (0, 'red');
rainbowGradient.addColorStop (0.25, 'yellow');
rainbowGradient.addColorStop (0.5, 'green');
rainbowGradient.addColorStop (0.75, 'blue');
rainbowGradient.addColorStop (1, 'violet');
// 3. set the fillStyle to this new gradient
context.fillStyle = rainbowGradient;
// 4. now draw some filled objects; in this case just a rectangle
context.fillRect (0, 0, 600, 100);
</script>
Der gesamte Vorgang ist komplizierter als nur das Zuweisen einer Farbe (z. B. 'green'
) fillStyle
. Stattdessen führen wir die folgenden Schritte aus:
Durch einen Anruf
var rainbowGradient = context.createLinearGradient (100, 50, 500, 50);
Wir erstellen einen linearen Gradienten (benannt
rainbowGradient
) vom Startpunkt (100,50) bis zum Endpunkt (500,50).
Dies wird durch die Linie in der Mitte der Leinwand angezeigt.Im nächsten Schritt fügen wir dem Farbverlauf fünf Farben hinzu, indem wir aufrufen
rainbowGradient.addColorStop (position, color);
fünf Mal.
Jedes Malposition
ist ein Wert zwischen0
und1
der relative Abstand zwischen Start- und Endpunkt. Anstelle von Farbnamen'red'
,'yellow'
usw. wir alle genommen haben könnte CSS - Farb String.Im dritten Schritt weisen wir diesen neu erstellten linearen Verlauf als Wert zu
fillStyle
context.fillStyle = rainbowGradient;
und wenn wir dann gefüllte Objekte zeichnen, werden diese Objekte gemäß der
rainbowGradient
Spezifikation gefärbt .In unserem Beispiel zeichnen wir nur eine
fillRect()
Übergröße der gesamten Leinwand, wodurch die gesamte Verlaufseinstellung sichtbar wird.
Der ganze Prozess funktioniert auch für mehrere Objekte und für strokeStyle
statt fillStyle
. Schauen Sie sich diese Leinwand an, um dies zu demonstrieren
generiert durch diesen Code (Schritte 2.-4. sind identisch mit dem strokeStyle
Beispielcode ):
<canvas id="RainbowStrokeStyleSample1" width=320 height=120> </canvas>
<script>
var context = document.getElementById('RainbowStrokeStyleSample1').getContext('2d');
// 1. set strokeStyle to a linear gradient value
var rainbowGradient = context.createLinearGradient (0, 60, 320, 60);
rainbowGradient.addColorStop (0, 'red');
rainbowGradient.addColorStop (0.25, 'yellow');
rainbowGradient.addColorStop (0.5, 'green');
rainbowGradient.addColorStop (0.75, 'blue');
rainbowGradient.addColorStop (1, 'violet');
context.strokeStyle = rainbowGradient;
// 2. draw a kind of half cirlce on the left
context.beginPath();
context.moveTo (60, 10);
context.lineTo (60, 110);
context.bezierCurveTo (0, 110, 0, 10, 60, 10);
context.stroke();
context.closePath();
// 3. draw a rectangle on the right top
context.strokeRect (80, 10, 230, 30);
// 4. set the text font and write 'Hello!' on the right bottom of the canvas
context.font = '60pt sans-serif';
context.strokeText ('Hello!', 80, 110);
</script>
2.2.5.4 createRadialGradient (x0, y0, r0, x1, y1, r1)
undaddColorStop (pos, color)
CanvasRenderingContext2D.createRadialGradient (x0, y0, r0, x1, y1, r1)
erzeugt ein
CanvasGradient
Objekt , das einen radialen Gradienten läuft von einem Ausgangskreis festlegt(x0,y0,r0)
bis zum Ende Kreis(x1,y1,r1)
. In jedem der beiden Kreise(x,y,r)
, der Mittelpunkt ist ,(x,y)
und der Radius istr
, wox
,y
undr
ist (floating point) Zahlen.
CanvasGradient.addColorStop (position, color)
weist dann ein
color
an der gegebenen zuposition
. Diesposition
ist ein Wert zwischen0.0
(Startpunkt des linearen Gradienten) und1.0
(Endpunkt). Dascolor
ist eine Zeichenfolge, die eine CSS-Farbe darstellt .Das neu generierte
CanvasGradient
kann dann als Stilwert fürstrokeStyle
oder definiert werdenfillStyle
.
Der Aufbau des radialen Gradienten ähnelt dem linearen Gradienten, außer dass das Gradientenfeld von einem Startpunkt (x0,y0)
zu einem Endpunkt nicht linear ist (x1,y1)
. Stattdessen ist sein Ursprung ein Kreis (x0,y0,r0)
, der sich in Richtung eines Endkreises bewegt (x1,y1,r1)
.
Mit einem radialen Farbverlauf können wir 3D-Effekte erzeugen, z. B. eine monochrome rote Scheibe in eine Kugel verwandeln, die von einer Lichtquelle beleuchtet wird:
Dieses Bild wird mit dem folgenden Code erstellt
<canvas id="RadialSample" width=240 height=240> </canvas>
<script>
var context = document.getElementById('RadialSample').getContext('2d');
// 1. create a radial gradient
var rg = context.createRadialGradient (80, 80, 20, 120, 120, 110);
// 2. add colors
rg.addColorStop (0, 'yellow');
rg.addColorStop (1, 'red');
// 3. set the fill style to the new gradient
context.fillStyle = rg;
// 4. now draw some filled objects; in this case just a circle
context.beginPath();
context.arc (120,120,110,0,2*Math.PI,false);
context.fill();
context.closePath();
</script>
Die Schritte sind wie folgt:
Wir beginnen mit der Erzeugung eines radialen Gradienten, den wir nennen
rg
var rg = context.createRadialGradient (80, 80, 20, 120, 120, 110);
Die Argumente dieses Aufrufs sind die Parameter für zwei Partikel: Der Startkreis
(x0,y0,r0)
=(80,80,20)
mit Mittelpunkt(80,80)
und Radius20
und der Endkreis(x1,y1,r1)
=(120,120,110)
.Der Prozess vom allmählichen Wechsel vom Startkreis zum Endkreis kann wieder zu einem kontinuierlichen Prozess von Position
0.0
zu Position nummeriert werden1.0
.
Zum Beispiel sind die fünf Positionen0.0
,0.25
,0.5
,0.75
und1.0
sindWir fügen dem Radienten nun Farbstopps hinzu. In unserem Fall nur
'yellow'
an der Startposition0.0
und'red'
an der Endposition1.0
rg.addColorStop (0, 'yellow'); rg.addColorStop (1, 'red');
Der Verlauf
rg
wird nun als Stilwert zugewiesenfillStyle
context.fillStyle = rg;
so dass alle nachfolgend gezeichneten gefüllten Objekte diese "Farbe" annehmen
rg
.Wir zeichnen schließlich gefüllte Objekte, in diesem Beispiel nur einen gefüllten Kreis, der genau den Endkreis des radialen Gradienten abdeckt
context.beginPath(); context.arc (120,120,110,0,2*Math.PI,false); context.fill(); context.closePath();
Wenn wir anstelle des Kreises ein gefülltes Rechteck über die Größe der gesamten Leinwand gezeichnet hätten, dh wenn diese eine Linie
context.fillRect (0, 0, 240, 240);
würde den Code im vorherigen Schritt 4 ersetzen, dann ist das Bild dies
Wenn wir dann die Farben 'yellow'
nach 'white'
und 'red'
nach ersetzen 'black'
, erhalten wir
Und schließlich, wenn wir nicht nur zwei Farbstopps hinzufügen, sondern stattdessen diese fünf
rg.addColorStop (0, 'red');
rg.addColorStop (0.25, 'yellow');
rg.addColorStop (0.5, 'green');
rg.addColorStop (0.75, 'blue');
rg.addColorStop (1, 'violet');
das Bild wird
Es ist wahrscheinlich wichtig, viele Beispiele zu üben, um mit den Verläufen umzugehen. Das folgende Beispiel zeigt Variationen des Start- und Endkreises des radialen Gradienten. Jedes Mal verwenden wir diese Codevorlage:
<canvas id="RadialGradient1" width=200 height=200> </canvas>
<script>
var context = document.getElementById('RadialGradient1').getContext('2d');
context.addGrid();
var rainbowGradient = context.createRadialGradient (x0, y0, r0, x1, y1, r1);
rainbowGradient.addColorStop (0, 'orange');
rainbowGradient.addColorStop (1, 'cyan');
context.fillStyle = rainbowGradient;
context.fillRect (0, 0, 200, 200);
</script>
und in jedem konkreten Beispiel werden die sechs Parameter in context.createRadialGradient (x0, y0, r0, x1, y1, r1)
variiert. Das erste Bild in jeder Spalte zeigt, wie die Leinwand gerendert wird. Das zweite Bild zeigt die Position des orangefarbenen Start- und des Cyan-Endkreises.
(x0,y0,r0,x1,y1,r1)=(100,100,10,100,100,75)
|
(x0,y0,r0,x1,y1,r1)=(80,80,10,120,120,75)
|
(x0,y0,r0,x1,y1,r1)=(50,50,50,150,150,50)
|
(x0,y0,r0,x1,y1,r1)=(30,30,10,150,150,50)
|
2.2.5.5 createPattern (image, repetition)
CanvasRenderingContext2D.createPattern (image, repetition)
Gibt ein
CanvasPattern
Objekt zurück, das als Wert für eine Stileigenschaft verwendet werden kann (siehefillStyle
undstrokeStyle
).
Dasimage
Argument muss aHTMLImageElement
, aHTMLVideoElement
oder ein anderes seinHTMLCanvasElement
.
Dasrepetition
Argument muss einer der folgenden Werte sein:'repeat-x'
(für die horizontale Wiederholung des Bildes),'repeat-y'
(für die vertikale Wiederholung des Bildes),'repeat'
(sowohl für die horizontale als auch für die vertikale Wiederholung) oder'no-repeat'
(für keine der beiden Wiederholungen). Der Standardwert ist'repeat'
.
Tatsächlich ist in Firefox überhaupt 'repeat'
der einzige akzeptierte Wert für repetition
.
Verwenden wir beispielsweise die JPG-Datei mit einer Größe von 49 × 70 Pixel grayhorse.jpg

als Musterbild für ein CanvasPattern
Objekt und verwenden Sie dieses Objekt als Wert für die fillStyle
Eigenschaft. Anschließend zeichnen wir einige gefüllte Objekte: mit fillRect()
, einen fill()
Pfad und einige fillText()
. Das vollständige Code-Snippet
<canvas id="CreatePatternSample1" width=600 height=210> </canvas>
<script>
var context = document.getElementById('CreatePatternSample1').getContext('2d');
// create an Image object from the grayhorse.jpg file
var horseImage = new Image ();
horseImage.src = 'grayhorse.jpg';
// create a CanvasPattern object with this image and make that the new fillStyle value
var horsePattern = context.createPattern (horseImage, 'repeat');
context.fillStyle = horsePattern;
// Now draw same objects: first a rectangle
context.fillRect (0, 0, 200, 210);
// then a triangle
context.beginPath();
context.moveTo (220, 0);
context.lineTo (220, 100);
context.lineTo (550, 50);
context.lineTo (220, 0);
context.fill();
context.closePath();
// and finally write "Hello!"
context.font = '120px sans-serif';
context.fillText ('Hello!', 210, 200);
</script>
rendert in deinem Browser so
2.2.6 Linienkappen und Verbindungen
Neben den allgemeinen Stil - Einstellungen gibt es spezielle Stileigenschaften definieren , die Darstellung von Linien, ihre Kappen und schließt sich, nämlich lineWidth
, lineCap
und lineJoin
. Und um die Spitzen von spitzen Winkeln zu begrenzen, gibt es auch miterLimit
.
2.2.6.1 lineWidth
CanvasRenderingContext2D.lineWidth
Enthält eine Gleitkommazahl, die die aktuelle Linienstärke definiert (in Koordinatenraumeinheiten). Der Standardwert ist
1.0
.
Die folgende Zeichenfläche zeigt verschiedene lineWidth
Einstellungen von 0.1
bis 20.0
. In jedem Linienbeispiel setzen wir zuerst context.lineWidth
die entsprechende Zahl und zeichnen dann die Linie.
Beachten Sie, dass alle Linien mit der strokeStyle
Einstellung (Standard) gezeichnet werden 'black'
, viele Linien jedoch grauer als schwarz erscheinen und ihre Kanten nicht sehr scharf sind. Dies ist kein Browser-Fehler, sondern hat damit zu tun, dass die Zeichenfläche in Pixel zerlegt wird. Wenn eine schwarze Linie oder Form ein weißes Pixel nur teilweise bedeckt, ist die tatsächliche Farbe dieses Pixels ein mittlerer Grauwert.
Im folgenden vergrößerten Canvas-Beispiel umfasst eine Linie von (0, 2) bis (10, 2) 20 halbe Pixel. Diese betroffenen Pixel werden daher grau dargestellt. Die Linie von (0, 1,5) bis (10, 1,5) passt dagegen vollständig in die betroffenen zehn Pixel, die Linie wird gestochen scharf und schwarz gerendert.
2.2.6.2 lineCap
CanvasRenderingContext2D.lineCap
definiert den Stil der Zeilenenden. Mögliche Werte sind
'butt'
,'round'
oder'square'
. Der Standardwert ist'butt'
.
Im folgenden Beispiel zeichnen wir dreimal drei Linien von der oberen zur unteren orangefarbenen Linie. Das lineWidth
ist auf 5.0
, 10.0
und 20.0
, respectively. Das lineCap
ist auf 'butt'
, 'round'
und 'square'
, wie in der Abbildung erläutert. Beachten Sie, dass die Linien mit den Zeilen round
und den square
Kappen ihre Endpunkte um die Hälfte der Linienbreite überschreiten.
2.2.6.3 lineJoin
CanvasRenderingContext2D.lineJoin
definiert den Linienstil an ihrem Treffpunkt. Mögliche Werte sind
'round'
,'bevel'
oder'miter'
. Der Standardwert ist'miter'
.
In den folgenden drei Canvas-Beispielen wird jeweils dieselbe lineJoin
Linienfolge gezeichnet , mit der Ausnahme, dass die Eigenschaft jedes Mal auf den entsprechenden Wert gesetzt wird, bevor die Linien gezeichnet werden.
2.2.6.4 miterLimit
CanvasRenderingContext2D.miterLimit
Die Gehrungslänge ist der Abstand zwischen dem Punkt, an dem die Verbindung zweier Linien erfolgt, und dem Schnittpunkt der Linienkanten an der Außenseite der Verbindung. Das mit dem Standardwert festgelegte Gehrungsgrenzverhältnis ist das maximal zulässige Verhältnis der Gehrungslänge zur halben Linienbreite. Wenn die Gehrungslänge dazu führen würde, dass das Gehrungsgrenzverhältnis überschritten wird, wird die Ecke so angezeigt, als wäre sie auf eingestellt .
miterLimit
10.0
lineJoin
bevel
2.2.7 Schatten
Das CanvasRenderingContext2D
kommt mit netten Werkzeugen, um allen Objekten auf der Leinwand ausgefallene Schatten hinzuzufügen, sogar Text. Es gibt vier Eigenschaften, die das Vorhandensein und das Aussehen des Schattens bestimmen: shadowOffsetX
, shadowOffsetY
, shadowBlur
und shadowColor
.
Es ist sinnvoll zu glauben, dass alle zum Kontext hinzugefügten Objekte Schatten haben. Außer diese Schatten in der Default - Einstellung sind unsichtbar, weil dann shadowOffsetX
und shadowOffsetY
sind auf 0
, shadowBlur
ist 0 und das shadowColor
ist transparent.
Die folgende Beispielleinwand zeigt drei Spalten mit jeweils unterschiedlichen Schatteneinstellungen. Die erste Spalte #1
zeigt den Standardfall, #2
hat einen scharfen orangefarbenen Schatten und in der Spalte #3
sind die Schatten unscharf und halbtransparent schwarz.
Der Quellcode für die Just Show Canvas lautet wie folgt
<canvas id="ShadowSample0" width=600 height=330 style="border: solid 1pt blue;"> </canvas>
<script>
var context = document.getElementById("ShadowSample0").getContext("2d");
// General settings
context.font = '40pt Arial'; // sets the font
context.lineWidth = '5' // sets the line width for the strokeRect() calls below
context.strokeStyle = 'green' // sets the color for the strokeRect() calls below
context.fillStyle = 'red'; // sets the color for the fillText() and fillRect() calls below
// #1 column with default (= no) shadow
context.fillText ("# 1", 25, 45);
context.fillRect (25, 70, 100, 100);
context.strokeRect (25, 200, 100, 100);
// #2 column
context.shadowOffsetX = 15; // shadow appears 15 pixel to the right
context.shadowOffsetY = 15; // shadow appears 15 pixel to the botttom
context.shadowColor = 'orange'; // shadow color now is 'orange'
context.shadowBlur = 0; // zero blur: this is a crisp shadow
context.fillText ("# 2", 225, 45);
context.fillRect (225, 70, 100, 100);
context.strokeRect (225, 200, 100, 100);
// #3 column
context.shadowOffsetX = 15; // again, lets shadows appear 15 pixel to the right
context.shadowOffsetY = 15; // ... and 15 pixel to the bottom
context.shadowColor = 'rgba(0,0,0,0.5)'; // shadow color is black, but half transparent
context.shadowBlur = 5; // shadow is blurred
context.fillText ("# 3", 425, 45);
context.fillRect (425, 70, 100, 100);
context.strokeRect (425, 200, 100, 100);
</script>
2.2.7.1 shadowOffsetX
CanvasRenderingContext2D.shadowOffsetX
enthält eine Gleitkommazahl, um den Schattenversatz in horizontaler Richtung zu definieren. Standardmäßig ist es auf eingestellt
0
.
Hier ist ein Beispiel mit vier verschiedenen shadowOffsetY
Werten:
In #1
der shadowOffsetX
Standardeinstellung ist 0
: Es gibt keinen Schatten, da er sich direkt hinter den Textzeichen befindet. In #2
der Horizontalen wird der Versatz auf gesetzt, 10
bevor der Text geschrieben wird, sodass er zehn Pixel rechts hinter dem Text angezeigt wird. In #3
und #4
das shadowOffsetX
ist -15
und 75
jeweils. Der Quellcode für all dies ist
<canvas id="ShadowOffsetXSample" width=650 height=60 style="border: solid 1pt blue;"> </canvas>
<script>
var context = document.getElementById("ShadowOffsetXSample").getContext('2d');
// settings for the use of fillText below
context.fillStyle = 'black';
context.font = '40pt Arial';
// set the shadow color to a visible 'orange'
context.shadowColor = 'orange';
// #1 text with horizontal shadow offset 0 (i.e. shadow behind the text and thus invisible)
context.shadowOffsetX = 0;
context.fillText ("#1", 50, 50);
// #2 text with horizontal shadow offset 10 (i.e. 10 pixel to the right)
context.shadowOffsetX = 10;
context.fillText ("#2", 200, 50);
// #3 text with horizontal shadow offset -10 (i.e. 10 pixel to the left)
context.shadowOffsetX = -10;
context.fillText ("#3", 350, 50);
// #4 text with horizontal shadow offset 75 (i.e. 75 pixel to the right)
context.shadowOffsetX = 75;
context.fillText ("#4", 500, 50);
</script>
2.2.7.2 shadowOffsetY
CanvasRenderingContext2D.shadowOffsetY
enthält eine Gleitkommazahl, um den Schattenversatz in vertikaler Richtung zu definieren. Standardmäßig ist es auf eingestellt
0
.
Hier ist ein Beispiel mit vier verschiedenen shadowOffsetY
Werten, auf Standard eingestellt 0
, 10
, -10
und 75
jeweils:
Der Quellcode für das vorherige Beispiel lautet:
<canvas id="ShadowOffsetYSample" width=650 height=130 style="border: solid 1pt blue;"> </canvas>
<script>
var context = document.getElementById("ShadowOffsetYSample").getContext('2d');
// settings for the use of fillText below
context.fillStyle = 'black';
context.font = '40pt Arial';
// set the shadow color to a visible 'orange'
context.shadowColor = 'orange';
// #1 text with vertical shadow offset 0 (i.e. shadow behind the text and thus invisible)
context.shadowOffsetY = 0;
context.fillText ("#1", 50, 50);
// #2 text with vertical shadow offset 10 (i.e. 10 pixel down)
context.shadowOffsetY = 10;
context.fillText ("#2", 200, 50);
// #3 text with vertical shadow offset -10 (i.e. 10 pixel up)
context.shadowOffsetY = -10;
context.fillText ("#3", 350, 50);
// #4 text with vertical shadow offset 75 (i.e. 75 pixel down)
context.shadowOffsetY = 75;
context.fillText ("#4", 500, 50);
</script>
2.2.7.3 shadowBlur
CanvasRenderingContext2D.shadowBlur
Enthält eine Gleitkommazahl, um den aktuellen Grad der Unschärfe zu definieren, der auf Schatten angewendet wird. Standardmäßig ist es auf eingestellt
0
.
Das folgende Beispiel zeigt der Schatten für vier verschiedene Unschärfe Ebene, nämlich den Standard 0
, 2
, 4
und 8
jeweils:
Der Quellcode für das vorherige Beispiel lautet:
<canvas id="ShadowBlurSample1" width=650 height=70 style="border: solid 1pt blue;"> </canvas>
<script>
var context = document.getElementById("ShadowBlurSample1").getContext('2d');
// settings for the use of fillText below
context.fillStyle = 'black';
context.font = '40pt Arial';
// set the shadow color to a visible 'orange' and the x- and y-offset to 15
context.shadowColor = 'orange';
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;
// #1
context.shadowBlur = 0;
context.fillText ("#1", 50, 50);
// #2
context.shadowBlur = 2;
context.fillText ("#2", 200, 50);
// #3
context.shadowBlur = 4;
context.fillText ("#3", 350, 50);
// #4
context.shadowBlur = 8;
context.fillText ("#4", 500, 50);
</script>
Selbst wenn shadowOffsetX
und shadowOffsetY
beide 0
so sind, dass sich der Schatten direkt hinter den gezeichneten Objekten befindet, erzeugt er dennoch einen sichtbaren Effekt, wenn er beispielsweise wie im folgenden Beispiel shadowBlur
einen positiven Wert hat5
Der Quellcode für das vorherige Beispiel:
<canvas id="ShadowBlurSample2" width=750 height=75 style="border: solid 1pt blue;"> </canvas>
<script>
var context = document.getElementById("ShadowBlurSample2").getContext('2d');
// text settings
context.font = '28pt Arial';
context.fillStyle = 'red';
// shadow settings
context.shadowColor = 'blue';
context.shadowBlur = 5;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
// add the text
context.fillText ("shadow: blur 5, color blue, x- and y-offset 0", 20, 50);
</script>
2.2.7.4 shadowColor
CanvasRenderingContext2D.shadowColor
enthält den CSS-Farbwert (siehe CSS-Farben ) für die aktuelle Schattenfarbe. Standardmäßig ist es auf eingestellt
transparent black
.
Es werden vier verschiedene Einstellungen für shadowColor
angezeigt
und der Quellcode für das vorherige Canvas-Beispiel ist dieser
<canvas id="ShadowColorSample" width=650 height=70 style="border: solid 1pt blue;"> </canvas>
<script>
var context = document.getElementById("ShadowColorSample").getContext('2d');
// settings for the use of fillText below
context.fillStyle = 'black';
context.font = '40pt Arial';
// set the shadow color to a visible 'orange' and the x- and y-offset to 15
context.shadowBlur = 3;
context.shadowOffsetX = 15;
context.shadowOffsetY = 15;
// #1
context.shadowColor = 'aqua';
context.fillText ("#1", 50, 50);
// #2
context.shadowColor = 'rgba(0%,0%,0%,0.5)';
context.fillText ("#2", 200, 50);
// #3
context.shadowColor = '#CCCCCC';
context.fillText ("#3", 350, 50);
// #4
context.shadowColor = 'hsl(120,50%,50%)';
context.fillText ("#4", 500, 50);
</script>
2.2.8 Einfache Formen (Rechtecke)
Der 2D-Kontext kennt nur eine Art einfacher Formen, "einfach" in dem Sinne, dass er mit einem einzigen Methodenaufruf gezeichnet werden kann, nämlich Rechtecke . Natürlich können alle Arten von Formen gezeichnet werden: Kreise, Dreiecke, komplexe Polygone , glatte Bézier-Kurven . All dies muss jedoch durch den Bau komplexerer Pfade zusammengesetzt werden .
Es gibt folgende Methoden für Rechtecken: fillRect()
, strokeRect()
und clearRect()
. Es gibt auch die einfache rect()
Methode, die jedoch nur als Teil einer Pfaddefinition dient und daher später im Abschnitt über komplexe Formen erläutert wird .
2.2.8.1 fillRect (x, y, w, h)
CanvasRenderingContext2D.fillRect (x, y, w, h)
malt ein festes oder "gefülltes" Rechteck mit den aktuellen Einstellungen für
fillStyle
. Dieses Rechteck hat seine linke obere Ecke bei(x,y)
, istw
Pixel breit undh
Pixel hoch.x
,y
,w
Undh
sind (floating point) Zahlen.
Hier ist ein Beispiel einer Leinwand mit drei "gefüllten" Rechtecken
Der Quellcode für das vorherige Bild ist dieser
// 1. draw a filled rectangle in default black
context.fillStyle = 'black'; // this line is actually superfluous, because 'black' is default
context.fillRect(50,50,100,100); // draw the first rectangle
// 2. draw a filled rectangle in redd
context.fillStyle = 'red'; // change the fillStyle to the color 'red'
context.fillRect(200,50,100,100); // draw the second rectangle
// 3. draw a fancy rectangle with linear gradient
var lg = context.createLinearGradient(350,50,450,150); // create a linear gradient
lg.addColorStop(0,'yellow'); // start (=0) the gradient with 'yellow'
lg.addColorStop(1,'red'); // finish (=1) the gradient with 'red'
context.fillStyle = lg; // set the fillStyle to this new linear gradient
context.fillRect(350,50,100,100); // draw the third rectangle
In jedem der drei Fälle setzen wir zuerst das fillStyle
und rufen dann fillRect()
auf, um ein entsprechendes Rechteck zu zeichnen. Standardmäßig fillStyle
ist die Farbe eingestellt 'black'
. Im zweiten Beispiel setzen wir es auf 'red'
und im dritten Beispiel ist es keine einfache Farbe, sondern ein linearer Farbverlauf .
2.2.8.2 strokeRect (x, y, w, h)
CanvasRenderingContext2D.strokeRect (x, y, w, h)
ein Rechteck auf die Leinwand zieht, die an ihrer linken oberen Ecke hat
(x,y)
, istw
Pixel breit undh
Pixel hoch. Der tatsächliche Stil der Zeichnung wird durch die Einstellungen instrokeStyle
und die aktuellen Linien- und Schatteneigenschaften bestimmt .
Ähnlich wie im vorherigen Beispielbereich mit gefüllten Rechtecken erstellen wir jetzt einen ähnlichen Bereich, indem wir alle fillStyle
Vorkommen durch a strokeStyle
und alle fillRect()
durch strokeRect()
Aufrufe ersetzen . Darüber hinaus demonstrieren wir die Variation des lineWidth
, da dies auch das Outfit des endgültigen Bildes bestimmt.
wird durch diesen Code generiert:
// 1. draw a rectangle with black strokes
context.lineWidth = 1.0; // this is actually superfluous, because 1.0 is default
context.strokeStyle = 'black'; // this is superfluous, too, because 'black' is default anyway
context.strokeRect(50,50,100,100); // draw the first rectangle
// 2. draw a rectangle with red strokes
context.lineWidth = 7.0; // change the line width to 7.0
context.strokeStyle = 'red'; // change the strokeStyle to the color 'red'
context.strokeRect(200,50,100,100); // draw the second rectangle
// 3. draw a rectangle with strokes in gradient style
context.lineWidth = 12.0; // increase the line width, once more
var lg = context.createLinearGradient(350,50,450,150); // define a linear gradient
lg.addColorStop(0,'yellow'); // start the gradient with the color 'yellow'
lg.addColorStop(1,'red'); // let the gradient end with the color 'red'
context.strokeStyle = lg; // set the strokeStyle to this new gradient
context.strokeRect(350,50,100,100); // draw the third rectangle
2.2.8.3 clearRect (x, y, w, h)
CanvasRenderingContext2D.clearRect (x, y, w, h)
Löscht den Rechteckbereich, der durch die linke obere Ecke
(x,y)
, Breitew
und Höhe definiert isth
.
Stellen Sie sich clearRect()
einen Radiergummi vor, der alle vorherigen Zeichnungen darin löscht.
Die folgende Leinwand wird zuerst mit einer grünen Farbe gefüllt (mittels eines fillRect()
Aufrufs). Dann wird ein gelbes rechteckiges Feld hinzugefügt. Und schließlich clearRect()
löscht ein Anruf wieder einen großen Teil des Bildes (nämlich alles rechts und unten von (100,50)
).
Der Quellcode für die vorherige Zeichenfläche lautet wie folgt:
// 1. fill the whole canvas area with a transparent green color
context.fillStyle = 'rgba(0%,100%,0%,0.3)'; // green color with 0.3 transparency
context.fillRect (0,0,300,200); // filled rectangle over the whole canvas area
// 2. draw a yellow rectangular box
context.lineWidth = 10.0; // set the line width to 10
context.strokeStyle = 'yellow'; // set the strokeStyle to the color 'yellow'
context.strokeRect(25,25,100,100); // draw the yellow box
// 3. cut out a rectangle from the canvas
context.clearRect (100,50,200,150); // delete all content in this rectangle
2.2.9 Komplexe Formen (Pfade)
Mit strokeRect()
und können fillRect()
wir (Striche oder gefüllte) Rechtecke zeichnen. In den meisten Fällen möchten wir aber auch andere und komplexere Formen zeichnen. Dies kann schrittweise durch Erstellen von Pfaden erfolgen . Das Standardverfahren zum Erstellen einer komplexen Form ist daher
Beginnen Sie einen neuen Pfad mit
beginPath()
.Erstellen Sie eine Folge von primitiven Schritten, wobei jeder Schritt vom aktuellen Punkt im Pfad zu einem neuen wechselt. Mögliche primitive Schritte sind: (mit zu einem neuen Punkt zu bewegen
moveTo()
), um eine gerade Linie zu einem neuen Punkt erstellen (mitlineTo()
), einem rechteckigen Kasten (mitrect()
) oder einer irgendwie gekrümmten Linie (mitquadraticCurveTo()
,bezierCurveTo()
,arc()
oderarcTo()
.Schließen Sie optional den Pfad mit
closePath()
, dh ziehen Sie erneut eine Linie vom aktuellen Endpunkt zum Anfangspunkt. Und dann tatsächlich den Weg mit entwederstroke()
oder zeichnenfill()
.
Als nächstes zeigen wir, wie wir die Methoden zum Zeichnen von Rechtecken durch Erstellen von Pfaden reproduzieren können. Anschließend geben wir einen Überblick über diese Bausteine ??für Pfade mit vielen Beispielen.
Leider ist es notwendig, das Pfadkonzept anhand vieler Beispiele zu erläutern, da es selbst im [W3C] -Standard kein gut ausgearbeitetes Konzept ist . Im vorhergehenden [WHATWG] -Standard wurden Path
Objekte explizit definiert und das Konzept war viel umfassender. In [W3C] wurden jedoch viele dieser Konzepte eliminiert. Pfade werden jetzt intern hinter den Szenen behandelt, und wir haben nur noch Möglichkeiten, auf das CanvasRenderingContext2D
Objekt ( beginPath()
usw.) einzuwirken . Dies reduzierte die Größe der API, hilft jedoch nicht wirklich, das Pfadkonzept zu verstehen. Nun, damit müssen wir leben. Und dennoch bleibt die ursprüngliche Ausdruckskraft erhalten: Es ist möglich, über alles zu zeichnen, was wir möglicherweise wollen können.
fillRect()
durch die Pfadmethode
Wir können ein gefülltes Rechteck mit einem einzigen Aufruf von zeichnen fillRect()
. Zum Beispiel dieser Code
context.fillStyle = 'rgba(255,0,0,0.5)'; // fill style is now set to a half transparent red color
context.fillRect (80, 20, 100, 60); // draw the rectangle with left upper corner (80,20), width 100 and height 60
erzeugt dieses Bild
Anstatt anzurufen fillRect()
, hätten wir einen Pfad entlang der Form des Rechteckbereichs und dann danach zeichnen fill()
können. Das folgende Codefragment erzeugt somit genau das gleiche Bild wie das vorherige:
// set the style for the fill() call below
context.fillStyle = 'rgba(255,0,0,0.5)';
// now create the path:
context.beginPath(); // 0. start a new path
context.moveTo (80, 20); // 1. moves the current point to (80,20)
context.lineTo (180, 20); // 2. horizontal line from (80,20) to (180,20)
context.lineTo (180, 80); // 3. vertical line from (180,20) to (180,80)
context.lineTo (80, 80); // 4. horizontal line from (180,80) to (80,80)
context.lineTo (80, 20); // 5. vertical line from (80,80) back to the start at (80,20)
context.fill(); // 6. draw the solid figure with the shape of the path lines
In dieser Version zeichnen wir den Pfad zunächst in fünf Schritten:
Beachten Sie, dass bei jedem moveTo()
Schritt (Schritt 1., angezeigt durch die Cyan-Linie) der aktuelle Punkt des Pfads nur an die neu angegebene Position verschoben wird. Jeder lineTo()
Schritt (Linien in Schwarz) zeichnet tatsächlich eine Linie von der vorherigen Position zum neuen angezeigten Punkt. Nachdem der Pfad umrissen wurde, erstellt ein Aufruf von fill()
ein gefülltes Objekt fillStyle
innerhalb der angegebenen Zeilen. In unserem Fall ergibt sich das gefüllte rote Rechteck.
strokeRect()
durch die Pfadmethode
Natürlich wird mit dieser Pfadmethode ein rotes "Strichrechteck" gezeichnet, wenn wir das fill()
durch die stroke()
Methode ersetzen , nachdem wir festgelegt haben, strokeStyle
wo das fillStyle
vorher war. Insgesamt das Code-Snippet
// set the style for the stroke() call below
context.strokeStyle = 'rgba(255,0,0,0.5)'; // now: strokeStyle instead of fillStyle
// the same path again as before:
context.beginPath();
context.moveTo (80, 20);
context.lineTo (180, 20);
context.lineTo (180, 80);
context.lineTo (80, 80);
context.lineTo (80, 20);
context.stroke(); // now: stroke() insted of fill()
context.closePath();
zeigt dieses Bild
Das ist natürlich das gleiche Bild wie das, das mit der strokeRect()
Methode von erzeugt wurde
context.strokeStyle = 'rgba(255,0,0,0.5)';
context.strokeRect (80, 20, 100, 60);
rect()
Übrigens, als noch eine Variation desselben Bildes: Wir können auch ein Rechteck mit einem Aufruf von erstellen rect()
, so dass
context.strokeRect (x, y, w, h);
ist das gleiche wie
context.beginPath();
context.rect (x, y, w, h);
context.stroke();
Und dementsprechend
context.fillRect (x, y, w, h);
kann zerlegt werden in
context.beginPath();
context.rect (x, y, w, h);
context.fill();
2.2.9.1 beginPath()
CanvasRenderingContext2D.beginPath()
beginnt einen neuen oder setzt den aktuellen Pfad zurück.
Ein neuer Weg wird dann gebaut mitmoveTo()
,lineTo()
,rect()
,quadraticCurveTo()
,bezierCurveTo()
,arc()
undarcTo()
.
Das eigentliche Zeichnen des Pfades erfolgt mitstroke()
oderfill()
.
Ein Aufruf vonclosePath()
schließt zwar den neuen Pfad, jedoch in dem Sinne, dass der aktuelle Punkt mit dem anfänglichen Startpunkt verbunden ist. Der Pfad wird nicht gezeichnet.
Für gängige Anwendungen beginPath()
siehe die folgenden Beispiele in den Abschnitten zur Erläuterung stroke()
und fill()
.
2.2.9.2 closePath()
CanvasRenderingContext2D.closePath()
In einem offenen Pfad "schließt" dieser Methodenaufruf den Pfad in dem Sinne, dass er den aktuellen Punkt mit dem Startpunkt des Pfads verbindet. Beachten Sie, dass
closePath()
der Pfad dadurch nicht in dem Sinne "beendet" wird, in dem er gezeichnet wird. Dazu müssen Sie noch die Methodestroke()
oder aufrufenfill()
.
Zum Beispiel dieses Code - Schnipsel (wo lineWidth
festgelegt ist 5.0
und strokeStyle
auf 'red'
)
context.beginPath();
context.moveTo(150,25); // starting point at the top of the triangle
context.lineTo(250,100); // line to right bottom corner
context.lineTo(50,100); // line to left bottom corner
context.stroke(); // draw the lines
erzeugt dieses "unvollständige Dreieck" Bild
Aber wenn wir jetzt ein closePath()
vor dem stroke()
Anruf einfügen
context.beginPath();
context.moveTo(150,25); // starting point at the top of the triangle
context.lineTo(250,100); // line to right bottom corner
context.lineTo(50,100); // line to left bottom corner
context.closePath(); // closes the shape with a line from the left bottom to the initial top point
context.stroke(); // draw the lines
Die Form ist "geschlossen", das Dreieck ist vollständig: 23
closePath()
das nicht zeichnet
Jeder beginPath()
benötigt entweder eine fill()
oder stroke()
irgendwann später, um tatsächlich eine Figur auf der Leinwand zu erstellen. Nur ein zu setzen, closePath()
schließt diesen Weg zwar, zeichnet ihn aber nicht. Das Weglassen des stroke()
Aufrufs im vorherigen Beispiel hätte zu einer leeren Leinwand (Bild) geführt.
closePath()
Anruf vor einem fill()
Anruf überflüssig ist
Der stroke()
Befehl des vorherigen Beispiels zeichnet die Form des Pfades, wobei fill()
wir die vollständige Form zeichnen. Genauer gesagt, wenn wir ersetzen stroke()
durch fill()
diesen Code und laufen (jetzt mit fillStyle
Set 'red'
)
context.beginPath();
context.moveTo(150,25);
context.lineTo(250,100);
context.lineTo(50,100);
context.closePath(); // (superfluous, actually)
context.fill(); // draw the full triangle shape
Wir erhalten dieses Bild
Da ein Pfad ohnehin geschlossen werden muss, bevor wir die Form "füllen" können, fill()
schließt der Befehl den Pfad standardmäßig. Dies macht den closePath()
Anruf überflüssig. Das Weglassen dieser Codezeile hätte genau das gleiche Bild erzeugt.
2.2.9.3 stroke()
CanvasRenderingContext2D.stroke()
Zeichnet den Umriss der durch den aktuellen Pfad definierten Form. Die Stileinstellungen für die eigentliche Zeichnung sind diejenigen, die in
strokeStyle
den aktuellen Eigenschaften für Linien und Schatten gespeichert sind .
Üblicherweise wird ein Pfad mit einem anfänglichen erstellt beginPath()
, gefolgt von einer Reihe von moveTo()
, lineTo()
, rect()
, quadraticCurveTo()
, bezierCurveTo()
, arc()
und arcTo()
Anrufen. Ein letzter stroke()
Aufruf zeichnet dann die Form.
Die folgende Leinwand enthält zwei Pfade für zwei Formen
Der Quellcode ist dies
// settings for both shapes
context.lineWidth = 10.0; // set the line width for both stroke figures to 10
// the first shape
context.beginPath(); // start a new path
context.strokeStyle = 'lime'; // set the color for subsequently called stroke() calls to 'lime'
context.moveTo (25, 25); // go to point (25,25) and make that the current point in the path
context.lineTo (25, 125); // add a line from (25,25) to (25,125) to the path
context.lineTo (125, 125); // add another line from (25,125) to 125,125) to the path
context.stroke(); // now the path is drawn, according to the lineWith and strokeStyle properties
// the second shape
context.beginPath(); // start another path
context.strokeStyle = 'maroon'; // now set the color for coming stroke drawings to 'maroon'
context.moveTo (175, 25); // go to (175,25)
context.lineTo (175, 125); // add a line from (175,25) to (175,125) to the path
context.lineTo (275, 125); // add a line from (175,125) to (275,125) to the path
context.stroke(); // eventually draw the path in stroke style
Wenn wir eine Zeile hinzufügen
context.closePath();
vor jedem der beiden Vorkommen der
context.stroke();
Zeilen im vorherigen Code sind die Pfade geschlossen und werden jeweils zu einem Dreieck. Das Bild ist dann das
2.2.9.4 fill()
CanvasRenderingContext2D.fill()
Zeichnet den gesamten Bereich der durch den aktuellen Pfad definierten Form. Die Stileinstellungen für die eigentliche Zeichnung sind diejenigen, die in gespeichert sind,
fillStyle
und die aktuellen Eigenschaften für Schatten .
Üblicherweise wird ein Pfad mit einem anfänglichen erstellt beginPath()
, gefolgt von einer Reihe von moveTo()
, lineTo()
, rect()
, quadraticCurveTo()
, bezierCurveTo()
, arc()
und arcTo()
Anrufen. Ein letzter fill()
Aufruf zeichnet dann die Form, die mit der durch definierten Farbe (Farbverlauf oder Muster) gefüllt ist fillStyle
.
Die folgende Leinwand besteht aus zwei "gefüllten" Dreiecken
Der Quellcode für dieses Bild ist dieser
// the first triangle
context.fillStyle = 'lime'; // set the color for shapes subsequently drawn with fill() to 'lime'
context.beginPath(); // start a new path
context.moveTo (25, 25); // go to (25,25), which now becomes the current point in the path
context.lineTo (25, 125); // add a line from (25,25) to (25,125); the latter is the new current point in the path
context.lineTo (125, 125); // add another line from (25,125) to (125,125) to the path
context.fill(); // the path is closed with a line from (125,125) to the initial (25,25) and
// the shape area is now drawn with the fillStyle color 'lime'
// the second triangle
context.beginPath(); // start another path
context.moveTo (175, 25); // go to (175,25)
context.lineTo (175, 125); // add a line from (175,25) to (175,125)
context.lineTo (275, 125); // add a line from (175,125) to (275,125)
context.fillStyle = 'maroon'; // set the fillStyle to the color 'maroon'
context.fill(); // close the path, making it a triangle, and draw the shape area in 'maroon' color
Angenommen, wir erstellen einen Pfad mit ein paar Zeilen
context.beginPath();
context.moveTo (50,25);
context.lineTo (50,125);
context.lineTo (150,25);
context.lineTo (150,125);
context.lineTo (250,25);
context.lineTo (250,125);
Wir können diesen Pfad visualisieren ( stroke()
natürlich durch Aufrufen ) und es sieht so aus 24
Beachten Sie jedoch, dass, wenn wir diese Zeilen zum Code hinzufügen
context.fillStyle = 'red';
context.fill();
wir nicht bekommen dieses Bild (von einem konvexen Polygon)
aber diese ( konkave ) stattdessen
Denken Sie daran, dass Aufruf fill()
bedeutet, dass der Pfad zuerst geschlossen wird, dh der Endpunkt (250,125)
ist (50,25)
wie folgt mit dem Anfangspunkt verbunden :
(Natürlich wurde diese Leinwand durch Aufrufen von closePath()
und erstellt stroke()
.)
Und mit dieser Ansicht des geschlossenen Pfades wird deutlich, was der fill()
Aufruf bewirkt: Er füllt alle geschlossenen Bereiche der erstellten Form aus.
2.2.9.5 lineTo (x, y)
CanvasRenderingContext2D.lineTo (x, y)
Fügt dem Pfad vom aktuellen Punkt zum neuen Punkt eine Linie hinzu
(x,y)
.
Ein typisches Beispiel für die Verwendung von lineTo()
ist die Konstruktion eines Polygons . Zeichnen wir ein Dreieck, das einfachste aller Polygone. Dieser Code
context.strokeStyle = 'navy'; // set the strokeStyle color to 'navy' (for the stroke() call below)
context.lineWidth = 3.0; // set the line width to 3 pixels
context.beginPath(); // start a new path
context.moveTo (150,30); // set (150,20) to be the starting point
context.lineTo (270,120); // line from (150,30) to (270,120)
context.lineTo (30,120); // horizontal line from (270,120) to (30,120)
context.lineTo (150,30); // line back to the starting point (we could have called closePath() instead)
context.stroke(); // actually draw the triangle shape in 'navy' color and 3 pixel wide lines
erzeugt dieses Bild
Beachten Sie, dass beim letzten Aufruf von lineTo()
im Quellcode erneut eine Linie von der linken Ecke zum anfänglichen oberen Punkt des Dreiecks gezogen wird. Wir hätten diese Codezeile durch einen Aufruf von ersetzen können context.closePath()
, da closePath()
dies für uns zum Ausgangspunkt zurückkehrt. 25
lineTo()
zeichnet keine Linien, das Zeichnen erfolgt mit dem stroke()
Aufruf. Wir hätten auch die fill()
Methode zur Erzeugung dieses Bildes aufrufen können
Eigentlich lautet der Quellcode wie folgt:
context.fillStyle = 'navy'; // set the fillStyle color to 'navy' (for the fill() call below)
context.beginPath(); // start a new path
context.moveTo (150,30); // set (150,20) to be the starting point
context.lineTo (270,120); // line from (150,30) to (270,120)
context.lineTo (30,120); // horizontal line from (270,120) to (30,120)
context.fill(); // actually draw the triangle shape in 'navy' color and 3 pixel wide lines
Beachten Sie, dass wir weder einen lineTo()
Anruf für eine Linie von der linken Ecke (30,120)
zur ersten oberen Ecke verwendet haben (150,30)
, noch closePath()
am Ende des Pfads angerufen haben . Dies wäre überflüssig gewesen, da fill()
der Pfad automatisch geschlossen wird.
2.2.9.6 moveTo (x, y)
CanvasRenderingContext2D.moveTo (x, y)
Verschiebt den Pfad zum neuen Punkt
(x,y)
. Anders alslineTo(x,y)
beimmoveTo(x,y)
Aufruf wird keine Linie zum neuen Punkt erstellt.
Dieser Code-Ausschnitt
// set the line style to be drawn with stroke()
context.lineWidth = 9.0;
context.strokeStyle = 'red';
// create the path
context.beginPath();
context.moveTo (50,25); context.lineTo (50,75); // first vertical line
context.moveTo (100,25); context.lineTo (100,75); // second vertical line
context.moveTo (150,25); context.lineTo (150,75); // third vertical line
context.stroke();
erzeugt dieses Bild
Aber wenn wir jeden der drei moveTo()
Aufrufe durch lineTo()
Aufrufe im Code ersetzt hätten, wäre das Bild wie folgt:
2.2.9.7 rect (x, y, w, h)
CanvasRenderingContext2D.rect (x, y, w, h)
Erstellt ein Rechteck mit der linken oberen Ecke bei
(x,y)
, dasw
Pixel breit undh
Pixel hoch ist.
Beachten Sie, dass das Rechteck mit diesem Befehl nicht gezeichnet wird. Daher ist ein nachfolgender stroke()
oder fill()
Anruf erforderlich.
Beachten Sie auch, dass die beiden Schritte des Erstellens und anschließenden Zeichnens des Rechtecks ??in den beiden Methoden strokeRect()
und kombiniert werden fillRect()
.
Angenommen, wir möchten ein kleines Haus zeichnen
Wir könnten einen Pfad aus sechs getrennten Linien konstruieren. Wir können es aber auch bauen, indem wir so ein Quadrat (mit rect()
) und ein Dach (zwei lineTo()
Aufrufe) erstellen
context.beginPath(); // start a new path
context.rect (20,60,60,60); // create the square body of the house
context.moveTo (10,70); // create the roof by 1. move to the left
context.lineTo (50,10); // 2. create the left line
context.lineTo (90,70); // 3. create the right line
context.strokeStyle = "black"; // draw the house by 1. set the strokeStyle to 'black'
context.lineWidth = 5.0; // 2. increase the default lineWidth to 5.0
context.stroke(); // 3. do the actual drawing
fill()
stattstroke()
Natürlich, wenn wir die letzten drei Zeilen des vorherigen Codes durch diese neuen Zeilen ersetzt hätten
var lg = context.createLinearGradient (20,20,100,130); // create a linear gradient named lg
lg.addColorStop (0, 'yellow'); // set the color of lg at the beginning (=top) to 'yellow'
lg.addColorStop (1, 'red'); // set the color of lg at the end (right bottom) to 'red'
context.fillStyle = lg; // set the fillStyle to lg
context.fill(); // draw the house with the fillStyle settings
wir hätten dieses Bild erhalten
Das eigentliche Zeichnen erfolgt mit fill()
statt stroke()
und dementsprechend erfolgt dies nicht in strokeStyle
aber fillStyle
. Und diesmal fillStyle
ist es nicht nur eine gewöhnliche Farbe, sondern ein linearer Farbverlauf (siehe createLinearGradient()
undaddColorStop()
).
rect()
Es ist möglich, die rect()
Methoden zu ersetzen , indem Sie das Rechteck mit ein paar Linien erstellen. Genauer gesagt, diese eine Zeile
context.rect (x, y, w, h);
kann nur als Abkürzung für diese sechs Zeilen angesehen werden
context.beginPath(); // start a new path
context.moveTo (x,y); // move to the top left corner as starting point
context.lineTo (x+w, y); // horizontal line to the top right corner
context.lineTo (x+w, y+h); // vertical line to the right bottom corner
context.lineTo (x, y+h); // horizontal line to the left bottom corner
context.closePath(); // vertical line back to the top left corner
2.2.9.8 quadraticCurveTo (cpx, cpy, x, y)
CanvasRenderingContext2D.quadraticCurveTo (cpx, cpy, x, y)
erzeugt eine gekrümmte Linie vom aktuellen Punkt 0 zum neuen Punkt 1 bei
(x,y)
, bestimmt durch einen Kontrollpunkt cp bei(cpx,cpy)
. Die Kurve zeigt zunächst bei 0 in die Richtung von cp und bewegt sich schließlich von cp zu Punkt 1 .
Der vollständige Titel dessen, was die Methode hier als "quadratische Kurve" bezeichnet, lautet " quadratische Beziér-Kurve ". Und die "Beziér-Kurve" aus der nächsten Methode (siehe bezierCurveTo()
unten) ist eine " kubische Beziér-Kurve " in der richtigen Termininologie. Der Wikipedia-Artikel über Bézier-Kurven enthält sehr schöne und intuitive Animationen zum Erstellen von Bézier-Kurven .
Dieser Code-Ausschnitt
context.lineWidth = 5.0;
context.strokeStyle = 'red';
context.beginPath();
context.moveTo (30,120);
context.quadraticCurveTo (210, 30, 210, 120);
context.stroke();
erzeugt dieses Bild
Mit moveTo(30,120)
dem aktuellen Punkt befindet sich 0 bei (30,120)
. Durch den Aufruf quadraticCurveTo(210,30,210,120)
, der Kontrollpunkt cp ist (210,30)
und der neue Punkt 1 ist (210,120)
.
Die rote Kurve beginnt bei 0 und bewegt sich in Richtung cp (geometrisch gesehen: Die Linie von 0 nach cp ist eine Tangente an die Kurve am Punkt 0 ) und biegt sich dann in Richtung 1 (wieder: Die Linie von cp nach 1 ist eine Tangente an die Kurve bei Punkt 1 ).
Angenommen, wir versuchen, eine Ellipse zu zeichnen, die schließlich so aussehen sollte 26
Offensichtlich sind die zwei horizontalen und zwei vertikalen Linien im nächsten Bild Tangenten der Ellipse
und wir können die Ellipse im Wesentlichen als eine Folge von vier quadraticCurveTo()
Aufrufen zusammensetzen.
Wir beginnen am obersten Punkt 0 und rufen quadraticCurveTo()
zum ersten Mal über den Kontrollpunkt cp1 bis Punkt 1 an :
Der entsprechende Code ist dies
context.moveTo (150,25); // move to point 0 at (150,25)
context.quadraticCurveTo (275,25,275,75); // curve from point 0 to point 1 at (275,75)
Wir wiederholen diesen Schritt noch dreimal.
Das heißt, wir fügen drei weitere quadraticCurveTo()
Aufrufe hinzu und wickeln die Teile zwischen a beginPath()
und stroke()
call ein, sodass der vollständige Code für die ursprüngliche Form dies ist
context.lineWidth = 5.0; // set the line width for the stroke() call below
context.strokeStyle = 'red'; // set the color to 'red' for the stroke() call below
context.beginPath(); // start the new path
context.moveTo (150,25); // move to point 0 at (150,25)
context.quadraticCurveTo (275,25,275,75); // curve from point 0 to point 1 at (275,75)
context.quadraticCurveTo (275,125,150,125); // curve from point 1 to point 2 at (150,125)
context.quadraticCurveTo (25,125,25,75); // curve from point 2 to point 3 at (25,75)
context.quadraticCurveTo (25,25,150,25); // curve from point 3 back to point 0
context.stroke(); // draw the shape defined by the current path
quadraticCurveTo()
als Sonderfall vonbezierCurveTo()
Theoretisch ist die quadraticCurveTo()
Methode nur ein Sonderfall von bezierCurveTo()
, der zwei statt eines Kontrollpunktes hat. Man muss nur den gleichen Kontrollpunkt noch einmal wiederholen, dh wir könnten einfach jeden ersetzen
quadraticCurveTo (cpx, cpy, x, y)
Rufen Sie an
bezierCurveTo (cpx, cpy, cpx, cpy, x, y)
Diese Möglichkeit könnte auch interessant sein, da die Firefox 1.5-Implementierung der quadraticCurveTo()
Methode einen Fehler aufweist . Dies wird im Canvas-Tutorial des Mozilla Development Network erwähnt , das auch eine Fehlerumgehung bietet.
Tatsächlich scheinen die Browser-Anbieter dies jedoch nicht so zu implementieren, wie Sie möglicherweise in Ihrem eigenen Browser feststellen, wenn Sie die folgenden beiden Bilder vergleichen. Betrachten wir noch einmal das Ellipsenbeispiel, das zuerst quadraticCurveTo()
wie zuvor mit Aufrufen implementiert wurde . Dieser Ausschnitt
context.beginPath();
context.moveTo (150,25);
context.quadraticCurveTo (275, 25, 275, 75);
context.quadraticCurveTo (275, 125, 150, 125);
context.quadraticCurveTo ( 25, 125, 25, 75);
context.quadraticCurveTo ( 25, 25, 150, 25);
context.stroke();
erzeugt diese Ansicht in Ihrem Browser
Vergleichen Sie das mit der Implementierung mit bezierCurveTo()
Aufrufen
context.beginPath();
context.moveTo (150,25);
context.bezierCurveTo (275, 25, 275, 25, 275, 75);
context.bezierCurveTo (275, 125, 275, 125, 150, 125);
context.bezierCurveTo ( 25, 125, 25, 125, 25, 75);
context.bezierCurveTo ( 25, 25, 25, 25, 150, 25);
context.stroke();
dieses Bild zu produzieren
2.2.9.9 bezierCurveTo (cp1x, cp1y, cp2x, cp2y, x, y)
CanvasRenderingContext2D.bezierCurveTo (cp1x, cp1y, cp2x, cp2y, x, y)
Erstellt eine gekrümmte Linie vom aktuellen Punkt 0 im Pfad zum neuen Punkt 1 bei
(x,y)
. Die beiden Kontrollpunkte cp1 bei(cp1x,cp1y)
und cp2 bei(cp2x,cp2y)
bestimmen die tatsächliche Form der Linie: Wenn die Kurve von 0 aus in Richtung cp1 geht und schließlich in 1 eingeht , kommt die Kurve aus der Richtung von cp2 heraus .
Betrachten wir den folgenden Ausschnitt
context.beginPath();
context.moveTo (30,120); // go to point 0 at (30,120)
context.bezierCurveTo (120, 30, 240, 30, 240, 120); // curve from point 0 to point 1 at (240,120)
context.stroke();
Dadurch wird die folgende rote Kurve erstellt
Die Kurve beginnt in Punkt 0 in Richtung cp1 und endet in Punkt 1, der von cp2 kommt .
Das gleiche Prinzip gilt, wenn wir die Position der beteiligten Punkte ändern. Zum Beispiel
Beachten Sie auch, dass selbst das "Ziehen" von cp1 von Punkt 0 (oder cp2 von 1 weg ) an der Kurve zieht und sie stärker biegt:
Wie bereits erwähnt, lautet der eigentliche Titel der hier als "Beziér-Kurve" bezeichneten Methode " kubische Beziér-Kurve ". Und die "quadratische Kurve" aus der vorherigen Methode (siehe quadraticCurveTo()
oben) ist tatsächlich eine " quadratische Beziér-Kurve " in mathematischen Begriffen. Sie sollten sich unbedingt die intuitiven Animationen im entsprechenden Wikipedia-Eintrag ansehen, insbesondere den Abschnitt zum Erstellen von Bézier-Kurven .
Die gesamte Theorie zu Beziér-Kurven wurde in Autofabriken entwickelt, um in der Praxis glatte Karosserien herzustellen. Das Finden des Codes für eine bestimmte Form von Hand kann jedoch eine entmutigende Aufgabe sein. Lassen Sie uns eine einfache Methode anwenden, wie dies getan werden kann. Angenommen, wir versuchen, den Code für beispielsweise die Form eines Herzens zu finden: 27
Wir beginnen mit der Identifizierung einiger signifikanter Punkte 0 , 1 , 2 , 3 , 4 , 5 und der Tangenten (grün angezeigt), dh der Linien, die die rote Form an diesem bestimmten Punkt berühren:
Dann lesen wir die bezierCurveTo()
Anrufe von jedem Stück im Pfad ab. Manchmal müssen wir ein wenig mit der besten Position der Kontrollpunkte auf der Tangente spielen, dh wir können wie zuvor beschrieben etwas ziehen, um die rote Linie in die beste Form zu bringen. Wir erhalten die folgenden sechs Ergebnisse:
Wir sammeln schließlich nur die Teile und erhalten den Code für das ursprüngliche Leinwandbild
context.fillStyle = 'red';
context.beginPath();
context.moveTo (150,60); // start at point 0
context.bezierCurveTo (150,30, 100,30, 90,30); // from point 0 to point 1
context.bezierCurveTo (60,30,30,60,30,90); // from point 1 to point 2
context.bezierCurveTo (30,180,90,210,150,240); // from point 2 to point 3
context.bezierCurveTo (210,210,270,180,270,90); // from point 3 to point 4
context.bezierCurveTo (270,60,240,30,210,30); // from point 4 to point 5
context.bezierCurveTo (180,30,150,30,150,60); // from point 5 to point 0
context.fill();
2.2.9.10 arc (x, y, r, start, end, anticlockwise)
CanvasRenderingContext2D.arc (x, y, r, start, end, anticlockwise)
definiert ein Stück eines Kreises. Der Mittelpunkt dieses Kreises ist
(x,y)
der Radiusr
. Derstart
und derend
Punkt des Bogens werden als Winkel im Bogenmaß angegeben. Der optionale boolescheanticlockwise
Parameter definiert, ob die Bögen gegen den Uhrzeigersinn (Werttrue
) oder im Uhrzeigersinn (Wertfalse
, der Standard ist) gemessen werden . Ein Aufruf vonarc()
ist Teil einer Pfaddeklaration. Das eigentliche Zeichnen erfolgt mit einem Aufruf vonstroke()
, Zeichnenfill()
eines Teils der Kreislinie oder Zeichnen eines Abschnitts der Kreisscheibe.
Zeichnen wir zum Beispiel Abschnitte von fünf Kreisscheiben mit jeweils einem 50
Pixelradius
welches vom Code-Snippet generiert wird
context.fillStyle = "rgba(255,0,0,0.33)"; // red color with 1/3 transparency
// now draw five filled circle pieces:
context.beginPath(); context.arc ( 60, 60, 50, 0, 2 * Math.PI, false); context.fill(); // 1st
context.beginPath(); context.arc (180, 60, 50, 0, Math.PI, false); context.fill(); // 2nd
context.beginPath(); context.arc (300, 60, 50, 0, Math.PI, true ); context.fill(); // 3rd
context.beginPath(); context.arc (420, 60, 50, 2, 6, false); context.fill(); // 4th
context.beginPath(); context.arc (540, 60, 50, 2, 6, true ); context.fill(); // 5th
Und wenn wir fillStyle
durch strokeStyle
und jedes Vorkommen von fill()
durch ersetzen stroke()
, erhalten wir dieses Bild von fünf Kreisbögen:
Fügen wir das Koordinatensystem und einen roten Punkt für die Mitte jedes Bogens hinzu, damit wir ihre genauen Positionen sehen können:
Jeder Anruf von
arc (x, y, r, start, end, anticlockwise)
definiert einen Kreis mit Mittelpunkt (x,y)
und Radius r
.
Jeder Winkel a
wird von der 3-Uhr-Position des gegebenen Kreises im Uhrzeigersinn gemessen:
Es ist zu beachten, dass die Einheit jedes Winkels a
im Bogenmaß angegeben ist rad
, dh der Winkel ist a rad
und die Länge des Bogens ist a * r
.
Der 4. Bogen des Anfangsbeispiels, gezeichnet von, arc(420,60,50,2,6,false)
hatte einen Startwinkel von 2 rad
und einen Endwinkel von6 rad
Und wenn wir den fünften Parameter false
in ändern true
, dh wenn wir aufrufen arc(420,60,50,2,6,true)
, so dass die Richtung auf dem Kreis nicht im Uhrzeigersinn, sondern gegen den Uhrzeigersinn ist, erhalten wir den fünften Bogen
Die meisten Benutzer kennen den Grad °
anstelle des Bogenmaßes rad
als Winkeleinheit besser . Denken Sie daran, dass ein vollständiger Kreis 2?
(ungefähr 6.283
) ist und dass dies ?
in JavaScript durch den konstanten Wert gegeben ist
Math.PI = 3.141592653589793
Wir konvertieren zwischen Bogenmaß und Grad unter Verwendung der Gleichung hin und her 360°=2?
Im ersten Beispiel war der 1. Bogen ein voller Kreis, und wir zeichnen diesen mit Startwinkel 0
und Endwinkel 2*Math.PI
. Der 2. und 3. waren Halbkreise vom Startwinkel 0
zum Endwinkel Math.PI
, die im Uhrzeigersinn bzw. gegen den Uhrzeigersinn gezeichnet wurden.
Aus der Trigonometrie geht hervor, dass ein Punkt auf einem Kreis mit Mittelpunkt (x,y)
, Radius r
und einem Winkel von a
die Koordinaten hat
(r cos(a) + x, r sin(a) + y)
In JavaScript ist dies gegeben durch
(r * Math.cos(a) + x, r * Math.sin(a) + y)
Zum Beispiel der schwarze Punkt in diesem Bild
mit a
= 135°
= 3/4?
hat die Koordinaten
(60*Math.cos(3/4*Math.PI)+80, 60*Math.cos(3/4*Math.PI)+80) === (37.573593128807154, 122.42640687119285)
arc()
als ein Stück im aktuellen Pfad
Ein Aufruf von arc()
ist Teil des aktuellen Pfads. Dies hängt vom aktuellen Punkt ab, bevor er aufgerufen wurde, und der Endpunkt des Bogens wird danach zum neuen aktuellen Punkt. Zum Beispiel dieser Code
context.lineWidth = 3.0;
context.strokeStyle = "red";
context.beginPath ();
context.moveTo (30, 90);
context.arc (210, 90, 60, 2, 6);
context.lineTo (390, 90);
context.stroke();
erzeugt dieses Bild
Der Anfangspunkt des Pfades ist (30,90)
. Der Aufruf von arc()
definiert diesen Bogen, aber auch die Linie vom Anfang (30,90)
bis zum Startpunkt des Bogens. Nach dem Aufruf ist der neue aktuelle Punkt der Endpunkt des Bogens. Und der letzte Aufruf von lineTo()
zieht die Linie vom Bogen nach(390,90)
Wenn Sie dieses Verhalten und die zusätzlichen Zeilen verhindern möchten, schließen Sie den arc()
Aufruf zwischen a beginPath()
und stroke()
oder ein fill()
, wie wir es bisher in allen unseren Beispielen getan haben. Dadurch wird sichergestellt, dass nur der Bogen selbst gezeichnet wird.
Betrachten wir noch einmal unser erstes Beispiel-Canvas-Beispiel mit fünf Bögen
Denken Sie daran, dass wir jeden arc()
Anruf in eine Sequenz eingeschlossen haben beginPath(); arc(); stroke();
. Wenn wir alle fünf arc()
Aufrufe in nur einen Pfad eingeschlossen hätten, dh wenn dies unser Code gewesen wäre
context.beginPath();
context.arc ( 60, 60, 50, 0, 2 * Math.PI, false); // 1st
context.arc (180, 60, 50, 0, Math.PI, false); // 2nd
context.arc (300, 60, 50, 0, Math.PI, true ); // 3rd
context.arc (420, 60, 50, 2, 5, false); // 4th
context.arc (540, 60, 50, 2, 5, true ); // 5th
context.stroke();
Das Bild würde so aussehen
Der Start- und Endpunkt des Bogens werden Teil der Pfaddefinition. Gleiches gilt im Allgemeinen für gefüllte Objekte und mit Zeichenmethoden innerhalb des Pfades.
Nehmen wir als letztes Beispiel diese Leinwand mit einem einzigen Bogen
durch diesen Code generiert
context.beginPath();
context.arc (120, 60, 50, 2, 5, true);
context.fill();
Wenn wir einen Punkt hinzufügen, sagen wir (30,25)
vor dem Bogen, und wenn wir danach eine Linie zeichnen, sagen (30,100)
wir zu , dh wenn wir diesen Code verwenden
context.beginPath();
context.moveTo (30,25);
context.arc (120, 60, 50, 2, 5, true);
context.lineTo (30,100);
context.fill();
Die Leinwand sieht so aus
Der Pfad selbst, der sichtbar ist, wenn wir den Code im Code fill
durch ersetzen stroke
, ist dieser
2.2.9.11 arcTo (x1, y1, x2, y2, radius)
CanvasRenderingContext2D.arcTo (x1, y1, x2, y2, radius)
Zeichnet einen Bogen mit dem Gegebenen
radius
, abhängig vom aktuellen Punkt im Pfad und den beiden angegebenen Punkten(x1, y1)
und(x2, y2)
. Weitere Einzelheiten zu dieser Methode finden Sie in den folgenden Beispielen und in der Beschreibung.
Sei context
der 2D-Kontext einer Leinwand mit Standardgröße (das lineWidth
ist auf gesetzt 5.0
, das strokeStyle
ist 'red'
). Dann das folgende Code-Snippet
context.beginPath();
context.moveTo (60, 120);
context.arcTo (150, 30, 240, 120, 50);
context.stroke();
erzeugt dieses Bild
Die von gezeichnete Form arcTo (x1, y1, x2, y3, radius)
hängt von drei Punkten ab:
Der aktuelle Punkt
(x0,y0)
im Pfad, im Beispiel(60,120)
der Status nach demmoveTo(60,120)
Aufruf.Punkt
(x1,y1)
, hier:(150,30)
und(x2,y2)
, was(240,120)
in unserem Beispiel ist.
Die Position dieser drei Punkte auf der Leinwand ist folgende:
Stellen Sie sich nun zwei halb-unendliche Linien mit Punkt 1 als Ursprung vor, von denen eine durch Punkt 0 und die andere über Punkt 1 verläuft.
Das Zeichnen arcTo (x1, y1, x2, y3, radius)
zeichnet nun eine Linie, die ihren Ursprung in Punkt 0 hat, in Richtung Punkt 1 verläuft und sich in Richtung Punkt 2 dreht, sodass dies radius
der tatsächliche Radius des Bogens ist. Der Endpunkt der arcTo()
Linie ist der Punkt, an dem der Bogen auf die Tangentenlinie trifft (von Punkt 1 zu Punkt 2).
Die ganze Idee wird wahrscheinlich offensichtlicher, wenn wir dasselbe Code-Snippet verwenden
context.beginPath();
context.moveTo (60, 120);
context.arcTo (150, 30, 240, 120, radius); // different values for radius
context.stroke();
und variieren Sie einfach die radius
. Die resultierenden Bilder sind diese:
2.2.9.12 clip()
CanvasRenderingContext2D.clip()
schneidet einen Bereich beliebiger Form und Größe von der Leinwand ab.
Angenommen, wir haben eine Zeichnung auf einer Leinwand, beispielsweise ein Rechteck mit Text
und nehmen wir an, wir möchten von dieser Leinwand den Teil abschneiden, der durch diesen Kreis definiert ist
so dass das Gesamtergebnis so aussieht
Die Standardmethode, um dies zu erreichen, besteht aus drei Schritten: 1. Zeichnen Sie die Form des zu beschneidenden Bereichs, 2. Rufen Sie die clip()
Methode auf und 3. Zeichnen Sie den Canvas-Inhalt
Der Quellcode des vorherigen Beispiels lautet
// 1. clipped circle area
context.fillStyle = 'yellow';
context.beginPath();
context.arc (60, 60, 60, 0, 2*Math.PI);
context.fill();
// 2. clip
context.clip();
// 3. draw a rectangle with text
context.fillStyle = 'aqua';
context.fillRect (30, 60, 180, 60);
context.fillStyle = 'red';
context.font = '60px sans-serif';
context.fillText ('Hello!', 30, 110);
Im vorherigen Beispiel waren sowohl der abgeschnittene Kreisbereich als auch die Leinwandzeichnungen gefüllte Formen. Aber wir können jede dieser Zahlen durch Strichzahlen ersetzen. Wenn wir beispielsweise jedes Vorkommen eines " fill
" durch ein " stroke
" im vorherigen Code ersetzen , ist dies das Bild
Die Clip-Technik funktioniert für alle Leinwandzeichnungen, einschließlich Bilder. Um eine Scheibe aus einem Pferdebild auszuschneiden, können wir diesen Code 28 verwenden
// clipped circle area
context.beginPath();
context.arc (60, 60, 60, 0, 2*Math.PI);
context.fill();
// clip
context.clip();
// insert the image
var image = new Image();
image.src = "horse.jpg";
context.drawImage (image, 0, 0, 120, 120); // insert the image at (0,0) on an area of 120x120 pixels
Das Ergebnis ist dies
2.2.9.13 isPointInPath (x, y)
CanvasRenderingContext2D.isPointInPath (x, y)
Gibt zurück,
true
wenn sich der angegebene Punkt(x,y)
im aktuellen Pfad befindet,false
andernfalls.
Zum Beispiel dieses Code-Snippet
// add a new path
context.beginPath();
context.moveTo (75,130); // make (75,130) the current point
context.lineTo (145,75); // line from (75,130) to (145,75)
context.arc (75,75,70,0,Math.PI,true); // draw half circle disk with center (75,75), radius 70 and counterclockwise
context.lineTo (75,130); // line from (5,70) to (75,130)
context.lineWidth = 3.0; // set the line width for the stroke drawing
context.strokeStyle = 'purple'; // set the line color for the stroke drawing
context.stroke(); // draw the shape
// determine the position of two points
var answer1 = context.isPointInPath (25,100); // answer1 is now either true or false
var answer2 = context.isPointInPath (100,25); // answer2 is also either true or false
// print out the result on the canvas
context.font = "14pt sans-serif"; // set the font for the text
context.fillText ( "isPointInPath(25,100) is " + answer1, 200, 50); // print the first line of text
context.fillText ( "isPointInPath(100,25) is " + answer2, 200, 100); // print the second line of text
erzeugt dieses Leinwandbild
2.2.10 Text
Text wird mit einer der beiden folgenden Methoden zum Canvas (Kontext) hinzugefügt:
fillText (text, x, y)
oder schreibt die angegebene Zeichenfolge an einer Stelle in "gefüllte Buchstaben" (gemäß den aktuellen Einstellungen)fillText (text, x, y, maxWidth)
text
(x,y)
fillStyle
strokeText (text, x, y)
oder schreibt die angegebene Zeichenfolge an einer Stelle in "Strichbuchstaben" (gemäß den aktuellen Einstellungen)strokeText (text, x, y, maxWidth)
text
(x,y)
strokeStyle
Das tatsächliche Rendern des Textes hängt auch von den aktuellen Werten der folgenden Eigenschaften ab:
textAlign
für die horizontale undtextBaseline
für die vertikale Textausrichtungdie aktuellen Schatteneinstellungen (
shadowOffsetX
,shadowOffsetY
,shadowBlur
,shadowColor
)
2.2.10.1 font
CanvasRenderingContext2D.font
Legt die Schriftart (dh den Stil, die Größe usw.) fest, mit der Text zur Zeichenfläche (Kontext) hinzugefügt wird. Sein Wert ist ein beliebiger Wert der CSS3-
font
Eigenschaft (siehe CSS-Schriftarten unten). Der Standardwertfont
ist'10px sans-serif'
. Werte, die nicht als CSS-Schriftwerte analysiert werden können, werden ignoriert. Relative Schlüsselwörter und Längen werden relativ zur Schriftart des Canvas-Elements berechnet.
Auf der folgenden Zeichenfläche wird in jeder Zeile der font
Wert auf einen anderen Wert gesetzt, und dieser Wert wird strokeText()
links und fillText()
rechts mit angezeigt :
Der Quellcode für das vorherige Leinwandbild lautet wie folgt:
// set both the strokeStyle and the fillStyle to black
context.strokeStyle = 'black';
context.fillStyle = 'black';
// first line of text in the default font:
context.strokeText(context.font, 10, 20);
context.fillText (context.font, 350, 20);
// second line of text:
context.font = '20px fantasy';
context.strokeText(context.font, 10, 40);
context.fillText (context.font, 350, 40);
// third line of text:
context.font = '40px Verdana';
context.strokeText(context.font, 10, 80);
context.fillText (context.font, 350, 80);
// fourth line of text:
context.font = '60px Arial';
context.strokeText(context.font, 10, 140);
context.fillText (context.font, 350, 140);
2.2.10.2 textAlign
CanvasRenderingContext2D.textAlign
Legt die horizontale Ausrichtung von Text fest (ähnlich der CSS-
text-align
Eigenschaft). Seine Werte ist eine der folgenden:'start'
,'end'
,'left'
,'right'
oder'center'
. Der Standardwert ist'start'
.
In jedem der folgenden Beispiele context
ist der 2d-Kontext des angegebenen Canvas-Elements angegeben.
Berufung
context.textAlign = 'left'; context.fillText ("Hello world!", 300, 30);</pre>
sieht aus wie das:
Berufung
context.textAlign = 'right'; context.fillText ("Hello world!", 300, 30);
sieht aus wie das:
Berufung
context.textAlign = 'center'; context.fillText ("Hello world!", 300, 30);
sieht aus wie das:
Das tatsächliche Erscheinungsbild des Textes, wenn er eingestellt textAlign
ist 'left'
oder 'right'
von der Richtung des Textes abhängt. Diese Richtung wird im dir
Attribut definiert , entweder 'ltr'
(von links nach rechts) oder 'rtl'
(von rechts nach links), und das Canvas-Element erbt diesen Wert.
Wenn die Direktionalität auf
'ltr'
undtextAlign
eingestellt'start'
ist oder
wenn die Direktionalität auf'rtl'
und eingestellttextAlign
ist'end'
, wird
der Text wie in angezeigttextAlign=left
.Wenn die Direktionalität auf
'ltr'
undtextAlign
eingestellt'end'
ist oder
wenn die Direktionalität auf'rtl'
und eingestellttextAlign
ist'start'
, wird
der Text wie in angezeigttextAlign=right
.
2.2.10.3 textBaseline
CanvasRenderingContext2D.textBaseline
stellt die vertikale Ausrichtung von Text und weist einen der folgenden Werte:
'top'
,'hanging'
,'middle'
,'alphabetic'
,'ideographic'
oder'bottom'
. Der Standardwert ist'alphabetic'
.
Das folgende Bild (aus dem W3.org-Text auf dem Canvas-Element entnommen ) erklärt die verschiedenen Zeilen, die beim Schreiben eine Rolle spielen :
Dieses Skript
<canvas id="TextBaselineSample" width=750 height=100></canvas>
<script>
var context = document.getElementById('TextBaselineSample').getContext('2d');
context.addGrid (50);
context.font = '20px monospace';
context.textBaseline = 'top'; context.fillText ( "top", 0, 50);
context.textBaseline = 'hanging'; context.fillText ( "hanging", 100, 50);
context.textBaseline = 'middle'; context.fillText ( "middle", 200, 50);
context.textBaseline = 'alphabetic'; context.fillText ( "alphabetic", 300, 50);
context.textBaseline = 'ideographic'; context.fillText ( "ideographic", 450, 50);
context.textBaseline = 'bottom'; context.fillText ( "bottom", 600, 50);
</script>
sieht so aus
2.2.10.4 fillText (text, x, y)
undfillText (text, x, y, maxWidth)
CanvasRenderingContext2D.fillText (text, x, y)
und
CanvasRenderingContext2D.fillText (text, x, y, maxWidth)
Zeichnen Sie die angegebene
text
Zeichenfolge an der(x,y)
Position in gefüllten Zeichen auf der Leinwand. Wenn die Option (Gleitkommazahl) festgelegtmaxWidth
ist, wird der Text so komprimiert, dass er in diese Grenze passt.
Standardmäßigx
ist dies derstart
Punkt dertext
Zeichenfolge (siehe textAlign ) undy
diealphabetic
Grundlinie (siehe textBaseline ).
Zum Beispiel das folgende Code-Snippet
context.fillStyle = 'black'; // explicitly sets the text color to (default) 'black'
context.font = '50px monospace';
context.fillText ("Hello world!", 0, 50);
context.fillText ("This is a longer string that is limited to 750 pixel.", 0, 100, 750);
context.fillText ("This is a longer string that is limited to 300 pixel.", 0, 150, 300);
rendert wie folgt
2.2.10.5 strokeText (text, x, y)
undstrokeText (text, x, y, maxWidth)
CanvasRenderingContext2D.strokeText (text, x, y, maxWidth)
und
CanvasRenderingContext2D.strokeText (text, x, y, maxWidth)
Zeichnen Sie die angegebene
text
Zeichenfolge an der(x,y)
Position in Strichzeichen auf der Leinwand. Wenn die Option (Gleitkommazahl) festgelegtmaxWidth
ist, wird der Text entsprechend skaliert.
Standardmäßigx
ist dies derstart
Punkt dertext
Zeichenfolge (siehe textAlign ) undy
diealphabetic
Grundlinie (siehe textBaseline ).
(Laut der Referenz auf w3schools.com wird die maxWidth
Eigenschaft vom Safari-Browser nicht unterstützt.)
Zum Beispiel dieser Code
context.strokeStyle = 'black'; // explicitly sets the text color to (default) 'black'
context.lineWidth = 2.0; // double of the default lineWidth
context.font = '50px monospace';
context.strokeText ("Hello world!", 0, 50);
context.strokeText ("This is a longer string that is limited to 750 pixel.", 0, 100, 750);
sieht wie folgt aus
2.2.10.6 measureText(text).width
CanvasRenderingContext2D.measureText(text).width
Gibt die Breite der
text
Zeichenfolge in den aktuellen Schriftarteinstellungen zurück und wird in Pixel gemessen.
Wenn context
es sich also um den 2d-Kontext der angegebenen context.measure('Hello world!').width
Zeichenfläche handelt , wird die Länge der Zeichenfolge "Hello world!"
in den aktuellen Einstellungen zurückgegeben.
Die Form dieses Aufrufs ist ziemlich umständlich und besteht natürlich aus zwei Schritten: canvas.measureText(text)
Gibt ein TextMetrics
Objekt zurück. In der [ WHATWG ] -Spezifikation enthielt ein TextMetrics
Objekt ziemlich viele Informationen. All dies ist jedoch im offiziellen [ W3C ] -Standard verdeckt , nur das width
Eigentum des TextMetrics
Objekts bleibt zugänglich. Durch einen Anruf erhalten canvas.measureText(text).width
wir diese Informationen.
Denken Sie daran, dass die aktuelle Texthöhe von der font
Eigenschaft festgelegt und gespeichert wird .
Im folgenden Beispiel wird w
der Wert für die Breite der Zeichenfolge "This is some text."
in den aktuellen Schriftarteinstellungen (nämlich 30px Arial
) verwendet. Wie sich herausstellt, w
ist 233
.
Der Quellcode des vorherigen Beispiels lautet wie folgt:
<canvas id="TextSampleMeasureText" width=700 height=70></canvas>
<script>
var canvas = document.getElementById('TextSampleMeasureText');
var context = canvas.getContext('2d');
context.addGrid (30);
var text = "This is some text.";
context.font = '30px Arial';
context.fillText (text, 0, 30);
var w = context.measureText(text).width;
context.fillText ("The previous line is " + w + " pixel wide.", 0, 60);
</script>
2.2.11 Bilder zeichnen
Wir können ein Bild mit in die Leinwand einfügen
context.drawImage (image, ...)
Wo
context
ist dasCanvasRenderingContext2D
Objekt der gegebenen Leinwand undimage
ist entweder
a
HTMLImageElement
(z. B. ein JPEG- oder PNG-Dateibild) oderein anderer
HTMLCanvasElement
oder sogara
HTMLVideoElement
.Die
drawImage(image,...)
Methode ist in mehreren Versionen mit zunehmender Flexibilität und Anzahl von Parametern erhältlich....
Diese werden im Folgenden beschrieben. 29
2.2.11.1 drawImage (image, dx, dy)
CanvasRenderingContext2D.drawImage (image, dx, dy)
zeichnet das
image
auf die Leinwand, wo(dx,dy)
ist der Punkt seiner linken oberen Ecke.
horse.jpg
Angenommen , die Datei ist ein 300 x 425 Pixel großes Bild und context
der 2D-Kontext einer bestimmten 400 x 500 Pixel großen Leinwand. Dann dieser Code
var image = new Image(); // 1. create the image: (a). create an image object
image.src = "horse.jpg"; // (b). set it to the jpg file
context.drawImage (image, 50, 50); // 2. draw the image onto the canvas at (50,50)
erzeugt dieses Bild
2.2.11.2 drawImage (image, dx, dy, dw, dy)
CanvasRenderingContext2D.drawImage (image, dx, dy, dw, dh)
Zeichnet ein
image
als Rechteck(dx,dy,dw,dy)
in die Leinwand, wobei(dx,dy)
die obere linke Ecke dieses Zielrechtecksdw
seine Breite unddh
Höhe ist.
Wenn wir beispielsweise unser horse.jpg
Bild erneut aufnehmen und context
es sich um den 2D-Kontext einer 700 x 500 Pixel großen Leinwand handelt, ist der Code
var image = new Image();
image.src = "horse.jpg";
context.drawImage (image, 50, 50, 600, 150);
context.drawImage (image, 50, 250, 150, 200);
context.drawImage (image, 350, 250, 100, 200);
context.drawImage (image, 600, 250, 50, 200);
rendert als
2.2.11.3 drawImage (image, sx, sy, sw, sh, dx, dy, dw, dh)
CanvasRenderingContext2D.drawImage (image, sx, sy, sw, sh, dx, dy, dw, dh)
schneidet ein Rechteck
(sx,sy,sw,sh)
aus der Quelle herausimage
und fügt es als(dx,dy,dw,dh)
in die Zielleinwand ein.
Wenn wir beispielsweise unser Pferdebild horse.jpg
erneut verwenden, context
ist dies der 2D-Kontext einer 350x350-Leinwand
var image = new Image();
image.src = "horse.jpg";
context.drawImage (image, 150, 40, 130, 120, 75, 100, 200, 150);
erzeugt dieses Bild
Das Rechteck (sx,sy,sw,sh) aus dem Quellbild hat die linke obere Ecke in (sx,sy) Breite sw und Höhe sh .
|
Das Rechteck (dx,dy,dw,dh) im Zielbereich hat die linke obere Ecke (dx,dy) , Breite dw und Höhe dh .
|
2.2.12 Pixel Manipulation
Das Bild einer Leinwand kann als Struktur formalisiert werden, die den Farbwert für jedes ihrer Pixel enthält. Dies geschieht durch ein ImageData
Objekt. Wir werden nun zeigen, wie man ein solches Objekt mit erstelltcreateImageData()
, wie man ein solches Objekt aus einer Leinwand ausschneidet getImageData()
und wie man ein solches Objekt in einen Bereich einer bestimmten Leinwand mit einfügt putImageData()
.
2.2.12.1 ImageData
Ein
ImageData
Objekt ist eine formale Darstellung eines Bildes und wird durch drei Eigenschaften angegeben: Die zwei ganzzahligen Wertewidth
undheight
für seine Größe sowiedata
ein Array (CanvasPixelArray
), das die Farbwerte für alle Pixel enthält.
Angenommen, wir haben ein Bild (eine Leinwand oder einen Ausschnitt aus einem Leinwandkontext) mit einer bestimmten Breite w
und Höhe h
. Die Farbe jeden Pixel (x,y)
wird durch die gegebene RGBA Farbe , wobei jede der vier Komponenten , , , ist ein Wert aus dem Satz und steht für die Menge an Rot, für Grün, für Blau, und für die „alpha“ oder Transparenzwert . Das gesamte Bild wird dann formal durch eine Tabelle wie diese dargestellt:rgba(R(x,y),G(x,y),B(x,y),A(x,y))
R(x,y)
G(x,y)
B(x,y)
A(x,y)
{0,1,2,...,255}
R
G
B
A
x = 0
|
x = 1
|
... |
x = w-1
|
|
---|---|---|---|---|
y = 0
|
rgba(R(0,0),G(0,0),B(0,0),A(0,0))
|
rgba(R(1,0),G(1,0),B(1,0),A(1,0))
|
... |
rgba(R(w-1,0),G(w-1,0),B(w-1,0),A(w-1,0))
|
y = 1
|
rgba(R(0,1),G(0,1),B(0,1),A(0,1))
|
rgba(R(1,1),G(1,1),B(1,1),A(1,1))
|
... |
rgba(R(w-1,1),G(w-1,1),B(w-1,1),A(w-1,1))
|
y = 2
|
rgba(R(0,2),G(0,2),B(0,2),A(0,2))
|
rgba(R(1,2),G(1,2),B(1,2),A(1,2))
|
... |
rgba(R(w-1,2),G(w-1,2),B(w-1,2),A(w-1,2))
|
...
|
... | ... | ... | |
y = h-1
|
rgba(R(0,h-1),G(0,h-1),B(0,h-1),A(0,h-1))
|
rgba(R(1,h-1),G(1,h-1),B(1,h-1),A(1,h-1))
|
... |
rgba(R(w-1,h-1),G(w-1,h-1),B(w-1,h-1),A(w-1,h-1))
|
In einem ImageData
Objekt werden diese Informationen in diesem Objekt mit drei Eigenschaften gespeichert:
{ Breite: w, Höhe: h, Daten: [R (0,0) , G (0,0) , B (0,0) , A (0,0) , R (1,0) , G (1,0) , B (1,0) ) , A (1,0) , ..., R (w-1, h-1) , G (w-1, h-1) , B (w-1, h-1) , A (w- 1, h-1) ] }}
Der data
Wert ist ein Array, das alle Farbwerte in einer einzigen Sequenz umfasst. Die Länge dieses Arrays beträgt4 * w * h
.
Betrachten wir das folgende Bild, ein Quadrat mit einer Seitenlänge von 256 Pixeln.
Die Farbe jedes Pixels (x,y)
wird wie folgt eingestellt:
die rote Komponente nimmt entlang der
x
Achse von0
bis zu zu255
, dhR(x,y)=x
die grüne Komponente nimmt entlang der
y
Achse von0
bis zu zu255
, dhG(x,y)=y
Die blaue Komponente ist konstant
0
für jedes Pixel, dhB(x,y)=0
Bei der Alpha- Komponente ist die Transparenz konstant
255
, was bedeutet, dass das Pixel überhaupt nicht transparent ist. SoA(x,y)=255
Zum Beispiel,
Das Pixel in der linken unteren Ecke
(0,255)
ist die Farbergba(0,255,0,255)
, die ein durchgehendes Grün ist.Das Pixel
(255,0)
in der rechten oberen Ecke hat dagegen die Farbergba(255,0,0,255)
, die rein rot ist.Das Pixel in der linken oberen Ecke
(0,0)
ist (nicht transparent) schwarzrgba(0,0,0,255)
undDas Pixel in der rechten unteren Ecke
(255,255)
ist eine vollständige rot-grüne Mischungrgba(255,255,0,255)
, die (nicht transparent) gelb ist.
Die numerische Tabellendarstellung dieses Bildes ist somit wie folgt gegeben
x = 0
|
x = 1
|
... |
x = 255
|
|
---|---|---|---|---|
y = 0
|
rgba(0,0,0,255)
|
rgba(1,0,0,255)
|
... |
rgba(255,0,0,255)
|
y = 1
|
rgba(0,1,0,255)
|
rgba(1,1,0,255)
|
... |
rgba(255,1,0,255)
|
y = 2
|
rgba(0,2,0,255)
|
rgba(1,2,0,255)
|
... |
rgba(255,2,0,255)
|
...
|
... | ... | ... | |
y = 255
|
rgba(0,255,0,255)
|
rgba(1,255,0,255)
|
... |
rgba(255,255,0,255)
|
und dies wird durch ein ImageData
Objekt mit den drei Eigenschaften dargestellt
{
width : 256,
height: 256,
data : [ 0,0,0,255, 1,0,0,255, ..., 255,0,0,255,
0,1,0,255, 1,1,0,255, ..., 255,1,0,255,
...,
0,255,0,255, 1,255,0,255, ..., 255,255,0,255 ]
}
wo die Länge des data
Arrays ist 4*256*256
, dh es enthält262144
ganzzahlige Komponenten.
(Informationen zur tatsächlichen Generierung dieses ImageData
Objekts und des vorherigen Leinwandbilds finden Sie in Beispiel 1 unten.)
2.2.12.2 createImageData (sw,sh)
undcreateImageData (imagedata)
CanvasRenderingContext2D.createImageData (sw,sh)
Gibt ein
ImageData
Objekt mit der angegebenen (Quell-) Breitesw
und Höhe zurücksh
. Alle4 * sw * sh
Komponenten imdata
Array sind auf eingestellt0
, dh jedes Pixel ist transparent schwarz.
CanvasRenderingContext.2D.createImageData (imagedata)
Gibt ein
ImageData
Objekt mit denselben Dimensionen wie das angegebene Argument zurück (das selbst einImageData
Objekt ist). Auch hier sind alle Pixel im zurückgegebenen Objekt transparent schwarz.
Der letztere der beiden Anrufe createImageData(imagedata)
ist somit nur eine Kurzversion zum Anrufen createImageData(imagedata.width, imagedata.height)
.
Jeder createImageData()
Aufruf gibt somit ein ImageData
Objekt zurück, in dem jedoch alle Array-Elemente des data
Arrays festgelegt sind 0
. Sobald das Objekt erstellt wurde, können alle diese RGBA-Farbkomponenten durch explizite Verweise auf geändert werden data[i]
.
Im Folgenden präsentieren wir einige Demonstrationen für diese Techniken.
2.2.12.3 getImageData (sx, sy, sw, sh)
CanvasRenderingContext2D.getImageData(in float sx, in float sy, in float sw, in float sh)
Gibt das zurück
ImageData
, das den rechteckigen Abschnitt des Gegebenen darstelltCanvasRenderingContext2D
, dessen Ursprung darin(sx,sy)
liegt, dersw
Pixel breit undsh
Pixel hoch ist.
Im Folgenden zeigen wir anhand einiger Beispiele, wie dies funktioniert.
2.2.12.4 putImageData (imagedata, dx, dy)
undputImageData (imagedata, dx, dy, sx, sy, sw, sh)
CanvasRenderingContext2D.putImageData (imagedata, dx, dy)
nimmt ein gegebenes
ImageData
Objektimagedata
und fügt es(dx,dy)
in das gegebene einCanvasRenderingContext2D
.
CanvasRenderingContext2D.putImageData (imagedata, dx, dy, dx, dy, dw, dh)
macht dasselbe wie der vorherige Funktionsaufruf, aber dieses Mal wird nur der Teil aus dem
imagedata
Bild genommen, der seine linke obere Ecke hat(dx,dy)
unddw
Pixel breit unddh
Pixel hoch ist.
Codebeispiele und Bilder finden Sie im nächsten Abschnitt .
2.2.12.5 Beispiele für die Pixelmanipulation
Betrachten Sie das vorherige Bild noch einmal:
Es wurde von diesem Code-Snippet generiert
<canvas id="ImageDataSample" width=256 height=256> </canvas>
<script>
var canvas = document.getElementById('ImageDataSample');
var w = canvas.width; // w is 256
var h = canvas.height; // h is 256
var context = canvas.getContext('2d');
context.addGrid(32);
var imDat = context.createImageData (w,h);
var i = 0;
for (var y = 0; y < h; y++) {
for (var x = 0; x < w; x++) {
imDat.data[i++] = x; // the Red component of (x,y), which is set to x
imDat.data[i++] = y; // the Green component of (x,y), which is set to y
imDat.data[i++] = 0; // the Blue component of (x,y), which is constant 0
imDat.data[i++] = 255; // the Alpha/transparency of (x,y), which is constant 255, i.e. fully visible
};
};
context.putImageData (imDat, 0, 0)
</script>
Zuerst erstellen wir ein ImageData
Objekt, es ruft imDat
, unter Berufung auf context.createImageData(w,h)
mit w
und h
auf beide gesetzt 256
. Zu diesem Zeitpunkt ist das imDat.data
Array ein Array mit einer Länge 4*256*256
, wobei jede Array-Komponente eine ist 0
. Das Einstellen aller dieser Komponenten auf den erforderlichen Farbcode erfolgt in der Doppelschleife for
. Wenn diese Schleife wieder verlassen wird, imDat
ist es so, wie wir es wollten. Im letzten Schritt context.putImageData(imDat,0,0)
fügt der Aufruf dieses ImageData
Objekt mit der linken oberen Ecke bei ein(0,0)
in die Zeichenfläche eingefügt.
Lassen Sie uns zeigen, wie wir einen rechteckigen Abschnitt ausschneiden und ihn erneut in dasselbe Bild kopieren. Betrachten Sie diese Leinwand
generiert durch dieses Code-Snippet
context.fillStyle = 'black';
context.font = '40pt sans-serif';
context.fillText ('Hi there!',30,70);
Wir schneiden nun das 260x60
Pixelrechteck bei aus (20,20)
und platzieren seine Kopie bei (320,20)
. Wenn wir diese Rechteckigkeit durch einen roten Rahmen anzeigen, wird der gesamte Vorgang als angezeigt
Das eigentliche Kopieren erfolgt durch Hinzufügen der folgenden zwei Zeilen zum vorherigen Code
var imDat = context.getImageData (20,20,260,60);
context.putImageData (imDat,320,20);
Mit der ersten Zeile löschen wir ein ImageData
Objekt namens imDat
. Mit der zweiten Zeile fügen wir dieses Objekt erneut in das Bild ein.
Das vom vorherigen Code erzeugte Bild ist tatsächlich dieses
Wir haben gerade eine einfache Kopie eines Canvas-Abschnitts in zwei Schritten erstellt: 1. Holen Sie sich ein ImageData
Objekt mit dem NamenimDat
und 2. fügen Sie es erneut in den Canvas-Kontext ein.
Wir ändern nun das erhaltene Objekt, bevor wir es zurücksetzen, und führen drei Schritte aus:
ausgeschnitten
imDat
wie zuvor mitgetImageData()
,Erstellen Sie ein neues
ImageData
ObjektmirImDat
mit dem Spiegelbild vonimDat
byInitialisieren Sie
mirImDat
mitcreateImageData()
alsImageData
Objekt mit der gleichen Größe wieimDat
Aktualisieren Sie alle Farbkomponenten von
mirImDat.data
(so dass jede Zeile vonimDat
umgekehrt wirdmirImDat
)
setzen
mirImDat
in das Bild zurück mitputImageData()
Das resultierende Bild ist dies
und der vollständige Quellcode zum Generieren dieser Zeichenfläche lautet wie folgt:
// 0. Generated the text field
context.fillStyle = 'black';
context.font = '40pt sans-serif';
context.fillText ('Hi there!',30,70);
// 1. Cut out the ImageData object named imDat
var w = 260; // explicitly define the width w of the rectangle area
var h = 60; // explicitly define the height h of the rectangle
var imDat = context.getImageData(20,20,w,h); // cut out the rectangle and save it in an ImageData object named imDat
// 2. Create a new ImageDate object with the mirror image, called mirImDat
var mirImDat = context.createImageData(imDat); // a. initialze mirImDat; all components of mirImDat.data are 0 here
for (var y = 0; y < h; y++) { // b. update the mirImDat.data components
for (var x = 0; x < w; x++) {
var d = 4 * (y * w + x);
var s = 4 * (y * w + (w - (x + 1)));
mirImDat.data [d + 0] = imDat.data [s + 0];
mirImDat.data [d + 1] = imDat.data [s + 1];
mirImDat.data [d + 2] = imDat.data [s + 2];
mirImDat.data [d + 3] = imDat.data [s + 3];
}; // done updating the mirImDat.data components
};
// 3. Insert the mirImDat into the image again
context.putImageData (mirImDat,320,20);
Beachten Sie, dass in Schritt 2.a mirImDat
durch initialisiert wird
var mirImDat = context.createImageData(imDat);
Wie bereits erläutert , createImageData(imDat)
wird nicht vollständig geklont imDat
, sondern nur ein ImageData
Objekt mit denselben Abmessungen erstellt, wobei jedoch alle Farbwerte im data
Array auf festgelegt sind 0
. Dementsprechend könnte die vorherige Zeile durch die folgende Zeile ersetzt werden, die genau dasselbe tut:
var mirImDat = context.createImageData(w,y);
In den verschachtelten Schleifen von Schritt 2.b werden die Komponenten von mirImDat.data
dann auf die korrekten Werte aktualisiert, die sich mirImDat
in das wahre Spiegelbild von verwandelnimDat
.
Dieses Beispiel einer Spiegelkopie zeigt, wie alle Transformationsmethoden von CanvasRenderingContext2D
durch diese Manipulationen auf Pixelebene erneut implementiert werden können.
3 Anhänge
3.1 Referenzzusammenfassung
Das Folgende ist eine Kopie der Schnittstellendefinitionen des HTMLCanvasElement
, des CanvasRenderingContext2D
und einiger anderer verwandter Objekte, wie sie im Standard [ W3C.org ] angegeben sind. Die Inhaltstabelle des Referenzteils dieses Canvas-Handbuchs ähnelt den ersten beiden Hauptschnittstellen.
interface HTMLCanvasElement : HTMLElement {
attribute unsigned long width;
attribute unsigned long height;
DOMString toDataURL(optional in DOMString type, in any... args);
Object getContext(in DOMString contextId);
};
interface CanvasRenderingContext2D {
// back-reference to the canvas
readonly attribute HTMLCanvasElement canvas;
// state
void save(); // push state on state stack
void restore(); // pop state stack and restore state
// transformations (default transform is the identity matrix)
void scale(in float x, in float y);
void rotate(in float angle);
void translate(in float x, in float y);
void transform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy);
void setTransform(in float m11, in float m12, in float m21, in float m22, in float dx, in float dy);
// compositing
attribute float globalAlpha; // (default 1.0)
attribute DOMString globalCompositeOperation; // (default source-over)
// colors and styles
attribute any strokeStyle; // (default black)
attribute any fillStyle; // (default black)
CanvasGradient createLinearGradient(in float x0, in float y0, in float x1, in float y1);
CanvasGradient createRadialGradient(in float x0, in float y0, in float r0, in float x1, in float y1, in float r1);
CanvasPattern createPattern(in HTMLImageElement image, in DOMString repetition);
CanvasPattern createPattern(in HTMLCanvasElement image, in DOMString repetition);
CanvasPattern createPattern(in HTMLVideoElement image, in DOMString repetition);
// line caps/joins
attribute float lineWidth; // (default 1)
attribute DOMString lineCap; // "butt", "round", "square" (default "butt")
attribute DOMString lineJoin; // "round", "bevel", "miter" (default "miter")
attribute float miterLimit; // (default 10)
// shadows
attribute float shadowOffsetX; // (default 0)
attribute float shadowOffsetY; // (default 0)
attribute float shadowBlur; // (default 0)
attribute DOMString shadowColor; // (default transparent black)
// rects
void clearRect(in float x, in float y, in float w, in float h);
void fillRect(in float x, in float y, in float w, in float h);
void strokeRect(in float x, in float y, in float w, in float h);
// path API
void beginPath();
void closePath();
void moveTo(in float x, in float y);
void lineTo(in float x, in float y);
void quadraticCurveTo(in float cpx, in float cpy, in float x, in float y);
void bezierCurveTo(in float cp1x, in float cp1y, in float cp2x, in float cp2y, in float x, in float y);
void arcTo(in float x1, in float y1, in float x2, in float y2, in float radius);
void rect(in float x, in float y, in float w, in float h);
void arc(in float x, in float y, in float radius, in float startAngle, in float endAngle, in boolean anticlockwise);
void fill();
void stroke();
void clip();
boolean isPointInPath(in float x, in float y);
// text
attribute DOMString font; // (default 10px sans-serif)
attribute DOMString textAlign; // "start", "end", "left", "right", "center" (default: "start")
attribute DOMString textBaseline; // "top", "hanging", "middle", "alphabetic", "ideographic", "bottom" (default: "alphabetic")
void fillText(in DOMString text, in float x, in float y, optional in float maxWidth);
void strokeText(in DOMString text, in float x, in float y, optional in float maxWidth);
TextMetrics measureText(in DOMString text);
// drawing images
void drawImage(in HTMLImageElement image, in float dx, in float dy, optional in float dw, in float dh);
void drawImage(in HTMLImageElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
void drawImage(in HTMLCanvasElement image, in float dx, in float dy, optional in float dw, in float dh);
void drawImage(in HTMLCanvasElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
void drawImage(in HTMLVideoElement image, in float dx, in float dy, optional in float dw, in float dh);
void drawImage(in HTMLVideoElement image, in float sx, in float sy, in float sw, in float sh, in float dx, in float dy, in float dw, in float dh);
// pixel manipulation
ImageData createImageData(in float sw, in float sh);
ImageData createImageData(in ImageData imagedata);
ImageData getImageData(in float sx, in float sy, in float sw, in float sh);
void putImageData(in ImageData imagedata, in float dx, in float dy, optional in float dirtyX, in float dirtyY, in float dirtyWidth, in float dirtyHeight);
};
interface CanvasGradient {
// opaque object
void addColorStop(in float offset, in DOMString color);
};
interface CanvasPattern {
// opaque object
};
interface TextMetrics {
readonly attribute float width;
};
interface ImageData {
readonly attribute unsigned long width;
readonly attribute unsigned long height;
readonly attribute CanvasPixelArray data;
};
interface CanvasPixelArray {
readonly attribute unsigned long length;
getter octet (in unsigned long index);
setter void (in unsigned long index, in octet value);
};
3.2 Einige Elemente von CSS
3.2.1 CSS-Farben
CSS-Farben können mit den folgenden Methoden angegeben werden:
hexadezimale Farben , angegeben als
#RRGGBB
, woRR
die rote bezeichnet,GG
die grüne undBB
die blaue Komponente der Farbe und jeder dieser sechs Buchstaben steht für einen hexadezimalen Wert, das heißt einer der0
, ...,9
,A
, ...,F
. Zum Beispiel,
#0000FF
hat keine (=00
) roten, keine grünen und vollen (=FF
) blauen Komponenten, mit anderen Worten, dies ist reines Blau.RGB - Farben auf die gleiche Weise , dass hexadezimale Farben tun, aber ihre Syntax ist anders, nämlich
rgb(R,G,B)
, woR
,G
undB
auch die Werte für die Rot-, Grün- und Blau - Komponenten sind. Hier sind die Werte entweder Dezimalzahlen zwischen0
und255
(einschließlich) oder Prozentwerte zwischen0%
und100%
. Zum Beispiel,
rgb(0,0,255)
ist die Farbe ohne rote, keine grünen und vollblauen Komponenten. Das ist also wieder reines Blau.
rgb(0%,0%,100%)
ist auch das reine Blau.RGBA Farben werden durch die Form festgelegt
rgba(R,G,B,A)
, wo dieR
,G
,B
Teil die gleichen wie in RGB - Farben ist. Der Alpha-ParameterA
gibt die Deckkraft an und ist ein Wert zwischen0.0
(vollständig transparent) und1.0
(vollständig undurchsichtig). Zum Beispiel,
rgba(100%,0%,0%,0.5)
ist eine rein rote Farbe, die halbtransparent ist.HSL-Farben haben die Form
hsl(H,S,L)
, die den Farbton, die Sättigung und die Helligkeit für eine zylindrisch koordinierte Darstellung von Farben angibt. Der FarbtonH
ist ein Grad im Farbkreis von0
bis360
, wobei0
(oder360
) rot,120
grün und240
blau ist. Die SättigungS
ist ein Prozentwert von0%
bis100%
, wobei0%
ein Grauton bedeutet und100%
die volle Farbe ist. Die HelligkeitL
ist auch ein Prozentsatz,0%
ist schwarz und100%
ist weiß. Zum Beispiel
hsl(120,65%,75%)
HSLA Farben hat die Form
hsla(H,S,L,A)
, in derH
,S
undL
sind die gleichen wie in HSL Farben und der alpha - ParameterA
definiert die Opazität von0.0
(für vollständig transparent) bis1.0
(vollständig undurchsichtig).Vordefinierte oder browserübergreifende Farbnamen sind Farben in HTML und CSS, die durch ihren Namen angegeben werden, z. B.
BlueViolet
oderDarkBlue
. Es gibt
17 Standardfarben:
aqua
,black
,blue
,fuchsia
,gray
,green
,lime
,maroon
,navy
,olive
,orange
,purple
,red
,silver
,teal
,white
undyellow
.130 weitere von
AliceBlue
bisYellowGreen
Links:
Die CSS3-Farbdefinition des W3 und auf w3schools.com
Eine Übersicht der Farbnamen, entweder alphabetisch nach ihrem Namen oder nach ihrem entsprechenden HEX-Wert sortiert
Die w3schools Seite hat auch eine Farbauswahl und Farbmischer
3.2.2 CSS-Schriftarten
Weitere Informationen finden Sie in der Standardbeschreibung auf w3.org oder in der Referenz auf w3schools.com .
Schrifteigenschaften in CSS | |
---|---|
CSS-Eigenschaft | mögliche Werte |
font-style
|
normal , italic , oblique , inherit Standard ist normal und die inherit Mittel von dem Mutterelement geerbt.
|
font-variant
|
normal (Standard), small-caps , inherit (Standard ist normal und inherit Mittel von dem Mutterelement geerbt.)
|
font-weight
|
normal , bold , lighter , 100 , 200 , 300 , 400 , 500 , 600 , 700 , 800 , 900 , inherit (Standardeinstellung ist normal , das ist das gleiche wie 400 . Und bold ist das gleiche wie 700 .)
|
font-size
|
xx-small , x-small , small , medium , large , x-large , xx-large , smaller , larger , inherit Oder irgendeine Länge wie angegeben nn px , nncm , nn? ,
|
font-family
|
Es gibt zwei Arten von Schriftfamiliennamen:
font-family Eigenschaft kann mehrere durch Kommas getrennte Werte als "Fallback" -System enthalten. Wenn der Browser die erste Schriftart nicht unterstützt, versucht er die nächste. Zum Beispiel,font-family="Verdana, cursive" font-family="'Times New Roman', Georgia, Serif, monospace"
|
font
|
Diese Eigenschaft legt alle Schrifteigenschaften in einer Deklaration fest. Die Eigenschaften , die eingestellt werden können , sind (in dieser Reihenfolge) font-style font-variant font-weight font-size font-family Zum Beispiel "italic small-caps bold 12px arial, sans-serif" ,
|
3.3 HTML5-Dateivorlagen
Beachten Sie, dass es einige neue Regeln für den Wechsel von HTML4 zu HTML5 gibt:
Die
doctype
Erklärung wurde erneut vereinfacht. Die langen und schwer zu merkenden Erklärungen gehören der Vergangenheit an: Just<!DOCTYPE html>
genügt.
Die verschiedenen Versionen für die
type
von<script>
Tags sind weg. Dastype="text/javascript"
Attribut muss nicht mehr hinzugefügt werden. Dies ist jetzt die angenommene Standardeinstellung. Gerade<script> // ... JavaScript code ... </script>
ist ausreichend für Skript-Tags.
Im Folgenden werden einige Vorlagen für HTML5-Dateien aufgelistet und erläutert, die Canvas-Elemente enthalten. Alle diese Beispiele erzeugen dieselbe Browseransicht, nämlich:

Der Unterschied liegt darunter in der Organisation des HTML- und JavaScript-Codes.
Der Text mit einem Kreis und einem Quadrat wird beispielsweise von der folgenden HTML-Datei generiert example.html
<!DOCTYPE html>
<html>
<head>
<title> First Example </title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style type="text/css">
canvas { border: solid 1pt blue; } /* draws a blue frame around each <canvas>...</canvas> tag */
</style>
</head>
<body>
A red circle
<canvas id="CanvasNo1" width=50 height=50> </canvas>
<script>
var canvas1 = document.getElementById('CanvasNo1');
var context1 = canvas1.getContext('2d');
context1.fillStyle = 'red';
context1.beginPath();
context1.arc (25,25,15,0,2*Math.PI);
context1.fill();
</script>
and a green square
<canvas id="CanvasNo2" width=50 height=50> </canvas>
<script>
var canvas2 = document.getElementById('CanvasNo2');
var context2 = canvas2.getContext('2d');
context2.fillStyle='green';
context2.fillRect (10,10,30,30);
</script>
and nothing else.
</body>
</html>
In dieser Datei haben wir die Methode aus der Einführung verwendet (siehe Ein erstes Beispiel und Grundeinstellung ): Für jede Zeichenfläche platzieren wir ein <canvas>...</canvas>
Tag mit einem separaten id
Attribut, gefolgt von a<script>...</script>
, in dem die Zeichenfläche weiterentwickelt wird.
Diese Methode reicht für einfache Bilder und kleine Dateien aus. Wenn die Bilder jedoch komplexer werden und externe Bild- oder Mediendateien betroffen sind, funktioniert dies nicht mehr und stattdessen werden leere Leinwandbilder angezeigt. Im Allgemeinen ist es daher kein guter Rat, Ihre Dateien so zu organisieren.
Übrigens , je nach Art des Codes gibt es unterschiedliche Syntaxregeln für Kommentare :
In HTML wird ein Kommentar
...
in a eingefügt<!-- ... -->
In CSS wird ein Kommentar
...
in a eingefügt/* ... */
In JavaScript ist ein Kommentar alles nach einem
//
in der angegebenen Zeile.
Alternativ gibt es auch den Blockkommentar/* ... */
wie in CSS.
Wenn wir uns mit nicht trivialen Projekten befassen, ist es eine gute Gewohnheit, Stil von Inhalt zu unterscheiden und die verschiedenen Codes in separate Dateien zu platzieren. In unserem Fall sind dies drei:
example.html
Daraus wird eine HTML5-Datei namens erstellt<!DOCTYPE html> <html> <head> <title> Second Example </title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="example.css" /> <script src="example.js"> </script> </head> <body> A red circle <canvas id="CanvasNo1" width=50 height=50> </canvas> and a green square <canvas id="CanvasNo2" width=50 height=50> </canvas> and nothing else. </body> </html>
eine aufgerufene CSS-Datei
example.css
, die enthältcanvas { border: solid 1pt blue; /* draws a blue frame around each <canvas>...</canvas> tag */ }
eine JavaScript-Datei namens
example.js
, die enthält// First canvas with the red circle var canvas1 = document.getElementById('CanvasNo1'); var context1 = canvas1.getContext('2d'); context1.fillStyle = 'red'; context1.beginPath(); context1.arc (25,25,15,0,2*Math.PI); context1.fill(); // Second canvas with the green square var canvas2 = document.getElementById('CanvasNo2'); var context2 = canvas2.getContext('2d'); context2.fillStyle='green'; context2.fillRect (10,10,30,30);
Die Haupt-HTML-Datei enthält den Inhalt und definiert die Organisation der gesamten Seite. Die CSS-Datei legt die nicht standardmäßigen Stilfunktionen fest und wird über integriert
<link rel="stylesheet" type="text/css" href="example.css" />
Anweisung. Das JavaScript enthält schließlich die Zeichnungen für die beiden Canvas-Elemente und wird über integriert
<script src="example.js"> </script>
Diese Trennung der Komponenten wird normalerweise als besseres Design angesehen.
Ist dies jedoch Mode, funktioniert es nicht! Anstelle des vorherigen Bildes mit Kreis und Quadrat sehen wir dies

im Browser. Es wird nur der CSS-Rand der Canvas-Elemente angezeigt, ohne dass die von JavaScript generierten Bildelemente vorhanden sind.
Wenn der Browser beginnt, die HTML-Datei zu lesen, lädt er die CSS- und JavaScript-Datei, wie im <head>...</head>
Abschnitt gefordert , und generiert dann die<body>...</body>
Abschnitt mit den beiden Canvas-Elementen weiter. In dieser Ausführungsreihenfolge wird der JavaScript-Code ausgeführt, bevor die Canvas-Elemente vorhanden sind, und dies schlägt fehl. Die Leinwandbilder bleiben leer.
Es gibt verschiedene Strategien, um dieses Problem zu lösen:
js
Dateien indefer
Modus
In der vorherigen HTML-Datei example.html
können wir die Zeile ersetzen
<script src="example.js"> </script>
durch
<script src="example.js" defer> </script>
dh wir fügen das defer
Attribut dem <script>
Tag hinzu. Auf diese Weise wird die Ausführung der JavaScript-Datei example.js
verzögert, bis zuerst die gesamte HTML-Datei geladen wird. Mit dieser Änderung erhalten wir das beabsichtigte Browserbild

nochmal.
onload
Zum <body>
Tag
hinzufügenDie Reihenfolge, in der verschiedene Codetypen ausgeführt werden, kann auch von JavaScript selbst beeinflusst werden. Alle Leinwandzeichnungen in JavaScript sind jetzt in einer Funktion mit dem Namen eingeschlossen draw()
. Außerdem wird dem Body ein Ereignis-Listener hinzugefügt, der sicherstellt, dass er draw()
nur ausgeführt wird onload
, dh wenn der HTML-Code im Body zuerst vollständig geladen ist. Die drei Dateien sind jetzt gegeben durch
example.html
ist<!DOCTYPE html> <html> <head> <title> Another Example </title> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <link rel="stylesheet" type="text/css" href="example.css" /> <script src="example.js"> </script> </head> <body onload=draw()> A red circle <canvas id="CanvasNo1" width=50 height=50> </canvas> and a green square <canvas id="CanvasNo2" width=50 height=50> </canvas> and nothing else. </body> </html>
Beachten Sie das neue
onload
Attribut im<body>
Tag.example.css
ist unverändert und enthält nochcanvas { border: solid 1pt blue; /* draws a blue frame around each <canvas>...</canvas> tag */ }
example.js
hat jetzt den gesamten vorherigen Inhalt in eine Funktionsdeklaration eingeschlossen:function draw() { // First canvas with the red circle var canvas1 = document.getElementById('CanvasNo1'); var context1 = canvas1.getContext('2d'); context1.fillStyle = 'red'; context1.beginPath(); context1.arc (25,25,15,0,2*Math.PI); context1.fill(); // Second canvas with the green square var canvas2 = document.getElementById('CanvasNo2'); var context2 = canvas2.getContext('2d'); context2.fillStyle='green'; context2.fillRect (10,10,30,30); };
window.onload
Als letzte Variation der vorherigen Vorlage können wir auch das gesamte JavaScript wieder aus der html
Datei entfernen und den Ereignis-Listener zur js
Datei hinzufügen . Der zugrunde liegende Mechanismus ist immer noch der gleiche, aber die Codierung ist unterschiedlich. Dies beinhaltet die folgenden Änderungen der vorherigen Dateilisten:
example.html
Jetzt wird dasonload
Attribut wieder aus dem<body>
Tag entfernt .example.js
hat eine zusätzliche Zeile, nämlichwindow.onload = draw;
Es spielt keine Rolle, wo wir diese Zeile in die Datei einfügen, weder vor noch nach der
draw()
Funktionsdeklaration.
Die letzten Vorlagen stellen sehr häufig die allgemein empfohlenen Methoden dar, wie Canvas-Elemente in Webseiten integriert werden sollen. Jede dieser Methoden kann noch verfeinert werden, indem die Fehlererkennung erhöht wird. Sowohl Browser als auch JavaScript sind ursprünglich so konzipiert, dass sie in dem Sinne "elegant degradieren", dass sie versuchen, den Zusammenbruch von Dingen zu vermeiden, aber dazu neigen, so viel wie möglich zu verarbeiten. Der Browser, der <canvas>
Tags nicht versteht, zeigt den Fallback (den Text ...
im <canvas>...</canvas>
) an, anstatt eine große Fehlermeldung auf dem gesamten Bildschirm zu drucken. Und wenn eine Variable in JavaScript nicht definiert ist, protestiert das Skript nicht im Browserfenster, sondern versucht, mit einem undefined
Wert für die Variable fortzufahren .
Der Preis für dieses fehlerverzeihende Design ist die Schwierigkeit, den Ursprung von Problemen zu lokalisieren, sobald sie aufgetreten sind. Und je professioneller die Programmierung, desto strenger und weniger fehlerverzeihend die Programmabläufe und desto mehr Fehlererkennungen sind eingebaut.
Für den HTML-Teil bedeutet dies, dass normalerweise ein Fallback-Text wie z
<canvas> HERE SHOULD BE THE CANVAS PICTURE, BUT YOUR BROWSER IS UNABLE TO RENDER IT! <canvas>
Für den JavaScript-Teil umfasst dies die Modularisierung von Code in separate Teile und eine gründliche Überprüfung der Richtigkeit von Variablen und Objekten.
Zum Beispiel können wir die draw()
Funktion für jedes vorkommende Canvas-Element in drawCanvas1()
und aufteilen drawCanvas2()
. Und anstatt zu schreiben, sagen Sie
function drawCanvas2() {
var canvas = document.getElementById('CanvasNo2');
var context = canvas.getContext('2d');
context.fillStyle='green';
context.fillRect (10,10,30,30);
};
Wir können solche Überprüfungen einbauen
function drawCanvas2() {
var canvas = document.getElementById('CanvasNo2');
if (canvas) {
var context = canvas.getContext('2d');
if (context) {
context.fillStyle='green';
context.fillRect (10,10,30,30);
} else {
throw Error ("The 2D context is undefined.");
}
} else {
throw Error ("There is no HTML element with the id='CanvasNo2'.");
};
};
Anstelle von ziemlich stillen Fehlermeldungen können wir auch Popup-Fenster alarmieren lassen: Ersetzen Sie einfach jedes
throw Error ("...");
durch
alert ("...");
3.4 Werkzeuge und Werkzeugbau
3.4.1 Wie schreibe ich eigene Funktionen wie strokeCircle()
undfillCircle()
In JavaScript ist es recht einfach, das Toolset für den Canvas- und 2D-Kontext nach Belieben durch Schreiben von Funktionen zu erweitern. Angenommen, wir möchten Funktionen schreiben, die Kreise erstellen, die dem Weg fillRect()
und sehr ähnlich sindstrokeRect()
zum Erstellen von Rechtecken funktionieren.
Diese Funktionen sollten zwei Zahlenargumente x
und y
für die Position des Kreismittelpunkts und habenr
für den Radius haben.
Die erste Version unserer Implementierung ist diese
function fillCircle (contextObj,x,y,r) {
contextObj.beginPath();
contextObj.arc (x,y,r,0,2*Math.PI);
contextObj.fill();
};
Dies bedeutet, dass die Syntax eines Funktionsaufrufs lautet
`fillCircle (contextObj, x, y, r)`
Wo contextObj
ist ein CanvasRenderingContext2D
Objekt? Also, um ein Bild mit einer grünen Kugel wie dieser zu erzeugen
Sie müssten einen Code wie diesen schreiben
<canvas id="FillCircleTest1" width=60 height=60> </canvas>
<script>
var context = document.getElementById('FillCircleTest1').getContext('2d');
context.fillStyle = 'green';
fillCircle(context,30,30,20);
</script>
Alternativ können wir die Funktionssyntax in ändern
`fillCircle (canvasId, x, y, r)`
Wo canvasId
ist der Wert des id
Attributs im entsprechenden <canvas>
Tag? Dies wird implementiert von
function fillCircle (canvasId,x,y,r) {
var context = document.getElementById (canvasId).getContext('2d');
context.beginPath();
context.arc (x,y,r,0,2*Math.PI);
context.fill();
};
Auf diese Weise könnten wir einfach schreiben
<canvas id="FillCircleTest2" width=60 height=60> </canvas>
<script>
fillCircle('FillCircleTest2',30,30,20);
</script>
um dieses Bild zu erzeugen
Da diese Version jedoch den Kontext ausschließt und der Kontext das Objekt ist, das Sie benötigen, wenn Sie beispielsweise die Farbe ändern möchten.
Wenn wir unsere Funktionen nach dem objektorientierten Design des Kontexts erstellen möchten, möchten wir den Kontext lieber nicht als Funktionsargument haben (wie in der ersten Version), sondern fillCircle()
sollten eine Methode für den 2d-Kontext sein, damit wir können es so nennen
context.fillCircle (x, y, r)
Dafür müssten wir das Methodenrepertoire des CanvasRenderingContext2D
Objekts erweitern. Tatsächlich ist dies in JavaScript möglich, indem das Prototypendesign verwendet wird. Die Implementierung wäre also so
CanvasRenderingContext2D.prototype.fillCircle = function (x,y,r) {
this.beginPath();
this.arc (x,y,r,0,2*Math.PI);
this.fill();
}
Jetzt erstellen wir dieses Leinwandbild
indem Sie diesen Code schreiben
<canvas id="FillCircleTest3" width=60 height=60> </canvas>
<script>
var context = document.getElementById('FillCircleTest3').getContext('2d');
context.fillStyle = 'purple';
context.fillCircle (30,30,20);
</script>
Die strokeCircle()
Implementierung auf diese Weise ist dann offensichtlich
CanvasRenderingContext2D.prototype.strokeCircle = function (x,y,r) {
this.beginPath();
this.arc (x,y,r,0,2*Math.PI);
this.stroke();
}
Diese dritte prototypbasierte Implementierung kommt dem ursprünglichen Stil wahrscheinlich am nächsten. 30
3.4.2 addGrid(delta,color,font)
CanvasRenderingContext2D.addGrid (delta, color, font)
Zeichnet ein Koordinatengitter auf der angegebenen Leinwand. Es hat drei Parameter:
delta
ist der Abstand der Linien im Raster, angegeben als Anzahl der Pixel, mit einem Standardwert von25
.color
ist eine CSS-Farbzeichenfolge , die die Farbe des Rasters und die Zahlenkoordinaten festlegt. Die Standardfarbe ist'blue'
.font
ist eine CSS-Schriftzeichenfolge zum Bestimmen der Schriftart der Zahlenkoordinaten. Der Standardwert für die Schriftart ist'8px sans-serif'
.Jeder der Parameter ist optional, Sie können anrufen
addGrid()
,addGrid(delta)
,addGrid(delta,color)
oderaddGrid(delta,color,font)
.
Beispiel: Auf einer Leinwand mit Standardgröße ( 300
x 150
)
addGrid()
verwendet die Standardeinstellungen und erzeugt
addGrid(50,'red')
ist
addGrid(20,'black','5px sans-serif')
ist das
addGrid()
Wenn Sie die addGrid()
Methode in Ihren eigenen Skripten verwenden möchten , kopieren Sie die folgende Implementierung der Funktion in Ihre eigene Datei.
CanvasRenderingContext2D.prototype.addGrid = function (delta, color, fontParams) {
// define the default values for the optional arguments
if (! arguments[0]) { delta = 25; }
if (! arguments[1]) { color = 'blue'; }
if (! arguments[2]) { fontParams = '8px sans-serif'; }
// extend the canvas width and height by delta
var oldWidth = this.canvas.width;
var oldHeight = this.canvas.height;
this.canvas.width = oldWidth + delta;
this.canvas.height = oldHeight + delta;
// draw the vertical and horizontal lines
this.lineWidth = 0.1;
this.strokeStyle = color;
this.font = fontParams;
this.beginPath();
for (var i = 0; i * delta < oldWidth; i ++) {
this.moveTo (i * delta, 0);
this.lineTo (i * delta, oldHeight);
}
for (var j = 0; j * delta < oldHeight; j ++) {
this.moveTo (0, j * delta);
this.lineTo (oldWidth, j * delta);
}
this.closePath();
this.stroke();
// draw a thicker line, which is the border of the original canvas
this.lineWidth = 0.5;
this.beginPath();
this.moveTo(0,0);
this.lineTo(oldWidth,0);
this.lineTo(oldWidth,oldHeight);
this.lineTo(0,oldHeight);
this.lineTo(0,0);
this.closePath();
this.stroke();
// set the text parameters and write the number values to the vertical and horizontal lines
this.font = fontParams
this.lineWidth = 0.3;
// 1. writing the numbers to the x axis
var textY = oldHeight + Math.floor(delta/2); // y-coordinate for the number strings
for (var i = 0; i * delta <= oldWidth; i ++) {
this.strokeText (i * delta, i * delta, textY);
}
// 2. writing the numbers to the y axis
var textX = oldWidth + 5; // x-coordinate for the number strings
for (var j = 0; j * delta <= oldHeight; j ++) {
this.strokeText (j * delta, textX, j * delta);
}
};
[HOME]
/handbuch/index.php?ordner=handbuch&name=CanvasHandbook.php
?[FORUM]
http://www-bucephalus-org.blogspot.nl/2013/09/the-html5-canvas-handbook.html
?Diese endgültige HTML-Datei CanvasHandbook.html wird aus den folgenden Quelldateien generiert:
CanvasHandbook.markdown enthält den Quelltext für das HTML-Dokument. Die Konvertierung in HTML erfolgt mit Pandoc .
CanvasHandbook.js enthält die Werkzeugfunktionen (z. B.
addGrid()
) und die Skripte für die Canvas-Elemente. Dieser Code wird gemäß der im Anhang beschriebenen Methode in das Hauptdokument integriert .
Ich habe auch den CodeDown- Dokumentgenerator verwendet, um diejs
Datei in eine besser lesbare Dokumentdatei CanvasHandbook.js.html zu konvertieren , die selbst aus einer Markdown-Zwischendatei CanvasHandbook.js.markdown generiert wurde .Zwei CSS-Dateien: das Standard- Stylesheet CodeDown.css und CodeDownPrint.css zum Drucken der Datei mit einer kleineren Schriftart.
Bilddateien: Horse.jpg , Grayhorse.jpg , Baselines.png , TemplateCircleAndSquare.png und TemplateCircleAndSquare2.png . Alle anderen Bilder im Browser werden durch
<canvas>
Tags und JavaScript generiert .
[W3C]
http://www.w3.org/TR/2009/WD-html5-20090825/the-canvas-element.html
?[WHATWG]
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#the-canvas-element
?[W3C / 2D]
http://dev.w3.org/html5/2dcontext
?Wenn Sie die Meldung "Hallo" nicht sehen oder "GO AND UPDATE YOUR BROWSER BEVOR SIE LESEN!" Lesen. Stattdessen sollten Sie diesen Rat wirklich befolgen. Andernfalls wird keines der Bilder in diesem Handbuch richtig angezeigt und der gesamte Text macht keinen Sinn. ?
Was Sie im
<script>...</script>
Tag sehen, ist nicht HTML, sondern JavaScript-Code, und das hat eine andere Syntax. Ein wichtiges Merkmal ist der Kommentar , eine Information, die in den Programmcode eingefügt wird und nur als Hilfe zum Verständnis und zur Pflege des Codes gedacht ist. Ein Kommentar dient nur dem menschlichen Leser des Codes und wird vom Computerprogramm, in diesem Fall der JavaScript-Engine des Browsers, ignoriert.
Der gesamte Text in einer Zeile nach einem doppelten Schrägstrich "//
" ist ein Kommentar in JavaScript. Im angegebenen Beispiel ist "// identify the canvas element
" ein Kommentar und erklärt, was der vom "//
" übrig gebliebene Code bewirkt. Wir werden Kommentare in all unseren JavaScript-Codebeispielen stark nutzen. ?Sie kennen wahrscheinlich das DOM (Document Object Model). Jedes Webdokument wird zunächst als HTML-Datei angegeben. Wenn dieser HTML-Code geladen wird, übersetzt der Browser das Dokument in ein hierarchisches JavaScript-Baumobjekt. Jedes Element des HTML-Codes wird in diesem Baum als Knotenobjekt dargestellt. Auf die Wurzel dieses Baums wird über das vordefinierte
document
Schlüsselwort zugegriffen . Auf jeden Elementknoten in diesem Baum, der einem Tag mit einem entspricht,id
wird dann durch einen Aufruf von zugegriffendocument.getElementById('...')
. Alternativ können wir auch das Array allerHTMLCanvasElement
Objekte in einem Dokument durch Aufrufen abrufendocument.getElementsByTagName('canvas')
. Dies werden wir in unserem Text hier jedoch nicht verwenden.?In JavaScript wird eine Zeichenfolge entweder in einfache
'...'
oder doppelte Anführungszeichen eingeschlossen"..."
. Zum Beispiel'Hello world!'
und"Hello world!"
beide bezeichnen dieselbe Zeichenfolge. Es gibt subtile Unterschiede zwischen diesen beiden Versionen, aber im Moment können wir diese Details vernachlässigen. Sodocument.getElementById('Example1')
unddocument.getElementById("Example1")
haben die gleiche Wirkung und Sie können zwischen diesen beiden Versionen frei wählen. ?Beachten Sie, dass die Richtung der y-Achse in kartesischen Koordinatensystemen wirklich der Standardrichtung entgegengesetzt ist ! ?
Tatsächlich ist der gezeichnete rote Punkt nicht nur 1 Pixel groß, sondern hat einen Radius von 4 Pixel. Andernfalls ist es möglicherweise zu schwer zu erkennen. ?
Es ist jedoch möglich, das gesamte Koordinatensystem auf der Leinwand so zu verschieben, dass z. B. der Ursprung
(0,0)
nicht mehr die linke obere Ecke ist, sondern sich in die Mitte bewegt und Punkte wie(-60,50)
jetzt Teil des Bildes werden. Dies kann mit Transformationen wietranslate(x,y)
. ?Die sechs Linien, die die drei farbigen Rechtecke zeichnen, werden gemäß unserer vorherigen Vorlage in diesen Code eingeschlossen:
?<canvas id="GermanFlag" width=200 height=120> </canvas> <script> // get the canvas object and its context var canvas = document.getElementById('GermanFlag'); var context = canvas.getContext('2d'); // add the grid with 40 pixels for each step to the next line (see the appendix on this addGrid() method context.addGrid(40); // THIS IS NOT A STANDARD METHOD!!! // now draw the colored rectangles // now draw the colored rectangles context.fillStyle = '#000000'; context.fillRect(0, 0,200,40); context.fillStyle = '#FF0000'; context.fillRect(0,40,200,40); context.fillStyle = '#FFCC00'; context.fillRect(0,80,200,40); </script>
Diese Idee der anklickbaren Zeichenfläche wurde in html5doctor.com vorgeschlagen . ?
Die
transform()
Methode ist jedoch nicht in der Lage, eine (topologische) Transformation im allgemeinen geometrischen Sinne durchzuführen, sondern nur eine sogenannte affine Transformation . Beispielsweise kann keine Fischaugenperspektive erzeugt werden , da bei affinen Transformationen gerade und parallele Linien gerade bzw. parallel bleiben müssen. Es ist jedoch möglich, topologische Transformationen unter Verwendung der Pixelmanipulationen zu implementieren , aber das ist ein anderer Ansatz. ?Mit der im Anhang beschriebenen Methode können wir
shear()
demCanvasRenderingContext2D
Objekt wie folgt eine neue Methode hinzufügen :CanvasRenderingContext2D.prototype.shear = function (x,y) { this.transform (1, y, x, 1, 0, 0); };
Ich habe die Idee und Definition der
shear()
Methode von David Flanagan , Canvas Pocket Reference, übernommen . ?- Es ist hier nicht wichtig, die genaue Datenstruktur für dieses Sechstel anzugeben
(a,b,c,d,e,f)
. Es kann als Array angegeben werden[a,b,c,d,e,f]
. In [WHATWG] wurde dies alsSVGMatrix
Objekt gespeichert . Für die Berechnung von Transformationszusammensetzungen ist es zweckmäßig, sie als 3x2- Matrix des Formulars zu speicherna
c
e
b
d
f
0
0
1
denn die Zusammensetzung ist dann nichts als eine Matrixmultiplikation . ?
- Die Definition der Zusammensetzung
?
lautet wie folgt:
Gegeben und dann(a1,b1,c1,d1,e1,f1)
(a2,b2,c2,d2,e2,f2)
(a1,b1,c1,d1,e1,f1)?(a2,b2,c2,d2,e2,f2)
=(a3,b3,c3,d3,e3,f3)
a3 = (a2 * a1) + (c2 * b1)
b3 = (b2 * a1) + (d2 * b1)
c3 = (a2 * c1) + (c2 * d1)
d3 = (b2 * c1) + (d2 * d1)
e3 = (a2 * e1) + (c2 * f1) + e2
b3 = (b2 * e1) + (d2 * f1) + f2
a2
c2
e2
b2
d2
f2
0
0
1
? a1
c1
e1
b1
d1
f1
0
0
1
= a3
c3
e3
b3
d3
f3
0
0
1
Beachten Sie, dass dies bedeutet, dass zuerst und dann ausgeführt wird. Bei der Matrixmultiplikation ist diese Reihenfolge umgekehrt: Die Matrix von wird mit der Matrix von multipliziert , nicht umgekehrt. (Zusammensetzung und Matrixmultiplikation sind nicht kommutativ . Sie sind jedoch assoziativ , dh = .) Wir können dies auch als JavaScript-Funktion implementieren: Geben Sie zwei Arrays an und geben Sie dann deren Zusammensetzung zurück .
?1??2
?1
?2
?2
?1
(?1??2)??3
?1?(?2??3)
arr1=[a1,b1,c1,d1,e1,f1]
arr2=[a2,b2,c2,d2,e2,f2]
composeTransform(arr1,arr2)
[a3,b3,c3,d3,e3,f3]
function composeTransform (arr1, arr2) { if (Array.isArray (arr1) && Array.isArray (arr2)) { if (arr1.length === 6 && arr2.length === 6) { // components of arr1 var a1 = arr1[0]; var b1 = arr1[1]; var c1 = arr1[2]; var d1 = arr1[3]; var e1 = arr1[4]; var f1 = arr1[5]; // components of arr2 var a2 = arr2[0]; var b2 = arr2[1]; var c2 = arr2[2]; var d2 = arr2[3]; var e2 = arr2[4]; var f2 = arr2[5]; // components of the resulting array var a3 = (a2 * a1) + (c2 * b1); var b3 = (b2 * a1) + (d2 * b1); var c3 = (a2 * c1) + (c2 * d1); var d3 = (b2 * c1) + (d2 * d1); var e3 = (a2 * e1) + (c2 * f1) + e2; var f3 = (b2 * e1) + (d2 * f1) + f2; return [a3, b3, c3, d3, e3, f3]; } else { throw Error ("The two array arguments of composeTransform(arr1,arr2) must both have six components each."); } } else { throw Error ("The two arguments of composeTransform(arr1,arr2) must both be arrays."); } };
Falls die Argumente
arr1
undarr2
nicht beide Arrays der Länge 6 sind, wird eine Fehlermeldung ausgegeben. ? Wie bereits erwähnt, waren in dieser Norm die Parameter
(a,b,c,d,e,f)
voncurrentTransform
einSVGMatrix
Objekt. ?- Die Definition der Zusammensetzung
?
lautet wie folgt:
Gegeben und dann(a1,b1,c1,d1,e1,f1)
(a2,b2,c2,d2,e2,f2)
(a1,b1,c1,d1,e1,f1)?(a2,b2,c2,d2,e2,f2)
=(a3,b3,c3,d3,e3,f3)
a3 = (a2 * a1) + (c2 * b1)
b3 = (b2 * a1) + (d2 * b1)
c3 = (a2 * c1) + (c2 * d1)
d3 = (b2 * c1) + (d2 * d1)
e3 = (a2 * e1) + (c2 * f1) + e2
b3 = (b2 * e1) + (d2 * f1) + f2
a2
c2
e2
b2
d2
f2
0
0
1
? a1
c1
e1
b1
d1
f1
0
0
1
= a3
c3
e3
b3
d3
f3
0
0
1
Beachten Sie, dass dies bedeutet, dass zuerst und dann ausgeführt wird. Bei der Matrixmultiplikation ist diese Reihenfolge umgekehrt: Die Matrix von wird mit der Matrix von multipliziert , nicht umgekehrt. (Zusammensetzung und Matrixmultiplikation sind nicht kommutativ . Sie sind jedoch assoziativ , dh = .) Wir können dies auch als JavaScript-Funktion implementieren: Geben Sie zwei Arrays an und geben Sie dann deren Zusammensetzung zurück .
?1??2
?1
?2
?2
?1
(?1??2)??3
?1?(?2??3)
arr1=[a1,b1,c1,d1,e1,f1]
arr2=[a2,b2,c2,d2,e2,f2]
composeTransform(arr1,arr2)
[a3,b3,c3,d3,e3,f3]
function composeTransform (arr1, arr2) { if (Array.isArray (arr1) && Array.isArray (arr2)) { if (arr1.length === 6 && arr2.length === 6) { // components of arr1 var a1 = arr1[0]; var b1 = arr1[1]; var c1 = arr1[2]; var d1 = arr1[3]; var e1 = arr1[4]; var f1 = arr1[5]; // components of arr2 var a2 = arr2[0]; var b2 = arr2[1]; var c2 = arr2[2]; var d2 = arr2[3]; var e2 = arr2[4]; var f2 = arr2[5]; // components of the resulting array var a3 = (a2 * a1) + (c2 * b1); var b3 = (b2 * a1) + (d2 * b1); var c3 = (a2 * c1) + (c2 * d1); var d3 = (b2 * c1) + (d2 * d1); var e3 = (a2 * e1) + (c2 * f1) + e2; var f3 = (b2 * e1) + (d2 * f1) + f2; return [a3, b3, c3, d3, e3, f3]; } else { throw Error ("The two array arguments of composeTransform(arr1,arr2) must both have six components each."); } } else { throw Error ("The two arguments of composeTransform(arr1,arr2) must both be arrays."); } };
Falls die Argumente
arr1
undarr2
nicht beide Arrays der Länge 6 sind, wird eine Fehlermeldung ausgegeben. Auch hier können wir die beiden Transformationen und Codezeilen kombinieren
durch Ausführen der Komposition zu einer einzigencontext.scale(-1,1); // same as context.transform(-1,0,0,1,0,0); context.translate(-300,0); // same as context.transform(1,0,0,1,-300,0);
(-1,0,0,1,0,0) ? (1,0,0,1,-300,0)
=(-1,0,0,1,-300,0)
Natürlich hätten wir den Pfad auch selbst schließen können, indem wir die
closePath()
Zeile im Code durch die alternative Zeile ersetzt hättencontext.lineTo(150,25); // line from left bottom back to the initial top point
Das resultierende Bild ist jedoch nicht immer genau das gleiche, da Anfang und Ende der Zeile möglicherweise nicht richtig zusammengeführt werden. ?
Bevor wir den
stroke()
Anruf hinzugefügt haben , haben wirlineWidth
auf2.0
undstrokeStyle
auf gesetzt'red'
. ?Tatsächlich ist das Ergebnis für
closePath()
und a nicht genau dasselbelineTo(x0,y0)
(wobei(x0,y0)
dies der Anfangspunkt des Pfades ist). Bei der letzteren Methode treffen sich zwei Zeilenenden, und ihre Endungen werden wie durch definiert definiertlineCap
. Ein ordnungsgemäßerclosePath()
Aufruf hingegen verbindet die beiden durch dielineJoin
Eigenschaft definierten Endungen . ?Die [WHATWG] -Spezifikation hatte eine separate
ellipse()
Methode, die jedoch im [W3C] -Standard verschwunden ist . Die Form, die wir hier mit vierquadraticCurveTo()
Aufrufen entwickeln, ist keine Ellipse im engeren mathematischen Sinne. In vielen praktischen Situationen reicht dies jedoch wahrscheinlich aus. ?Dieses Beispiel wurde von dem Beispiel im Canvas-Tutorial des Mozilla Development Network inspiriert . ?
Das Einfügen von Bildern mit
drawImage()
wird unter Zeichnen von Bildern ? erläutertDie Standardliteratur verwendet die Variablen
dx
,dy
,dw
,dh
,sx
,sy
,sw
,sh
. Es kann hilfreich sein, wenn Sie wie gewohnt "d
" als Ziel , "s
" als Quelle und "x
", "y
", "w
" und "h
" als Punktkoordinaten, Breite und Höhe lesen . ?Angenommen, Sie mögen die objektorientierte, prototypbasierte oder prozedurale Programmierung nicht und bevorzugen stattdessen einen rein funktionalen Stil. In diesem Fall würden wir uns eine Funktion
fillCircle()
vorstellen, die ein Kreisobjekt zurückgibt, wenn es aufgerufen wird. Die [WHATWG] hatte einPath
Objekt, das Formen im Allgemeinen abdeckte, sodassfillCircle()
einPath
Objekt zurückgegeben werden konnte. Aber in der "Evolution" zum [W3] -Standard wurden einige Konzepte, einschließlichPath
, weggeschnitten, und die von mir getesteten Browser verbergen den Zugriff auf all dies. ?