TweenJSのTimelineを使ったテキストアニメーション

前回の投稿「トゥイーンで簡単canvasアニメーション!TweenJSの使い方」では、TweenJSの基本的な使い方を紹介しましたが、TweenJSにはTimelineクラスが用意されており、Flashのタイムラインに似た概念で複数のトゥイーンをまとめて操作することができます。今回は、TweenJSのTimelineクラスを使って、EaselJSのTextクラスをアニメーションさせてみます。

TweenJSのTimelineを使ったアニメーションのサンプル

TweenJSのTimelineを使ったアニメーションのサンプルを作ってみました。canvas上をクリックするとテキストがアニメーションで切り替わります。このサンプルを使って、EaselJSのTextクラスとTweenJSのTimelineクラスについて解説していきたいと思います。

EaselJSのTextクラス

まず、EaselJSのTextクラスを見てみましょう。Textクラスは、HTML5のcanvasにテキストを表示することができるクラスで、new演算子でインスタンスを生成します。コンストラクタの第1引数で表示したい文字列、第2引数でフォントの指定、第3引数でテキストの色を指定します。

下記は、引数で受け取った文字列からTextインスタンスを生成するメソッドです。今回は、一文字ずつアニメーションさせたかったので、引数で受け取った文字列を一文字ずつ取り出し、それぞれの文字でTextインスタンスを生成しています。

生成したTextインスタンスは、addChild()で表示リストに加えることにより、canvas上に表示されます。Textクラスは、DisplayObjectを継承しているので、x, y, scaleX, scaleYといったプロパティを指定することができます。

JavaScript

function createText(word) {
  var l = word.length;
  var centeringValue = (_letterSpacing * (l - 1)) >> 1;
  var texts = [];
  for (var i = 0; i < l; ++i) {
    var str = word.substring(i, i + 1);
    var text = new Text(str, _font, _color);
    text.textAlign = "center";
    text.textBaseline = "bottom";
    text.x = _letterSpacing * i - centeringValue;
    text.y = _canvas.height;
    text.scaleY = 0;
    _container.addChild(text);
    texts[i] = text;
  }
  _texts_array.push(texts);
  createTimeline();
}

TweenJSのTimelineクラス

続いて、TweenJSのTimelineクラスを見てみます。TweenJSのTimelineは、Flashのタイムラインに似た概念で複数のトゥイーンをまとめて操作することができ、FlashのMovieClipでおなじみのフレームラベルやgotoAndPlay(), gotoAndStop()といった機能も用意されています。

下記は、サンプル内のTimelineを生成するメソッドです。最初にnew演算子でTimelineインスタンスを生成しています。コンストラクタの第1引数でトゥイーンを格納した配列、第2引数でラベル名とミリ秒のペアをオブジェクト形式で指定します。第3引数では、loop, useTicks, pausedといったオプションをオブジェクト形式で指定します。

トゥイーンやラベルは後から追加することもできます。トゥイーンを追加するには、addTween()で追加するTweenの参照を渡します。ラベルを追加するには、addLabel()の第1引数でラベル名、第2引数でミリ秒を指定します。

JavaScript

function createTimeline() {
  var timeline = new Timeline([], {entry:0}, {paused:true});
  var texts = _texts_array[_texts_array.length - 1];
  var l = texts.length;
  for (var i = 0; i < l; ++i) {
    var text = texts[i];
    var tween = Tween.get(text)
    .wait(i * 100)
    .to({y:-10, scaleY:2}, 400, Ease.circOut)
    .to({y:0, scaleY:1}, 400, Ease.backInOut);
    if (i === l - 1) {
      tween.call(tweenComplete, ["entry"], _instance);
    }
    tween.wait((l - 1) * 100 + 100)
    .to({y:-10, scaleY:0.5}, 400, Ease.sineOut)
    .wait(100)
    .to({y:-_canvas.height, scaleY:2}, 800, Ease.circOut);
    if (i === l - 1) {
      tween.call(tweenComplete, ["exit"], _instance);
    }
    timeline.addTween(tween);
  }
  timeline.addLabel("exit", (l - 1) * 100 + 800 + 100);
  _timelines.push(timeline);
}

Timelineの再生コントロール

Timelineは、setPaused(), gotoAndPlay()といったメソッドでコントロールできます。下記は、フレームインやフレームアウトのトゥイーン終了時に呼ばれる関数です。setPaused()やgotoAndPlay()でTimelineの再生をコントロールしています。

JavaScript

function tweenComplete(label) {
  var timeline = _timelines[_currentIndex];
  timeline.setPaused(true);
  switch (label) {
    case "entry" :
      _canvas.addEventListener("click", clickHandler, false);
      break;
    case "exit" :
      _currentIndex = (_currentIndex < _timelines.length - 1) ? ++_currentIndex : 0;
      timeline = _timelines[_currentIndex];
      timeline.gotoAndPlay("entry");
      break;
  }
}

TimelineのuseTicksオプション

Timelineは、コンストラクタの第3引数でuseTicks:trueを指定することにより、Flashのフレームに似た概念で操作することもできます。この場合、トゥイーンのdurationはミリ秒でなく、フレーム数で指定します。

下記は、Timelineを生成するメソッドをuseTicks:trueで書き直したものです。Flashのタイムラインになれている人にとってはわかりやすい反面、Ticker.setFPS()で容易にFPSを変更できなくなるデメリットもあるので、好みに応じて使い分けると良いと思います。

JavaScript

function createTimeline() {
  var timeline = new Timeline([], {entry:0}, {paused:true, useTicks:true});
  var texts = _texts_array[_texts_array.length - 1];
  var l = texts.length;
  for (var i = 0; i < l; ++i) {
    var text = texts[i];
    var tween = Tween.get(text)
    .wait(i * 6)
    .to({y:-10, scaleY:2}, 24, Ease.circOut)
    .to({y:0, scaleY:1}, 24, Ease.backInOut);
    if (i === l - 1) {
      tween.call(tweenComplete, ["entry"], _instance);
    }
    tween.wait((l - 1) * 6)
    .to({y:-10, scaleY:0.5}, 24, Ease.sineOut)
    .wait(6)
    .to({y:-_canvas.height, scaleY:2}, 48, Ease.circOut);
    if (i === l - 1) {
      tween.call(tweenComplete, ["exit"], _instance);
    }
    timeline.addTween(tween);
  }
  timeline.addLabel("exit", (l - 1) * 6 + 48);
  _timelines.push(timeline);
}