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

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

4.図形の変形

基本図形だけでもグラフィックを描くことは可能だが,何れも座標が固定化されているので位置の変更やサイズの変更を行うのが面倒である.このような操作を簡略化するためtransform属性が提供されている.これはcss3でのtransform属性とほぼ同様の機能を提供する.

transform属性:座標軸の変形

svgにおける図形要素の描画は,通常その要素が属するコンテナ要素(svg要素,symbol要素,marker要素等)のveiwBox属性の値に従って行われる.即ち,viewBoxから定まる座標軸とスケールを元に図形要素の実際の描画位置が計算される.ここで,この座標軸を変形する事を思い浮かべてみよう.同じ図形要素であっても,描画する基準が異なるため,座標軸の変形度合いに応じ描かれる図形が変形することだろう.

この座標軸の変換をアフィン変換と呼び,svgではこの変換をtransform属性として設定することができる.

アフィン変換の行列表現

アフィン変換は一般に3×3の行列(アフィン行列)として表すことができる.つまり変換前の座標系を(X,Y),変換後の座標系(x,y)とすると次のような行列とベクトルの掛け算として表せる.

( X Y 1 ) = ( a c e b d f 0 0 1 ) ( x y 1 )
X = a*x + c*y + e
Y = b*x + d*y + f

transform属性が見つかると,この関係式を元に図形の内容を元の座標系での位置に変換することでグラフィックが描画される.

transform属性に設定可能な関数

transform属性では下記のtransform関数を記述することでアフィン変換を指定する.

transform
座標軸の変形を行う(考え方はhtmlのtransform,canvasの関数と同様).その結果この属性が設定された図形は変形される.
複数の関数が列挙された場合,前(左)から順に座標軸に適用されていく
matrix
変換行列による変形[6引数を用いる汎用1次変換]
translate
移動[tx,ty]
scale
拡大・縮小[sx,sy].マイナスの値も設定可能.その場合は図形が反転する.
rotate
回転[angle,cx,cy].なお角度は0〜360を指定.(deg等の単位は不要)
skewX
横方向の傾斜[angle]
skewY
縦方向の傾斜[angle]

これらの関数はtransform属性で用いる他にもgradientTransform属性,animateTransform要素でも関連項目として表れる.

因みにjavascriptではこのtransform属性の値がアフィン行列として管理されているため,スクリプトからこの属性を操作する場合はこの構造を良く理解しておく必要がある.

matrix関数・matrix(a,b,c,d,e,f)

先ほどのアフィン行列の6パラメータをそのまま利用したもので,その他関数は全てこのmatrixに書きなおすことができる.

translate関数・translate(tx,ty)

平行移動を表す関数で,指定した値の分だけ座標軸をその方向にずらす効果をもたらす.行列で表すと次のようになる.

( X Y 1 ) = ( 1 0 tx 0 1 ty 0 0 1 ) ( x y 1 )
X = x + tx
Y = x + ty

scale関数・scale(sx,sy)

座標軸の目盛の拡大,縮小を表す関数で,指定した値の分だけ図形のサイズが変化する.

( X Y 1 ) = ( sx 0 0 0 sy 0 0 0 1 ) ( x y 1 )
X = x * sx
Y = x * sy

sy値を省略すると,sxと同じ値が与えられたものとして扱われる.下の例ではscale(1.5)なので,x軸方向y軸方向ともに1.5倍される.

スケール値にマイナス値を設定することで図形を反転することができる.

反転

rotate関数・rotate(angle,cx,cy)

座標軸を指定した角度の分だけ傾ける効果を得る.

( X Y 1 ) = ( cos(angle) -sin(angle) 0 sin(angle) cos(angle) 0 0 0 1 ) ( x y 1 )
X = x * cos(angle) - y * sin(angle)
Y = x * sin(angle) + y * cos(angle)

またその際の回転の中心を設定することができる.

skewX関数・skewX(angle)

x軸方向のせん断効果を得る.一般的な用語でないため判りにくいが要は横方向に傾けるといった風に憶えれば良い.
なお,tan関数の特性から180度毎に元に戻る.

( X Y 1 ) = ( 1 tan(angle) 0 0 1 0 0 0 1 ) ( x y 1 )
X = x + y * tan(angle)
Y = y

skewY関数・skewY(angle)

y軸方向のせん断効果を得る.先ほどとは異なり今度は縦方向に傾けると考えれば良い.

( X Y 1 ) = ( 1 0 0 tan(angle) 1 0 0 0 1 ) ( x y 1 )
X = x
Y = x * * tan(angle) + y

座標軸変換の重ねがけ

transform属性には複数の関数を設定することができる.この場合は前(左)に記述された関数から順に座標軸に適用していき,最終的に得られた座標軸を基準としてグラフィックの描画を行う.下の例では座標軸を段階的にずらした模様を色を変えて記述したものである.座標軸の変化により,図形がどのように変化しているか確認して欲しい.

なお,座標軸の変換処理は行列の掛け算に相当するものであり,その関数適用の順番を交換することはできない

変換関数の集約

なお,各関数を行列で表した上でその積を計算すると,単一のmatrix関数にまとめることが出来る.例えば予めscale(2,2)とtranslate(50,50)とをかけ合わせると,matrix(2,0,0,2,100,100)となる.

g要素におけるtransform属性

g要素によりグループ化された図形はg要素に定義されたtransform属性の内容の影響を受ける.例えば次の二つの要素は同じ変換のもとで描かれることになる.

transform属性のもうひとつの捉え方

