[SVG|JavaScript] JSにSVGを埋め込んで、パースしたSVGをいろいろやりたい

2018/03/28

こんにちは。きんくまです。

イラレから書き出したSVGのデータをhtmlに取り込む方法はいろいろとあります。
外部SVGを非同期で読み込んだりとか。
でも今回は、JSにSVGを静的に埋め込んで、パースしたSVGを使いたいです。

JSにSVGを埋め込む

埋め込むといっても、ES6のヒアドキュメントを使えば簡単です。
イラレから書き出したSVGには id とか title とか入っているので消しておきました。あと下のデータめっちゃ適当です。

export const SVGData = `
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 768">
  <rect x="131" y="121" width="637" height="449" fill="#29abe2" stroke="#000" stroke-miterlimit="10" stroke-width="10"/>
  <circle cx="536" cy="229" r="163" fill="#ff0" stroke="red" stroke-miterlimit="10" stroke-width="10"/>
  <polygon points="262 81 323 221 501 212 496 481 262 459 78 443 261 345.5 262 81" fill="#006837" stroke="#7ac943" stroke-miterlimit="10" stroke-width="10"/>
  <path d="M381,490c41.18-56.62,118-136,171-42s101,52,136,24l46,70s-180,35-255,17S341,545,381,490Z" fill="blue" stroke="#7ac943" stroke-miterlimit="10" stroke-width="10"/>
</svg>
`;

slackとか、markdownみたいに バッククォートを3個書いてうまくいかなかったのはナイショです。
ヒアドキュメントは1個で良かったです。

パースしてhtml側のSVGに入れる

サンプルのhtmlを用意して、この中にさきほど埋め込んだSVGを入れたいです。

    <svg version="1.1" xmlns="http://www.w3.org/2000/svg"
      id="sample_svg"
      width="600" height="600">
    </svg>

文字列から動的にSVGを生成するにはDOMParserを使えばいいみたい。

>> Create an SVG DOM element from a String
>> Parsing an SVG or HTML document

それでポイントとしては、DOMParserで返ってくるオブジェクトはルートがDocumentになっているので、一番上の子供のSVGを取得する必要があることです。

        const svgText = SVGData;
        const domParser = new DOMParser();
        const parsedSVGDoc = domParser.parseFromString(svgText, 'image/svg+xml');
        const parsedSVG = parsedSVGDoc.childNodes[0];

        //htmlのSVG
        const svg = document.querySelector('#sample_svg');
        //生成したSVGをhtmlにそのまま入れる
        svg.appendChild(parsedSVG);

この場合は、htmlのSVGの中に、生成したSVGが入れ子で入っている状態です。(SVGふたつ)

生成したSVGの中の一部を使って中身を変えたい

さきほどは生成したSVGをそのまま入れましたけど、SVGなのでツリー構造になっているから、一部の塗りだけを変更したりとか、一部分だけを移植したりとかいろいろできます。


        const svgText = SVGData;
        const domParser = new DOMParser();
        const parsedSVGDoc = domParser.parseFromString(svgText, 'image/svg+xml');
        const parsedSVG = parsedSVGDoc.childNodes[0];
        const svg = document.querySelector('#sample_svg');
        //ここまで同じ =====

        //IE11だと querySelectorAll のあとのforEachができないから polyfill
        //https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach
        if (window.NodeList && !NodeList.prototype.forEach) {
            NodeList.prototype.forEach = function (callback, thisArg) {
                thisArg = thisArg || window;
                for (var i = 0; i < this.length; i++) {
                    callback.call(thisArg, this[i], i, this);
                }
            };
        }

        //やりたいことはここから ===

        //元データから塗りが青だけのpathを取り出して
        const blueFillPaths = parsedSVG.querySelectorAll('path[fill="blue"]');

        //塗りを赤にして、そのpathだけhtmlに埋め込む
        blueFillPaths.forEach((path)=>{
            path.setAttribute('fill', '#ba82de');
            svg.appendChild(path);
        });

この場合は、htmlのSVGの中に、生成したSVGから移植した一部のNodeが入っている状態です。(SVGひとつ)

SVGを使ってグラフやツールを作ってるのですが、Retina対応とか考えなくてもきれいに見えるのでSVGは便利だと思いますです。(IE11でも動く)
グラフはd3.js、ツールはvue.jsとそれぞれ組み合わせてやっています。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る