Snap.svgを使ってSVG画像を簡単アニメーション!

投稿日
  • コーディング

最近ではWEBデザインの世界でもSVG画像を利用する機会が増えてきました。
SVG画像とは簡単に言うと、点や線といった幾何学的な情報から成り立つ画像の形式で、いくら拡大しても綺麗なままでかつ、ファイルサイズもそのままであるのが特徴です。
またXML形式で保存されるため画像であるにもかかわらず、テキストエディタ(メモ帳)で編集することもできます。
ロゴやイラストなどのデザインによく使われますね。

さて、SVG画像を取り入れると従来のビットマップ画像(ラスター画像)では出来なかった、アニメーション効果を作ることができます。
以下の画像は実際にSVG画像を動かして「カエルがほっぺたを膨らませて鳴いている」様子をアニメーションにしたものです。図1
このような変化はスタイルシートによるアニメーション効果では実現出来ません。

図1 カエルのなく頃に

これはSVGのパス(点と点を曲線で結んだもの)をJavaScriptで動的に変化させることで実現しています。
普通にプログラムを書くととても大変なのですが、「Snap.svg」というSVG用のJavaScriptライブラリを使用すると簡単に実現することができます。
今回はこのカエルのほっぺたを膨らませるアニメーションを例に、Snap.svgの基本的な使用方法について説明いたします。

Snap.svgをダウンロードする

まずはSnap.svgをダウンロードしましょう。
以下の公式サイトに飛び、ページの右上の [Download]ボタンをクリックし[zipファイル]をダウンロードします。

Snap.svg

ダウンロードしたzipファイルを解凍するとたくさんのフォルダ・ファイルが展開されますが、使用するのは[dist]フォルダ[snap.svg-min.js]ファイルの1つだけです。

このファイルがライブラリの本体となります。

Snap.svgを使ってみる

まずは基本的な動作を確かめてみましょう。

空のSVG要素を用意する

それでは実際にSnap.svgを使ってみましょう。
まずはsnap.svg-min.jsを<script>要素にて読み込み、空の<SVG>要素を用意します。

<script src="snap.svg-min.js"></script>
<svg id="sampleSVG01" viewbox="0 0 200 200" width="200" height="200"></svg>

ここでSVG要素に見慣れない[viewbox]という属性がありますが、これはこのSVGファイルの表示領域を定義する属性になります。
Illusratorのアートボードを想像すると分かりやすいです。
この例の場合は200×200の表示領域が存在することになります。
なおSVGの座標は単位を持たないため、200ピクセル×200ピクセルではないことに気を付けましょう。
実際にブラウザにて表示する時にはこの200x200の表示領域をどのように表示させるかを、単位を持った数値で指定します。
CSSで指定しても大丈夫なのですが、今回はSVG要素の [width]属性と[height]属性にて設定しています。
またSVGの座標と実際の表示が理解しやすいように200ピクセル×200ピクセルとしました。
(これによりSVG座標の1が1pxとなります)

Snap.svgで円を描く

次に実際にプログラムを書いてみましょう。
まず[Snapメソッド]にて既存のSVG要素をSnap.svgで使用するオブジェクト(Elementオブジェクト)に変換します。引数にはCSSセレクタが使用可能です。
取得したElementオブジェクトにはSVG側で用意されている色々な関数が使用できます。
ここでは[Circleメソッド]を使い円を描画します。図2

<script src="snap.svg-min.js"></script>    //Snap.svgライブラリを読み込む
<svg id="sampleSVG01" viewbox="0 0 200 200" width="200" height="200"></svg>    //空のSVG要素を設置
<script>
    var svg = Snap('#sampleSVG01');
    svg.circle(100, 100, 50);
</script>
図2 Snap.svgで円を描く様子1

プログラムを実行すると、真っ黒な円が表示されました。
これでは味気ないので、プログラムを以下のように書き換えましょう。

<script>
    var svg = Snap('#sampleSVG01'),
        eCircle = svg.circle(100, 100, 50);
    //円に属性を追加
    eCircle.attr({
        'fill': '#f1cc23',  //塗りつぶし色
        'stroke': '#333'    //線色
    });
</script>

まず先ほどのcircleメソッドの戻り値として、作成された円のElementオブジェクトが返されるので、それをeCircleという変数で受け取ります。
そのeCircleオブジェクトに対して、今度は[attrメソッド]を使ってこの円(circle要素)の属性を設定します。
ここではsvg要素の塗りつぶし色を設定する [fill]属性と線の色を設定する[stroke]属性を使いました。図3

図3 Snap.svgで円を描く様子2

これでもまだ面白くないので、今度は変化に動きを付けるために以下のようにプログラムをさらに書き換えます。
まずアニメーションの動作をSVG要素のクリックで発生させるために、addEventListenerにて Clickイベントを登録します。
今度はeCircleオブジェクトに対して[animateメソッド]を使用します。
jQueryのanimateメソッドと非常に似ており、第一引数に変化させる属性値を、第二引数に変化にかかる時間(単位はミリ秒)を入力します。

