スタートアップ SVG

第2回SVG実習

前回はSVGの概要を解説したので、今回はSVGの具体的な書き方をざっくりと見ていきます。

と、その前に前回のおさらいとして、SVGをウェブページで用いる方法を2つにまとめます。

  1. SVGをXMLとして記述し、svgファイル(もしくはdataスキームなど)をobjectタグなどで埋め込むか、もしくはXHTMLを用いてHTMLに埋め込む(Firefox 4.0betaやIE9ppなどはHTML(XHTMLでない)に直接記述することも可能)
  2. JavaScriptから動的にSVGを作る

SVGをXMLとしてあらかじめ記述しておく方法は画像フォーマットとしても利用できますし、InkScapeのようなグラフィカルなインターフェースで作成したものを表示するのに向いています。一方、JavaScriptでSVGを描画する方法は動的に図を描けるので、データを元にグラフを描くといったケースに適していますし、Raphaelを用いることでIE 6~8にも対応することができます。

この特集では、svg単体の書き方、JavaScriptから動的にSVGを描く方法、さらにRaphaelで描く方法という順番で見ていきます。まずはSVGを単体で描くときの決まりごとを見ていきます。

文書型とルート要素

SVG文書はXML文書でもあるので、XML宣言、文書型宣言、ルート要素の3つを軸に構成されます。XML宣言は文書の文字コードがUTF-8かUTF-16で、XMLのversionが1.0、スタンドアロン文書宣言がnoという条件を満たしていれば省略が可能です。

続いて、SVGの文書型宣言は次のとおりです。

<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">

そしてルート要素はsvgです。svg要素に指定できる属性はDocument Structure - SVG 1.1 (Second Edition) で定義されているように数多くありますが、特に重要なのは名前空間の宣言です。

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">

このように、svgの名前区間と、必要に応じてxlinkの名前空間などを定義します。また、width属性とheight属性では図形の基本サイズを定義します。width="32px" height="32px" のように指定すれば、32×32pxのキャンバスに図形を書く事になります。

以上を元に、骨組みとなるSVGの基本構造は次のとおりです。

<?xml version="1.0" standalone="no" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="32px" height="32px"
 xmlns="http://www.w3.org/2000/svg"
 xmlns:xlink="http://www.w3.org/1999/xlink">
</svg>

なお、svg要素にはviewBoxという属性を指定できます。このviewBoxは原点の座標と1pxの長さを定義することができます。例えば、上記のようにwidth、heightを32pxに設定したSVG文書をブラウザなどで表示すると画面右上に32pxのサイズでSVGが表示されますが、ここでwidth、heightの指定を100%に変え、viewBox="0 0 32 32" という指定を加えると、画面にいっぱいにSVGが表示されるようになります。

<?xml version="1.0" standalone="no" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
        "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 32 32"
 xmlns="http://www.w3.org/2000/svg"
 xmlns:xlink="http://www.w3.org/1999/xlink">
  <svg:circle cx="16" cy="16" r="16" style="fill:red;" />
</svg>
width="32px" height="32px"
viewBox="0 0 32 32"

XLinkとは

ここで簡単にXLinkについて説明します。XLinkとはXML文書間のリンクを実現するための仕様です。文書間のリンクというとHTMLのaタグ(ハイパーリンク)が思い浮かぶかと思いますが、その機能拡張版と言えます。

その機能・仕様の詳細な説明は長くなってしまうので省略しますが、SVGでのXLinkの主な使い方は、あるところで定義した要素などの対象を別の場所からそこにあるかのように使いまわすといったケースによく用いられます。

XLinkのサンプルコード
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="200" height="200"
 xmlns="http://www.w3.org/2000/svg"
 xmlns:xlink="http://www.w3.org/1999/xlink">
  <defs>
    <circle id="C" cx="20" cy="20" r="20" style="fill:red;" />
  </defs>
  <use xlink:href="#C" x="20" y="20" />
  <use xlink:href="#C" x="80" y="80" />
  <use xlink:href="#C" x="140" y="140" />
</svg>
XLinkのサンプル

このように、要素や自体を使いまわすことができるのがXLinkの特徴の1つです。

SVGの基本図形

大まかに外枠を抑えたので、ここからはSVGでの描画方法の具体例を見ていきます。まずは基本的な図形のサンプルです。

四角形の描画

rectという要素で四角形を描画することができます。x,y属性で座標を、width,height属性で大きさを定義します。

