SVG と変形

作成日 : 2022-05-06
最終更新日 :

SVG と図形変形

正五角形を描く

ABCDE

正五角形を描くのには、直交座標系で正五角形の頂点を指定すればいい。 正五角形の内角は 108° であるからこれを利用する。 ただこれには sin 108° や cos 108° の値を求めなければならず、 これらを導くのが少し難しく、実際自分で一から導く自信がない。 そこで、 sin 108° や cos 108° の値を知らなくてもよい正五角形の書き方を考えてみた。

まず、右の図で底辺にあたる線分 CD はどちらもピクセル単位の整数で書ける。C(-50,100), D(50,100) とすれば線分 CD は次で書ける。
<line x1="-50" y1="100" x2="50" y2="100" stroke="black" stroke-width="1" />
次に線分 BC を描こう。線分 BC は線分CD を 108° 反時計回りに回転させることで得られる。これは、 SVG の transform 属性で得られる。具体的には、
<line x1="-50" y1="100" x2="50" y2="100" stroke="black" stroke-width="1" transform="rotate(-108, -50, 100)" />
と指定すればいい。最初の引数は degree を単位とする回転角で、時計回りが正である。 第2、第3の引数は回転中心のそれぞれ x 座標、y座標である。同様に線分DE は次で書ける。
<line x1="-50" y1="100" x2="50" y2="100" stroke="black" stroke-width="1" transform="rotate(108, 50, 100)" />
問題は AB と EA である。これらの端点は x 座標も y 座標も無理数である。 ということで、線分 BA は 点 B を中心にして BC を反時計回り 108° 傾けた線分であることを利用して、 次のように書いてみた。
<line x1="-50" y1="100" x2="50" y2="100" stroke="black" stroke-width="1" transform="rotate(-108,-50,100)rotate(-108,50,100)" />
この transform 属性、rotate(-108,-50,100)rotate(-108,50,100) のように、 二重に rotate をしているのがミソである。まず最初の(左側の)rotate は、 点 C の回りに反時計回りに 108° 回していることを意味している。 次の(右側の) rotate は点 B のまわりに反時計回りに 108° 回していることを意味している。というのは、 右側の rotate の(50,100)という座標は、CB の回転後の座標であるからだ。 CB の回転前は CD であり、D の座標は(50,100) だった。ということは、回転した後の座標の B も、 (50, 100)となるからだ。
同様にして線分 EA も次のように書ける。
<line x1="-50" y1="100" x2="50" y2="100" stroke="black" stroke-width="1" transform="rotate(108,50,100)rotate(108,-50,100)" />

星形を描く

ABCDE

正五角形の次は星形である。星形の場合は sin 36° や cos 36° の値が必要だが、 これらの値を知らなくてもよい書き方を考えてみた。これも正五角形と考え方は同じだ。最初に線分 BE の位置を決めて、次に線分 BD と線分 CE を描き、最後に線分 AC と線分 AD を描いて完成だ。

SVG と JavaScript

上記のような三角関数の計算を行なうのであれば、JavaScript の三角関数を呼び出すのが普通の考えだろう。 もちろんそれもできる。そこで、まず三角関数を出さずに、JavaScript における SVG の操作例を見てみよう。 既存の SVG の図形の要素を書き換えたり、新しい SVG の図形を追加したりする例を参考リンク [3] より多少変更してお見せする。 次は、ボタンをクリックすると図形の色が変わったり新たな図形が書き加わったりする例である。


HTML 部は次のようになる。body で囲まれていることが前提である。


    <svg id="svg">
        <circle id="circle1" cx="100" cy="100" r="25" fill="#ffff00" stroke="#ff0000" />
        <polygon points="50,50 100,50 100,100 50,50" fill="#ff0000" stroke="#ff0000" />
    </svg>
    <button id="changeColor">Change circle color</button>
    <button id="addRect">Add rectangle</button>

JavaScript 部は次のようになる。U.$(id) という見慣れない関数があるが、これは document.getElementById(id) と同じである。

<script> function changeColor() { //setAttributeメソッドでfill属性の値を青に変更 U.$('circle1').setAttribute("fill", "#0000ff"); } //新しいSVGの要素を作成する関数 function addRect() { //id属性でsvg要素を取得する let svgElement = U.$('svg'); //新しいSVG要素(rect)を作成する。createElementNSメソッドを使うことに注意 let newRect = document.createElementNS("http://www.w3.org/2000/svg", 'rect'); //SVGの各種属性を設定する。 [["x",100],["y",50],["width",50],["height",40],["fill", "#00ff00"]].forEach(e => {newRect.setAttribute(e[0], e[1])}) //作成したrect要素をsvg要素の下に追加すると描画される svgElement.appendChild(newRect); } U.$("changeColor").addEventListener("click", changeColor) U.$("addRect").addEventListener("click", addRect) </script>

参考リンク

[1] http://defghi1977.html.xdomain.jp/tech/svgMemo/svgMemo_04.htm
[2] https://developer.mozilla.org/ja/docs/Web/SVG/Tutorial/Basic_Transformations
[3] https://thinkit.co.jp/story/2012/05/17/3530?page=0%2C1

まりんきょ学問所コンピュータの部屋マーク付け言語手習い > SVG と変形


MARUYAMA Satosi