10.2Skripte definieren
JavaScript-Code kann entweder direkt in das SVG-Dokument, in eine separate .js-Datei oder z.B. auch in eine (X)HTML-Datei, in der sich eine SVG-Grafik befindet oder in der eine selbige referenziert wird, geschrieben werden.
10.2.1Direkte Einbindung
Listing 10-2 zeigt zuerst die direkte Einbindung in eine SVG-Grafik. Diese SVG-Datei beschreibt einen roten Kreis, der seinen Radius verändert, sobald er mit der Maus angeklickt wird.
<?xml version="1.0"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg"> <script type="text/ecmascript"> <![CDATA[ function aendereRadius(evt) { var kreis = evt.target; var radius = kreis.getAttributeNS(null, 'r'); if(radius < 75) { kreis.setAttributeNS(null, 'r', parseInt(radius) + 5); } else { kreis.setAttributeNS(null, 'r', 25); } } ]]> </script> <circle cx="75" cy="75" r="25" fill="#F00" onclick="aendereRadius(evt)" /> </svg>
Ein Skriptbereich wird immer durch das <script>
-Element eingeleitet. Damit der Betrachter weiß, welche Skriptsprache er für diesen Bereich verwenden soll, bekommt das Attribut type
den MIME-Type der gewünschten Sprache zugewiesen. Die SVG 1.1-Spezifikation definiert als Standardwert den Typ text/ecmascript
(der SVG 1.2-Entwurf derzeit application/ecmascript
), der wohl auch am häufigstens benutzt wird. Möchte man im gesamten Dokument von vornherein nur eine einzige Sprache verwenden, kann man im <svg>
-Element auch das contentScriptType
-Attribut mit dem entsprechenden MIME-Type versehen.
Nach dem einleitenden <script>
-Tag folgt die Umklammerung des JavaScript-Codes durch <![CDATA[
und ]]>
. Liegt ein Bereich innerhalb eines solchen CDATA-Blocks (CDATA steht für "character data"), wird alles, was sich darin befindet, vom XML-Parser ignoriert. Nur die Zeichenfolge ]]>
, die das Ende des CDATA-Blocks bekannt gibt, wird von ihm interpretiert. In solche Blöcke läßt sich z.B. SVG-Code schreiben, der als Kommentar dienen soll. Im vorherigen Beispiel ist der CDATA-Bereich zwingen notwendig, weil in der if
-Bedingung das Zeichen <
vorkommt, das dem Parser den Anfang eines Tags anzeigt. Verzichtet man in diesem Fall also auf den CDATA-Block, wird die Validierung des SVG-Dokuments fehlschlagen. Um Schwierigkeiten schon im voraus zu vermeiden, sollte man sich unbedingt angewöhnen, Skript-Code grundsätzlich in einen CDATA-Block zu schreiben.
10.2.2Einbindung in eine separate Skript-Datei
Die folgende Methode zeigt, wie JavaScript-Code in eine separate JavaScript-Datei ausgelagert werden kann. Um SVG-Beschreibung und Programm-Code aus Listing 10-2 zu trennen, genügt es die Funktion aendereRadius()
aus dem CDATA-Block zu entfernen und in eine neue Datei zu transferieren, welche man anschließend mit der Endung .js abspeichert. Der nun leere, übriggebliebene Skript-Abschnitt wird durch ein <script>
-Element ersetzt, das den MIME-Type der verwendeten Sprache und einen Link auf die neu erstellte JavaScript-Datei enthält. Während Listing 10-3 die um den Skript-Code reduzierte SVG-Grafik beinhaltet, stellt Listing 10-4 die neue Datei mit der umgezogenen JavaScript-Funktion dar.
<?xml version="1.0"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> <script type="text/ecmascript" xlink:href="script3_example.js" /> <circle cx="75" cy="75" r="25" fill="#F00" onclick="aendereRadius(evt)" /> </svg>
function aendereRadius(evt) { var kreis = evt.target; var radius = kreis.getAttributeNS(null, 'r'); if(radius < 75) { kreis.setAttributeNS(null, 'r', parseInt(radius) + 5); } else { kreis.setAttributeNS(null, 'r', 25); } }
10.2.3Einbindung in eine HTML-Datei
Um die SVG-Grafik mit Hilfe eines externen Skripts steuern zu können, muß das obige Beispiel leicht abgeändert werden. Um Zugriff auf das <circle>
-Objekt zu erhalten, wird dieses nun mit der ID kreis
ausgestattet. Mittels document.getElementById("kreis")
kann somit der Variablen kreis
eine Referenz auf das Objekt übergeben werden (siehe Listing 10-5).
<?xml version="1.0"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="150" height="150"> <script type="text/ecmascript"> <![CDATA[ function aendereRadius() { var kreis = document.getElementById("kreis"); var radius = kreis.getAttributeNS(null, 'r'); if(radius < 75) { kreis.setAttributeNS(null, 'r', parseInt(radius) + 5); } else { kreis.setAttributeNS(null, 'r', 25); } } ]]> </script> <circle id="kreis" cx="75" cy="75" r="25" fill="#F00" /> </svg>
Listing 10-6 zeigt die zu diesem Beispiel dazugehörige XHTML-Datei. Darin wird die SVG-Grafik mittels <object>
-Element eingebunden. Zusätzlich enthält sie eine Schaltfläche, die bei Aktivierung die Funktion aendereRadius()
des SVG-Dokuments aufruft. Damit diese Kopplung von XHTML- und SVG-Dokument funktioniert, befindet sich eine kleine Funktion mit dem Namen init()
im Header der XHTML-Datei. Sie ermöglicht den Zugriff auf die beiden Objekte document
und window
des SVG-Dokuments.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de"> <head> <title>SVG Scripting - Variante 2a</title> <meta http-equiv="Content-Script-Type" content="text/ecmascript" /> <script type="text/ecmascript"> <![CDATA[ var svgDoc = null; var svgWin = null; function init() { var object = document.getElementById('object'); svgDoc = object.contentDocument; svgWin = svgDoc.defaultView; } ]]> </script> </head> <body onload="init()"> <div> <object id="object" data="script2a_example.svg" type="image/svg+xml" width="150" height="150" style="border:1px solid #000000"> </object> <p> <button onclick="svgWin.aendereRadius()">Ändere Radius</button> </p> </div> </body> </html>
Es ist zu beachten, daß es sich bei dieser Zugriffsmethode um die standardkonforme, vom W3C verabschiedete Methode handelt. Leider wurde im Internet Explorer 6 die HTMLObjectElement
-Schnittstelle, mit welcher der obige Zugriff auf das <object>
-Element realisiert wird, nicht implementiert. Allerdings bietet der SVG-Standard selbst eine Schnittstelle des Namens GetSVGDocument
an, mit der man eine Referenz auf das SVG-Dokument erhält. Wegen Sicherheitsproblemen wurde jedoch deren Unterstützung im Adobe SVG Plugin 3.03 entfernt. Aber auch den Mozilla-basierten Browsern mit nativer SVG-Unterstützung fehlt noch eine Implementierung der GetSVGDocument
-Schnittstelle für das <object>
-Element. Der Zugriff auf das window
-Objekt des SVG-Dokuments mit dem Adobe SVG Plugin bereitet ebenfalls Schwierigkeiten. Mit Mozilla-basierten Browsern kann man die vom W3C standardisierte Eigenschaft defaultView
des document
-Objekts problemlos nutzen, um eine Referenz auf das window
-Objekt zu erhalten. Dem Adobe SVG Plugin für den Internet Explorer fehlt jedoch die dafür notwendige DocumentView
-Schnittstelle. Und auch die proprietäre Eigenschaft window
oder die ebenfalls nicht standardkonforme Methode getWindow()
wurden wegen den bereits erwähnten Sicherheitsproblemen entfernt. Somit scheint es derzeit nicht möglich zu sein mit dem Adobe SVG Plugin auf mittels <object>
-Element eingebundene SVG-Dokumente zuzugreifen. Eine Alternative wäre die Verwendung des HTML-Elements <embed>
, das jedoch als veraltet gilt und in neueren Standards nicht mehr berücksichtig wird.
Selbstverständlich besteht auch die Möglichkeit das komplette Scripting innerhalb des (X)HTML-Dokuments zu notieren. In einem solchen Fall sieht die SVG-Grafik mit dem roten Kreis wie in Listing 10-7 dargestellt aus.
<?xml version="1.0"?> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="150" height="150"> <circle id="kreis" cx="75" cy="75" r="25" fill="#F00" /> </svg>
Das leicht veränderte und um die Funktion aendereRadius()
erweiterte XHTML-Dokument zeigt Listing 10-8.
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="de"> <head> <title>SVG Scripting - Variante 2b</title> <meta http-equiv="Content-Script-Type" content="text/ecmascript" /> <script type="text/ecmascript"> <![CDATA[ var svgDoc = null; var svgWin = null; function init() { var object = document.getElementById('object'); svgDoc = object.contentDocument; svgWin = svgDoc.defaultView; } function aendereRadius() { var kreis = svgDoc.getElementById("kreis"); var radius = kreis.getAttributeNS(null, 'r'); if(radius < 75) { kreis.setAttributeNS(null, 'r', parseInt(radius) + 5); } else { kreis.setAttributeNS(null, 'r', 25); } } ]]> </script> </head> <body onload="init()"> <div> <object id="object" data="script2b_example.svg" type="image/svg+xml" width="150" height="150" style="border:1px solid #000000"> </object> <p> <button onclick="aendereRadius()">Ändere Radius</button> </p> </div> </body> </html>