SVG-Programmierung mit Javascript
Vektordynamik

DeveloperIT-ProjekteSoftwareWorkspaceZubehör

Das Vektorgrafikformat SVG lässt sich mit Javascript nahezu beliebig erweitern und an eigene Bedürfnisse anpassen. Internet Professionell zeigt die SVG-Aktionsprogrammierung in der Praxis.

Voraussetzung: SVG-Plug-in

SVG-Programmierung mit Javascript

Scalable Vector Graphics (SVG) führen zumindest im Bereich Web-Anwendungen noch immer ein Nischendasein, was jedoch nicht an den vielfältigen Möglichkeiten zur Umsetzung hochwertiger Vektorgrafiken liegt. Man benötigt vielmehr weiterhin separat zu installierende Plug-ins, um SVG in die Webbrowser zu bringen. Obwohl die Mozilla-Entwickler stetig Fortschritte bei der Etablierung von SVG als direkt unterstütztes Format vermelden, hat sich in der Praxis der Adobe SVG Viewer (ASV) auf unterschiedlichen Plattformen bewährt. Für diesen Workshop sollte eine aktuelle ASV-Version auf dem PC installiert sein.


SVG aufgebohrt

SVG-Programmierung mit Javascript

In früheren Beiträgen wurden bereits allgemeine Grundlagen (Ausgabe 7/2002), die Animationstechniken (Ausgabe 6/2003) und die serverseitige Umsetzung von SVG mit XSLT und PHP (Ausgabe 5/2004) in Workshops vermittelt.

Hier steht die Verarbeitung auf Seiten des Clients im Mittelpunkt. Die Kombination von SVG mit Skriptsprachen wie Javascript beziehungsweise ECMA-Script ist keine spezielle Erfindung einzelner Software-Hersteller, sondern ein integraler Bestandteil der SVG-Spezifikation. Aktuell ist die Version 1.1, siehe www.w3.org/TR/SVG11.

Vor allem die Anhänge B und E sind für Entwickler interessant. SVG unterstützt das Document Object Model (DOM) Level 2 sowie eine Vielzahl von spezifischen Erweiterungen. Als hilfreiches Nachschlagewerk hat sich ObjJob (phrogz.net/ObjJob) erwiesen.


Aktionsprogrammierung

SVG-Programmierung mit Javascript

Der Einsatz von Javascript innerhalb eines SVG-Dokuments funktioniert prinzipiell genauso wie im HTML-Kontext. Zu Grunde liegt dem Skript jeweils ein Objektmodell, das eine große Palette an Eigenschaften und Methoden zur Verfügung stellt. Aktionen lassen sich über Ereignisse steuern.
Ein typisches SVG-Gerüst mit Skripteinbindung hat diesen Aufbau:




xmlns:xlink="http://www.w3.org/1999/ xlink">
Titel
Beschreibung




Der CDATA-Abschnitt ist nötig, um XML-spezifische Zeichen wie < oder & im Skriptcode direkt verwenden zu können. Alternativ ist es möglich, dass Sie im Definitionsteil (Element defs) auch externe Bibliotheken einbinden. Das geschieht wie folgt: Die Verwendung von Variablen, Funktionen, Kontrollstrukturen und Ähnlichem unterscheidet sich nicht vom Vorgehen in einem HTML-Dokument. Eine erste Funktion könnte also lauten: function Test()
{
alert("Hallo Welt!");
}
Test(); // Aufruf Der Aufruf dieser Funktion kann direkt im Anschluss an ihre Definition mit Test() erfolgen oder praktikabler über einen Event-Handler wie onload, das heißt, die Funktion wird unmittelbar nach dem vollständigen Laden des Dokuments ausgeführt:

Ereignissteuerung im Detail

SVG-Programmierung mit Javascript

Ereignisse treten bei der Nutzerinteraktion ständig auf. Wird ein Objekt angeklickt, startet ein click-Ereignis. Sofern ein entsprechender Event-Handler installiert wurde, hier also onclick, kann das eingetretene Ereignis verarbeitet werden. SVG unterscheidet drei Kategorien von Ereignissen für: - Grafik- und Containerelemente (activate, click, focusin, focusout, load, mousedown, mouseup, mouseover, mouseout, mousemove)
- das Dokument-Element (abort, error, resize, scroll, unload, zoom)
- Animationselemente (begin, end, repeat) Zur Unterscheidung der Herkunft eines bestimmten Ereignisses und zur Zuordnung eines bestimmten Elements existiert das Event-Objekt, das mit dem reservierten Namen evt als Parameter einer Funktion angesprochen werden kann. Das Konstrukt evt.target verweist auf den Ausgangspunkt eines Ereignisses. Möchten Sie viele Elemente auf bestimmte Ereignisse prüfen und den Programmablauf entsprechend steuern, bietet sich die Verwendung der Methode addEventListener() an. Diese kann an ein Elementobjekt gebunden werden und erwartet drei Parameter: das Ereignis, den Namen der aufzurufenden Funktion und einen Boole-schen Wert, der die beiden Phasen der Ereignisverarbeitung Capturing (Einfangen, Wert true) und Bubbling (Aufsteigen, Wert false) berücksichtigt. In vielen Fällen ist der Wert false geeignet. Durch removeEventListener() kann die Überwachung aufgehoben werden.