<script>
    var svg = Snap('#sampleSVG01'),
        eCircle = svg.circle(100, 100, 50);
    //SVG要素をクリックするとアニメーション動作が始まるように
    document.getElementById('sampleSVG01').addEventListener('click', function() {
        eCircle.animate({
            'fill': '#f1cc23',
            'stroke': '#333',
            'r': 90;    //円の半径を90に
        }, 1000);
    }, false);
</script>

以下の円をクリックすると背景色と線色がおよび円の半径が徐々に変化していくことが分かります。
実はfill属性とstroke属性はスタイルシートでも変更可能なため、CSS3のTransitionやAnimationプロパティを使ってアニメーション効果を付けることは可能なのですが、半径を設定するr属性はスタイルシートでは変更できません。
Snap.svgではこのようなスタイルシートでは実現不可能なアニメーションも簡単に作れることが分かりますね。

図4 Snap.svgで円を描く様子3(クリッックで変化します)

カエルのほっぺたを膨らませる(SVGによるモーフィング)

ここまでSnap.svgの基本的な動作を確認してきました。
最後にカエルのほっぺたを膨らませるアニメーションを作ります。
まずそのためにはほっぺたが膨らんでいない図形と膨らんでいる図形の2種類をあらかじめ用意する必要があります。

まずIllustratorそれらの図形をパスで描きます。
最終的にそれらの図形はぴったりと重なるように配置します。
次にAI形式ではなくSVG形式で保存を行います。
すると[SVGオプション]が表示されるので、[SVGコード...]をクリックします。
テキストエディタが立ち上がり、このSVGのコードが表示されるので、それを丸ごとコピーします。図5

図5 SVGコード取得

Illustratorより出力されたSVG要素はHTMLの要素(インラインSVG)として使うには不要な記述がたくさんあります。
SVG要素に関しては [viewbox]属性のみで十分ですので、そのように調整します。
その他塗りつぶし(fill)や線(stroke)の属性も、後からスタイルシートで別途設定する際には不要となるので削除しても大丈夫です。
シンプルにしたものを以下に記します。(d属性の値はとても長いため省略しています)

<svg id="sampleSVG02" viewbox="0 0 200 200" width="200" height="200">
    <path id="faceAfter" d="M157.2,88.1c-0.2,0-0.3..."/>
    <path id="faceBefore" d="M157.1,88.6c-0.1-0.2-..."/>
</svg>
<style>
    #faceBefore {
        fill: #9BC532;
    }
    #faceAfter {
        display: none;
    }
</style>

ほっぺたの膨らむ前のパス(path要素)には「faceBefore」というIDを、膨らむ後のパスには「faceAfter」というIDを付けています。
また膨らむ後のパスは非表示となるように、スタイル「display:none;」を加えました。

これで前準備は完了ですので、プログラムを作っていきます。
まず大元になるSVG画像を取得するまでは同じですが、次にそのSVG画像の中のpath要素を取得するために、[selectメソッド]を使います。
selectメソッドも、Snapメソッドと同様に引数にCSSセレクタを使用できますので、先ほど設定したIDを用いてそれぞれのpath要素のElementオブジェクトを取得します。
次にpath要素のd属性を変数に保存しておきます。
あとはほっぺを膨らませる関数を作るだけです。
初めはほっぺが膨らんでいない状態なので、まずanimateメソッドにてd属性を膨らんでいる値に変化させます。
変化後はコールバック関数にて再び膨らんでいない状態に変化させます。
これらを関数にしておき、繰り返し読み出すことでほっぺが膨らむ→元に戻るという動作を繰り返し発生させます。

<script>
    var svg = Snap('#sampleSVG02'),
    eFaceBefore = svg.select('#faceBefore'),
    eFaceAfter = svg.select('#faceAfter'),
    dFaceBefore = eFaceBefore.attr('d'),
    dFaceAfter = eFaceAfter.attr('d'),
    fnAnimation = function() {
        eFaceBefore.animate({
            'd': dFaceAfter
        }, 1000, function() {
            this.animate({
                'd': dFaceBefore
            }, 1000, function() {
                fnAnimation();
            });
        });
    };
    fnAnimation();
</script>

下図のように綺麗にアニメーションできたら成功です。図6
なおこのような変化(モーフィング)ですが、あらかじめ2つのパスのアンカーポイントやハンドルなどを同数にしておかないと綺麗に変化しません
それぞれの画像を別に作成するのではなく、1つの画像を作成した後にそのパスを変化させながら形を作ると良いと思います。

図6 カエルのほっぺたアニメ

Snap.svgによるアニメーション、いかがでしたでしょうか?
スタイルシートによるアニメーションでは再現できない、パスの変化がとても楽しいですね。
SVG画像の作り込みだけではなくプログラムも必要なため少し敷居が高いですが、ぜひ使いこなしてリッチなアニメーションを作りましょう。