transform属性はもともと座標軸の変形によって描画される図形が「結果的に」変形されると言った視点で定義されているが,逆に変形される図形側から考えることもできる.この見方では座標系が変換されるのではなくて図形そのものが変形されるものとして考える.この視点に立つとtransform属性は次のような特徴を持つように捉え直すことができる.

  • 図形の変形はtransform属性の右側にある関数から順に適用される
  • g属性にtransform属性が定義されていた場合は,内側の変形処理から順に実行される

この考え方は図形の描画位置を基準にtransform属性を捉えることができるので,最終的な図形の形を想像しやすいと言ったメリットがある.

なお,視点が異なるだけで先ほどの座標軸による説明と矛盾する内容ではない.文脈によって判りやすい方で考えるようにすると良い.

※本文書では当初この視点でtransform属性を解説していたが,仕様書に説明を近づけるために内容を修正した.

図形の変形の基準をずらす

この視点に基づくとscale関数,skewX関数,skewY関数による図形の変形は,必ず原点を基準に行われる.従ってこれを任意の点を基準に行いたい場合は,基準となる点を原点にずらし(translateでずらす),変形処理を行い,元の位置に戻すことで実現することができる.下の例では矩形の左上の頂点を基準にサイズを1.5倍にする例である.基準を(10,10)に取るため,-10,-10だけずらし図形の左上頂点を原点に重ねscaleでサイズを変更する.それを元の位置に戻せば目的の図形が得られる.

座標軸を基準に考えると判りにくい事象も,このように視点を変えると分かりやすくなる.

Current Transformation Matrix

このように図形を描画する上で非常に重要となる座標変換だが,transform属性による変換は直近の親要素に対して相対的に定義している.そのため,ある図形要素について全体としてどのような変換が為されているかを把握することが難しい.そこで基準となる座標系を一つ固定し,そこからどれだけ変換されているかを表したものをCTM(current transformation matrix)と呼ぶ.SVGDOMではこのCTMを取得するためのapiが定められている.

transform属性を伴わない変換

svg要素にviewBox属性,preserveAspectRatio属性が設定されていた場合,この内容に応じて暗黙的に座標の変換が発生する.CTMではtransform属性のみならず,この内容も含む.

getCTMとgetScreenCTM

基準となる座標軸のとり方により,CTMにはgetCTMとgetScreenCTMから得られるものの2種類が存在する.

  • getCTM
    基準をグラフィックを定める(最も外側の)svg要素の左上角に取るもの.
  • getScreenCTM
    基準をグラフィックを定める(最も外側の)svg要素が配置されているスクリーンの左上角に取るもの.

いずれも,svgグラフィックに対するカーソル操作とsvgの内部座標系とを結びつける上で有用である.

スケーリングに依存しないストローク

stroke等のグラフィック内容は通常transform属性等の影響を受けて線の描画幅が変化してしまうが,svg2ではvector-effect属性を用いることで常にスクリーン上のスケールで線を描画することが出来る.

vector-effect
stroke属性によるグラフィック描画にCTMの影響を指定する
non-scaling-stroke
固定スケールでの線描画.
none
通常の線描画.

補足)svg要素に対する3d変換

htmlにsvgが埋め込まれている場合はtransform3dを適用してsvg画像全体を3d変形することが可能だ.もちろんブラウザが対応している必要がある.

補足)svg2におけるtransform属性

svg2では正式にtransform3dをsvgでも利用可能となるが,それに伴い正式にtransform属性がプレゼンテーション属性となる.従ってtransformプロパティによる変形処理をcssから実行できることとなり,css-transition機能やcss-animation機能と組み合わせることでsmilに依らない動きのあるグラフィックを定義することが可能となる.現状ではfirefoxでその動作を確認することが可能だ.

例を示す.

現状での注意点

現行のブラウザではsvg-tranform機構とcss-transform機構はまだ統合されておらず,別々に動作する点に注意しよう.つまり(仕様上でこそcssによる指定が優先されることとなっているが)二つのtransform機構を混在させた場合,意図せぬ動作を引き起こす.

補足)図形を直接変形する

path要素を変形したい場合,transform属性を用いずにパス文字列を直接書き換える方法もある.素朴考えると各操作の始点と終点及び制御点の座標を変換すればよいように見えるが,円弧を表すA操作だけは複雑な計算を経る必要がある.というのも,A操作を構成するパラメータが単なる座標の変換だけでは得られない為だ.(ベジェ曲線の優位性はここにある)

その為,次のような数学的な議論(線形代数と呼ばれる)を元に計算することとなる.詳しいやり方についてはここでは省くので,必要に応じて各自考えてみて欲しい.

  • 変換元の楕円は「x2/r12+y2/r22=1」を充たすはずなので,この条件から変換後の楕円の方程式を求め,ここから長径と短径及び傾きを計算する事ができる.こちらを参照.この計算が必要となる理由は,もともと傾いている楕円をx軸方向もしくはy軸方向に変形するとその傾きが変化するためだ.(円をせん断で楕円に変換した場合も同様)
  • matrix関数による座標軸の変換は数学的に回転(rotate),鏡像・拡大縮小(scale),せん断(skew),平行移動(translate)の積として表すことができることが分かっている(岩沢分解).matrixを分解した際,鏡像成分が含まれていればsweepフラグを反転させる.

※実際にスクリプトを書いてみた所,意外に面倒なので注意のこと.

※この方法では計算の誤差により,ベクタデータの劣化を引き起こす点に注意が必要だ.

※この方法が有効となる場面はそれほど多くない.path要素からd属性を取り出してglyph要素を生成する時ぐらいのものである.