Warnung
Da ich im Moment diese Seite leider nicht mehr aktiv pflegen und auf dem neuesten Stand halten kann, können manche Informationen bereits veraltet sein. Sollten Änderungen von euch bei mir eintreffen, bin ich jedoch gerne bereit diese hier einzupflegen. Auch Leute, die sich um die Seite bzw. deren Inhalt kümmern möchten, sind gerne gesehen.
 Inhaltsverzeichnis  Interaktivität  Zugriff auf das DOM

10.5Zugriff auf das DOM

Möchte man auf ein Element einer SVG-Grafik zugreifen, benötigt dieses Element in der Regel eine ID. Dadurch ist gewährleistet, daß das Element im Baum eindeutig identifiziert und somit von identischen Objekten unterschieden werden kann. Das folgende  Listing 10-12 zeigt einen solchen Zugriff auf ein SVG-Dokument.

 Anzeigebeispiel

<?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 toggleColor(evt)
    {
      var textlink = evt.target;
      var rectangle = document.getElementById("square");
      if(evt.type == "mouseover")
      {
        rectangle.setAttributeNS(null, "fill", "brown");
      }
      else
      {
        rectangle.setAttributeNS(null, "fill", "gold");
      }
    }
  ]]>
  </script>

  <text x="10" y="20" style="font-size:11pt" onmouseover="toggleColor(evt)" onmouseout="toggleColor(evt)">
    Berühre diesen Text, um die Farbe des Quadrats zu ändern.
  </text>
  <rect id="square" x="10" y="30" height="100" width="100" fill="gold" stroke="black" />
</svg>
Listing 10-12: Zugriff auf ein SVG-Element mit Hilfe einer ID

Die Aufgabe der Funktion toggleColor() besteht in der Änderung der Farbe des Quadrats in Abhängigkeit der beiden Mausereignisse mouseover und mouseout. Bei dem Übergabeparameter evt handelt es sich um eine Referenz auf ein Objekt des Typs Event - also um ein Ereignisobjekt. Dabei ist zu beachten, daß evt beim Funktionsaufruf wie auch im Funktionskopf zwingend angegeben werden muß. Mit Hilfe von evt bzw. dessen Eigenschaft target erhält man eine Referenz auf das <text>-Element, die in der Variablen textlink gespeichert wird. Um ebenfalls eine Referenz auf das Quadrat zu erhalten, wird die Methode getElementById() des document-Objekts verwendet. Sie erhält als Parameter den Wert des id-Attributs des <rect>-Elements - in diesem Fall square. Anschließend wird das Quadrat, sollte sich der Mauszeiger darin befinden, braun eingefärbt. Befindet sich der Zeiger außerhalb des Quadrats, erhält es die Farbe Gold.

zum Anfang der Seitezum Ende der Seite

10.5.1DOM Level 1 vs. DOM Level 2

Für die Manipulation von Elementen und Attributen eines SVG-Dokuments existieren spezielle Methoden, die zum einen dem DOM Level 1 und zum anderen dem DOM Level 2 zugeordnet werden können. Da die DOM Level 1-Spezifikation [ W3C05i] vor der Spezifikation Namespaces in XML 1.0 [ W3C05h] veröffentlicht wurde, kennt DOM Level 1 keine Namensräume, so daß die Verwendung dieser Methoden bei vielen modernen XML-Sprachen zu Schwierigkeiten führen kann. Um diese Probleme zu umgehen, wurde das Document Object Model zum DOM Level 2 Core [ W3C05j] weiterentwickelt.  Tabelle 10-2 beinhaltet alle DOM Level 1-Methoden und deren DOM Level 2-Äquivalente, wobei nur noch letztere Verwendung finden sollten.

DOM Level 1 (veraltet)DOM Level 2
createAttribute()createAttributeNS()
createElement()createElementNS()
getAttributeNode()getAttributeNodeNS()
getAttribute()getAttributeNS()
getElementsByTagName()getElementsByTagNameNS()
getNamedItem()getNamedItemNS()
hasAttribute()hasAttributeNS()
removeAttribute()removeAttributeNS()
removeNamedItem()removeNamedItemNS()
setAttribute()setAttributeNS()
setAttributeNode()setAttributeNodeNS()
setNamedItem()setNamedItemNS()
Tabelle 10-2: Vergleich der herkömmlichen mit den namensraumfähigen DOM-Methoden

