TECHNOLOGY 2014.04.14

【後編】気軽かつ高機能なベクターベースの2次元描画ライブラリTwo.jsのご紹介

  • HTML5/CSS3
  • javascript

こんにちは、フロントエンド・エンジニアの荒井です。
前回に引き続き、HTML5のSVG, Canvas, WebGLに対応したJavaScriptの2次元描画ライブラリ「Two.js」のご紹介です。

【前編】気軽かつ高機能なベクターベースの2次元描画ライブラリTwo.jsのご紹介」では、Two.jsを使用してSVGデータを元に図形を描画するまでの話をしました。

今回はこの図形をアニメーションさせて描画する方法について説明したいと思います。

図形の頂点データについて

前回の記事でTwo.jsにおける単体の図形を表すクラスは「Two.Polygon」という話をしました。
その「Two.Polygon」には「vertices」というプロパティに配列が格納されています。

「vertices」配列の各要素は「Two.Anchor」インスタンスとなっていて、図形を構成する1つの頂点を表しています。
「Two.Anchor」には頂点の座標を表す「x」, 「y」プロパティが含まれているので、この値を変更して図形の形状をアニメーションさせる事ができます。

曲線の場合

頂点データが曲線を表している場合には、「Two.Anchor」には「controls」というプロパティが追加されて、この中にベジエ曲線のコントロールポイントも一緒に格納されています。

3次ベジエ曲線なのでコントロールポイントは2つあって、「controls.left」と「controls.right」にそれぞれ 「Two.Vector」というインスタンスが格納されています。
詳しくは後で述べますが、この「Two.Vector」にも「x」, 「y」プロパティがあります。

「Two.Anchor」自身が持つX、Y座標がアンカーポイントとなり、上記の2つの「Two.Vector」のX、Y座標がコントロールポイントとなって、曲線を表現しています。
そのため、曲線の形状をアニメーションをさせる場合には合計で3つの座標を変更する必要があります。

Two.Vector クラス

「Two.Vector」は2次元の座標保持とベクトル演算機能を兼ね備えたクラスです。
そこまで多くの機能は入っていないようですが、単位ベクトルや内積を取得するメソッドは用意されてるので、アニメーションをさせる分には充分かなと思っています。

頻繁に使うことになるX、Y座標を取得/設定するコードを下記に示しておきます。

// コンストラクタで座標を設定
v = new Two.Vector(10, 20);
// x, yプロパティで座標を設定
v.x = 30;
v.y = 40;
// setメソッドでも座標を設定可能
v.set(30, 40);
// x, yプロパティで座標を取得
console.log(v.x, v.y) // 30, 40

Two.Anchor クラス

冒頭で挙げた「Two.Anchor」ですが、実は「Two.Vector」を継承しています。
そのため、「Two.Vector」と同様の方法で、X、Y座標を操作することができます。

曲線の場合は「Two.Anchor」に「controls.left」と「controls.right」プロパティが含まれ、コントロールポイントを表す「Two.Vector」インスタンスが格納されています。

その他にもいくつかメソッドやプロパティが追加されてますが、今回はこの違いだけを頭に入れておけば大丈夫です。

描画を定期的に更新する

頂点データの中身が理解できたら、続いて描画を定期的に更新する方法について説明します。

Two.jsには一定間隔で描画を行うための便利な方法が用意されています。

// Twoインスタンス生成時に autostart を true にしておく
var two = new Two({ type: Two.Types.svg, width: 1280, height:720, autostart: true });

// あるいは、play メソッドを呼び出す
two.play();

前者はインスタンス生成時のオプションを使用する方法で描画の定期更新がすぐに開始されます。
後者は任意のタイミングで two.play() を実行する事で開始しています。

こうする事で、後は自動的に「requestAnimationFrame」使って定期的に描画を更新してくれるようになります。
「requestAnimationFrame」を使っているので、フレームレートは基本的には60で固定です。

Two インスタンスの update イベント

Two インスタンスは描画を更新する前に「update」イベントを発行するようになっています。
このイベントをハンドリングして図形の座標を変更すると次の描画のタイミングで反映されるようになります。