rectのサンプルコード(SVG)
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 
  "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="200" height="200" xmlns="http://www.w3.org/2000/svg">
  <rect x="20" y="20" width="160" height="160" style="fill:skyblue;" />
</svg>
rectのサンプルコード(SVGDOM)
var root = document.getElementById('S-sample4');
var SVG = 'http://www.w3.org/2000/svg';
// svg要素を作る
var svg = document.createElementNS(SVG,'svg');
svg.setAttribute('width', '120');
svg.setAttribute('height', '120');

// rect要素を作成
var rect = document.createElementNS(SVG,'rect');
rect.setAttribute('x', '20');
rect.setAttribute('y', '20');
rect.setAttribute('width', '80');
rect.setAttribute('height', '80');
// 塗りつぶし色を指定
rect.setAttribute("fill", "lightpink");
// 文書に追加
svg.appendChild(rect);
root.appendChild(svg);
rectのサンプルコード(Raphael)
var root = document.getElementById('R-sample4');
// ベースとなる要素を作る
paper = Raphael(root, 120, 120);
// rectを作成
var rect = paper.rect(20, 20, 80, 80);
// 塗りつぶし色を指定
rect.attr("fill", "greenyellow");
// 枠線をなしに
rect.attr("stroke", "none");
rectのサンプル(SVG)
rectのサンプル(SVGDOM)
rectのサンプル(Raphael)

円の描画

circleという要素では円を描画することができます。cx,cy属性で円の中心の座標を、r属性で円の半径を定義します。なお、以降のコードはrectのサンプルコードと重複する部分(文書型宣言、名前区間宣言、SVG要素の作成など)を省略します。

circleのサンプルコード(SVG)
  <circle cx="60" cy="60" r="40" style="fill:skyblue;" />
circleのサンプルコード(SVGDOM)
// circle要素を作成
var circle = document.createElementNS(SVG,'circle');
circle.setAttribute('cx', '60');
circle.setAttribute('cy', '60');
circle.setAttribute('r', '40');
circleのサンプルコード(Raphael)
// circleを作成
var circle = paper.circle(60, 60, 40);
circleのサンプル(SVG)
circleのサンプル(SVGDOM)
circleのサンプル(Raphael)

楕円の描画

ellipseという要素では楕円を描画することができます。cx,cy属性で円の中心の座標を、rx,ry属性で円の半径を定義します。

ellipseのサンプルコード(SVG)
  <ellipse cx="60" cy="60" rx="40" ry="10" style="fill:skyblue;" />
ellipseのサンプルコード(SVGDOM)
// ellipse要素を作成
var ellipse = document.createElementNS(SVG,'ellipse');
ellipse.setAttribute('cx', '60');
ellipse.setAttribute('cy', '60');
ellipse.setAttribute('rx', '40');
ellipse.setAttribute('ry', '10');
ellipseのサンプルコード(Raphael)
// ellipseを作成
var ellipse = paper.ellipse(60, 60, 40, 10);
ellipseのサンプル(SVG)
ellipseのサンプル(SVGDOM)
ellipseのサンプル(Raphael)

直線の描画

