1. Code
  2. JavaScript

Zeichnen mit Two.js

Fortgeschrittene Grafiken sind heutzutage ein großer Teil des Webs, aber es gibt ein paar verschiedene Renderer im Mix. Sie könnten natürlich Leinwand verwenden; SVG und WebGL sind jedoch auch Optionen. In diesem Tutorial werden wir eine relativ neue Zeichnungsbibliothek, two.js, überprüfen, die eine API bereitstellt, die mit allen drei dieser Renderer dasselbe tut. Wenn Sie bereit sind, schauen wir es uns an!
Scroll to top

German (Deutsch) translation by Valentina (you can also view the original English article)

Fortgeschrittene Grafiken sind heutzutage ein großer Teil des Webs, aber es gibt ein paar verschiedene Renderer im Mix. Sie könnten natürlich Leinwand verwenden; SVG und WebGL sind jedoch auch Optionen. In diesem Tutorial werden wir eine relativ neue Zeichnungsbibliothek, two.js, überprüfen, die eine API bereitstellt, die mit allen drei dieser Renderer dasselbe tut. Wenn Sie bereit sind, schauen wir es uns an!


Schritt 1 - Einrichten

Der erste Schritt besteht darin, eine two-Instanz zu erstellen und auf der Seite zu platzieren. Der Two-Konstruktor nimmt ein Objekt mit einer Reihe von Parametern auf:

1
    var two = new Two({
2
       fullscreen: true 
3
    });

In diesem Fall verwenden wir die fullscreen-Option, mit der der Zeichenbereich das gesamte Browserfenster einnimmt. Wenn unser Zeichenbereich eine bestimmte Größe haben soll, können wir stattdessen die Eigenschaften width und height verwenden. Diese beiden nehmen eine Zahl für einen Pixelwert an. Es gibt auch den autostart-Parameter; Wenn dies auf true gesetzt ist, werden alle Animationen sofort ausgeführt, wenn die Seite geladen wird.

Es gibt auch den type-Parameter: Hiermit wird entschieden, welcher Renderer verwendet wird. Sie können zwischen Canvas, SVG und WebGl wählen. Sie geben jedoch nicht nur den Namen ein: Sie verwenden eine Art Bibliothekskonstante: entweder Two.Types.canvas, Two.Types.svg oder Two.Types.webgl. Um ganz klar zu sein, verwendet two.js standardmäßig SVG. Es wird keine Funktionserkennung durchgeführt, um festzustellen, was der Browser unterstützt. Sie müssen das selbst tun (und ich denke, das ist eine gute Idee: kleine Werkzeuge, eine Sache gut und all das).

Was machen wir damit, wenn wir eine Two-Instanz haben? Zunächst möchten Sie es an die Seite anhängen. Es verfügt über eine appendTo-Methode, die ein HTML-Element als Parameter verwendet. Richten Sie Folgendes ein:

1
<div id="main"></div>
2
<script src="./two.min.js"></script>
3
<script src="./main.js"></script>

Dann beginnen wir in main.js damit:

1
var el = document.getElementById("main"),
2
    two = new Two({ 
3
        fullscreen: true
4
    });
5
6
two.appendTo(el);

Mit all diesen Einstellungen sind wir bereit, einige Formen zu zeichnen.


Schritt 2 - Grundformen zeichnen

Wir beginnen mit Grundformen; Während wir mit dem new Two.Polygon unsere eigenen komplexen Formen erstellen können, können die einfachsten Formen mit ein paar praktischen Methoden erstellt werden.

Beginnen wir mit Kreisen. Die Funktion makeCircle akzeptiert drei Parameter:

1
var circle = two.makeCircle(110, 110, 100);
2
circle.fill = "#881111";
3
4
two.update();