Der erste Parameter aller namenraumsfähigen DOM-Methoden ist grundsätzlich der Namensraumbezeichner - meistens eine URI und deshalb auch oft Namensraum-URI genannt. Im Falle von SVG wäre dies z.B. http://www.w3.org/2000/svg. Zu beachten ist allerdings, daß der Namensraumbezeichner für präfixlose Attribute keinen Wert besitzt, d.h. obwohl ein Attribut zum Namensraum seines Elements gehört, verwendet man nicht den Namensraumbezeichner dieses Elements. Stattdessen muß null als Bezeichner für solche Attribute angegeben werden. Hat man also beispielsweise mit el = document.createElementNS("http://www.w3.org/2000/svg", "rect"); ein Rechteck erzeugt und möchte auf das Attribut x dieses Rechtecks zugreifen, so muß man el.getAttributeNS(null, "x"); dazu verwenden.

Sollen Attribute manipuliert werden, die nicht zum selben XML-Dialekt gehören wie das Element, in dem sie sich befinden, sprich die mit einem Namensraumpräfix ausgestattet sind, so muß man den entsprechenden DOM Level 2-Methoden deren Namensraum übergeben. Um z.B. den Wert eines xlink:href-Attributs eines <a>-Elements auszulesen, würde man eine Anweisung der Form el.getAttributeNS("http://www.w3.org/1999/xlink", "href"); benutzen. Beim Setzen von Attributen ist es im übrigen ratsam, wenn auch nicht notwendig, im zweiten Argument dem Attributnamen das entsprechende Präfix gefolgt von einem Doppelpunkt voranzustellen (z.B. el.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "image.png");), so daß das DOM später einfacher in ein XML überführt werden kann.

 Listing 10-13 faßt all das oben Genannte zu einem Beispiel zusammen und demonstriert wie man dynamisch Elemente erzeugen und bearbeiten sollte.

var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
var image = document.createElementNS(svgNS, "image");

image.setAttributeNS(null, "width", "100");
image.setAttributeNS(null, "height", "100");
image.setAttributeNS(xlinkNS, "xlink:href", "image.png");
Listing 10-13: Dynamischen Erstellung und Manipulation eines Elements mit Rücksicht auf Namensräume

Um Probleme mit diversen SVG-Betrachtern von vorherein zu vermeiden, sollte man also innerhalb eines SVG-Dokuments generell Namensräume deklarieren und Elemente nur mit den eben vorgestellten DOM Level 2-Methoden bearbeiten. Die folgende Schablone aus  Listing 10-14 beherrbergt die wichtigsten Namensraumdeklarationen und kann somit dem Entwickler u.U. einiges an Ärger ersparen.

<svg version="1.1"
  baseProfile="full"
  xmlns="http://www.w3.org/2000/svg"
  xmlns:xlink="http://www.w3.org/1999/xlink"
  xmlns:ev="http://www.w3.org/2001/xml-events">
</svg>
Listing 10-14: Schablone für ein SVG-Dokument mit den wichtigsten Namensraumdeklarationen
zum Anfang der Seitezum Ende der Seite

10.5.2Zugriff auf Knoten

Bevor man einen Knoten verschieben oder löschen kann, muß man selbstverständlich erst einmal Zugriff auf ihn bekommen. Bewerkstelligen läßt sich dies mit der oben bereits erwähnten Methode getElementById() des SVG-Dokumentobjekts, welche als Parameter die ID des Elements erhält, auf das man zugreifen möchte.

Eine weitere nützliche Methode, um auf mehrere Knoten gleichzeitig zugreifen zu können, nennt sich getElementsByTagNameNS(). Sie erwartet als ersten Parameter einen Namensraumbezeichner und als zweiten einen Elementtyp, wie etwa rect, circle oder path. Als Rückgabewert bekommt man eine Liste aller Elemente desselben Typs. Um eine Liste aller Elemente der SVG-Grafik zu erhalten, wird anstelle des Typbezeichners * angegeben.

Im Zusammenhang mit getElementsByTagNameNS() sollte auch noch kurz das Interface NodeList erwähnt werden. Es besitzt zum einen das Attribut length, mit dem die Länge der Liste ermittelt werden kann, und zum anderen die Methode item(), welche eine Referenz auf ein Node-Objekt (einen Knoten) der Liste liefert. Dazu erhält item() als Parameter den Index des gewünschten Objekts. Wie man length und item() einsetzten kann, zeigt das folgende  Listing 10-15. Das Ergebnis dieses SVG-Codes findet sich in  Abbildung 10-2.

 Anzeigebeispiel

