web-dev-qa-db-ja.com

(埋め込み)D3やJavaScriptを介して外部SVGを参照する

.svgファイルがあり、それを私のd3-graphicのsvg構造に埋め込みたいです。

また、特定の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'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)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>
19
Seb Waynee

より良い解決策があります。

d3.xml() 関数が読み込みXMLファイルを ドキュメントフラグメント として返すことを(JSONに変換するのではなく)気づきませんでした。つまり、必要なときにメインドキュメントのDOM内に挿入できる既製のDOMツリーを返します。

これがわかっている(スタンドアロンのSVGファイルもXMLファイルであることがわかっている)ことを知っていると、これはおそらく外部SVGコンテンツを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);

});

ここでフィドル: http://jsfiddle.net/J8sp3/4/

特に、(a)既存のSVGにコンテンツを追加しており、(b)そのSVGの現在のコンテンツは削除していないことに注意してください。

もちろん、SVGを<div>またはそれを含むことができるその他の要素に追加することもできます。 http://jsfiddle.net/J8sp3/3/

このメソッドは、SVGをサポートするすべてのブラウザーで機能します。 IE8でも試してみましたが、IE8が円や長方形の描き方を知らなくてもDOM構造は正しいです!

@Seb、これを承認済みの回答として選択するときに、前の回答の選択を解除してください。

36
AmeliaBR

別のファイルからSVGコンテンツを埋め込むための適切な形式は、 _<use>_ 要素を使用することです。ただし、ネストされたSVGのDOM構造(つまり、個々の要素)にアクセスすることはできません。すべてが1つの画像として扱われます。

外部ファイルで記述されたグラフィックを変更できるようにしたい場合は、外部ファイルをテキスト/ XMLファイルとして読み取り( _d3.text_ を使用)、次に使用することをお勧めします。コンテナの内部HTMLとしてコンテンツを書き込むことでDOMにSVGグラフィックを作成するXMLテキスト_<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」属性が競合しないことを確認してください。属性はページ全体で一意である必要があります。

ここの例では、d3を使用してSVGに追加された追加コンテンツと、外部SVGから要素を選択および変更するd3遷移を示しています。
http://jsfiddle.net/J8sp3/2/

警告

この回答の元のバージョンでは、D3で既に作成されているSVG内にネストされたSVGとして外部SVGコンテンツを追加することを提案しました。

Sebが発見したように、この方法は、最新のSafariおよびOperaブラウザ、またはChromeでは機能しません。 31歳以下。

問題は、WebキットブラウザーがinnerHTML関数を実装する方法にあります。これは、d3のselection.html()関数によって呼び出されます。具体的には innerHTML関数はSVG要素にまったく実装されていません

最も混乱しているのは、メソッドがエラーを返さないことです。Chromeの一部のバージョンは、実際にはSVGコンテンツをDOMに追加せずに表示します(_<use xlink:href="external.svg"/>_を使用した場合と同様)。

4
AmeliaBR