Fabric.js – Einführung in die mächtige JavaScript-Library
Dieser Artikel stellt Fabric.js vor – eine mächtige JavaScript-Library, die den Umgang mit dem HTML5-Element <canvas> zum Kinderspiel macht. Fabric stellt ein fehlendes Objektmodell zur Verfügung, sowie einen SVG Parser, eine Ebene für Interaktivität und eine ganze Suite voller unverzichtbarer Werkzeuge. Es ist ein Open-Source-Projekt unter der MIT-Lizenz, zu welchem über Jahre hinweg viel beigetragen wurde.
Ich habe vor drei Jahren angefangen, Fabric zu entwickeln, da mir die Arbeit mit der nativen Canvas-API viel zu kompliziert war. Ich erstellte einen interaktiven Design-Editor für die Website meines Startup-Unternehmens printio.ru, über die sich Kunden ihre eigene Kleidung gestalten können. Damals gab es die Art von Interaktivität, die ich mir vorstellte, nur in Flash-Anwendungen. Heutzutage allerdings gibt es nur sehr wenige Libraries, die auch nur annähernd an das herankommen, was mit Fabric möglich ist.
Warum Fabric?
Mit Canvas kann man heute absolut beeindruckende Grafiken im Web erstellen, aber die API, die dafür zur Verfügung steht, arbeitet auf einer enttäuschend niedrigen Ebene. Wenn man nur ein paar Grundformen auf eine Fläche zeichnen will und sie danach nicht mehr anfassen muss, ist das eine Sache. Braucht ihr aber auch nur die geringste Interaktivität, wollt ihr ein Bild zu einem späteren Zeitpunkt ändern oder müsst ihr komplexere Formen zeichnen, dann erhöht sich der Arbeitsaufwand erheblich. Fabric soll dieses Problem lösen.
Native Canvas-Methoden erlauben euch lediglich, einfache grafische Befehle abzusetzen und damit quasi im Blindflug die ganze Canvas-Bitmap zu verändern. Wollt ihr ein Rechteck? Dann schreibt ihr fillRect(left, top, width, height). Wollt ihr eine Linie? Dann verwendet ihr eine Kombination aus moveTo(left, top) und lineTo(x,y). Es ist gerade so, als ob ihr mit einem Pinsel Schicht für Schicht immer mehr Öl- und Acrylfarbe auftragt, jedoch mit sehr wenig Kontrolle.
Anstatt auf so niedriger Ebene zu arbeiten, bietet Fabric ein einfaches, aber gleichzeitig mächtiges Objektmodell an, das auf den nativen Methoden aufsetzt. Es kümmert sich um den Canvas-Zustand und das Rendern und lässt euch direkt mit den Objekten arbeiten.
Hier ist ein einfaches Beispiel, das den Unterschied demonstriert: Das folgende Codebeispiel zeigt, wie ein rotes Rechteck mittels nativer Canvas-API irgendwo auf den Canvas gezeichnet würde:
// Das Canvas-Element referenzieren (with id="c") var canvasEl = document.getElementById('c'); // Einen 2D-Kontext erstellen um darauf zu zeichnen (die vorhin erwhnte "Bitmap") var ctx = canvasEl.getContext('2d'); // Die Fllfarbe fr den Kontext setzen ctx.fillStyle = 'red'; // Ein geflltes Rechteck auf Position 100,100 Pixel, mit einer Ausdehnung von 20x20 Pixel erstellen. ctx.fillRect(100, 100, 20, 20);
Der untere Code zeigt euch, wie man genau das selbe mit Fabric erreicht. Das (identische) Ergebnis beider Herangehensweisen ist in Bild 1 gezeigt.
// Erstelle einen Wrapper um das native canvas-Element (with id="c") var canvas = new fabric.Canvas('c'); // erstelle ein Rectangle-Objekt var rect = new fabric.Rect({ left: 100, top: 100, fill: 'red', width: 20, height: 20 }); // das Rechteck auf den canvas "hinzufgen". canvas.add(rect);
In diesem Beispiel ist der Code noch annähernd gleich lang, ihr könnt aber schon sehen, wie unterschiedlich die Arbeit mit Fabric ist. Mit den nativen Methoden arbeitet ihr auf dem Kontext – einem Objekt, das für die gesamte Canvas-Bitmap steht. In Fabric dagegen arbeiten ihr an Objekten: Ihr definieren nur Instanzen, ändert deren Eigenschaften und fügt sie dem Canvas hinzu. Ihr seht schon, dass sich in der Fabric-Welt alles um diese Objekte dreht.
Ein schlichtes Rechteck zeichnen zu lassen, ist viel zu einfach. Macht es doch ein bisschen interessanter und dreht die Form ein wenig. Probieren wir mal 45 Grad, zuerst mit den nativen Canvas-Methoden:
var canvasEl = document.getElementById('c'); var ctx = canvasEl.getContext('2d'); ctx.fillStyle = 'red'; ctx.translate(100, 100); ctx.rotate(Math.PI / 180 * 45); ctx.fillRect(-10, -10, 20, 20);
Und so würdet ihr das mit Fabric machen. (Siehe Bild 2 für die grafische Ausgabe)
var canvas = new fabric.Canvas('c'); // create a rectangle with angle=45 var rect = new fabric.Rect({ left: 100, top: 100, fill: 'red', width: 20, height: 20, angle: 45 }); canvas.add(rect);
Lasst uns rekapitulieren: In Fabric müsst ihr lediglich den Wert des Objektwinkels auf 45 ändern. Mit den nativen Methoden ist da schon mehr Arbeit nötig. Denkt daran, dass ihr nicht mit Objekten arbeiten könnt. Stattdessen müsst ihr die Positionierung und den Winkel der gesamten Canvas-Bitmap (ctx.translate, ctx.rotate) euren Anforderungen anpassen. Erst dann zeichnet ihr das Rechteck. Vergesst dabei nicht, die Bitmap entsprechend zu versetzen (-10, -10), damit das gedrehte Rechteck immer noch am Punkt 100,100 gezeichnet wird. Damit es nicht zu langweilig wird, dürfen ihr beim Drehen der Canvas-Bitmap auch noch die Winkelgrade ins Bogenmaß umrechnen.
Sicher könnt ihr schon sehen, warum es Fabric gibt und wie viel nervigen, sich wiederholenden Low-Level-Kauderwelsch es einem spart.
Schauen wir uns noch ein Beispiel an: Verfolgung des Canvas-Zustands.
Was ist, wenn ihr irgendwann das Rechteck an eine andere Stelle auf dem Canvas verschieben wollt? Wie könntet ihr das tun, ohne mit Objekten zu arbeiten? Würdet ihr einfach einen weiteren fillRect-Befehl auf einer Canvas-Bitmap aufrufen? Bestimmt nicht. Ein neuer fillRect-Befehl legt ja einfach ein Rechteck über alles, was bereits auf dem Canvas gezeichnet wurde. Um das Rechteck zu verschieben, müsst ihr zuerst den ganzen vorher gezeichneten Inhalt löschen und dann das Rechteck an einer neuen Position zeichnen (siehe Bild 3).
var canvasEl = document.getElementById('c'); ... ctx.strokRect(100, 100, 20, 20); ... // gesamten Canvas lschen ctx.clearRect(0, 0, canvasEl.width, canvasEl.height); ctx.fillRect(20, 50, 20, 20);
Und so würden Sie das mit Fabric machen:
var canvas = new fabric.Canvas('c'); ... canvas.add(rect); ... rect.set({ left: 20, top: 50 }); canvas.renderAll();
Achtet auf folgenden wichtigen Unterschied: Mit Fabric müsst ihr nicht erst den Inhalt löschen, bevor ihr irgendeinen Inhalt ändert. Ihr arbeitet ja immernoch nur mit Objekten, deren Eigenschaften ihr einfach ändern könnt. Erst am Schluss lasst ihr den Canvas rendern, um ein neues Bild zu erhalten.
Objekte
Im obigen Kapitel habt ihr gesehen, wie man mit Rechtecken arbeitet, indem man Instanzen des fabric.Rect-Konstruktors erstellt. Fabric unterstützt natürlich auch noch andere Grundformen – Kreise, Dreiecke, Ellipsen und so weiter. Die Formen sind im Fabric-Namensraum als fabric.Circle, fabric.Triangle, fabric.Ellipse et cetera ansprechbar. Fabric stellt sieben Grundformen zur Verfügung:
- fabric.Circle
- fabric.Ellipse
- fabric.Line
- fabric.Polygon
- fabric.Polyline
- fabric.Rect
- fabric.Triangle
Um einen Kreis zu zeichnen, braucht ihr nur ein Kreis-Objekt erstellen und es zum Canvas hinzufügen.
var circle = new fabric.Circle({ radius: 20, fill: 'green', left: 100, top: 100 }); var triangle = new fabric.Triangle({ width: 20, height: 30, fill: 'blue', left: 50, top: 50 }); canvas.add(circle, triangle);
Auf die selbe Weise könnt ihr alle anderen Grundformen erstellen. Bild 4 zeigt ein Beispiel, bei dem ein grüner Kreis an Position 100,100 gezeichnet wird und ein blaues Dreieck auf Position 50,50.
Objekte manipulieren
Grafische Objekte wie Rechtecke oder Kreise zu erstellen, ist nur der Anfang. Irgendwann werden Sie wahrscheinlich Ihre Objekte verändern müssen. Vielleicht soll eine bestimmte Aktion eine Zustandsveränderung auslösen oder eine Art von Animation abspielen. Oder vielleicht wollen Sie die Objekteigenschaften, wie Farbe, Transparenz, Größe oder Position, auf irgendwelche Mausaktionen hin ändern.
Fabric übernimmt für euch das Rendern des Canvas‘ und die Verwaltung der Zustände. Wir müssen nur die Objekte selbst verändern. Das vorherige Beispiel verwendete die set-Methode und zeigte, wie das Aufrufen von set({ left: 20, top: 50 }) das Objekt von seiner ursprünglichen Position verschob. In einer ähnlichen Weise könnt ihr die Eigenschaften eines Objektes ändern.
Wie zu erwarten, haben Fabric-Objekte Eigenschaften für Positionierung (left, top), Größe (width, height), Rendern (fill, opacity, stroke, strokeWidth), Skalierung und Drehung (scaleX, scaleY, angle) und Spiegelung (flipX, flipY). Will man also ein Objekt spiegeln, muss man lediglich die flip*-Eigenschaft auf true setzen.
Ihr könnt alle diese Eigenschaften mit einer get-Methode auslesen und mit einer set-Methode setzen. Das folgende Beispiel zeigt euch, wie einige der Eigenschaften des roten Rechtecks verändert werden. Bild 5 veranschaulicht das Ergebnis.
var canvas = new fabric.Canvas('c'); ... canvas.add(rect); rect.set('fill', 'red'); rect.set({ strokeWidth: 5, stroke: 'rgba(100,200,200,0.5)' }); rect.set('angle', 15).set('flipY', true);
Zuerst setzen wir die Füllfarbe auf „red”. In der nächsten Zeile definieren wir Werte für strokeWidth und stroke, was dem Rechteck eine 5 Pixel breite Umrandung in einem Pastellgrün verleiht. Zum Schluss ändert der Code die Eigenschaften angle (Drehwinkel) und flipY (Spiegelung an der Y-Achse). Achtet darauf, dass alle drei Zeilen verschiedene Arten der Syntax demonstrieren.
Dies zeigt uns, dass set eine Universal-Methode ist. Ihr werden sie wahrscheinlich ziemlich oft verwenden und sie ist auch für ein einfaches Handhaben gedacht. Und was ist mit get-Methoden? Es gibt eine allgemeine get-Methode und auch ein paar spezifische get*-Methoden. Um die Breite eines Objekts auszulesen, würdet ihr get(‚width‘) oder getWidth() verwenden. Um den Wert für scaleX zu bekommen, könnt ihr get(’scaleX‘) oder getScaleX() verwenden, und so weiter. Es gibt eine Methode mit der selben Schreibweise wie getWidth oder getScaleX für jede der Objekteigenschaften, die „public” sind (stroke, strokeWidth, angle et cetera).
Ihr werdet vielleicht festgestellt haben, dass in den oberen Beispielen die Objekte gleich beim Erstellen des Objekts mit allen Eigenschaften konfiguriert, aber bei dem letzten Beispiel die Eigenschaften erst mit der set-Methode definiert wurden. Beides ist möglich und in seiner Wirkweise identisch. Ihr könnt ein Objekt entweder gleich beim Erstellen konfigurieren, oder erst nachher mit der set-Methode, wie ihr im folgenden Vergleich seht:
var rect = new fabric.Rect({ width: 10, height: 20, fill: '#f55', opacity: 0.7 }); // oder anders geschrieben, aber funktionell identisch. var rect = new fabric.Rect(); rect.set({ width: 10, height: 20, fill: '#f55', opacity: 0.7 });
Standardwerte
An diesem Punkt fragt ihr euch vielleicht, was passiert, wenn ihr ein Objekt erstellt, ohne ihm irgendein „Konfigurationsobjekt” zu übergeben. Hat es trotzdem diese Eigenschaften?
Ja. Wenn gewisse Einstellungen während der Erstellung weggelassen werden, haben Objekte in Fabric immer eine Reihe von voreingestellten Eigenschaften. Ihr könnt den folgenden Code benutzen, um das zu sehen:
var rect = new fabric.Rect(); // Beachten Sie: Keine Eigenschaften werden per Argument bergeben. rect.getWidth(); // 0 rect.getHeight(); // 0 rect.getLeft(); // 0 rect.getTop(); // 0 rect.getFill(); // rgb(0,0,0) rect.getStroke(); // null rect.getOpacity(); // 1
Dieses Rechteck (im Code-Beispiel oben) hat nur voreingestellte Werte für seine Eigenschaften. Es ist positioniert an der Stelle 0,0, ist schwarz und komplett undurchsichtig, hat keinen Rand und keine Ausdehnung (width und height sind beide 0). Weil es keine Ausdehnung hat, könnt ihr es nicht auf dem Canvas sehen. Wenn ihr irgendwelche positiven Werte für width und height setzt, würdet ihr ein schwarzes Rechteck in der rechten oberen Ecke des Canvas sehen, genau wie in Bild 6.
Hierarchie und Vererbung
Fabric-Objekte existieren nicht völlig unabhängig voneinander. Sie stehen in einer ganz genauen Hierarchie. Die meisten Objekte erben von der Wurzel fabric.Object. Das Wurzelelement fabric.Object steht (mehr oder weniger) für eine zweidimensionale Form, die auf einer zweidimensionalen Canvas-Fläche positioniert ist. Es ist eine Einheit, die Eigenschaften wie left/top und width/height und eine ganze Menge anderer grafischer Charkterisika hat. Die aufgelisteten Eigenschaften für Objekte – fill, stroke, angle, opacity, flip* und so weiter – sind allen Fabric-Objekten gemein, die von fabric.Object Eigenschaften vererbt bekommen.
Die Vererbung erlaubt euch, Methoden für fabric.Object zu definieren und sie dann mit allen Kind-„Klassen“ zu teilen. Wollt ihr beispielsweise eine Methode getAngleInRadians für alle Objekte haben, würdet ihr sie einfach wie folgt für fabric.Object.prototype definieren:
fabric.Object.prototype.getAngleInRadians = function() { return this.getAngle() / 180 * Math.PI; }; var rect = new fabric.Rect({ angle: 45 }); rect.getAngleInRadians(); // 0.785... var circle = new fabric.Circle({ angle: 30, radius: 10 }); circle.getAngleInRadians(); // 0.523... circle instanceof fabric.Circle; // true circle instanceof fabric.Object; // true
Wie ihr sehen könnt, ist die Methode sofort für alle Instanzen verfügbar.
Auch wenn Kind-„Klassen” von fabric-Object erben, werden Methoden oft oder Eigenschaften auch speziell nur für die Kind-„Klassen” definiert. Zum Beispiel braucht fabric.Circle eine Eigenschaft radius. fabric.Image braucht die Methoden getElement und setElement, um das HTML-Element <img alt=““ />, wovon die Image-Instanz ursprünglich herkommt, auslesen und setzen zu können.
Canvas
Jetzt, nachdem ihr ein wenig mehr über Objekte gelernt habt, lasst uns zu Canvas zurückkehren.
Das erste, was ihr in allen Fabric-Beispielen seht, ist das Erstellen eines Canvas-Objekts – new fabric.Canvas(‚…‘). Das fabric.Canvas Objekt dient als Wrapper um das <canvas>-Element und regelt alle Fabric-Objekte auf diesem einen Canvas. Es nimmt dazu eine ID eines HTML-Elements und liefert eine Instanz von fabric.Canvas zurück.
Ihr könnt Objekte zum Canvas hinzufügen, sie von dort auslesen oder von ihm entfernen:
var canvas = new fabric.Canvas('c'); var rect = new fabric.Rect(); canvas.add(rect); // add object canvas.item(0); // reference fabric.Rect added earlier (first object) canvas.getObjects(); // get all objects on canvas (rect will be first and only) canvas.remove(rect); // remove previously-added fabric.Rect
Objekte zu regeln ist die Hauptaufgabe von fabric.Canvas, man kann aber auch einiges damit konfigurieren. Ob ihr eine Hintergrundfarbe oder ein Hintergrundbild für den gesamten Canvas definieren, alle Inhalte eines bestimmten Bereichs abschneiden, andere Werte für width und height setzen, oder den Canvas als interaktiv oder nicht interaktiv setzen müsst – all diese Optionen (und noch mehr) könnt ihr für fabric.Canvas setzen, entweder zur Zeit der Objekterstellung oder später. Der folgende Code zeigt dazu ein Beispiel:
var canvas = new fabric.Canvas('c', { backgroundColor: 'rgb(100,100,200)', selectionColor: 'blue', selectionLineWidth: 2 // ... }); // or var canvas = new fabric.Canvas('c'); canvas.backgroundImage = 'http://...'; canvas.onFpsUpdate = function(){ /* ... */ }; // ...
Interaktivität
Eines der Features, das Fabric einzigartig macht, ist eine Ebene für Interaktivität, die auf dem Objektmodell aufsetzt. Das Objektmodell besteht, um Programmierzugang und Manipulation von Objekten auf dem Canvas zu ermöglichen, aber außerhalb – auf der Benutzerebene – gibt es eine Möglichkeit, diese Objekte mit dem Mauszeiger (oder mit Berührungen auf Geräten mit Touchscreen) zu manipulieren. Sobald ihr einen Canvas mit dem Aufruf new fabric.Canvas(‚…‘) initialisiert, ist es möglich, Objekte auszuwählen (siehe Bild 7), sie zu ziehen, zu skalieren oder zu drehen und sogar zu gruppieren (siehe Bild 8), um alle zusammen in einem Schwung zu manipulieren.
Wenn ihr dem Anwender erlauben wollt, etwas auf dem Canvas herumzuziehen – zum Beispiel ein Bild –, müsst ihr lediglich den Canvas initialisieren und ihm ein Objekt hinzufügen. Es ist kein weiteres Konfigurieren oder Einstellen notwendig.
Zur Kontrolle dieser Interaktivität könnt ihr Fabrics Boole’sche Eigenschaft selection in Zusammenhang mit dem Canvas-Objekt verwenden und sie mit der Boole’schen Eigenschaft selectable für einzelne Objekte kombinieren:
var canvas = new fabric.Canvas('c'); ... canvas.selection = false; // Gruppierungsmglichkeit deaktivieren rect.set('selectable', false); // Ein Objekt nicht auswhlbar machen
Was aber, wenn ihr gar keine Interaktivitätsebene wollt? In diesem Fall könnt ihr statt fabric.Canvas einfach fabric.StaticCanvas schreiben. Die Syntax zur Initialisierung ist identisch zu der von fabric.Canvas:
var staticCanvas = new fabric.StaticCanvas('c'); staticCanvas.add( new fabric.Rect({ width: 10, height: 20, left: 100, top: 100, fill: 'yellow', angle: 30 }));
Dies erstellt quasi eine „Light“-Version von Canvas, ohne jeglicher Logik zum Behandeln von Ereignissen. Ihr könnt immernoch mit dem Objektmodell arbeiten, mit dem ihr Objekte hinzufügt, verändert oder entfernt, sowie die Einstellungen des Canvas selbst ändern könnt. All das funktioniert noch, nur das Behandeln von Ereignissen ist nicht mehr möglich.
Gleich behandle ich in diesem Artikel die Custom-Build-Möglichkeit. Ihr seht dann, dass ihr sogar eine abgespeckte Version von Fabric erstellen könnt, wenn StaticCanvas alles ist, was ihr braucht. Dies könnte eine nette Alternative sein, wenn ihr so etwas wie Diagramme oder Bilder ohne Interaktivität, aber mit Filter für eure Anwendung braucht.
Bilder
Rechtecke und Kreise zu einem Canvas hinzuzufügen ist nett, aber wie ihr euch schon denken könnt, macht es euch Fabric auch kinderleicht, mit Bildern zu arbeiten. Hier seht ihr, wie ihr eine Instanz eines fabric.Image-Objekts erstellen und sie zu einem Canvas hinzufügt. Zuerst den HTML-Code, dann das Javascript:
HTML:
<canvas id="c"></canvas> <img src="my_image.png" id="my-image">
JavaScript:
var canvas = new fabric.Canvas('c'); var imgElement = document.getElementById('my-img'); var imgInstance = new fabric.Image(imgElement, { left: 100, top: 100, angle: 30, opacity: 0.85 }); canvas.add(imgInstance);
Beachtet, dass ihr ein Bild-Element an den fabric.Image-Kostruktor übergebt. Dies erstellt eine Instanz von fabric.Image, die genauso aussieht wie das Bild im Dokument. Aber zusätzlich habt ihr gleich left/top auf 100,100 gesetzt, einen Drehwinkel von 30 Grad bestimmt und die Transparenz auf 0.85 erhöht (Transparenz von 1.00 ist ganz sichtbar, 0.00 ist durchsichtig). Sobald das Bild dem Canvas hinzugefügt wird, wird es an der Position 100,100 mit einer Drehung von 30 Grad und einer leichten Transparenz dargestellt (Bild 9).
Wenn ihr nur eine URL zu einem Bild im Dokument habt, können Sie fabric.Image.fromURL verwenden:
fabric.Image.fromURL('my_image.png', function(oImg) { canvas.add(oImg); });
Sieht doch recht simpel aus, oder? Einfach fabric.Image.fromURL aufrufen, mit einer URL zu einem Bild und einer Rückruffunktion, die aufgerufen wird, sobald das Bild geladen und erstellt ist. Der Rückruffunktion wird das bereits erstellte fabric.Image-Objekt als ihr erstes Argument übergeben. Jetzt könnt ihr es eurem Canvas hinzufügen oder zuerst verändern und dann hinzufügen, wie hier gezeigt:
fabric.Image.fromURL('my_image.png', function(oImg) { // scale image down, and flip it, before adding it onto canvas oImg.scale(0.5).setFlipX(true); canvas.add(oImg); });
Path und PathGroup
Wir haben nun einfache Formen und Bilder besprochen. Aber was ist mit komplexen, reicheren Formen und Inhalten? Hier kommen Path und PathGroup ins Spiel, die ein starkes Team bilden.
Pfade bezeichnen in Fabric den Weg um eine Form, der gefüllt, umrandet und auf andere Weise verändert werden kann. Pfade bestehen aus einer Reihe von Befehlen, die im Grunde einen Stift nachahmen, der von einem Punkt zu einem anderen fährt. Mithilfe von Befehlen wie move, line, curve und arc können Pfade unglaublich komplexe Formen erstellen. Und unter der Verwendung von gruppierten Pfaden (PathGroup) eröffnen sich sogar noch mehr Möglichkeiten.
Pfade sind SVG -Elementen sehr ähnlich. Sie verwenden dieselben Befehle, können aus <path>-Elementen erzeugt sowie in <path>-Elemente gewandelt werden. Ich werde später mehr das SVG-Parsen schreiben. Momentan ist es ausreichend zu erwähnen, dass ihr wahrscheinlich nur selten Pfad-Instanzen von Hand erstellen werdet. Stattdessen werdet ihr den in Fabric eingebauten SVG-Parser verwenden. Aber zum Zwecke des Verständnisses, was Pfadobjekte sind, lasst uns hier eines per Hand erstellen (In Bild 10 sehen Sie das Ergebnis)
var canvas = new fabric.Canvas('c'); var path = new fabric.Path('M 0 0 L 200 100 L 170 200 z'); path.set({ left: 120, top: 120 }); canvas.add(path);
Hier erstellt ihr eine Instanz des fabric.Path-Objekts und übergebt ihm eine Zeichenkette mit Pfadanweisungen. Dies sieht vielleicht kryptisch aus, aber es ist eigentlich sehr einfach zu verstehen. M bezeichnet den move-Befehl und weist den unsichtbaren Stift an, zum Punkt 0,0 zu gehen. L steht für line und lässt den Stift eine Linie zum Punkt 200,100 zeichnen. Dann kommt ein zweites L, das ein Linie zum Punkt 170,200 zeichnet. Am Ende zwingt z den Stift, den aktuellen Pfad zu schließen und damit die Form zu vervollständigen.
Nachdem fabric.Path genau wie jedes andere Objekt in Fabric ist, könnt ihr auch einige seiner Eigenschaften verändern oder das Objekt sogar noch weiter modifizieren, wie hier in Bild 11 gezeigt.
... var path = new fabric.Path('M 0 0 L 300 100 L 200 300 z'); ... path.set({ fill: 'red', stroke: 'green', opacity: 0.5 }); canvas.add(path);
Lasst uns, nur der Neugier wegen, eine etwas komplexere Pfadsyntax ansehen. Ihr werdet sehen, warum es vielleicht nicht die beste Idee ist, Pfade per Hand zu erstellen.
... var path = new fabric.Path('M121.32,0L44.58,0C36.67,0,29.5,3.22,24.31,8.41 c-5.19,5.19-8.41,12.37-8.41,20.28c0,15.82,12.87,28.69,28.69,28.69c0,0,4.4, 0,7.48,0C36.66,72.78,8.4,101.04,8.4,101.04C2.98,106.45,0,113.66,0,121.32 c0,7.66,2.98,14.87,8.4,20.29l0,0c5.42,5.42,12.62,8.4,20.28,8.4c7.66,0,14.87 -2.98,20.29-8.4c0,0,28.26-28.25,43.66-43.66c0,3.08,0,7.48,0,7.48c0,15.82, 12.87,28.69,28.69,28.69c7.66,0,14.87-2.99,20.29-8.4c5.42-5.42,8.4-12.62,8.4 -20.28l0-76.74c0-7.66-2.98-14.87-8.4-20.29C136.19,2.98,128.98,0,121.32,0z'); canvas.add(path.set({ left: 100, top: 200 }));
Hier steht M immer noch für den move-Befehl. Der Stift fängt seine Zeichnungsreise am Punkt 121.32, 0. Dann kommt ein L-Befehl (line), der den Stift nach 44.58, 0 fahren lässt. Soweit so gut. Jetzt kommt der C-Befehl, der für „cubid bezier” steht. Dieser Befehl lässt den Stift eine Beziérkurve vom aktuellen Punkt nach 36.67, 0 zeichnen. Der Befehl benutzt 29.5, 3.22 als Kontrollpunkt für den Anfang einer Linie und 24.31, 8.41 als Kontrollpunkt am Ende der Linie. Diesem ganzen Prozess folgen dann noch ein Dutzende weiterer Beziér-Befehle, die schlussendlich eine nett-aussehende Pfeilform bilden, wie in Bild 12 gezeigt.
Wahrscheinlich werdet ihr nicht direkt mit solchen Ungetümen arbeiten. Stattdessen könnt ihr zum Beispiel die Methoden fabric.loadSVGFromString oder fabric.loadSVGFromURL verwenden, um eine ganze SVG-Datei zu laden und Fabrics SVG-Parser die mühsame Arbeit erledigen zu lassen, über all die SVG-Elemente zu gehen und entsprechende Pfadobjekte zu erstellen.
Während das Path-Objekt in Fabric üblicherweise ein SVG-<path>-Element darstellt, wird eine Sammlung an Pfaden, wie sie oft in SVG-Dokumenten vorkommt, mit einer Instanz von PathGroup (fabric.PathGroup) verkörpert. PathGroup ist nichts anderes als eine Gruppe von Path-Objekten und weil fabric.PathGroup alles von fabric.Objekt vererbt bekommt, kann es wie jedes andere Objekt einem Canvas hinzugefügt und auf die selbe Weise manipuliert werden.
Genau wie bei Pfaden, werden ihr kaum direkt an Pfadgruppen arbeiten. Aber solltet ihr nach dem Parsen eines SVG-Dokuments doch einmal über eine stolpern, wisst ihr nun genau was es ist und welchen Zweck es erfüllt.
Momentane Zusammenfassung
Ich habe nur ein wenig an der Oberfläche gekratzt, was die Möglichkeiten mit Fabric angeht. Ihr könnt jetzt leicht alle möglichen einfachen Formen, komplexen Formen oder Bilder erstellen, sie zu einem Canvas hinzufügen oder sie in irgendeiner Weise verändern: ihre Positionen, Ausdehnungen, Drehwinkel, Farben, Umrandungen, Transparenzen – was immer ihr wollt.
Im nächsten Artikel dieser Serie erläutere ich den Umgang mit Gruppen, Animation, Text, SVG-Parsen, Rendern, Ereignisse, Image-Filter und noch mehr.
In der Zwischenzeit könnt ihr euch ja schon mal die kommentierten Demos und Benchmarks ansehen, euch an der Diskussion bei Stack Overflow beteiligen oderr gleich in die Dokumentation, Wiki und den Source-Code eintauchen. Ihr könnt auch mehr über HTML5-Canvas im MSDN IE Developer Center lernen oder lest Rey Bangos auf Script Junkie.
Viel Spaß beim Experimentieren mit Fabric!
Über den Autor
Juriy Zaytsev ist ein leidenschaftlicher JavaScript-Entwickler, der in New York lebt. Er ist ein ehemaliges Kernmitglied von Prototype.js, Blogger auf perfectionkills.com, und der Schöpfer der Fabric.js-Canvas-Library. Zurzeit arbeitet Juriy an seinem Startup-Unternehmen Printio.ru und daran, dass es noch mehr Spaß macht, Fabric zu verwenden.
Hier könnt ihr Juriy finden:
Twitter – @kangax
Juriy’s Blog
Die Liste der Github-Links führt zu 404ern. Ansonsten ne sehr geile Library!