So greifen Sie mit Javascript auf SVG-Elemente zu

83

Ich spiele mit SVG herum und hatte gehofft, ich könnte SVG-Dateien in Illustrator erstellen und mit Javascript auf Elemente zugreifen.

Hier ist die SVG-Datei, die Illustrator startet (es scheint auch eine Menge Müll am Anfang der Datei hinzuzufügen, die ich entfernt habe).

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
     width="276.843px" height="233.242px" viewBox="0 0 276.843 233.242" enable-background="new 0 0 276.843 233.242"
     xml:space="preserve">
<path id="delta" fill="#231F20" d="M34.074,86.094L0,185.354l44.444,38.519l80.741-0.74l29.63-25.186l-26.667-37.037
    c0,0-34.815-5.926-37.778-6.667s-13.333-28.889-13.333-28.889l7.407-18.519l31.111-2.963l5.926-21.481l-12.593-38.519l-43.704-5.185
    L34.074,86.094z"/>
<path id="cargo" fill="#DFB800" d="M68.148,32.761l43.704,4.445l14.815,42.963l-7.407,26.667l-33.333,2.963l-4.444,14.074
    l54.074-1.481l22.222,36.296l25.926-3.704l25.926-54.074c0,0-19.259-47.408-21.481-47.408s-31.852-0.741-31.852-0.741
    l-19.259-39.259L92.593,8.316L68.148,32.761z"/>
<polygon id="beta" fill="#35FF1F" points="86.722,128.316 134.593,124.613 158.296,163.872 190.889,155.724 214.593,100.909 
    194.593,52.02 227.186,49.057 246.444,92.02 238.297,140.909 216.074,172.761 197.556,188.316 179.778,169.798 164.963,174.983 
    163.481,197.946 156.815,197.946 134.593,159.428 94.593,151.279 "/>
<path class="monkey" id="alpha" fill="#FD00FF" d="M96.315,4.354l42.963,5.185l18.519,42.222l71.852-8.148l20.74,46.667l-5.926,52.593
    l-24.444,34.074l-25.185,15.555l-14.074-19.259l-8.889,2.964l-1.481,22.222l-14.074,2.963l-25.186,22.963l-74.074,4.444
    l101.481,4.444c0,0,96.297-17.777,109.63-71.852S282.24,53.983,250.389,20.65S96.315,4.354,96.315,4.354z"/>
</svg>

Wie Sie wahrscheinlich sehen können, hat jedes Element eine ID, und ich hatte gehofft, mit Javascript auf einzelne Elemente zugreifen zu können, um das Fill-Attribut zu ändern und auf Ereignisse wie Klick zu reagieren.

Der HTML-Code ist einfach

<!DOCTYPE html>
<html>
    <head>
        <title>SVG Illustrator Test</title> 
    </head>
    <body>

        <object data="alpha.svg" type="image/svg+xml" id="alphasvg" width="100%" height="100%"></object>

    </body>
</html>

Ich denke, das sind wirklich zwei Fragen.

  1. Ist es möglich, dies auf diese Weise zu tun, anstatt etwas wie Raphael oder jQuery SVG zu verwenden?

  2. Wenn es möglich ist, wie ist die Technik?


AKTUALISIEREN

Im Moment habe ich Illustrator zum Erstellen der SVG-Datei verwendet, und ich verwende Raphaël JS , um Pfade zu erstellen und einfach die Punktdaten aus der SVG-Datei zu kopieren und in die path()Funktion einzufügen . Das Erstellen komplexer Pfade, wie sie möglicherweise für eine Karte erforderlich sind, durch manuelles Codieren der Punktdaten ist (meines Wissens) unerschwinglich komplex.

gigantisch
quelle

Antworten:

113

Ist es möglich, dies auf diese Weise zu tun, anstatt etwas wie Raphael oder jQuery SVG zu verwenden?

Bestimmt.

Wenn es möglich ist, wie ist die Technik?

Dieses kommentierte Code-Snippet funktioniert:

<!DOCTYPE html>
<html>
    <head>
        <title>SVG Illustrator Test</title> 
    </head>
    <body>

        <object data="alpha.svg" type="image/svg+xml"
         id="alphasvg" width="100%" height="100%"></object>

        <script>
            var a = document.getElementById("alphasvg");

            // It's important to add an load event listener to the object,
            // as it will load the svg doc asynchronously
            a.addEventListener("load",function(){

                // get the inner DOM of alpha.svg
                var svgDoc = a.contentDocument;
                // get the inner element by id
                var delta = svgDoc.getElementById("delta");
                // add behaviour
                delta.addEventListener("mousedown",function(){
                        alert('hello world!')
                }, false);
            }, false);
        </script>
    </body>
</html>

Beachten Sie, dass eine Einschränkung dieser Technik darin besteht, dass sie durch die Richtlinie mit demselben Ursprung eingeschränkt ist und daher alpha.svgin derselben Domäne wie die .htmlDatei gehostet werden muss , da sonst auf das innere DOM des Objekts nicht zugegriffen werden kann.

Wichtig , um diesen HTML- Code auszuführen, benötigen Sie eine Host-HTML-Datei auf einem Webserver wie IIS, Tomcat

jbeard4
quelle
4
Hinweis zu @ jbeard4: In einigen Browsern erfordert diese Richtlinie mit demselben Ursprung die Verwendung eines Servers (auch wenn Ihr Code nur HTML und js [serverseitig] verwendet). Die Zugriffsrichtlinie verhindert den Zugriff auf die SVG.
Michael
1
Wichtig, um diesen HTML-Code auszuführen, benötigen Sie eine Host-HTML-Datei auf einem Webserver wie IIS, Tomcat
Hien Nguyen
Wie @HienNguyen erwähnte, funktionierte es nicht, bevor es auf einem Webserver ausgeführt wurde. Der zurückgegebene Wert document.getElementById("alphasvg").contentDocumentwar null.
am.rez
TL; DR: contentDocumentBrücken vom HTML-Kontext zum SVG-Kontext
Abdull
19

Wenn Sie jQuery verwenden, müssen Sie warten $(window).load, da das eingebettete SVG-Dokument möglicherweise noch nicht geladen wurde$(document).ready

$(window).load(function () {

    //alert("Document loaded, including graphics and embedded documents (like SVG)");
    var a = document.getElementById("alphasvg");

    //get the inner DOM of alpha.svg
    var svgDoc = a.contentDocument;

    //get the inner element by id
    var delta = svgDoc.getElementById("delta");
    delta.addEventListener("mousedown", function(){ alert('hello world!')}, false);
});
jediz
quelle
3
Bei Verwendung dieses Codes kann diese andere Antwort eine nützliche Ergänzung sein: stackoverflow.com/a/5990945/1515819
Stéphane Bruckert
im Falle von jQuery verwenden Sie besser $('#alphasvg').loadanstelle von $(window).load. Dies ermöglicht es Ihnen, Attribut dataim
laufenden Betrieb
Beachten Sie, dass Sie mit jQuery zwar auf Elemente in svg zugreifen können, jedoch nicht zum Anhängen von Elementen an ein svg. Informationen zum Warum finden Sie unter stackoverflow.com/questions/3642035/… .
Hrabinowitz
4

Wenn Sie ein <img>Tag für die SVG verwenden, können Sie deren Inhalt nicht manipulieren (soweit ich weiß).

Wie die akzeptierte Antwort zeigt, ist die Verwendung <object>eine Option.

Ich brauchte dies kürzlich und verwendete es gulp-injectwährend meines gulp-Builds, um den Inhalt einer SVG-Datei als <svg>Element direkt in das HTML-Dokument einzufügen, was dann mit CSS-Selektoren und querySelector/ oder sehr einfach zu handhaben ist getElementBy*.

Drew Noakes
quelle
imgTag ist nützlich für große SVG-Last ... Um komplexe (und interaktive!) SVG zu verwenden , ist es besser, D3js zu verwenden , das ist wie eine lite jQuery, die auf SVG + DOM + -Datenmanipulation spezialisiert ist.
Peter Krauss