(Вставить и) Обратитесь к внешнему SVG через D3 и/или javascript

У меня есть .svg файл и вы хотите встроить его в структуру svg моей d3-графики.

Мне также нужно ссылаться на все пути/многоугольники, прикрепленные к g-элементам через id определенных g элементов.

Я пробовал разные способы встраивания и ссылки на svg (g), но по некоторым причинам он не работал:

(1) первая попытка

// 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 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) вторая попытка

// 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) svg файл выглядит примерно так:

<?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>

Ответы

Ответ 1

Там лучшее решение.

Я не понял, что функция d3.xml() возвращает xml файл для чтения как фрагмент документа (в отличие от преобразования его в JSON). Другими словами, он возвращает готовое дерево DOM, которое может быть вставлено в ваш основной документ DOM, где вам это нужно.

Зная, что (и зная, что автономные файлы SVG также являются файлами XML), это, вероятно, самый надежный способ добавления внешнего содержимого SVG на вашу веб-страницу:

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 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);

});

Заклинание здесь: http://jsfiddle.net/J8sp3/4/

Обратите внимание, что (a) я добавляю содержимое к существующему SVG и (б) я не удаляю ни одно из текущего содержимого SVG.

Конечно, вы также можете добавить SVG в <div> или любой другой элемент, который может его содержать: http://jsfiddle.net/J8sp3/3/ p >

Этот метод должен работать в любом браузере, поддерживающем SVG. Я даже пробовал его в IE8, а структура DOM верна, даже если IE8 не знает, как рисовать круги и прямоугольники!

@Seb, пожалуйста, отмените выбор предыдущего ответа, выберите этот вариант в качестве принятого ответа.

Ответ 2

Правильный формат для встраивания содержимого SVG из другого файла заключается в использовании элемента <use>. Однако вы не можете получить доступ к структуре DOM (то есть к отдельным элементам) вложенного SVG - все это рассматривается как одно изображение.

Если вы хотите изменить графику, описанную внешним файлом, вам лучше читать внешний файл в виде текстового /XML файла (используя d3.text), а затем с помощью этого XML-текста создайте SVG-графику в DOM, написав контент как внутренний HTML-контейнер контейнера <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();
});

Теперь ваш DOM должен выглядеть как

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

Теперь вы можете выбирать элементы как обычно, а также задавать положение или размер созданного svg или удалять g-элементы или что-то еще - все они являются просто нормальными элементами вашего DOM. Убедитесь, что ваши атрибуты "id" не конфликтуют - они должны быть уникальными для всей страницы.

Пример здесь, показывающий дополнительный контент, добавленный в SVG с d3, и переход d3, выбирающий и изменяющий элемент из внешнего SVG:
http://jsfiddle.net/J8sp3/2/

ВНИМАНИЕ!

В исходной версии этого ответа предлагается добавить внешний SVG-контент в виде вложенного SVG внутри SVG, который уже был создан с помощью D3.

Как выяснил Seb, этот метод не работает в последних браузерах Safari и Opera или в Chrome 31 и ниже.

Проблема заключается в том, как браузеры webkit реализуют функцию innerHTML, которая вызывается функцией d3 selection.html(). В частности, функция innerHTML вообще не реализована в элементах SVG!

Самое смутное, что метод не возвращает никаких ошибок, а некоторые версии Chrome фактически отображают содержимое SVG без добавления его в DOM (как если бы вы использовали <use xlink:href="external.svg"/>).