SVGでうねうね動く円のアニメーション
今回は弊社の森崎が「有機的な円のアニメーション」の実装について話しました。
たまたま 2 案件続いて円のアニメーションを有機的に動かしたいという要望が出たので、実装方法を考えてみました。
01 方法を考える
最終目標は、SVG でウネウネする円を描画することです。
ということで方法をいくつか考えて、それぞれのメリットとデメリットを書き出してみます。
gifアニメ、APNG
- メリット
- 実装は
img
で挿入するだけなので楽。
- 実装は
- デメリット
- 画像を作成するのが大変。
- 調整/修正しづらい。
- 決まった動きしかできないため単調になる。
canvas
- メリット
- パフォーマンスに優れる。
- デメリット
- ラスター形式のため描画が荒くなってしまう可能性がある。
- 拡大縮小への対応が大変。
SVG
- メリット
- ベクター形式のため描画がキレイ。
- パフォーマンスも悪くない。
- デメリット
- 実装が少し大変。
案件の内容的に、単色でぼかしなどのエフェクトも使用しないシンプルなアニメーションだったので、 今回は SVG を採用することにしました。
02 SVG とは
SVG は Scalable Vector Graphics の略です。直訳すると「拡大縮小可能なベクター画像」。
1999年に W3C によって開発された xml に基づくマークアップ言語です。テキストなので script などから操作が可能で、またテキストエディタで編集できます。
ベクター画像とは、
画像データの表現形式の一つで、画像を図形を表す数値情報の集合として表現したもの。サイズや解像度によらず同じ品質の出力結果を得ることができる。
いわゆる写真などはラスター画像と呼ばれておりベクター画像とは対極のもので、拡大・縮小するとピクセルの荒さが目立ったりしますが、ベクター画像は全てテキスト情報で計算されるため綺麗にレンダリングされます。
なので、レスポンシブなディスプレイが使用されるようになって以降ウェブ制作で使われることが増えました。
基本図形にはこれらがあって、
それぞれ専用のタグを持っています。
中でも path は基本図形の中で最も汎用的な要素で、それだけで全ての基本図形の作成が可能です。
<path d="M 10 10 H 90 V 90 H 10 L 10 10 Z"/>
のように、コマンド(命令)とパラメータ(座標)を指定して描画させます。
コマンド
コマンドには大きく分けて直線コマンドと曲線コマンドがあり、例えば moveTo
、lineTo
というコマンドを使いたい時には M or m
、L or l
などの1文字で表します。というのもそのまま moveTo
のように書いていくとものすごい長さになってしまうからだそうです。この時、大文字は絶対座標、小文字は相対座標を表しています。
直線コマンド
コマンド | 命令 | 意味 |
---|---|---|
| moveto | 指定した座標に移動。 |
| lineto | 指定した座標まで線を描画。 |
| horizontal lineto | 指定したx座標まで線を描画。 |
| vertical lineto | 指定したy座標まで線を描画。 |
| closepath | 始点に向かってパスを閉じる。 |
曲線コマンド
コマンド | 名前 | 意味 |
---|---|---|
| curveto | 三次ベジェ曲線 |
| shorthand/smooth | 現在の点から点 (x, y) へ三次ベジェ曲線を描く。 |
| quadratic Bézier curveto | 二次ベジェ曲線 |
| Shorthand/smooth | 現在の点から点 (x, y) へ二次ベジェ曲線を描く。 |
| elliptical arc | 現在の点から点 (x, y) へ楕円形の弧を描く。 |
フロントエンドでの SVG の扱い方
フロントエンドでは img
タグや svg
タグを使って描画させます。img
タグ
- メリット
src
に パスを指定するだけなので簡単。
- デメリット
- 基本的に扱いは
画像
となるので、細かな操作は出来ない。
- 基本的に扱いは
svg
タグ
- メリット
- テキストデータとして扱えるので、script で細かな操作が可能。
- CSS による装飾が可能。
- デメリット
- 書くことが増えるためコードの見通しが悪くなる。
object
タグを使っても実装できますが、使うメリットはなさそうな印象。
ライブラリが充実しているのでそれを使った方が実装も簡単になるし、表現の自由度も上がりそうでした。さらにレガシーブラウザへの対応も可能になるため使っておいて損はないように思います。
代表的なところだと、
- Raphaël.js
- 昔からあるパイオニア的ライブラリ。
- IE 6+/Safari 3.0+/Firefox 3.0+ に対応。
- Snap.svg
Adobe
製。Raphaël.js
と同じ人が作っている。- 機能豊富。
- チェーンメソッド採用で、
JQuery
と相性がいい。 - Typescript対応。
- IE 9+/Chrome/Safari/Firefox に対応。
- SVG.js
- 軽量かつ高速。
- チェーンメソッド採用。
- プラグインで機能追加可能。
- Typescript対応。
- IE 9+/Chrome 4.0+/Safari 3.2+/Firefox 3.0+ に対応。
- GraphicsJS
- 比較的新しい。
- AnyChart というデータビジュアライゼーションが得意な会社が作成。
- グラフやチャートなどを作成する機能が豊富。
- 仮想DOMに対応。
- IE 6+/Chrome 1.0+/Safari 4.0+/Firefox 2.0+ に対応。
などがあります。
03 実際にやってみる
目標:円周を動かしたい
SVGの circle
タグでは円の描画はできても、円弧のアニメーションは作れないので path
タグを使う必要があります。
また、path
を使うなら二次ベジェ曲線か三次ベジェ曲線どちらを使うのか決めないといけませんが、三次ベジェの方がちょっと複雑になりそうだったので、今回は二次ベジェを使うことにしました。
STEP-1
まずポイントを作成します。
大体8等分ぐらいでほぼ真円と区別がつかないぐらいの近似曲線が描画できるそうです。
ポイントは、
- コントロールポイント(制御点)
- アンカーポイント(始点、終点)
の 2 パターンを作ります。
それらを結びつけながら円弧を描画していきます。
ライブラリは SVG.js 使用しました。
右上のパネル 1 つ目のチェックボックスはコントロールポイントです。
2 つ目をクリックするとそれらが線で結ばれます。
3 つ目がアンカーポイント。線と線の中点を取っています。アンカーポイント 2 つと、その間にあるコントロールポイントで円弧を描いています。
STEP-2
準備ができたので、いよいよアニメーションを実装します。
やり方としては、
- コントロールポイント(青い点)を円周に対して直角に上下動させる
- 隣り合うコントロールポイントの中点を取得して、アンカーポイント(赤い点)の位置を計算し直す
- コントロールポイントとアンカーポイントを元に円弧を再描画する
こうすることで、一つずつの線が動いているようなアニメーションを実装しました。
パネルを操作することで楕円形にしたり、座標を変更して部分的に円が見えるようにしたり、色々な設定が可能です。
ポイントを増やすことで複雑な動きをさせることも可能ですが、円のアニメーションに見えなくなってしまうので 8~16 ぐらいがちょうど良さそうに思いました。
今回は SVG と SVG.js を使って実装しましたが、他に何か良い方法があればぜひ教えてください。