SVGと戯れる 第2話「大量のSVGイラストに個別でアニメーションをつける with Snap.svg 中編」

Author: tsukasa

こんにちは、ヤムチャーtsukasaです。
前回はSVGを用意するとこまで解説しました。フロントエンド編は書いてみると予想以上に長くなったので、今回はsvgの準備からマウス移動の視差効果の付加まで解説します。パーツのアニメーション付加は後編で解説します!

各種ライブラリを用意する

  • jQuery(無くてもいいですが、今回のサンプルで使ってます)
  • Tweenエンジン(今回はTweenLiteを使用しています)
  • Snap.svg

TweenエンジンはjQueryのAnimateでも何とかなりますが、滑らかさや柔軟性を考えるとTweenエンジンの方がいいです。
もしTweenエンジンのライブラリ容量さえも気になるコンテンツであれば、今回のようなSVGコンテンツは見送った方がいいでしょう。

また、書き出されたSVGのidをフックにするため、svgにできる圧縮は改行やスペース等を取ることぐらいで、極端な容量削減はできません。とはいえ、SVG1つはpng1枚程度なので(ベクターデータの複雑さに左右されるので、もっともっともーっと軽くなる時もあります。)、普通のwebサイトであればそこまで気にする程ではありません。SVGを圧縮する際には設定に注意してください。ちなみに案件ではgulp-svgminの圧縮設定を以下のように設定しました。まだ圧縮の余地はあると思うので、参考にしてみてください。恐らくgruntも同じです。

Snap.svgについて

screen

今回はさくっとSVGアニメーションを実装するためにSnap.svgというライブラリの力を借りました。Snap.svgはモダンブラウザ向けの多機能性が特徴です。手軽にSVGをこねくりまわすことができます。また、npmにもありますので、さくっとbrowserifyにも組み込めます(僕個人としてはここが重要だったりする)。

ブラウザ間の差異を吸収してくれるものではないので、あらかじめ利用するプロパティの対応ブラウザ範囲を調べておいた方がいいでしょう。

ちなみに前身となるRaphael.jsは安定した挙動とIE8対応能力を持ち合わせています。
対応環境によってはRaphael.jsも視野に入れてみてもいいかもしれません。

使い方についてはsvgの解説で有名なDEFGHI1977@xboxliveさんがとても詳しく解説されているので、是非そちらを読んでいただければと思います。ざっと読んでいただけると、以降の内容が理解しやすくなります。

Snap.svgの使い方まとめ

Paperオブジェクトの作成

まずはベースとなるPaperオブジェクトの作成を行います。

まずはpaperという名前でPaperオブジェクトを生成しました。
この時点でsvgのベースが生成されるので、paper.elによってtitleを追加します。
titleは立ち位置的にはimgのaltに近いものです。できるだけ入れましょう。

この時点でPaperオブジェクトの中身はこんな感じです。

SVGファイルのロードとviewBoxの設定

次にSnap.load()を用いてSVGを読み込みます。読み込んだファイルのソースから.selectによってsvg要素を取り出します。このsvg要素を格納した変数svgは後で使います。さらに.attrによってPaperにviewBoxを設定します。viewBoxの値は取り出したsvg要素から.node.viewBox.baseVal.XXXで取り出します。

この時点でPaperの中身はこんな感じです。

svg要素の整形

後は先ほど読み込んだファイルのソースから部分的に抜き出したg要素を整形してPaperオブジェクトに入れ込めば準備完了です。

変数graphicには一番外側のg要素が入るので、つまりid=”svg-container”のg要素が格納されます。今後は要素を絞る時にこのgraphicを起点にして指定します。次にgraphic内にある全てのg要素とpath要素を精査し、idを抜き出して正規表現+replaceで連番部分を取り除きます。直接idを連番無しのidに差し替えても動作しますが、同じidが並ぶのは良くないのでclassとして付加します。例ではidを取り除いてますが、元々ついているidはかぶらないように連番になっているので、気にならないのであれば取り除かなくても問題ありません。後は整形されたgraphicをPaperにappendして、Paperを入れたい要素に挿入すれば表示されます。

これでsvgの下準備は終わりです。前回用意したSVGファイルを使うと、最終的にPaperは以下のようになります。
前編で書き出されたSVGと見比べると何が行われたか分かりやすいと思います。

視差効果用にリサイズ処理を追加

まずはリサイズ時にリサイズ後のbodyの大きさと位置を取得する処理を追加します。
triggerを用いてイベントの登録と同時に一度処理を走らせます。

マウス移動による視差効果の追加

3つの変数shortObj,middleObj,longObjに視差効果のレイヤー名を持つg要素を格納します。後は取得したマウスの位置から移動量を計算し、各グループにtransformを適用します。coefficientは移動量の最大値です。今回はxとyに両方同じcofficientを適用していますが、別々の値を用いてもらっても全然問題ありません。イラストの余白の決定はこのcofficientとの兼ね合いが強いです。今回は固定値ですが、計算してsvgの大きさに対する割合とかにした方がいいかもしれませんね。

Snap.svgにも簡単にtransformを適用するメソッドは存在しますが、このようにSVGDOMが提供しているapiを使用した方が高速です。これは後半に解説するパーツアニメーションでも同様です。

この時点でデモはこんな感じになっています。
マウス移動による視差効果のデモ

パーツが少なすぎて遠近感が全然出ない!!絵が下手すぎる!
上手いこと遠近感を考えてイラストの構成を考えると、これだけでもインパクトは大きくなります。さらに後半で解説するアニメーションがついたら印象がガラリと変わります。このイラストもきっといい感じになるでしょう。

スマートフォンのジャイロ(傾き)にも対応する

スマートフォンの傾きに対応させたい場合は上のような記述になります。殆ど同じですね!スマホを手で持っている時は大体本体は斜めに傾いているので、その辺をどう補正させるかは決めておいた方がいいですね。

視差効果をアニメーションさせたい時は

この視差効果をアニメーションさせたい時はSnap.svgのもつanimateメソッドを使えばアニメーションさせることができます。しかし、Snap.svgのanimateは軽くない上に柔軟性に欠けているので、TweenエンジンとSVGDOMのapiを併用するのがいいかもしれません。

イベントの間引き

mousemoveやdeviceorientationはイベントの発火回数が非常に多いので、underscore.jslodash.js等のthrottle用いて発火回数を間引いてあげると負荷が軽減されます。

長くなったので、今回はここまで。
後半では各パーツのアニメーションの実装について解説します!