HTML5 Canvas mit KineticJS

Avatar von Johannes Brosi

KineticJS ist eine JavaScript-Bibliothek, die den Funktionsumfang des HTML5-Canvaselements erweitert und es dem Entwickler erleichert, interaktive Desktop- und Mobileanwendungen zu schreiben. In diesem Artikel wird KineticJS vorstellt und die Möglichkeiten aufgezeigt, die von der Bibliothek geboten werden.

Das Publikum: Welche Browser werden unterstützt?

Grundsätzlich muss der Browser für die Verwendung von KineticJS nur JavaScript und das HTML5-Canvaselement unterstützen. Weitere Abhängigkeiten sind nicht nötig. Hierbei spielt es keine Rolle, ob es sich um einen Desktop- oder einen Mobilebrowser handelt. Bei der Verwendung von Multitouch-Events sollte man sich jedoch im Hinterkopf behalten, dass nicht alle mobilen Browser das Tracking mehrerer Finger unterstützen. Das Canvaselement selbst wird mittlerweile in nahezu allen aktuellen Browsern unterstützt. Siehe Tabelle auf caniuse.

Anmerkung: Bei der Verwendung im Internet Explorer empfiehlt es sich, folgendes Meta-Tag in die HTML-Seite mit einzufügen, da es sonst zu Problemen mit dem Canvaselement kommen kann.

<meta http-equiv="X-UA-Compatible" content="chrome=1, IE=edge" />

Die Story: Warum ein Canvas-Wrapper?

Das Canvaselement bietet von Haus aus bereits Möglichkeiten, Objekte und Bilder zu zeichnen, wozu dann KineticJS? Insbesondere wenn Objekte nicht zur gezeichnet werden sollen, sondern auch Interaktion zwischen diesen erwünscht ist, wird man schnell an die Grenzen des Canvaselementes stoßen. Das Verschieben von Objekten per Touch oder Maus, die relative Positionierung von Objekten zueinander und der Einsatz von Animationen sind mit reinen Canvas-Funktionen ohne zusätzlichen eigenen Code nicht möglich. Genau hier setzt KineticJS an und erweitert das Canvaselement um eben diese Funktionen.

Beispiel für eine einfache Canvas-Zeichenoperation (das Zeichnen eines Kreises):

var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
context.beginPath();
context.arc(320, 240, 40, 0, 2 * Math.PI);
context.stroke();

Die Bühne: Der Aufbau von KineticJS

Struktur von KineticJS

KineticJS bietet einen einfachen Szenengraphen, über den die Grafikobjekte verwaltet werden können. Die Bühne, in KineticJS Stage genannt, ist der Container für alle weiteren Elemente. Konkret können ihm mehrere Ebenen zugeordnet werden. Jede Ebene wiederum kann Grafikobjekte oder Gruppen enthalten.

Eine Gruppe kann aus mehreren Grafikobjekten und weiteren Gruppen bestehen. Wie es sich für einen Szenengraphen gehört, können alle Ebenen, Gruppen und Grafikobjekte rotiert, skaliert und bewegt werden. Hierbei gilt eine Transformation eines Elternelementes (zum Beispiel einer Ebene) ebenso für alle Kindelemente (zum Beispiel Gruppen und Grafikobjekte). So lassen sich auf sehr einfache Weise komplexe Positionierungen und Bewegungsmuster abbilden.

Im hier dargestellten Beispiel (einen canvasfähigen Browser vorausgesetzt) sieht man ein vereinfachtes Sonnensystem. Die Bewegungen der Monde um die Planeten ohne einen Szenengraphen zu berechnen ist nicht unbedingt trivial. Mit dem Szenengraph ist hier jedoch nicht viel mehr nötig als ein orbit.rotate() (siehe Code). Um das Sonnensystem seinerseits um das Zentrum der Milchstraße rotieren zu lassen, würden ein paar Zeilen zusätzlicher Code ausreichen, ohne dass die Bewegungen der Planeten oder Monde angepasst werden müssten. Im gezeigten Beispiel lässt sich die Lage des Sonnensystems per Drag & Drop anpassen. Die Planeten behalten trotz Bewegung ihre relative Position zur Sonne.

