(Embed et) se référer à un SVG externe via D3 et/ou javascript

j'en ai un .svg et vous voulez l'intégrer dans la structure svg de mon D3-graphic.

je dois aussi référencer tous les chemins / polygones attachés aux G-elements via un id de certains g-elements.

j'ai essayé différentes façons d'intégrer et de référencer les svg( g), mais cela n'a pas fonctionné pour certaines raisons:

(1) première tentative

// Firefox displays my svg but when i open it with Chrome the svg     
//is not displayed (just default placeholder icon)
// I can't reference the svg-g id's with d3.select functions. 
main_chart_svg
        .append("svg:image")
        .attr("xlink:href", "mySVGpicture.svg")
        .attr("x", "50")
        .attr("y", "50")
        .attr("width", "500")
        .attr("height", "500");  

main_chart_svg.select("#anIdWhichIsInTheSvgFile").remove(); //// This doesn't work

(2) deuxième tentative

// This displays the svg but -not- inside my main-chart-svg. I want to keep the graphic   
//things seperate to html-stuff.
d3.xml("mySVGpicture.svg", "image/svg+xml", function(xml) {
        document.body.appendChild(xml.documentElement);
    });
//----------or----------//
    d3.select("body")
        .append("object")
        .attr("data", "mySVGpicture.svg")
        .attr("width", 500)
        .attr("height", 500)
        .attr("type", "image/svg+xml");

d3.select("#anIdThatIsInTheSvgFile").remove(); //does not work.

(3) Le svg fichier ressemble à quelque chose comme ça:

<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 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" x="0px" y="0px" width="400px"
     height="400px" viewBox="0 0 400 400" enable-background="new 0 0 400 400" xml:space="preserve">
    <g id="anIdWhichIsInTheSvgFile">
        <g id="DE">
            <path fill="#FEDCBD" d="M215.958,160.554c0,0-0.082, ... ,1.145
                l0.865,0.656L215.958,160.554z"/>
            <path fill="#FEDCBD" d="M208.682,155.88l1.246,1.031c0,0,0.191,0.283, ... ,0.572L208.682,155.88z"/>
            <polygon fill="#FEDCBD" points="190.76,153.007 190.678, ... ,153.938 
                191.427,152.906"/>
            <polygon fill="#FEDCBD" points="170.088,151.015 169.888,150.067 169.125,150.075 168.846,150.836 169.521,151.588"/>
            <polygon fill="#FEDCBD" points="168.953,152.067 168.188,151.505 168.674,152.639"/>
            <polygon fill="#FEDCBD" points="170.105,153.099 170.666,152.052 170.002,152.248"/>
    </g>
    <g id="anIdThatIsInTheSvgFile">
    ...
    </g>
</svg>
18
demandé sur Seb Waynee 2014-01-19 00:36:08

2 réponses

il y a une meilleure solution.

je n'avais pas réalisé que le d3.xml() la fonction retourne un fichier xml lu comme un fragment de document (par opposition à la conversion en JSON). En d'autres termes, il retourne un arbre DOM prêt à l'emploi qui peut être inséré dans le DOM de votre document principal où que vous en ayez besoin.

sachant que (et sachant que les fichiers SVG autonomes sont aussi des fichiers XML), c'est probablement l'approche la plus fiable pour ajouter des fichiers externes SVG contenu de votre page web:

d3.xml("http://upload.wikimedia.org/wikipedia/commons/a/a0/Circle_-_black_simple.svg", 
        function(error, documentFragment) {

    if (error) {console.log(error); return;}

    var svgNode = documentFragment
                .getElementsByTagName("svg")[0];
    //use plain Javascript to extract the node

    main_chart_svg.node().appendChild(svgNode);
    //d3's selection.node() returns the DOM node, so we
    //can use plain Javascript to append content

    var innerSVG = main_chart_svg.select("svg");

    innerSVG.transition().duration(1000).delay(1000)
          .select("circle")
          .attr("r", 100);

});

Violon ici: http://jsfiddle.net/J8sp3/4/

Notez en particulier que (a) j'ajoute le contenu à une SVG existante, et (b) Je ne supprime aucun contenu de cette SVG.

bien sûr, vous pouvez aussi ajouter le SVG à un <div> ou tout autre élément qui peut contenir: http://jsfiddle.net/J8sp3/3/

cette méthode devrait fonctionner dans n'importe quel navigateur qui supporte SVG. J'ai même essayé dans IE8, et la structure du DOM est correcte même si IE8 ne sait pas dessiner des cercles et des rectangles!

@Seb, veuillez désélectionner la réponse précédente en choisissant celle-ci comme réponse acceptée.

33
répondu AmeliaBR 2014-01-22 17:37:19

le format approprié pour intégrer le contenu SVG d'un autre fichier est d'utiliser un <use> élément. Cependant, vous ne pouvez pas accéder à la structure DOM (c'est-à-dire les éléments individuels) du SVG imbriqué -- tout est traité comme une seule image.

si vous voulez pouvoir modifier le graphique décrit par le fichier externe, vous feriez mieux de lire le fichier externe comme un fichier texte/XML (en utilisant d3.text), puis en utilisant ce texte XML pour créer le graphique SVG dans le DOM en écrivant le contenu comme le HTML intérieur d'un conteneur <div>

d3.text("mySVGpicture.svg", function(error, externalSVGText) {
         if (error) {console.log(error); return;}

         chart_div.html(externalSVGText);

         svg = chart_div.select("svg");

         do_stuff();
});

votre DOM devrait maintenant ressembler à

body
  div.chart
     svg
       g#anIDWhichIsInTheSVGFile
         g#DE
           path
           /*etc*/
       g#anotherIDWhichIsInTheSVGFile

vous pouvez maintenant sélectionner des éléments comme normal, et définir la position ou la taille du svg que vous avez créé ou supprimer des éléments g ou autre -- ce sont tous des éléments normaux dans votre DOM. Assurez-vous que vos attributs "id" n'entrent pas en conflit -- ils doivent être uniques pour toute la page.

Exemple ici, montrant ajout de contenu supplémentaire à la SVG avec d3, et transition d3 sélection et modification d'un élément de la SVG externe:

http://jsfiddle.net/J8sp3/2/

avertissement

la version originale de cette réponse suggérait d'ajouter le contenu SVG externe comme SVG imbriqué dans le SVG qui avait déjà été créé avec D3.

comme Seb l'a découvert, cette méthode ne fonctionne pas sur le dernier Safari et L'Opéra les navigateurs, ou sur Chrome 31 et moins.

le problème est dans la façon dont les navigateurs webkit implémentent le innerHTML la fonction qui est appelée par d3 selection.html() fonction. Plus précisément, innerHTML la fonction n'est pas mis en œuvre à tous les éléments SVG!

ce qui est le plus déroutant, c'est que la méthode ne renvoie aucune erreur, et que certaines versions de Chrome affichent effectivement le contenu SVG sans l'ajouter au DOM (comme si vous utilisiez <use xlink:href="external.svg"/>).

4
répondu AmeliaBR 2014-01-20 22:25:59