Wir werden von unten nach oben überprüfen: Der Aufruf von two.update-Updates ist ein Zeichenbereich und rendert den Inhalt tatsächlich. Die ersten beiden Parameter sind die x- und y-Koordinaten für den Mittelpunkt des Kreises. Der dritte Parameter ist dann der Radius für den Kreis. Alle two.make...-Funktionen geben ein Two.Polygon-Objekt zurück. Während wir dieses Tutorial durcharbeiten, sehen Sie verschiedene Eigenschaften und Methoden, die Sie für diese Formen verwenden können. Hier ist die erste: fill. Wie Sie vielleicht erraten haben, wird die Füllfarbe festgelegt: Jedes gültige CSS reicht aus.

Das Ergebnis sollte folgendermaßen aussehen:

Was ist nun mit Rechtecken? Die two.makeRectangle-Methode akzeptiert vier Parameter. Genau wie der Kreis markieren die ersten beiden Parameter die x- und y-Koordinaten für die Mitte des Rechtecks. Dann ist Parameter drei width und Parameter vier height des Rechtecks.

1
var rect = two.makeRectangle(115, 90, 150, 100);
2
rect.fill = "orange";
3
rect.opacity = 0.25;
4
rect.noStroke();
5
6
two.update();

Wieder verwenden wir die fill-Eigenschaft. Wir verwenden auch die opacity-Eigenschaft, die einen Dezimalwert zwischen 0 und 1 akzeptiert. Wir haben hier eine Viertelopazität. Schließlich verwenden wir die noStroke-Methode, mit der die Kontur (Rand) aus dem Rechteck entfernt wird. Folgendes haben wir:

Ellipsen sind auch ziemlich einfach: Wie Sie sich vorstellen können, legen die ersten beiden Parameter die Mitte der Ellipse fest. Dann haben wir Breite und Höhe:

1
var ellipse = two.makeEllipse(100, 40, 90, 30);
2
ellipse.stroke = "#112233";
3
ellipse.linewidth = 5;
4
ellipse.noFill();
5
6
two.update();

Für neue Eigenschaften: Wir haben strocke, der die Farbe des Rahmens festlegt. Um die Breite dieses Rahmens festzulegen, verwenden wir die Eigenschaft linewidth. Dann erinnerst du dich an noStroke? Die noFill-Methode ist dieselbe, außer dass die Füllfarbe für unsere Form entfernt wird (ohne diese verwenden unsere Formen standardmäßig eine weiße Füllung).

Die einfachsten Formen sind natürlich Linien.

1
var line = two.makeLine(10, 10, 110, 210);
2
line.linewidth = 10;
3
line.stroke = "rgba(255, 0, 0, 0.5)";

Die ersten beiden Parameter sind x und y für ein Ende der Zeile. Der zweite Satz ist für das andere Ende.

Die wahrscheinlich umständlichste Form ist die Kurve. Die two.makeCurve-Methode verwendet so viele Sätze von x, y-Parametern, wie Sie möchten - jedes Paar ist ein Punkt, an dem sich die Linie krümmt. Dann ist der letzte Parameter ein Boolescher Wert: Machen Sie es true, wenn die Form offen ist, was bedeutet, dass die Enden keine Verbindung herstellen. Wenn Sie möchten, dass two.js eine Linie zeichnet, die die beiden Enden der Kurven verbindet, sollte dies false sein.

1
var curve = two.makeCurve(110, 100, 120, 50, 140, 150, 160, 50, 180, 150, 190, 100, true);
2
curve.linewidth = 2;
3
curve.scale = 1.75;
4
curve.rotation = Math.PI / 2; // Quarter-turn
5
curve.noFill();

Sie kennen die linenwidth, aber was ist mit der skale? Wir können dies verwenden, um unsere Form zu verkleinern oder zu erweitern; hier erweitern wir die Form um 175%. Dann können wir rotation verwenden, um unsere Form um eine Anzahl von Bogenmaß zu drehen. Wir machen 90 Grad, das ist ein halber PI-Bogenmaß.