<?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 getColors(evt)
    {
      var svgNS = "http://www.w3.org/2000/svg";
      var textlink = evt.target;
      var allRects = document.getElementsByTagNameNS(svgNS, "rect");
      var msg = "";
      for(var i = 0; i < allRects.length; i++)
      {
        var oneRect = allRects.item(i);
        msg += "Farbe des " + (i + 1) + ". Rechtecks: " + oneRect.getAttributeNS(null, "fill") + "\n";
      }
      alert(msg);
    }
  ]]>
  </script>

  <text x="10" y="20" onclick="getColors(evt)" style="font-size:11pt">
    Klicke auf diesen Text, um alle verwendeten Farben aufgelistet zu bekommen.
  </text>
  <rect x="10" y="30" height="30" width="30" fill="gold" />
  <rect x="50" y="30" height="30" width="30" fill="orange" />
  <rect x="90" y="30" height="30" width="30" fill="brown" />
  <rect x="130" y="30" height="30" width="30" fill="black" />
</svg>
Listing 10-15: Zugriff auf mehrere Elemente mittels getElementsByTagNameNS()

Abbildung 10-2: Das getElementsByTagNameNS()-Beispiel dargestellt von Mozilla Firefox 1.5.0.6
zum Anfang der Seitezum Ende der Seite

10.5.3Manipulation von Attributen

Nun wieder zurück zu dem Beispiel aus  Listing 10-12. Der Variablen rectangle wurde durch die Methode getElementById() eine Referenz auf das Rechteck übergeben. Um nun die Attribute des Rechtecks ändern zu können, werden spezielle Methoden benötigt, die jedes Elementobjekt besitzt. Die beiden wichtigsten sind getAttributeNS() und setAttributeNS(). getAttributeNS() erhält neben dem Namensraumbezeichner zustzlich den Namen des gewünschten Attributs als Übergabeparameter und liefert als Rückgabewert dessen Inhalt. setAttributeNS() erhält ebenso als ersten Parameter den Namensraumbezeichner gefolgt von dem Namen des zu setzenden Attributs und dessen neuen Wert.

Stileigenschaften können natürlich auch durch die Methoden getAttributeNS() und setAttributeNS() ausgelesen bzw. gesetzt werden. Möchte man aber nur eine einzige Stileigenschaft ändern, so muß man dennoch die gesamte Zeichenkette, die alle Eigenschaften enthält, setzen. Dazu ein Blick auf  Listing 10-16, das eine etwas veränderte Form des vorherigen Beispiels aus  Listing 10-12 zeigt.

 Anzeigebeispiel

<?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 toggleColor(evt)
    {
      var textlink = evt.target;
      var rectangle = document.getElementById("square");
      if(evt.type == "mouseover")
      {
        rectangle.setAttributeNS(null, "style", "fill:brown;stroke:black");
      }
      else
      {
        rectangle.setAttributeNS(null, "style", "fill:gold;stroke:black");
      }
    }
  ]]>
  </script>

  <text x="10" y="20" style="font-size:11pt" onmouseover="toggleColor(evt)" onmouseout="toggleColor(evt)">
    Berühre diesen Text, um die Farbe des Quadrats zu ändern.
  </text>
  <rect id="square" x="10" y="30" height="100" width="100" style="fill:gold;stroke:black" />
</svg>
Listing 10-16: Stileigenschaften auslesen und setzen

Das Auslesen eines style-Attributs mittels getAttributeNS() bzw. die Verarbeitung der darin enthaltenen Daten macht die Sache noch etwas komplizierter. Denn um an die gewünschten Stileigenschaften zu gelangen, muß man die zurückgelieferte Zeichenkette komplett nach diesen durchsuchen.

Um Stilattribute zu setzen, gibt es auch noch das sogenannte CSSStyleDeclaration-Objekt. Der Aufruf elementObj.getStyle() liefert ein solches Objekt mit einer Liste aller Stilattribute von elementObj. Analog zu den Methoden getAttributeNS() und setAttributeNS() besitzt dieses Objekt die Methoden getPropertyValue() und setPropertyValue(). Außerdem kann man mittels removeProperty() ein Stilattribut aus der Liste löschen.

Obwohl es sich hierbei um eine äußerst elegante Möglichkeit handelt, Stileigenschaften zu manipulieren, ist vom Einsatz des CSSStyleDeclaration-Objekts unbedingt abzuraten. Denn es handelt sich hierbei um eine von Adobe entwickelte Erweiterung, die nicht der SVG-Spezifikation entspricht. Um kompatiblen SVG-Code zu erzeugen, der nicht nur auf dem Adobe SVG Viewer funktioniert, sollte man also auf jeden Fall auf dieses Objekt verzichten.

zum Anfang der Seitezum Ende der Seite

10.5.4Elemente entfernen und erstellen

