(嵌入和)通过D3和/或javascript参考外部SVG

时间:2014-01-18 20:36:09

标签: javascript xml svg d3.js

我有一个.svg文件,想把它嵌入到我的d3-graphic的svg结构中。

我还需要通过某些g元素的id引用附加到g元素的所有路径/多边形。

我尝试了不同的方法来嵌入和引用svg(g's),但由于某些原因它不起作用:

(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'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)第二次尝试

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

2 个答案:

答案 0 :(得分:34)

有一个更好的解决方案。

我还没有意识到d3.xml()函数将读入的xml文件作为document fragment返回(而不是将其转换为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'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);

});

在这里小提琴:http://jsfiddle.net/J8sp3/4/

特别注意:(a)我将内容添加到现有SVG,以及(b)我没有删除任何SVG的当前内容。

当然,您也可以将SVG添加到<div>或可以包含它的任何其他元素:http://jsfiddle.net/J8sp3/3/

此方法适用于任何支持SVG的浏览器。我甚至在IE8中尝试过,即使IE8不知道如何绘制圆形和矩形,DOM结构也是正确的!

@Seb,请在选择此答案时取消选择上一个答案。

答案 1 :(得分:4)

从另一个文件嵌入SVG内容的正确格式是使用<use>元素。但是,您无法访问嵌套SVG的DOM结构(即单个元素) - 它们都被视为单个图像。

如果您希望能够修改外部文件描述的图形,最好将外部文件作为文本/ XML文件(使用d3.text)读取,然后使用该XML文本通过将内容编写为容器<div>

的内部HTML,在DOM中创建SVG图形
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”属性不会发生冲突 - 它们必须对整个页面都是唯一的。

此处示例,显示使用d3添加到SVG的附加内容,以及从外部SVG选择和修改元素的d3转换:
http://jsfiddle.net/J8sp3/2/

警告

此答案的原始版本建议将外部SVG内容添加为已使用D3创建的SVG内的嵌套SVG。

正如Seb发现的那样,这种方法在最新的Safari和Opera浏览器上,或在Chrome 31及更低版本上无效

问题在于webkit浏览器实现innerHTML函数的方式,该函数由d3的selection.html()函数调用。具体来说,the innerHTML function isn't implemented at all on SVG elements

最令人困惑的是该方法不会返回任何错误,并且某些版本的Chrome实际上会显示SVG内容而不将其添加到DOM(就像您使用<use xlink:href="external.svg"/>一样)。