Schließlich könnten Sie denken, dass wir, da wir die Form geöffnet haben, keine Füllung bekommen werden; das stimmt aber nicht. Eine nicht geschlossene Kurve hat immer noch eine Füllung, daher verwenden wir noFill, um die Füllung zu entfernen und nur die Kurve zu erhalten.

Der letzte Formtyp ist allumfassend: Es ist das allgemeine Polygon. Eigentlich ist es ziemlich genau wie die Kurve, nur dass die Linien direkt von Punkt zu Punkt verlaufen. 

1
var poly = two.makePolygon(110, 100, 120, 50, 140, 150, 160, 50, 180, 150, 190, 100);
2
poly.linewidth = 4;
3
poly.translation = new Two.Vector(60, 60);
4
poly.stroke = "#cccccc";
5
poly.fill = "#ececec";

Wie bei der Kurve haben wir so viele Koordinatenpaare, wie wir möchten, und dann den offenen Booleschen Wert. Hier setzen wir es auf false, damit die Form geschlossen wird.

Wir stellen hier auch eine translation ein. Dadurch können wir die Form nach links oder rechts und nach oben oder unten verschieben. Wir setzen die translation-Eigenschaft auf eine Two.Vector-Instanz. Der Two.Vector-Konstruktor akzeptiert zwei Parameter: ein x und ein y. Diese sind letztendlich die Koordinaten für den Mittelpunkt der Form. Sie müssen dafür keinen neuen Vektor erstellen. Sie können einfach das x- und y-Werteverzeichnis zuweisen:

1
poly.translation.x = 60;
2
poly.translation.y = 60;

Folgendes bekommen wir:


Schritt 3 - Gruppen bilden

Bisher haben wir mit einzelnen Formobjekten gearbeitet. Es ist jedoch möglich, Formen zu gruppieren und als ein Stück mit ihnen zu interagieren.

Sie können eine Gruppe mit der Methode two.makeGroup erstellen. Dann können wir die add-Methode verwenden, um der Gruppe eine Form hinzuzufügen.

1
var group = two.makeGroup(),
2
    rect = two.makeRectangle(0, 0, 100, 100),
3
    circ = two.makeCircle(50, 50, 50);</p>
4
5
rect.fill = "red";
6
circ.fill = "blue";
7
8
group.add(rect);
9
group.add(circ);
10
11
two.update();

Wenn Sie dies ausführen, ist es ziemlich einfach; Genau wie Sie es ohne die group-Bits bekommen würden.

Aber dann können wir mit der Gruppe arbeiten und jede der Transformationen verwenden, die wir an einer individuellen Form durchführen können. Wie wäre es zum Beispiel mit einer Übersetzung (translation)? 

1
group.translation.x = 100;
2
group.translation.y = 100;
3
4
two.update();

Wie bei normalen Formen werden Gruppen beim Erstellen von hinten nach vorne geordnet. Wenn Sie jedoch einer Gruppe und dann einer anderen Gruppe eine Form hinzufügen, wird diese aus der ersten Gruppe entfernt. Dies ist ideal, wenn Sie beim Animieren die Reihenfolge der Formen von vorne nach hinten ändern müssen (worauf wir noch eingehen werden). Also, wenn wir damit beginnen:

1
var topGroup = two.makeGroup(),
2
    bottomGroup = two.makeGroup(),
3
    rect = two.makeRectangle(100, 100, 100, 100),
4
    circ = two.makeCircle(150, 150, 50);
5
rect.fill = "red";
6
circ.fill = "blue";
7
8
topGroup.add(rect);
9
topGroup.add(circ);  
10
11
two.update();

Wir haben das gleiche wie oben:

Aber wenn wir stattdessen das rect zur bottomGroup hinzufügen. . .

1
bottomGroup.add(rect);

Jetzt ist unser Platz oben.

Schritt 4 - Formen animieren

