sieではsvg要素をscript要素で囲んだものをインラインsvgとして描画することになっていますので,sieの処理が走る前に(1)svgの中身を取り出し,(2)script要素に設定して,(3)元のsvg要素のあった場所にscript要素を挿入することになります.
しかしieではこのsvg要素の中身を取得するのが困難で,sieが標準的に配布しているsvginhtml.jsというスクリプトファイルでは,svg要素の中身を取得するのにbody要素全体をscript要素化するといったトリッキーな処理を行なっています.
これはieにおいてsvg要素をdocument.getElementsByTagNameメソッドで取得できないのが原因なのですが,実はこれを回避する方法があります.
このテクニックはHTML5 Shivと呼ばれており,html5で追加された要素をレガシーieにてスタイルを指定可能とするために用いられます.かいつまんで言うと,事前に「document.createElement("article");」を実行しておけば,スタイルシートでarticle要素にアクセスすることが可能となるのです.
この挙動を参考とし,svg要素に応用できないか試してみたのが次のコードです.事前にsvgに対応するElementを生成すると,実にそれ以降document.getElementsByTagNameメソッドを使ってsvg要素にアクセスすることが可能となります.
但し,ieのinnerHTMLプロパティは次のような余計な処理をしてしまいます.
- 要素の名称を全て大文字に変更してしまう.
- 属性の値の二重引用符を外してしまうケースがある.
単にbody要素の構造を操作しているだけなので, svginhtml.jsよりも制御しやすいと思います.
[使い方]
下記のコードをsie.jsを宣言してhtmlファイル内部で実行する.
※sie.jsは事前にインラインsvg用の修正を施しておくこと.
※ie8では動作を確認しましたが,ie6などではエラーが発生する?
サンプルはこちら
/*
sie用インラインsvg表示スクリプト
*/
//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;
}
}
0 件のコメント:
コメントを投稿