svg要素の基本的な使い方まとめ

Written by defghi1977@xboxLIVE.この文書は全てテキストエディタで作成しています.えーと,そりゃもうゴリゴリと.
Powered by sie.

21.sieを用いたベクタグラフィックの描画

Internet Explorerはバージョン8までsvgに対応しておらず,バージョン9になってからようやくsvgの描画に対応した.しかし,windows XPが依然それなりのシェアを保っている事などからie8の利用は暫くの間続くものと思われ,web制作の足かせとなっているのは否めない.これらの制約を緩和する方法には様々なものがあるが,ここではsvgを古いieでも表示可能とするjavascriptライブラリ「sie」の利用したsvgの表示について説明する.なお利用したバージョンは1.0である.
※このページはie8で動作を確認しています.
※現状,sieはsvgの一部の機能のみに対応しているため,本ページのサンプルの全てが動作するわけではありません.従って他のブラウザと見た目が異なるケースがあります.

sieとは?

sieはその名の通りsvgをMicrosoft Internet Explorer上で表示させることができる国産のjavascriptライブラリである.ieでは長年の間svgと競合するベクタグラフィックの記述言語vmlをサポートしていたため,標準仕様のsvgへの対応が遅れていた経緯があり,svgに正式に対応したのはバージョン9からと歴史的には日が浅い.とは言えベクタグラフィックを描画する機能そのものは実装されているため,このvmlの機能を使ってsvgを描画してしまおうというのがsieの発想の原点である.似たような機能を提供するものとしてRaphaelが挙げられるが,Raphaelがjavascriptコードからのアクセスを想定しているのに対し,sieではsvg文書そのものを解析し,html文書に自動的にvml要素を挿入するといったユースケースを想定しており,既存のsvgファイルを流用できるというメリットがある.

その一方で,svgとvmlの仕様の間にはやはり相応の隔たりがあり,着々と機能が向上しているとはいえsvgの全ての機能を利用できるには至っていない.利用する上ではどの機能まで利用可能か検証した上で利用する必要がある.なお,基本図形の描画については概ね良好な出力結果を得ることができるので,inkscapeで作った画像を表示するといった場合は正常に動作する可能性が高い.

sieの導入

sieは内部でajax機構を用いているため,ローカル環境では思うように動作しない.apacheやiis等のwebサーバー上にファイルをアップロードした上で検証しよう.(なお,埋め込みsvgだけならローカル環境でも動作を確認することはできる.)

公式サイトから「sie.js」もしくは「sie-mini.js」を入手したら,webサーバー上の適切な場所(例えばhtmlファイルと同じ階層)にアップロードする.sie.jsを利用する側では次のような記述をhead要素に追加しよう.

<!DOCTYPE html>
<html>
    <head>
        <title>sie svg sample</title>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
        <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
<!--[if lte IE 8]>
        <script defer="defer" type="text/javascript" src="sie.js"></script>
<!--<![endif]-->

    </head>
    <body>
    </body>
</html>

ここで,「<!--[if lte IE 8]>」はieにおける条件付きコメントを表す記述である.条件付きコメントとはhtmlを読み込んでいるieのバージョンにより,有効としたいhtmlの記述を切り替えるための仕組みで,他のブラウザからは単なるコメントとして扱われるものだ.上の例ではhtmlを読み込んだブラウザがie8以前の場合にのみ,コメントで囲まれたscript要素が有効となる.元来sieはchromeやoperaでの動作をも考慮しているのだが,各ブラウザにおけるsvgへの対応が進んできた昨今は無用な検証を省くためにも有効となるブラウザを制限するほうが良いだろう.

※なお条件付きコメントはie10以降廃止(標準モード時)される模様である.

これでsvgを外部参照してグラフィックを描画する準備が整った.早速試してみよう.このページをie8で表示すると,以下にsvgの内容が表示されるはずだ.

object要素embed要素img要素

一方他のブラウザで内容を確認してみよう.グラフィックの内容に差異が発生しているはずだ.このようにsieを持ってしても完璧にはsvgのグラフィックを再現することはできない.事前にsvg文書をsieで解釈可能な範囲で書き換えておく必要が有る点に注意しよう.

sieの動作原理

sieはobject,embed,img要素によるsvgの表示埋め込み(インライン)svgの両方に対応している.それぞれ特有な動作をするので,ある程度その原理を知っておくとhtmlを構築する際に迷わなくて済む筈だ.