Lassen Sie uns abschließend über Animation sprechen. Sie wissen bereits, dass two.js die Formen rendert, die Sie beim Aufrufen von two.update() erstellt haben. Wenn Sie stattdessen two.play() aufrufen, rufen Sie update() wiederholt mit dem Anforderungsanimationsrahmen auf. Jedes Mal, wenn dies passiert, löst two.js ein "Update" -Ereignis aus. So können wir Animationen erstellen: Warten Sie auf das Ereignis "Update". Führen Sie in diesem Fall eine Funktion aus, um den nächsten Frame einzurichten.

Unsere bisherigen Beispiele waren recht einfach. Lassen Sie uns also noch einen Schritt weiter gehen: Wir werden einen umlaufenden Planeten mit einem eigenen umlaufenden Mond erschaffen. Denken Sie daran, wir erstellen zunächst zwei Instanzen:

1
var el = document.getElementById("main"),
2
    two = new Two({ 
3
        fullscreen: true
4
    }).appendTo(el);

Als nächstes müssen wir einige Variablen einrichten.

1
var earthAngle = 0,
2
    moonAngle  = 0,
3
    distance   = 30,
4
    radius     = 50,
5
    padding    = 100,
6
    orbit      = 200,
7
    offset     = orbit + padding,
8
    orbits     = two.makeGroup();

Wir werden earthAngle und moonAngle erhöhen, um unseren Planeten und Mond um ihre Umlaufbahnen zu bringen. Die distance-Variable gibt an, wie weit unser Mond von unserer Erde entfernt sein wird. Der radius ist das Raduis unseres Planeten Erde, und padding gibt an, wie viel Platz unser Planet außerhalb seiner Umlaufbahn haben wird. Diese Umlaufbahn stammt aus der orbit-Variablen. Die offset-Variable gibt an, wie weit unser Planet vom Rand der Leinwand versetzt sein wird. Schließlich enthält die orbits-Gruppe die beiden Umlaufbahnkreise, sodass wir sie nach Belieben ein- oder ausblenden können. Machen Sie sich keine Sorgen, wenn Sie ein bisschen verwirrt sind. Sie werden gleich sehen, wie sie alle zusammenarbeiten.

Wir beginnen mit der Erdumlaufbahn. Das ist natürlich nur ein einfacher Kreis:

1
var earthOrbit = two.makeCircle(offset, offset, orbit);
2
earthOrbit.noFill();
3
earthOrbit.linewidth = 4;
4
earthOrbit.stroke = "#ccc";
5
orbits.add(earthOrbit);
6
7
two.update();

Hier gibt es überhaupt nichts Neues. Folgendes sollten Sie sehen:

Dann müssen wir einen Planeten erschaffen und ihn auf seine Umlaufbahn bringen. Erstens brauchen wir ein Mittel, um herauszufinden, wo auf der Umlaufbahn der Planet platziert werden sollte; Dies muss sich natürlich für jeden Animationsrahmen ändern. Erstellen wir also eine Funktion, die die mittleren x- und y-Koordinaten für die Umlaufbahn basierend auf dem aktuellen Winkel für die Positionierung um den Kreis und dem Radius der Umlaufbahn zurückgibt:

1
function getPositions(angle, orbit) {
2
    return {
3
        x: Math.cos(angle * Math.PI / 180) * orbit,
4
        y: Math.sin(angle * Math.PI / 180) * orbit
5
    };
6
}

Ja, es ist ein bisschen Trigonometrie, aber keine Sorge: Im Grunde genommen konvertieren wir den Winkel (der ein Grad ist) in einen Bogenmaß, verwenden die JavaScript-Sinus- und Cosinus-Methoden und multiplizieren ihn dann mit orbit. Jetzt können wir diese Funktion verwenden, um die Erde zum Bild hinzuzufügen:

1
var pos = getPositions(earthAngle++, orbit),
2
    earth = two.makeCircle(pos.x + offset, pos.y + offset, radius);
3
4
earth.stroke = "#123456";
5
earth.linewidth = 4;
6
earth.fill = "#194878";

Wir beginnen damit, die Position für den ersten earthAngle  zu ermitteln (Wert 0, erinnern Sie sich?); Dann machen wir unsere earth basierend auf diesen Positionen (plus dem Versatz) und färben sie ein. Folgendes haben wir am Ende:

Jetzt animieren wir diesen Planeten. Der Ereignisbindungscode stammt tatsächlich direkt aus dem Backbone, daher kommt er Ihnen möglicherweise bekannt vor:

1
two.bind("update", function (frameCount) {
2
    var pos = getPositions(earthAngle++, orbit);
3
    earth.translation.x = pos.x + offset;
4
    earth.translation.y = pos.y + offset;
5
});
6
7
two.play();

Was hier passiert, ist, dass wir jedes Mal, wenn das update-Ereignis auftritt, die getPositions-Funktion verwenden, um die Position für den nächsten Winkel auf der Erde zu berechnen. Dann müssen wir nur noch den Erdmittelpunkt auf diese neuen Positionen plus den Versatz setzen. Schließlich rufen wir two.play() auf, um die Update-Ereignisse zu starten. Wenn Sie die Seite jetzt neu laden, sollte sich die Erde um die Umlaufbahn drehen.

Bisher gute Arbeit, oder? Wie wäre es nun mit dem Mond und seiner Umlaufbahn? Dies geht über die bind-Anweisung hinaus.

1
var moonOrbit = two.makeCircle(earth.translation.x, earth.translation.y, radius + distance);
2
moonOrbit.noFill();
3
moonOrbit.linewidth = 4;
4
moonOrbit.stroke = "#ccc";
5
orbits.add(moonOrbit);
6
7
var pos = getPositions(moonAngle, radius + distance), 
8
    moon = two.makeCircle(earth.translation.x + pos.x, earth.translation.y + pos.y, radius / 4);
9
10
moonAngle += 5;
11
moon.fill = "#474747";

Dies sieht dem Code für den Planeten sehr ähnlich: Wir zentrieren den Umlaufkreis des Mondes anhand seiner translation-Eigenschaften im Erdmittelpunkt. Sein Radius ist der Radius der Erde plus die Entfernung, die der Mond von der Erde entfernt sein sollte. Wieder fügen wir den moonOrbit zur orbits-Gruppe hinzu.

Als nächstes erstellen wir den Mond, indem wir zuerst die gewünschte Position ermitteln und an dieser Stelle einen Kreis erstellen. Für einen Radius verwenden wir ein Viertel des Radius, den wir für die Erde verwendet haben. Wir werden den Winkel des Mondes jedes Mal um 5 erhöhen, damit er sich schneller als die Erde bewegt.

Wenn Sie die Animation ausschalten (indem Sie die Anweisung two.bind auskommentieren), erhalten Sie Folgendes:

Letzter Schritt: Lassen Sie den Mond animieren. Fügen Sie in derselben two.bind-Anweisung die folgenden Zeilen hinzu:

1
var moonPos = getPositions(moonAngle, radius + distance);
2
moon.translation.x = earth.translation.x + moonPos.x;
3
moon.translation.y = earth.translation.y + moonPos.y;
4
moonAngle += 5;
5
6
moonOrbit.translation.x = earth.translation.x;
7
moonOrbit.translation.y = earth.translation.y;

Nach wie vor erhalten wir die neue Position für den Mond und positionieren sie relativ zur Erde. Dann bewegen wir auch den Umlaufbahnring des Mondes so, dass er auf der Erde zentriert bleibt.

Mit all dem ist unser kleines Beispiel vollständig: Hier ist ein Standbild der Aktion:

Wie gesagt, wir können auch die Umlaufbahnen verstecken. Da beide in der orbits-Gruppe sind, können wir die visible-Eigenschaft der Gruppe verwenden:

1
orbits.visible = false;

Und nun:


Abschluss

Nun, das ist ein Abschluss dieses Tutorials. Denken Sie, dass Sie two.js in einem Ihrer eigenen Projekte verwenden werden? Oder haben Sie eine bessere Alternative? Lassen Sie es uns in den Kommentaren hören!