Ein Element kann nicht nur manipuliert, sondern auch komplett aus dem Baum entfernt oder durch ein anderes Element ersetzt werden. Hierfür gibt es die zwei Methoden removeChild() und replaceChild(). Als Parameter erhält die Methode removeChild() eine Referenz auf den zu löschenden Knoten. replaceChild() hingegen besitzt zwei Parameter, von denen der erste auch eine Referenz auf den zu löschenden Knoten und der zweite eine Referenz auf einen neuen Knoten beinhaltet. Damit diese Methoden angewendet werden können, muß das Vaterelement des zu löschenden oder zu ersetzenden Knotens bekannt sein. Die Eigenschaft parentNode eines Knotens liefert dessen Vaterknoten.

Erstellen läßt sich ein Element mit createElementNS() und einem Elementtyp als Parameter. Danach werden mittels setAttributeNS() die Eigenschaften gesetzt und das neue Element durch appendChild() dem Baum hinzugefügt. Dabei erhält appendChild() als Parameter den neu erzeugten Knoten.

 Listing 10-17 zeigt wie man parentNode, removeChild(), createElementNS() und appendChild() einsetzen kann.

 Anzeigebeispiel

<?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 changeElement(evt)
    {
      var svgNS = "http://www.w3.org/2000/svg";
      var textlink = evt.target;
      var rectangle = document.getElementById("square");
      var parent = null;
      var circle = null;
      if(rectangle)
      {
        parent = rectangle.parentNode;
        parent.removeChild(rectangle);
        circle = document.createElementNS(svgNS, "circle");
        circle.setAttributeNS(null, "cx", 60);
        circle.setAttributeNS(null, "cy", 80);
        circle.setAttributeNS(null, "r", 50);
        circle.setAttributeNS(null, "fill", "gold");
        circle.setAttributeNS(null, "stroke", "black");
        parent.appendChild(circle);
      }
      else
      {
        alert("Das Quadrat wurde schon durch den Kreis ersetzt!")
      }
    }
  ]]>
  </script>

  <text x="10" y="20" onclick="changeElement(evt)" style="font-size:11pt">
    Um das Quadrat durch einen Kreis zu ersetzen, klicke auf diesen Text.
  </text>
  <rect id="square" x="10" y="30" height="100" width="100" fill="gold" stroke="black" />
</svg>
Listing 10-17: Entfernen und Erzeugen eines Elements
zum Anfang der Seitezum Ende der Seite

10.5.5Zugriff auf einen Text

Damit der Inhalt des <text>-Elements ausgelesen und verändert werden kann, benötigt man zuerst eine Referenz auf dessen Knoten. Mit der Eigenschaft firstChild erhält man anschließend den Zugriff auf den ersten Subknoten. Dieses Text-Objekt besitzt u.a. die folgenden Attribute und Methoden.

Attribute:

Methoden:

Der SVG-Code in  Listing 10-18 benutzt die eben vorgestellten Eigenschaften und Methoden und demonstriert deren Arbeitsweise.

 Anzeigebeispiel

<?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[
    var i = 0;
    function changeText(evt)
    {
      var textElement = evt.target;
      text = textElement.firstChild;
      switch(i)
      {
        case 0:  alert("Aktueller Inhalt des Textknotens: " + text.data);
                 i++;
                 break;
        case 1:  text.insertData(text.length, " Fragt der Barkeeper:");
                 alert("Neuer Inhalt: " + text.data);
                 i++;
                 break;
        case 2:  text.appendData(" \"Wieso so'n langes Gesicht?\"");
                 alert("Die Zeichenkette '\" Wieso so'n langes Gesicht?\"' wurde an den Text angehängt.");
                 i++;
                 break;
        case 3:  text.replaceData(49, 5, "Weshalb");
                 alert("Die Zeichenfolge 'Wieso' wurde durch 'Weshalb' ersetzt.");
                 i++;
                 break;
        case 4:  alert("Zwischen den Zeichen 9 und 15 befindet sich folgendes Tier: " + text.substringData(9, 5));
                 i++;
                 break;
        case 5:  text.deleteData(0, text.length);
                 alert("Der gesamte Text wurde entfernt.");
                 i++;
                 break;
      }
    }
  ]]>
  </script>

  <text x="10" y="20" style="font-size:11pt;font-weight:bold">Klicke bitte auf den untenstehenden Text.</text>
  <text x="10" y="40" onclick="changeText(evt)" style="font-size:11pt">Kommt 'n Pferd in 'ne Bar.</text>
</svg>
Listing 10-18: Verschiedene Methoden der Textmanipulation
zum Anfang der Seite
zum vorherigen Kapitel  Ereignisbehandlung
zum nächsten Kapitel  SVG-Software
 Inhaltsverzeichnis  Interaktivität  Zugriff auf das DOM