スタートアップ SVG

第4回 SVGを活用する

この記事を読むのに必要な時間:およそ 6 分

第1回はSVGの基礎知識を,第2回第3回でIE9がサポートする範囲(予定含む)を中心にSVGの書き方を解説しました。最終回となる今回はSVGを実際に活用していく上でのノウハウを解説したいと思います。

HTMLなページへのSVGの埋め込みテクニック

第1回で解説しましたが,SVGは画像フォーマットでもあり,InkScapeなどのグラフィカルなインターフェースを持ったアプリケーションで作成することができます。そのsvgファイルをページに読み込むにはobjectタグを使う方法が一般的です。しかし,この方法ではobjectタグはiframeのように親ページと子ページで独立したDOMを構築するため,SVGを動的に扱いたい場合には適しません。そういった場合,svgファイルをXMLHttpRequestで読み込む方法がオススメです。

まずはシンプルにresponseXMLを使う方法です。この方法はFirefox, Opera, Safari, Chromeなどで動作します。残念ながらIE9 Platform Preview 3(以降,IE 9 pp3)では動作しませんが,正式版がリリースされるまでに対応する可能性は高いと思われます。

XMLHttpRequestのresponseXMLの利用

var xhr = new XMLHttpRequest();
xhr.open('GET', 'blue-star.svg', true);
xhr.onload = function(){
  var stage = document.getElementById('svg-sample-1');
  var svgroot = xhr.responseXML.documentElement;
  if (svgroot){
    var svg = stage.appendChild(document.adoptNode(svgroot));
  }
};
xhr.send();
画像

responseXMLの代わりにDOMParserを利用する方法もあります。DOMParserが文字列をDOMに変換する処理を担います。XMLHttpRequest以外をソースにすることもできますし,変換前に文字列の状態で手を入れるといったことも可能です。ただし,IE 9 pp3ではDOMParserが定義されていないためこの方法は動作しません。DOMParserは元々Firefoxの独自拡張であり2010年7月時点で標準化はされていないため,将来的な対応には不安があります。

XMLHttpRequestとDOMParserの利用

var xhr = new XMLHttpRequest();
xhr.open('GET', 'blue-star.svg', true);
xhr.onload = function(){
  var svgtext = xhr.responseText;
  var svgdom = new DOMParser().parseFromString(svgtext,'application/xhtml+xml');
  var stage = document.getElementById('svg-sample-2');
  var svg = stage.appendChild(document.adoptNode(svgdom.documentElement));
};
xhr.send();
画像

これ以外に,OperaとFirefoxがサポートしているdocument.load(DOM Level 3 Load and Saveより)や,XSLTProcessor(IEの場合MSXML2.XSLTemplate)などを使う方法もありますが,今回は省略します。

現時点では,次のようにIE 9以外はresponseXML,IE 9はresponseTextをinnerHTMLに入れる方法が有効です。なお,IE 9 pp3はXMLHttpRequestのonloadにも対応していないため,代わりにonreadystatechangeを使う必要があります。

XMLHttpRequestとinnerHTMLの利用

if (svgroot) {
  svg = stage.appendChild(document.adoptNode(svgroot));
} else {
  stage.innerHTML = xhr.responseText.replace(/^\s*<\?xml[\s\S]*?\?>/i, '').replace(/^\s*<\!DOCTYPE[\s\S]*?>/i,'');
  svg = stage.querySelector('svg');
}
画像

グラフの作成

この連載のまとめとして,SVGを使った折れ線グラフを描いてみます。データは気象庁 | 観測開始からの毎月の値より,東京の一日あたりの平均気温の月平均値の過去135年分を用います。

まずはシンプルにpolylineを使って描いてみます。

東京の4月の平均気温のデータ