イベントリスナーの設定は「Two」クラスに含まれる「bind」メソッドを使うと楽だと思います。

// Twoインスタンス
var two;

// update イベントをハンドリング
two.bind('update', function () {
    // ここに図形の座標を更新する処理を書く
});

// 描画の定期更新を開始
two.play();

ちなみに、「Two」クラスはbackbone.jsにある「Backbone.Events」を継承しているので、「Two.bind」メソッドは「Backbone.Events.on」と同じ意味になります。

図形の座標を更新する

さて、最後は実際に図形の座標を更新する方法について説明します。

下記のコードは、ひとつの「Two.Group」に 複数の「Two.Polygon」が含まれている構造を想定したサンプルになります。

Two.Group → children(Two.Polygonの配列) → vertices(Two.Anchorの配列) → controls.left/right (Two.Vector)

の順に処理を行っています。

// Twoインスタンス
var two;
// Two.Groupインスタンス。この中に複数のTwo.Polygonが含まれているとする
var group;

// update イベントをハンドリング
two.bind('update', function () {

    // Two.Group の children に Two.Polygon の配列が格納されている
    // ※Two.Group が入れ子になっている事は考えない。
    _.each(group.children, function (child) {

        // Two.Polygon の vertices に Two.Anchor の配列が格納されている
        _.each(child.vertices, function (v) {
            v.x = ... // X座標を変更
            v.y = ... // Y座標を変更

            // 曲線の場合のみ存在
            if (v.controls) {
                if (v.controls.left) {
                    v.controls.left.x = ... // X座標を変更
                    v.controls.left..y = ... // Y座標を変更
                }
                if (v.controls.right) {
                    v.controls.right.x = ... // X座標を変更
                    v.controls.right.y = ... // Y座標を変更
                }
            }

        });

    });

});

「update」イベントをハンドリングした関数の中で2つのループ処理が行われています。

最初のループは、「Two.Group」の「chirdren」プロパティを参照してその中にある「Two.Polygon」をひとつずつ取り出しています。

2番目のループでは、最初のループで取り出した「Two.Polygon」の「vertices」プロパティを参照して、その中にある「Two.Anchor」をひとつずつ取り出しています。

後は「図形の頂点データについて」で説明した方法で、全ての座標を変更します。

ループが入れ子になっているので複雑に見えますが、それぞれの処理の意味を考えればシンプルなコードになっている事が分かるかと思います。

完成したサンプル

ここまでで説明した方法を使って作成したサンプルがこちらになります。
http://lab.invogue.jp/y-arai/02_twojs/sample/

前回の記事に載せたデモと同様に、マウスカーソルの位置に応じて図形の全ての頂点の座標を更新してアニメーションを行っています。
ここでは、詳しい説明は省きますが、JavaScriptのソースコードにコメントを入れておきましたので、興味がある方は是非一度覗いてもらえればと思います。

まとめ

2回に渡って、Two.jsライブラリの基本的な使い方と、SVGデータを元にした図形のアニメーションを作成する方法を説明してきました。

おさらいをすると大まかな流れは以下になります。

  1. Twoインスタンスを生成し、DOM上に配置(Two.appendToメソッド)
  2. SVGデータを取り込んでTwo.jsが扱える形式に変換(Two.GroupとTwo.Polygonクラス)
  3. 描画の定期更新を開始(Two.Playメソッド)
  4. 描画の更新イベントをハンドリング(Two.updateイベント)
  5. ハンドリングした関数の中で全ての座標を更新(Two.AnchorとTwo.Vectorクラス)

Two.jsはとてもシンプルなライブラリなので、実際はこの流れさえ覚えておけば充分だと思います。
後はこの方法でいかに面白い動きのアニメーションを作れるかが、腕の見せ所になるのではないでしょうか。

Two.jsは日本ではまだまだ話題になる事も少ないですが、ベクターベースの2次元描画ライブラリの代表として今後に期待したいですね。

それでは、良きTwo.jsライフを!