Die Beispielanwendung

SVG-Programmierung mit Javascript

An dieser Stelle soll dem theoretischen Exkurs die Praxis folgen. Die für diesen Workshop ausgewählte Anwendung stammt aus dem Fundus SVG ? Learning By Coding (svglbc.datenverdrahten.de) des Autors. Es wird die Umsetzung eines kleinen Zeichenprogramms mit SVG-Mitteln demonstriert. Auf der Heft-CD liegt der Beispiel-Code als drawshapes.svg vor. Der Code ist auf 445 Zeilen verteilt und enthält 19 separate Funktionen und 32 globale Variablen, die von den Funktionen gemeinsam verwendet werden.

Bedienoberfläche festlegen

SVG-Programmierung mit Javascript

Die Bedienoberfläche besteht aus einem 640 x 480 Pixel umfassenden Zeichenbereich und einigen am linken Rand angeordneten Werkzeugen zur Auswahl von Farben, Strichstärken, Zeichenobjekten und zusätzlichen Operationen. Dazu dienen ein Rechteck mit den genannten Dimensionen sowie ein Rechteck mit der ID aktfill zur Anzeige der gewählten Farbe und eine Linie mit der ID aktline für die gewählte Strichstärke und -farbe Über kleine, ebenfalls mit Rechtecken angelegte Kästchen lassen sich elf vorgegebene Farbwerte zuweisen. Die Auswahl von Strichstärken ist im Bereich von 1 bis 5 Pixel möglich. Beim Anklicken der Farbkästchen beziehungsweise der Auswahllinien werden die Funktionen SetColors() und SetLineWidth() aufgerufen und die gewählten Eigenschaften in Variablen abgelegt. Sie können weiterhin eine der Zeichenformen Linie, Kreis oder Rechteck wählen und über Text-Links vier Zusatzoptionen nutzen.

Initialisierungen

SVG-Programmierung mit Javascript

Bevor überhaupt auch nur ein Strich auf dem Zeichenfeld erscheint, sind einige Initialisierungen notwendig. Dazu wird nach dem Laden (onload) die Funktion getSVGDoc() aufgerufen: function getSVGDoc(load_evt)
{
svgdoc=load_evt.target.ownerDocument;
svgroot=svgdoc.rootElement;
aktfill=svgdoc.getElementById("aktfill");
aktline=svgdoc.getElementById("aktline");
drawing=svgdoc.getElementById("drawing");
grid=svgdoc.getElementById("grid");
shape=svgdoc.getElementById("shape");
svgroot.addEventListener("mousedown",MDown,false);
svgroot.addEventListener("mousemove",MMove,false);
svgroot.addEventListener("mouseup",MUp,false);
DrawGrid(zbreite,zhoehe,posminx,posminy,gridbox);
} Insbesondere werden die globalen Objektvariablen aktfill, aktline, grid und shape verfügbar gemacht und die permanente Überwachung der beim Zeichnen eintretenden Mausereignisse mousedown, mousemove und mouseup über die genannten Funktionen eingeleitet. Die Hilfsfunktion DrawGrid() legt ein definierbares Raster über die Zeichenfläche. Die in Klammern erwarteten Parameter haben die ebenfalls global definierten Werte posminx=50, posminy=50, zbreite=640, zhoehe=480, gridbox=20.

Zeichentechniken

SVG-Programmierung mit Javascript

Sind Farben, Strichstärken sowie ein konkretes Objekt über die Funktion SetShape() ausgewählt, kann der Anwender wie in einem Grafikprogramm einfache geometrische Formen zeichnen. Ist beispielsweise eine Linie aktiviert und im Zeichenbereich zur Auswahl des Startpunkts die linke Maustaste gedrückt, registriert die Funktion MDown() dieses mousedown-Ereignis und ruft die Funktion Coords() auf posx=mouse_event.clientX;
posy=mouse_event.clientY; die die aktuellen x- und y-Koordinaten (posx, posy) in die Variablen startx und starty schreibt: startx=posx;
starty=posy; Je nach gewähltem Objekt wird eine passende Funktion aufgerufen, zum Beispiel StartLine(): if(curshape=="l")StartLine();
if(curshape=="c")StartCircle();
if(curshape=="r")StartRect();
check=true; Die Variable check speichert den Status der aktuellen Operation. Solange diese den Wert true behält, ist die Zeichenoperation noch nicht abgeschlossen. Erst beim Loslassen der Maustaste setzt die Funktion MUp() diese Variable beim Eintreten des mouseup-Ereignisses auf false. Zwischen beiden Zuständen liegt jedoch der durch MMove() kontrollierte Bereich, also die Bewegung der Maus bei gedrückter Taste (Ereignis mousemove). Die Funktion StartLine() hat mittlerweile ein neues Element line im SVG-DOM erzeugt, aber noch nicht in die Baumstruktur eingehängt: function StartLine()
{
newline=svgdoc.createElement("line");
newline.setAttribute("x1",posx);
newline.setAttribute("x2",posx);
newline.setAttribute("y1",posy);
newline.setAttribute("y2",posy);
newline.setAttribute("stroke",linecol);
newline.setAttribute("stroke-width",linewidth);
} Die Koordinaten des Endpunkts werden zunächst auf die des Startpunkts gelegt und innerhalb von MMove() flexibel angepasst. Schließlich wird die Linie durch die Funktion FinishLine() finalisiert: function FinishLine()
{
newline.setAttribute("x2",posx);
newline.setAttribute("y2",posy);
drawing.appendChild(newline);
}