lineという要素では直線を描画することができます。x1,y1属性で線を開始する座標を、x2,y2で線を終了する座標を指定します。線なので、塗りつぶしはありません。なお、Raphaelではlineが定義されていないので、pathで代替しています(pathのほうが高機能なので困ることはありません。pathについては後述します⁠⁠。

lineのサンプルコード(SVG)
  <line x1="10" y1="20" x2="100" y2="80" style="fill:skyblue;" />
lineのサンプルコード(SVGDOM)
// line要素を作成
var line = document.createElementNS(SVG,'line');
line.setAttribute('x1', '10');
line.setAttribute('y1', '20');
line.setAttribute('x2', '100');
line.setAttribute('y2', '80');
lineのサンプルコード(Raphael)
// lineを作成(pathで代替)
var line = paper.path("M10 20L100 80");
lineのサンプル(SVG)
lineのサンプル(SVGDOM)
lineのサンプル(Raphael)

折れ線と多角形の描画

polylineとpolygonという要素ではそれぞれ折れ線と多角形を描画することができます。両者の違いは開始点と終点を繋ぐかどうかという違いです。どちらもpoints属性に座標を指定します。なお、やはりRaphaelではpolylineとpolygonは定義されていないので、pathで代替しています。

polyline,polygonのサンプルコード(SVG)
  <polyline points="15,15 15,95 95,95 95,15 35,15 35,75 75,75 75,35 55,35 55,55"
    stroke="blue" stroke-width="3" fill="none"  />
  <polygon points="25,25 25,105 105,105 105,25 45,25 45,85 85,85 85,45 65,45 65,65"
    stroke="red" stroke-width="3" fill="none" />
polyline,polygonのサンプルコード(SVGDOM)
// polyline要素を作成
var polyline = document.createElementNS(SVG,'polyline');
polyline.setAttribute('points', '10,15 10,95 90,95 90,15 30,15 30,75 70,75 70,35 50,35 50,55');
// polygon要素を作成
var polygon = document.createElementNS(SVG,'polygon');
var points = [{x:25,y:25}, {x:25,y:105}, {x:105,y:105}, {x:105,y:25}, {x:45,y:25}, {x:45,y:85}, {x:85,y:85}, {x:85,y:45}, {x:65,y:45}, {x:65,y:65}];
for (var i = 0;i < points.length;i++){
  // SVGPoint要素作成
  var p = svg.createSVGPoint();
  p.x = points[i].x;
  p.y = points[i].y;
  // pointsにPointを追加
  polygon.points.appendItem(p);
}

このように、points属性を直接指定する方法のほかに、createSVGPointでPointを作り、appendItemでポイントを追加するという方法もあります。createSVGPointを使うことでより動的に図形を書くことが可能です。

polyline,polygonのサンプルコード(Raphael)
// polyline,polygonを作成(pathで代替)
var polyline = paper.path("M10 20L100 80");
polylineのサンプル(SVG)
polylineのサンプル(SVGDOM)
polylineのサンプル(Raphael)

パスによる描画

path要素は様々な図形を描画することができます。実はここまでに出てきた基本的な図形はすべてパスを使っても描くことが可能です。ただし、パスの指定方法は少々わかり難いところがあります。

pathはコマンドと座標の組み合わせで図形を描画します。[コマンド][引数1] [引数2]… を1セットとして、これを組み合わせていきます。引数と引数の間はスペースでもカンマでも構いません。コマンドには位置を移動するM(moveTo⁠⁠、直線を描くL(lineTo⁠⁠、曲線を描くC(curveTo⁠⁠、⁠楕)円弧を描くA(arcTo)に、パスを閉じるZなどがあります。コマンドは大文字で絶対座標、小文字で相対座標として解釈されます。

pathのサンプルコード(SVG)
  <path d="M25 25L25 105L105 105L105 25L45 25L45 85L85 85L85 45L65 45L65 65 z" stroke="red" stroke-width="3" fill="none" />
pathのサンプルコード(SVGDOM)
// path要素を作成
var path = document.createElementNS(SVG,'path');
path.setAttribute('d', 'M10,15L10,95L90,95L90,15L30,15L30,75L70,75L70,35L50,35L50,55');
var path2 = document.createElementNS(SVG,'path');
var paths = [{x:25,y:25}, {x:25,y:105}, {x:105,y:105}, {x:105,y:25}, {x:45,y:25}, {x:45,y:85}, {x:85,y:85}, {x:85,y:45}, {x:65,y:45}, {x:65,y:65}];
for (var i = 0;i < paths.length;i++){
  var x = paths[i].x;
  var y = paths[i].y;
  var p = (i === 0) ? 
    path2.createSVGPathSegMovetoAbs(x,y) :
    path2.createSVGPathSegLinetoAbs(x,y);
  path2.pathSegList.appendItem(p);
}
// path2を閉じる
path2.pathSegList.appendItem(path2.createSVGPathSegClosePath());

path要素(SVGPathElement)Paths - SVG 1.1 (Second Edition) で定義されている通り、Path Segmentを作るメソッドを持っています。これらの要素を組み合わせることで複雑な描画を動的に作ることも可能です。

pathのサンプルコード(Raphael)
// pathを作成
var path = paper.path("M10 15L10 95L90 95L90 15L30 15L30 75L70 75L70 35L50 35L50 55");
var path2 = paper.path("M25 25L25 105L105 105L105 25L45 25L45 85L85 85L85 45L65 45L65 65 z");
pathのサンプル(SVG)
pathのサンプル(SVGDOM)
pathのサンプル(Raphael)

まとめ

今回はSVGの描画方法の実例をざっくりと紹介しました。こういったシンプルな図形ではRaphaelの簡潔さに歩があるようです。次回は座標変換やSVGでのテキストの扱い、装飾関連などを中心に解説したいと思います。

おすすめ記事

記事・ニュース一覧