var temperature = [
12.2,13.5,11.4,12.2,12.1,11.3,13.4,12.1,11.7,10.7,12.4,12.3,12.5,12.0,14.2,12.0,13.1,13.3,13.8,12.9,13.7,11.3,11.2,12.8,11.4,13.4,11.6,12.7,
13.2,10.9,12.9,12.4,12.3,13.6,12.3,13.8,13.0,13.7,11.8,11.6,12.7,12.7,11.7,13.4,12.6,13.8,13.3,12.0,14.7,11.9,11.1,13.5,12.5,12.6,14.0,12.4,
12.3,12.3,11.5,12.5,12.0,12.8,13.2,12.7,13.1,12.7,13.6,11.7,10.6,13.5,14.3,13.1,14.2,12.1,13.9,13.3,13.3,12.7,14.9,13.6,13.1,14.3,13.9,15.3,
12.8,14.9,14.1,13.9,15.3,11.1,13.6,14.5,14.1,14.6,13.0,13.5,13.4,15.3,14.8,14.3,13.0,15.1,13.9,13.9,13.6,13.9,14.0,15.9,11.6,14.2,13.9,14.4,
14.3,15.6,14.7,15.4,15.1,13.4,15.8,15.0,12.7,15.2,16.3,15.0,14.5,15.7,16.1,15.1,16.4,15.1,13.6,13.7,14.7,15.7,12.4
];

polylineによるグラフの描画

var svg = document.createElementNS(SVG,'svg');
svg.setAttribute('viewBox', '0 0 150 40');

var polyline = document.createElementNS(SVG,'polyline');
var line = temperature.map(function(v, i){return i+','+v;}).join(' ');
polyline.setAttribute('points', line);
polyline.setAttribute('fill', 'none');
polyline.setAttribute('stroke', '#0080FF');
svg.appendChild(polyline);
root.appendChild(svg);

ここでのポイントはviewBoxで1つの値を何ピクセル相当にするか調整している点です。グラフの表示エリアを幅450px,高さ120pxとして,viewBoxを150px,40pxにしてあるので,実際には3倍に拡大されて描画されることになります。

polylineによるグラフ

画像

このままでは情報が少ないので補助線などを追加してみます。

補助線の追加

// 0度の線
var zero_line = document.createElementNS(SVG,'line');
zero_line.setAttribute('stroke-dasharray', 1);
zero_line.setAttribute('x1', '0');
zero_line.setAttribute('y1', '30');
zero_line.setAttribute('x2', '135');
zero_line.setAttribute('y2', '30');
zero_line.setAttribute("stroke", "#999");
zero_line.setAttribute("stroke-width", "0.3");
g.appendChild(zero_line);

// 15度の線
var half_line = document.createElementNS(SVG,'line');
half_line.setAttribute('stroke-dasharray', 1);
half_line.setAttribute('x1', '0');
half_line.setAttribute('y1', '15');
half_line.setAttribute('x2', '135');
half_line.setAttribute('y2', '15');
half_line.setAttribute("stroke", "#999");
half_line.setAttribute("stroke-width", "0.3");
g.appendChild(half_line);

var start = 1876;
var gvline = document.createElementNS(SVG,'g');
gvline.setAttribute("stroke", "#999");
gvline.setAttribute('stroke-dasharray', 1);
gvline.setAttribute("stroke-width", "0.3");
g.appendChild(gvline);
for (var i = 0, len = temperature.length;i < len;i++){
  if ((i+start)%10 === 0){
    // 10年置きに縦に線を引く
    var vline = document.createElementNS(SVG,'line');
    vline.setAttribute('x1', i);
    vline.setAttribute('y1', 0);
    vline.setAttribute('x2', i);
    vline.setAttribute('y2', 40);
    gvline.appendChild(vline);
  }
}
// クリックしたときにズーム
var zoom = false;
root.onclick = function(e){
  if (zoom){
    root.style.position = 'static';
    root.style.width  = '450px';
    root.style.height = '120px';
  } else {
    root.style.position = 'fixed';
    root.style.top = '5%';
    root.style.left = '5%';
    root.style.width  = document.documentElement.clientWidth*0.9 +'px';
    root.style.height = document.documentElement.clientHeight*0.9+'px';
  }
  zoom = !zoom;
};

グラフの領域をクリックしたときにSVGの親要素のサイズを画面に合わせて拡大するようにしました。svg要素はデフォルトで親要素いっぱいに表示を広げるため,グラフも拡大されることになります。

補助線付きのグラフ

画像

著者プロフィール

太田昌吾(おおたしょうご,ハンドルネーム:os0x)

1983年生まれ。JavaScriptをメインに,HTML/CSSにFlashなどのクライアントサイドを得意とするウェブエンジニア。2009年12月より、Google Chrome ExtensionsのAPI Expertとして活動を開始。

URLhttp://d.hatena.ne.jp/os0x/

コメント

コメントの記入