いずれの処理もhtmlファイルのロード時にのみ動作するため,後から動的にグラフィックを追加するといった用途には向いておらず,あくまで静的なhtmlファイルでのsvg出力に利用したほうが良い.動的にグラフィックを描画したいのであればRaphaelを用いることをおすすめする.

sieでの埋め込みsvgの利用

前述のとおりsieはhtmlに埋め込まれたsvg記述のグラフィック出力に対応している.実際にこの機能を利用するにはかなりの試行錯誤が必要となる.ここではできる限りクロスブラウザでのsvg表示を容易にする方法を紹介するので,これをベースに各自カスタマイズして欲しい.

なお,配布されているsvg.jsには現状埋め込みsvgをするのに問題のある箇所が存在するため,事前にコードの次の部分を修正しておこう.

更に,次のスクリプトを文字コードutf-8でjsファイルに保存し,(例えばファイル名を「sie-inline.js」として)サーバーにアップロードしておこう.このページで使っているものはこちら

/*
sie用インラインsvg表示スクリプト
by defghi1977
*/
//http://ejohn.org/blog/html5-shiv/
document.createElement("svg");
window.onload = function(){
    //svg要素名称のマッピング
    var elementNameMap = {
        "A" : "a",
        "ALTGLYPH" : "altGlyph",
        "ALTGLYPHDEF" : "altGlyphDef",
        "ALTGLYPHITEM" : "altGlyphItem",
        "ANIMATE" : "animate",
        "ANIMATECOLOR" : "animateColor",
        "ANIMATEMOTION" : "animateMotion",
        "ANIMATETRANSFORM" : "animateTransform",
        "CIRCLE" : "circle",
        "CLIPPATH" : "clipPath",
        "COLOR-PROFILE" : "color-profile",
        "CURSOR" : "cursor",
        "DEFS" : "defs",
        "DESC" : "desc",
        "ELLIPSE" : "ellipse",
        "FEBLEND" : "feBlend",
        "FECOLORMATRIX" : "feColorMatrix",
        "FECOMPONENTTRANSFER" : "feComponentTransfer",
        "FECOMPOSITE" : "feComposite",
        "FECONVOLVEMATRIX" : "feConvolveMatrix",
        "FEDIFFUSELIGHTING" : "feDiffuseLighting",
        "FEDISPLACEMENTMAP" : "feDisplacementMap",
        "FEDISTANTLIGHT" : "feDistantLight",
        "FEFLOOD" : "feFlood",
        "FEFUNCA" : "feFuncA",
        "FEFUNCB" : "feFuncB",
        "FEFUNCG" : "feFuncG",
        "FEFUNCR" : "feFuncR",
        "FEGAUSSIANBLUR" : "feGaussianBlur",
        "FEIMAGE" : "feImage",
        "FEMERGE" : "feMerge",
        "FEMERGENODE" : "feMergeNode",
        "FEMORPHOLOGY" : "feMorphology",
        "FEOFFSET" : "feOffset",
        "FEPOINTLIGHT" : "fePointLight",
        "FESPECULARLIGHTING" : "feSpecularLighting",
        "FESPOTLIGHT" : "feSpotLight",
        "FETILE" : "feTile",
        "FETURBULENCE" : "feTurbulence",
        "FILTER" : "filter",
        "FONT" : "font",
        "FONT-FACE" : "font-face",
        "FONT-FACE-FORMAT" : "font-face-format",
        "FONT-FACE-NAME" : "font-face-name",
        "FONT-FACE-SRC" : "font-face-src",
        "FONT-FACE-URI" : "font-face-uri",
        "FOREIGNOBJECT" : "foreignObject",
        "G" : "g",
        "GLYPH" : "glyph",
        "GLYPHREF" : "glyphRef",
        "HKERN" : "hkern",
        "IMAGE" : "image",
        "LINE" : "line",
        "LINEARGRADIENT" : "linearGradient",
        "MARKER" : "marker",
        "MASK" : "mask",
        "METADATA" : "metadata",
        "MISSING-GLYPH" : "missing-glyph",
        "MPATH" : "mpath",
        "PATH" : "path",
        "PATTERN" : "pattern",
        "POLYGON" : "polygon",
        "POLYLINE" : "polyline",
        "RADIALGRADIENT" : "radialGradient",
        "RECT" : "rect",
        "SCRIPT" : "script",
        "SET" : "set",
        "STOP" : "stop",
        "STYLE" : "style",
        "SVG" : "svg",
        "SWITCH" : "switch",
        "SYMBOL" : "symbol",
        "TEXT" : "text",
        "TEXTPATH" : "textPath",
        "TITLE" : "title",
        "TREF" : "tref",
        "TSPAN" : "tspan",
        "USE" : "use",
        "VIEW" : "view",
        "VKERN" : "vkern"
    };
    var svgs = document.getElementsByTagName("svg");
    for(var i = 0, len = svgs.length; i<len; i++){
        var svg = svgs[0];
        var source
            = "<svg"
            + toAttributesNotation(svg)
            + ' xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">'
            + fixHTML(svg.innerHTML)
            + "</svg>";
        var script = document.createElement("script");
        script.type = "image/svg+xml";
        script.text = source;
        var parent = svg.parentNode;
        parent.replaceChild(script, svg);
    }
    
    //svg要素の属性を属性記述に変換する.
    function toAttributesNotation(svg){
        var attrs = svg.attributes;
        var result = "";
        for(var i=0, len=attrs.length; i<len; i++){
            var attr = attrs[i];
            if(attr.value == "null"){
                continue;
            }
            result += (" " + attr.name + '="' + attr.value + '"');
        }
        return result;
    }
    
    //勝手に変えられてしまったinnerHTMLを元に戻す.
    function fixHTML(html){
        var result = html;
        //属性の値を二重引用符で囲む.
        result = result.replace(/\s([a-z|A-Z|0-9|-]+?)=([^"]+?)([\s|>])/g,' $1="$2"$3');
        //大文字に変換されてしまった要素名を正しいものに直す.
        result = fixTagName(result);
        return result;
    }
    
    //タグの名称を修正する.
    function fixTagName(text){
        var result = text;
        var regex = /<([A-Z|-]+?)[\s|>]/;
        var match;
        while((match = result.match(regex)) != null){
            var tag = match[1];
            var fixed = elementNameMap[tag];
            if(!fixed){
                fixed = tag.toLowerCase();
            }
            result = result.replace("<" + tag, "<" + elementNameMap[tag]);
            result = result.replace("</" + tag + ">", "</" + elementNameMap[tag] +">");
        }
        return result;
    }
    
}

このスクリプトをsie.jsと一緒に読み込ませるようにすると,インラインsvgを表示することが可能となる.

<!DOCTYPE html>
<html>
    <head>
        <title>sie-inline svg sample</title>
        <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
        <script type="text/javascript" src="jquery-1.7.2.min.js"></script>
        <!--[if lte IE 8]>
            <script defer="defer" type="text/javascript" src="sie.js"></script>
            <script type="text/javascript" src="sie-inline.js"></script>
        <!--<![endif]>-->
    </head>
    <body>
    </body>
</html>

さて試しにインラインsvgを描画してみよう.なおsvg要素にサイズを指定しておかないと動作しないので注意のこと.

動作原理は次の通りである.

同様の機能を提供するスクリプトとしてはsie標準添付の「svginhtml.js」もあるが,body要素内部の構造が変化してしまうので,レイアウトの崩れにつながる可能性がある.また,動作機構が幾分かトリッキーであるため,筆者としてはお勧めできない.

svgをsieで表示する際の制約事項

このようにsieを用いるとsvgをie上でも描画することが可能となるが,その一方で注意すべき点が多々存在する.なかなか全てを調べ尽くすのは難しいが,気がついたものについて列挙してみよう.これらはクロスブラウザでのsvgの描画を行う際に重要となる.なお,バージョンアップに伴い少しづつ条件は緩和されていくことと思う.

スクリプトによる埋め込みsvgの操作

最初に動的なsvgグラフィックの出力は難しいとしたが,工夫をすればieでも不可能ではない.但し,ieはSVGDocument,SVGElementを実装しているわけではないため,無名のhtml要素を扱うといった標準的でない操作をせねばならない.以下に注意点について述べる.

いずれもクロスブラウザでの動作を目指した際の障壁となるため,使い勝手の良いものではない.一からグラフィックを描画する面倒さは残るものの,このようなケースにはRaphaelを用いるべきであろう.

埋め込みsvgカタログ

本サイトで紹介したサンプルをピックアップしてみた.sieの動作確認用として活用して欲しい.

0 1 1 2 曇天 本日は晴天なり 文字の描画される基準ライン 本日は晴天なり 本日は晴天なり 本日はなり 寿限無、寿限無五劫の擦り切れ海砂利水魚の水行末雲来末風来末食う寝る処に住む処やぶら小路の藪柑子パイポパイポパイポのシューリンガンシューリンガンのグーリンダイグーリンダイのポンポコピーのポンポコナーの長久命の長助 グラデーション方向 ここがクリップ領域 _replace _self _parent _top _blank