SVG und JavaScript/DOM-Scripting
SVG verwendet genau wie HTML das DOM (Document Object Model), bei dem Sie mit JavaScript auf jedes SVG-Element einfach zugreifen können.
Vor diesem Kapitel sollten die Themen der Kurse Einstieg in SVG und Einstieg in das DOM bekannt sein, da die dort besprochenen Methoden hier eingesetzt werden.
Inhaltsverzeichnis
Inline-SVG
Wenn Sie SVG-Fragmente inline in HTML-Webseiten integrieren, sind die SVG-Elemente Teil des DOM. Sie können auf jedes SVG-Element wie auf ein beliebiges HTML-Element zugreifen.
Event-Handling
JavaScript wird im Allgemeinen beim Laden der Seite geladen und dann durch Benutzeraktionen aufgerufen. Diese Aktionen nennt man auch Events (dt. Ereignisse) .[1]
document.addEventListener('DOMContentLoaded', function () {
function changeFill () {
var farben = new Array(
'red', 'skyblue', '#dfac20', '#ebf5d7','#e4ebf2', '#5a9900',
'lime', '#df6c20', 'brown', '#5c82d9', 'burlywood',
'blueviolet', '#c32e04', '#ffebe6' ,'#5c82d9'
);
var fuellFarbe = Math.floor(farben.length * Math.random());
if (fuellFarbe == farben.length) {
fuellFarbe = farben.length-1;
}
fuellFarbe = farben[fuellFarbe];
kreis.setAttribute('fill', fuellFarbe);
}
document.getElementById('kreis').addEventListener('click', changeFill);
document.getElementById('text').addEventListener('click', changeFill);
});
Der Kreis wird mit document.getElementById angesprochen und erhält mit addEventListener einen Event-Handler zugewiesen. Der Text ebenfalls, sonst passiert ausgerechnet dann nichts, wenn der Benutzer tatsächlich auf den Text (und nicht auf die Kreisfläche daneben) klickt.
Wenn nun auf den Kreis geklickt wird, wird die Funktion changeFill()
aufgerufen, die nach dem Zufallsprinzip Farbwerte aus einem Array
ausliest und dem Kreis mit setAttribute()
zuweist.
SVG-Elemente erzeugen und löschen
Im Vergleich zu HTML wirkt die Syntax von SVG mit den vielen Geometrie-Attributen unübersichtlich. Anstatt Elemente direkt im Markup zu notieren, ist es oft vorteilhaft, diese mit aus aktuellen Berechnungen oder Eingaben ermittelten Werten dynamisch zu erzeugen.
<svg viewbox="0 0 880 450">
<text x="60" y="420">Erzeuge Ellipse!</text>
<rect id="createButton" tabindex="1" x="50" y="400" width="150" height="30" rx="5" />
</svg>
fill-opacity: .5
, damit der Text durchscheint.tabindex="1"
als XML-Attribut und cursor: pointer
im CSS erreicht. function createEllipse(){
svg.appendChild( getNode('ellipse', {
id: 'ellipse' + count,
cx: rand(0,880),
cy: rand(0,400),
rx: 30,
ry: 20,
fill: colors[rand(0, colors.length-1)]
}) );
count++;
}
function getNode(elem, v) {
elem = document.createElementNS("http://www.w3.org/2000/svg", elem);
for (var p in v)
elem.setAttribute(p, v[p]);
return elem;
}
Information
Methoden mit Namensraumangaben
Die Helferfunktion getNode erzeugt aus den zwei Parametern elem
und v
ein neues SVG-Element. Anstelle des evtl. schon bekannten Document.createElement(), die ein HTML-Element erzeugt, wird hier die XML-Variante createElementNS() verwendet.
Die in v übergebenen Attribute werden mit ihren Werten mit elem.setAttributeNS() zugewiesen.
function removeEllipse(event) {
var elem = event.target;
if ('rect' != elem.nodeName) {
var parent = elem.parentNode;
parent.removeChild(elem);
}
}
document.querySelector('svg').addEventListener('click', removeEllipse);
Ein weiterer EventListener lauscht auf Klicks in das svg-Element. Falls das angeklickte Elemente kein rect-Element (der Button) ist, wird das Elternelement (das svg-Element) aufgerufen und dessen Kindelement mit removeChild gelöscht.
tabindex
und cursor
entsprechend zugänglich zu machen. Einfacher ist es, …
- SVG für die Beschreibung grafischer Inhalte zu verwenden
- für Interaktionen die passenden HTML-Elemente mit ihrem Standardverhalten zu verwenden.
Rahmen um Text erzeugen
SVG-Text besteht nur aus den Zeichen oder Glyphen. Ein „Hintergrund“, den man wie bei HTML-Elementen mit CSS gestalten könnte, existiert nicht, kann aber mit JavaScript dynamisch erzeugt werden.
<svg xmlns="http://www.w3.org/2000/svg">
<text id="txt" x="20" y="40" font-size="24" >Das ist der Text.</text>
</svg>
Mit Javascript können wir den Text nun selektieren und seine Dimensionen auslesen.
document.querySelector('button').addEventListener('click', drawBanner);
function drawBanner(){
const horizontalPadding = 1.05,
lineHeight = 1.25; //größer wegen der Unterlängen!
var textobj = document.getElementById('txt'),
textWidth = textobj.getComputedTextLength().toFixed(1),
textHeight = textobj.getAttribute("font-size"),
rectobj = document.createElementNS('http://www.w3.org/2000/svg', 'rect');
rectobj.setAttribute('x', textobj.getAttribute('x') - 5);
rectobj.setAttribute('y', textobj.getAttribute('y') - textHeight);
rectobj.setAttribute('height', (lineHeight * textHeight).toFixed(1));
rectobj.setAttribute('width', (horizontalPadding * textWidth).toFixed(1));
textobj.parentNode.insertBefore(rectobj, textobj);
};
Mit getComputedLength()
wird die Länge des vorhandenen Texts ermittelt und der Variable textWidth
übergeben. Die Höhe wird aus der Schriftgröße, die im font-size-Attribut festgelegt wurde, ermittelt und textHeight
zugewiesen. (Wenn die Schriftgröße nur im CSS festgelegt wäre, müsste sie dort mit getPropertyCSSValue()
ermittelt werden.)
Jetzt wird mit createElementNS() ein neues SVG-Element erzeugt und ihm mit setAttribute() die Geometrie-Attribute mit den passenden Werten hinzugefügt. Die Breite und Höhe errechnet sich aus den ermittelten Werten des Textes, die mit horizontalPadding
und lineHeight
, die als Konstanten definiert werden, multipliziert werden. Da in der font-size Unterlängen nicht berücksichtigt wurden, ist der Wert für lineHeight
höher.
Anschließend wird das neue rect-Element mit insertBefore vor dem Text gezeichnet, da es ja (noch) keinen z-index bei SVG gibt. So wird erst der Hintergrund und Rahmen und dann davor der Text gezeichnet.
externe SVG-Dokumente ansprechen
Eine solche Veränderung des DOMs einer SVG-Grafik ist auch bei externen SVGs möglich. Im folgenden Beispiel wird die rechts gezeigte Grafik in die Webseite eingebunden und dann mit JavaScript verändert:
<object id="svgObject" data="Beispiel.svg" type="image/svg+xml" height="250" width="600">
SVG-Grafik konnte nicht geladen werden!
</object>
Achtung!
Um Cross Site Scripting (XSS) zu verhindern, unterbinden moderne Browser das Laden externer SVG-Grafiken von anderen Domains, da diese ja auch JavaScript enthalten können.
document.addEventListener('DOMContentLoaded', function () {
// Get the Object by ID
var mySVG = document.getElementById('svgObject'),
svgDoc;
// Get the SVG document inside the Object tag - Wait until it's loaded!
mySVG.addEventListener('load',function() {
svgDoc = mySVG.contentDocument;
alert('SVG contentDocument is geladen!');
}, false);
function changeFill () {
var svgItem = svgDoc.getElementById('quadrat');
svgItem.setAttribute('fill', '#5a9900');
}
document.querySelector('#button').addEventListener('click', changeFill);
});
Wenn das im object-Element enthaltene (SVG-)Dokument und die Webseite von gleicher Herkunft sind (Same-Origin-Policy), kann man mit contentDocument auf den Inhalt des externen SVG-Dokuments zugreifen.
Die einfache Zuweisung svgDoc = mySVG.contentDocument;
hat bei mir nicht funktioniert, bzw. null
ergeben, da das externe Objekt beim Ausführen des Scripts noch nicht geladen war. Die anonyme Funktion, die erst nach dem Laden des Objekts feuert, stellt sicher, dass die SVG-Grafik auch wirklich zur Verfügung steht.
Anwendungsbeispiele
Farben einer SVG-Karte aktualisieren
Stellen Sie sich eine Webseite vor, auf der Sie eine interaktive Karte mit Ländern anzeigen. Jedes Land auf der Karte wird als Pfad in einer externen SVG-Datei dargestellt. Benutzer können auf ein Land klicken, um es zu markieren, oder dynamisch Daten laden (z. B. Bevölkerung, BIP), um die Karte farblich zu gestalten.
ToDo (weitere ToDos)
Weblinks
- datenverdrahten.de: SVG-DOM-Scripting kompakt von Thomas Meinike
- srufaculty.edu SVG animation with JavaScript and SMIL von David Dailey
umfangreiche, aber auch unsortierte Sammlung von Ideen und Beispielen (JavaScript auf Stand von 2000!)- polylineTest (ein einfacher SVG-Editor von David Dailey)
- JS anim