Link zum Code auf JSFiddle

Die Hauptdarsteller: Ein erstes Grafikobjekt

kreisVerglichen mit dem Canvas-Beispiel weiter oben sind hier einige Zeilen mehr nötig, dafür wird man sich jedoch bei der Erweiterung um beispielsweise Touch-Events deutlich leichter tun. Folgender Code entspricht dem obigen Beispiel in KineticJS:

var stage = new Kinetic.Stage({
  container: 'container',
  width: 640,
  height: 480
});

var layer = new Kinetic.Layer();

var circle = new Kinetic.Circle({
  x: 320,
  y: 240,
  radius: 40,
  stroke: 'black',
  strokeWidth: 1
});

// add the shape to the layer
layer.add(circle);

// add the layer to the stage
stage.add(layer);

Zu der Funktionsweise des Codes:

Zunächst wird die Bühne (Stage) erstellt, auf der das Geschehen stattfinden soll. Da Grafikobjekte nicht direkt der Stage, sondern einer Ebene (Layer) zugewiesen werden müssen, wird anschließend noch eine Ebene erstellt. Mit var circle = new Kinetc.Circle(){}  erzeugt man letztendlich das Kreisobjekt. Abschließend wird der Kreis der Ebene und die Ebene wiederum der Bühne zugeordnet.

Die Kulisse: Das Einbinden von Bildern

Bilder lassen sich in KineticJS ebenfalls sehr einfach verwenden. Hierfür nutzt man die Kinetic.Image-Klasse. Zum Erstellen eines neuen Images reicht folgender Code:

var image = new Kinetic.Image({
  x: 0,
  y: 0,
  image: imageObj,
  width: 120,
  height: 80
});

Wobei imageObj hier ein ganz normales JavaScript-Image-Objekt ist, das wie folgt erzeugt und geladen werden kann:

var imageObj = new Image();
imageObj.src = „image.png“;

Es empfiehlt sich unter Umständen auf das Load-Event des Bildes zu warten, bevor man es im Kinetic-Kontext verwendet. Auch Data-URLs sind hier möglich (siehe Beispiel).

Möchte man den gerenderten Inhalt eines Canvas speichern/exportieren oder als Quelle für ein Kinetic-Image-Objekt benutzen, kann man wie gewohnt den Canvas-Inhalt via canvas.toDataURL()  in einen Data-URL exportieren und entsprechend an den Webserver oder den Client als Download senden bzw. als src-Attribut im imageObj verwenden. Für das Senden des Bildes an den Webbrowser empfiehlt sich unter anderem die Verwendung von Canvas2Image.

Und Action: Die Funktionsweise von Animationen

KineticJS bietet auch eine Unterstützung für Animationen. Durch folgenden Code wird eine Animationsfunktion erstellt:

var anim = new Kinetic.Animation(function(frame) {
  // update stuff
}, node);

Die Funktion function(frame)  wird für jedes Frame einmal aufgerufen. In dem frame-Parameter befinden sich die Attribute time und timeDiff, über die die Gesamtlaufzeit der Animation (time) und die seit dem letzten Frame vergangene Zeit (timeDiff) in Millisekunden zur Verfügung stehen. Da nicht garantiert ist, dass die Funktion in exakt gleichen Zeitabständen ausgeführt wird, sollte man bei seinen Animationen diese Angaben berücksichtigen.

Ist die Funktion einmal erstellt, kann sie jederzeit gestartet (anim.start()) bzw. gestoppt werden (anim.stop()).

Damit die Änderungen in der Animationsfunktion sichtbar werden, muss gegebenenfalls die draw()-Methode des geänderten Layers oder der Stage verwendet werden.

Hier die Animationsfunktion aus dem Sonnensystem-Beispiel:

    //create new animation
    var animation = new Kinetic.Animation(function(frame) {
        //rotate the earth around the sun
        earthOrbit.rotate(frame.timeDiff * 0.002);
        //rotate the mars around the earth
        marsOrbit.rotate(frame.timeDiff * 0.001);
        //rotate the mars around the earth
        marsMoonOrbit.rotate(frame.timeDiff * 0.001);
        //rotate the moon around the earth
        moonOrbit.rotate(frame.timeDiff * 0.005);
        //refresh drawing
        layer.draw();
    });