Kreise und Rechtecke

SVG-Programmierung mit Javascript

Mit analogen Start- und Finish-Funktionen werden die Objekte Kreis und Rechteck erzeugt. Kreise entstehen ausgehend von einem Startpunkt, der als Mittelpunkt verwendet wird, und der durch die Mausbewegung beschriebenen Länge als Radius, während Rechtecke ausgehend vom linken oberen Eckpunkt und der Diagonalen zum rechten unteren Eckpunkt erzeugt werden. Mathematisch werden die für ein rect-Element erforderlichen Werte für Breite und Höhe durch den Satz des Pythagoras erzeugt, siehe die Anwendung von Methoden des Math-Objekts im Quellcode. Auch die Ausdehnung der Objekte wird an das Zeichenfeld angepasst ? man kann nicht darüber hinauszeichnen.

Einige DOM-Details

SVG-Programmierung mit Javascript

Im aufgeführten Code wird zunächst die an das Document-Objekt (svgdoc) gebundene Methode createElement() mit dem Namen des zu erzeugenden Elements (line) aufgerufen und das Ergebnis in der Variablen newline abgelegt. Anschließend bemühen Sie mehrfach die Methode setAttribute() zur paarweisen Zuweisung von Attributname und Attributwert. Das Einhängen des zunächst virtuellen Kindelementknotens in den DOM-Baum erreichen Sie durch die Anwendung von appendChild(). Die konkrete Position wird durch drawing festgelegt. Dahinter verbirgt sich ein Gruppenelement (g), das nacheinander alle auf der Zeichenfläche angelegten Objekte aufnimmt. Auch das Entfernen von misslungenen Objekten (»Undo«) oder gar das Löschen der kompletten Zeichnung (»Clear«) ist im Beispiel kein Problem. Zu diesem Zweck bedienen Sie sich der Methode removeChild(): function UndoLastShape()
{
shapes=drawing.childNodes;
anzahl=shapes.length;
if(anzahl>0)drawing.removeChild(drawing.lastChild);
} Dieses Prinzip wird in der Funktion ClearDrawing() innerhalb einer Schleife angewendet, die alle Objekte entfernt. Da die eingebaute Sicherheitsabfrage nur mit der Kombination ASV und Internet Explorer funktioniert, lässt sich die komplette Zeichnung bei der Verwendung von anderen Plug-ins und Browsern nicht löschen. Auch das Kopieren des intern erzeugten SVG-Codes (»Copy«) in die Zwischenablage ist den IE-Benutzern vorbehalten, da hier das clipboardData-Objekt des IE angesprochen wird. Auf der Heft-CD liegt zusätzlich die Datei clipboard.svg, die zur abgebildeten Testzeichnung gehört. Der letzte Punkt im Bereich Options ist mit Grid benannt und ermöglicht das Aus- und Einschalten des am Anfang erzeugten Rasters. Dabei wird in der Funktion ShowHideGrid() lediglich die CSS-Eigenschaft visibility auf die Werte hidden oder visible gesetzt: if(gr)
{
grid.style.setProperty("visibility","hidden");
gr=false;
}
else
{
grid.style.setProperty("visibility","visible");
gr=true;
}

Fazit

SVG-Programmierung mit Javascript

Die ereignisgesteuerte Aktionsprogrammierung ermöglicht die Umsetzung von Ideen, die allein mit den bereits sehr umfangreichen Möglichkeiten von SVG nur umständlich oder überhaupt nicht realisierbar wären. Dabei bietet der Javascript-Sprachumfang in Kombination mit dem W3C-DOM eine echte Schatzkiste für Programmierer. Letztlich sind die Browser-Hersteller gefordert, diese Schätze durch bessere SVG-Unterstützung der breiten Öffentlichkeit zugänglich zu machen.
Alle Listings zum Workshop finden Sie auf der Heft-CD und im Bereich Listings auf der Website.