Wie man sieht, werden lediglich die Orbit-Gruppen rotiert und anschließend die Ebene neu gezeichnet. Den vollen Code zum Beispiel gibt es hier: JSFiddle

Image based animation

KineticJS bietet neben dem reinen Bewegen/Rotieren und Skalieren der Objekte auch noch eine Sprite-basierte Animationsmöglichkeit, auf die hier aber nur am Rande eingegangen werden soll. Dabei verwendet man anstelle eines einzelnen Bildes ein sogenanntes Spritesheet. Dieses besteht aus mehreren Einzelbildern, die in einer einzigen Bilddatei nebeneinander angeordnet sind. Es können beliebig viele Animationsphasen definiert werden, die festlegen in welcher Reihenfolge die Einzelbilder angezeigt werden sollen. Über die in der Definition frei wählbaren Namen der Animationen kann man später wählen, welche Animationsphase des Sprites angezeigt werden soll.

Weitere Informationen inklusive Beispiel befinden sich hier.

Interaktion: Die Funktionsweise der Events

Grafikobjekte und Gruppen lassen sich in KineticJS sehr einfach Drag&Drop-fähig machen. Hierzu reicht ein simples draggable: true in den Optionen des erstellten Objekts. Anschließend lässt sich das Objekt beliebig per Maus und Touch auf dem Canvas verschieben. Das mag in einigen Fällen ausreichen, in anderen benötigt man jedoch mehr Kontrolle über das genaue Verhalten.

KineticJS bietet dem Entwickler die Möglichkeit, sich auf verschiedene Events zu registrieren, um das Verhalten wie gewünscht ändern zu können. Als einfachstes Beispiel sei hier das Click-Event genannt. Ähnlich zu der JQuery-Syntax reicht ein einfaches shape.on(‚click‘, callback) bereits aus, um die Callback-Funktion auf das Click-Event zu registrieren. Es werden eine Vielzahl an Events unterstützt, wie mouseover, mouseout, mousedown, mouseup, touchstart, touchend, dblclick, click, dbltap, tap

Die meisten dürften selbsterklärend sein. Genaueres findet man hier.

Über die Events lassen sich auch fortgeschrittenere Techniken wie Snap-To-Grid oder Snap-To-Objekt realisieren („magnetische“ Objekte). Auch Pinch-To-Zoom und andere Touch-Gesten können recht einfach implementiert werden. Im folgenden ein einfaches Beispiel, bei dem ein Kreis die Farbe ändert, sobald die Maus über ihm ist oder er verschoben wird.

Den Code dazu gibt es hier.

Fazit

Mit KineticJS steht ein wertvolles Hilfsmittel zur Verfügung, wenn es darum geht, mit interaktiven Grafiken auf Basis des HTML-Canvas zu arbeiten. Denkbar sind grafische Planungstools, In-Browser-Grafikprogramme, Konfiguratoren (mit Drag&Drop der Elemente an die entsprechenden Positionen), Spiele und vieles mehr. Die Tests mit mobilen Endgeräten waren äußerst vielversprechend und laden dazu ein, grafisch anspruchsvollere Webanwendungen – auch für mobile – zu konstruieren.

An die Grenzen stößt man erst bei grafisch extrem aufwendigen Anwendungen oder bei einem Wechsel in den 3D-Bereich. Doch auch hier gibt es Lösungen. In Sachen 3D ist hier Three.js auf jeden Fall einen Blick wert. Zu diesem Thema werde ich in Kürze einen weiteren Artikel veröffentlichen.

Links

Avatar von Johannes Brosi

Kommentare

3 Antworten zu „HTML5 Canvas mit KineticJS“

  1. […] Schneeflocken erzeugen kann. Auch bei Mayflower geht es heute um Canvas, in diesem Falle um “HTML5 Canvas mit KineticJS“. Bei Digitpaint kümmerte man sich gestern um […]

  2. „kann man wie gewohnt den Canvas-Inhalt via canvas.toDataURL()“
    Das würde mich detaillierter interessieren …

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.