サイトトップ

Director Flash 書籍 業務内容 プロフィール
 

HTML5 / Flash ActionScript講座
HTML5のCanvasでつくる
ダイナミックな表現
―CreateJSを使う
Twitter: @FumioNonaka
Facebook Page: CreateJS

CreateJS Workshop

TweenJSを使ったアニメーションとマウスイベントの扱い

日本時間2013年2月14日に公開されたCreateJSの新バージョンにもとづいて解説する。このレジュメをもとに解説したCreateJS勉強会のUSTREAM録画は「第一回勉強会フォローアップ」で公開されている。なお、リンクしたサンプルのHTMLファイルは、ライブラリをダウンロードしなくて済むよう、CDN(Content Delivery Network)のライブラリを使った。

01 EaselJSでCanvasに星形を描く

EaselJSでCanvasの真ん中に星形を描いてみよう(図001)。

図001■Canvasの真ん中に青い星形を描く
図001

01-01 CanvasにStageオブジェクトをつくる

HTMLドキュメントのbody要素にcanvas要素を加え、id属性にJavaScriptで参照するための名前("myCanvas")をつける。また、body要素のonload属性には、初期設定の関数の呼出し("initialize()")を定めておく。

<body onLoad="initialize()">
  <canvas id="myCanvas" width="240" height="180"></canvas>
</body>

HTMLドキュメントのhead要素には、script要素でEaselJSライブラリを読込む(ライブラリは予めダウンロードしておく)。

  1. <script src="lib/easeljs-0.6.0.min.js"></script>

EaselJSを使うには、まずCanvasにステージ(Stageオブジェクト)をつくらなければならない。new演算子でStageクラスのコンストラクタを呼出し、引数にはcanvas要素の参照を渡す。なお、CreateJSのクラスを参照するときは、頭に「名前空間」として「createjs」を添える。

new createjs.Stage(canvas要素)

canvas要素の参照は、document.getElementById()メソッドにidを渡すと得られる(第5行目)。初期設定の関数(initialize())で、Stageオブジェクトをつくった(第6行目)。

  1. var stage;
  2. function initialize() {
  3.   var canvasElement = document.getElementById("myCanvas");
  4.   stage = new createjs.Stage(canvasElement);
  1. }

01-02 Stageオブジェクトに加えたShapeインスタンスに星形を描く

描画はShapeインスタンスをつくって行う。new演算子でShapeクラスのコンストラクタを呼出す。

new createjs.Shape()

インスタンスをCanvasに表示するためには、Stageオブジェクトの子に加えなければならない。Stageオブジェクトに対してContainer.addChild()メソッドを呼出し、加えたい子オブジェクトを引数に渡す。

親オブジェクト.addChild(子オブジェクト)

Shapeインスタンスをつくる関数(createShape())は、別に定めた(第11〜17行目)。関数の引数に配置するxy座標を渡すと、つくったインスタンスが返される。そのインスタンスをStageオブジェクトの子に加えている(第8行目)。

  1. function initialize() {
  1.   var myShape = createShape(canvasElement.width / 2, canvasElement.height / 2);
  2.   stage.addChild(myShape);
  1. }
  2. function createShape(nX, nY) {
  3.   var myShape = new createjs.Shape();
  4.   myShape.x = nX;
  5.   myShape.y = nY;
  6.   drawStar(myShape.graphics);
  7.   return myShape;
  8. }
  9. function drawStar(myGraphics) {
  10.   myGraphics.beginFill("#0000FF");
  11.   myGraphics.drawPolyStar(0, 0, 40, 5, 0.6, -90);
  12. }

Shapeインスタンスへの描画は、Shape.graphicsプロパティのGraphicsオブジェクトに対して行う。Graphicsオブジェクトに星を描く関数(drawStar())も別に定めた(第18〜21行目)。引数にGraphicsオブジェクトを渡す。

描画の塗りはGraphics.beginFill()メソッドで引数にカラーを定め(第19行目)、星形はGraphics.drawPolyStar()メソッドで描く(第20行目)。星形の谷の深さは、0から1までの数値で定める(図002)。また、起点角は3時の方向がデフォルトの0なので、12時方向であれば-90度とする。

Graphicsオブジェクト.beginFill(カラー)

Graphicsオブジェクト.drawPolyStar(x座標, y座標, 半径, 頂点数, 谷の深さ, 起点角)

図002■異なる谷の深さで描かれた5頂点の星形

図002左
0.8

図002中央
0.6

図002右
0

EaselJSでステージ(Stageオブジェクト)を描き替えるには、必ずStage.update()メソッドを呼出さなければならない(第9行目)。

Stageオブジェクト.update()
  1. function initialize() {
  1.   stage.update();
  2. }

つぎのコード001は、Canvasの真ん中にShapeインスタンスを置いて、インスタンスに青い星形を描く(前掲図001参照)。

コード001■EaselJSでCanvasの真ん中に青い星形を描く
  1. <script src="lib/easeljs-0.6.0.min.js"></script>
  2. <script>
  3. var stage;
  4. function initialize() {
  5.   var canvasElement = document.getElementById("myCanvas");
  6.   stage = new createjs.Stage(canvasElement);
  7.   var myShape = createShape(canvasElement.width / 2, canvasElement.height / 2);
  8.   stage.addChild(myShape);
  9.   stage.update();
  10. }
  11. function createShape(nX, nY) {
  12.   var myShape = new createjs.Shape();
  13.   myShape.x = nX;
  14.   myShape.y = nY;
  15.   drawStar(myShape.graphics);
  16.   return myShape;
  17. }
  18. function drawStar(myGraphics) {
  19.   myGraphics.beginFill("#0000FF");
  20.   myGraphics.drawPolyStar(0, 0, 40, 5, 0.6, -90);
  21. }
  22. </script>

02 TweenJSでオブジェクトをトゥイーンアニメーションさせる

TweenJSでShapeインスタンスをトゥイーンアニメーションさせよう。インスタンスはCanvasの上端に置いて(図003)、落ちるアニメーションにする。そのため、Shapeインスタンスの位置を水平方向は真ん中、垂直方向は上端とした(第11行目)。

02-01 星形のShapeオブジェクトをCanvasの上端に置く

図003■星形をCanvas真ん中の上端に描く
図003

  1. function initialize() {
  2.   var canvasElement = document.getElementById("myCanvas");
  3.   var nWidth = canvasElement.width;
  4.   var nHeight = canvasElement.height;
  1.   var myShape = createShape(nWidth / 2, 0);   // canvasElement.height / 2);
  1. }

02-02 Tweenクラスでオブジェクトにトゥイーンを定める

script要素には、TweenJSライブラリの読込みを加える(第2行目)。

  1. <script src="lib/tweenjs-0.4.0.min.js"></script>

Tweenクラスのコンストラクタには、引数としてトゥイーンアニメーションさせるオブジェクトを渡す。

new createjs.Tween(対象オブジェクト)

オブジェクトのプロパティをトゥイーンするには、Tween.to()メソッドを用いる。第1引数にはトゥイーンするプロパティと値の組を納めたObjectインスタンスを渡す。第2引数はトゥイーンにかける時間で、第3引数はイージングを関数で渡す。イージングの関数は、Easeクラスから選べる。

Tweenオブジェクト.to(プロパティ値のObject, 間隔, イージング関数)

トゥイーンは新たな関数(setTween())で定めることとし、初期設定の関数(initialize())から呼出した(第12行目)。引数には、トゥイーンするオブジェクトと移動先の垂直座標を渡す。

トゥイーン設定の関数(setTween())は、引数のオブジェクトをTween()コンストラクタに渡し(第18行目)、Tween.to()メソッドでy座標の移動と回転(rotation)をプロパティに定めた(第19行目)。イージング関数には、バウンドのように値が変化するEase.bounceOutを選んだ。

  1. function initialize() {
  2.   var canvasElement = document.getElementById("myCanvas");
  3.   var nWidth = canvasElement.width;
  4.   var nHeight = canvasElement.height;
  1.   setTween(myShape, nHeight - radius);
  1. }
  2. function setTween(target, bottom) {
  3.   var myTween = new createjs.Tween(target);
  4.   myTween.to({y:bottom, rotation:360}, 5000, createjs.Ease.bounceOut);
  5. }

02-03 TickerクラスでStageオブジェクトを繰返し描き替える

EaselJSでアニメーションを表示するには、ステージ(Stageオブジェクト)が繰返し描き替えられなければならない。そのためには、Tickerクラスの"tick"イベントにリスナー関数を加え、その関数からStage.update()メソッドを呼出す。リスナー関数を加えるメソッドはTicker.addEventListener()で、第1引数にはイベントの"tick"、第2引数にリスナー関数を渡す。

createjs.Ticker.addEventListener("tick", リスナー関数)

初期設定の関数(initialize() )で、Tickerクラスの"tick"イベントにリスナー関数を加えた(第14行目)。リスナー関数(refreshScreen())は、Stage.update()メソッドを呼出している(第22行目)[*1]

  1. function initialize() {
  1.   createjs.Ticker.addEventListener("tick", refreshScreen);
  1. }
  1. function refreshScreen() {
  2.   stage.update();
  3. }

つぎのコード002は、星形のインスタンスをCanvas上端から回しながら落として弾ませる。

コード002■TweenJSで星形を回しながら落として弾ませる
  1. <script src="lib/easeljs-0.6.0.min.js"></script>
  2. <script src="lib/tweenjs-0.4.0.min.js"></script>
  3. <script>
  4. var stage;
  5. var radius = 40;
  6. function initialize() {
  7.   var canvasElement = document.getElementById("myCanvas");
  8.   var nWidth = canvasElement.width;
  9.   var nHeight = canvasElement.height;
  10.   stage = new createjs.Stage(canvasElement);
  11.   var myShape = createShape(nWidth / 2, -radius);
  12.   setTween(myShape, nHeight - radius);
  13.   stage.addChild(myShape);
  14.   createjs.Ticker.addEventListener("tick", refreshScreen);
  15.   stage.update();
  16. }
  17. function setTween(target, bottom) {
  18.   var myTween = new createjs.Tween(target);
  19.   myTween.to({y:bottom, rotation:360}, 5000, createjs.Ease.bounceOut);
  20. }
  21. function refreshScreen() {
  22.   stage.update();
  23. }
  24. function createShape(nX, nY) {
  25.   var myShape = new createjs.Shape();
  26.   myShape.x = nX;
  27.   myShape.y = nY;
  28.   drawStar(myShape.graphics);
  29.   return myShape;
  30. }
  31. function drawStar(myGraphics) {
  32.   myGraphics.beginFill("#0000FF");
  33.   myGraphics.drawPolyStar(0, 0, radius, 5, 0.6, -90);
  34. }
  35. </script>

[*1] Function.bind()メソッドを使えば、Stage.update()メソッドをリスナーに定められる。

  1.   // createjs.Ticker.addEventListener("tick", refreshScreen);
      createjs.Ticker.addEventListener("tick", stage.update.bind(stage));

ただし、タイプが楽になるほかは、処理のうえでの利点は感じられない。詳しくは、「EaselJSのイベントリスナーにFunction.bind()メソッドを適用するとリスナー内から削除できない」参照。

また、Ticker.addEventListener()メソッドの第2引数にStageオブジェクトを渡すと、Ticker.tickイベントで内部的にStage.update()メソッドが呼出される。Function.bind()メソッドを使うより、こちらの方がよいだろう。詳しくは、F-site「Ticker.addEventListener()メソッドにStageオブジェクトを渡す」参照。

  1.   // createjs.Ticker.addEventListener("tick", refreshScreen);
      createjs.Ticker.addEventListener("tick", stage);

02-04 トゥイーンに待ちとフェードアウトを加える

TweenオブジェクトにTweenのメソッドで設定を加えれば、それらは順にトゥイーンアニメーションされる。バウンドし終えた後、1秒後にインスタンスをアルファでフェードアウトしてみる(図004)。

図004■バウンドし終えた星が1秒後にフェードアウトする
図004左   図004右

トゥイーンをしばらく待たせるには、Tween.wait()メソッドを使う。引数には待ち時間をミリ秒で渡す。

Tweenオブジェクト.wait(待ち時間)

回りながら落ちて弾むトゥイーン(第16行目)の後に、1秒間の待ち(第17行目)とアルファのフェードアウト(第18行目)を加えた。

  1. function setTween(target, bottom) {
  2.   var myTween = new createjs.Tween(target, {loop:true});
  3.   myTween.to({y:bottom, rotation:360}, 5000, createjs.Ease.bounceOut);
  4.   myTween.wait(1000);
  5.   myTween.to({alpha:0}, 2500, createjs.Ease.circIn);
  6. }

さらに、Tween()コンストラクタの第2引数にObjectインスタンスを加え、loopプロパティをtrueに定めた。すると、定めたトゥイーンはずっと繰返される。つぎのコード003は、インスタンスが回りながら落ちてバウンドし、1秒待ってフェードアウトするというトゥイーンを繰返す。

コード003■TweenJSでトゥイーンを組合わせて繰返す
  1. var stage;
  2. var radius = 40;
  3. function initialize() {
  4.   var canvasElement = document.getElementById("myCanvas");
  5.   var nWidth = canvasElement.width;
  6.   var nHeight = canvasElement.height;
  7.   stage = new createjs.Stage(canvasElement);
  8.   var myShape = createShape(nWidth / 2, -radius);
  9.   setTween(myShape, nHeight - radius);
  10.   stage.addChild(myShape);
  11.   createjs.Ticker.addEventListener("tick", refreshScreen);
  12.   stage.update();
  13. }
  14. function setTween(target, bottom) {
  15.   var myTween = new createjs.Tween(target, {loop:true});
  16.   myTween.to({y:bottom, rotation:360}, 5000, createjs.Ease.bounceOut);
  17.   myTween.wait(1000);
  18.   myTween.to({alpha:0}, 2500, createjs.Ease.circIn);
  19. }
  20. function refreshScreen() {
  21.   stage.update();
  22. }
  23. function createShape(nX, nY) {
  24.   var myShape = new createjs.Shape();
  25.   myShape.x = nX;
  26.   myShape.y = nY;
  27.   drawStar(myShape.graphics);
  28.   return myShape;
  29. }
  30. function drawStar(myGraphics) {
  31.   myGraphics.beginFill("#0000FF");
  32.   myGraphics.drawPolyStar(0, 0, radius, 5, 0.6, -90);
  33. }

TweenJSのページのデモ「SPARK TABLE」は、Easeクラスのイージング関数による値の変化をグラフで表す。

図005■Easeクラスのイージング関数による値の変化が確かめられる「SPARK TABLE」
図005


03 EaselJSでマウスイベントを扱う

オブジェクトへのマウスクリックと、ドラッグ&ドロップを試してみる。

03-01 オブジェクトをクリックしたら回す

インスタンスへのマウス操作で行いたい処理は、そのインスタンスにEventDispatcher.addEventListener()メソッドでリスナー関数を加える。

オブジェクト.addEventListener(イベント, リスナー関数)

マウスクリックは"click"イベントで捉える(第6行目)。リスナー関数が受取るイベントオブジェクトのMouseEvent.targetプロパティにより、マウス操作されているインスタンスの参照が得られる(第12行目)。したがって、つぎのリスナー関数(rotate())は、クリックしたインスタンスを回転する(図006)。

図006■インスタンスをクリックすると回る
図006左   図006右

  1. function initialize() {
  1.   myShape.addEventListener("click", rotate);
  1. }
  2. function rotate(eventObject) {
  3.   var instance = eventObject.target;
  4.   instance.rotation += 15;
  5.   stage.update();
  6. }

つぎのコード004は、Canvasの真ん中に置いた星形のShapeインスタンスに"click"イベントのリスナー関数を加え、クリックするたびに回転する。

コード004■オブジェクトをクリックしたら回す
  1. var stage;
  2. function initialize() {
  3.   var canvasElement = document.getElementById("myCanvas");
  4.   stage = new createjs.Stage(canvasElement);
  5.   var myShape = createShape(canvasElement.width / 2, canvasElement.height / 2);
  6.   myShape.addEventListener("click", rotate);
  7.   stage.addChild(myShape);
  8.   stage.update();
  9. }
  10. function rotate(eventObject) {
  11.   var instance = eventObject.target;
  12.   instance.rotation += 15;
  13.   stage.update();
  14. }
  15. function createShape(nX, nY) {
  16.   var myShape = new createjs.Shape();
  17.   myShape.x = nX;
  18.   myShape.y = nY;
  19.   drawStar(myShape.graphics);
  20.   return myShape;
  21. }
  22. function drawStar(myGraphics) {
  23.   myGraphics.beginFill("#0000FF");
  24.   myGraphics.drawPolyStar(0, 0, 40, 5, 0.6, -90);
  25. }

03-02 オブジェクトをドラッグ&ドロップする

インスタンスのドラッグ&ドロップは、インスタンス上でマウスボタンを押した"mousedown"イベントで、ドラッグの処理(startDrag())を始める(第6行目)。ドラッグはマウスを動かす"mousemove"イベントにリスナー関数(drag())を定め、マウスポインタの座標にインスタンスの座標を合わせる(図007)。

図007■インスタンスをドラッグ&ドロップする
図007左   図007右

"mousemove"イベントのリスナー関数は、MouseEventオブジェクトに加える(第13行目)。また、マウスポインタの座標は、リスナーが受取ったMouseEventオブジェクトのプロパティMouseEvent.stageXMouseEvent.stageYで得られる(第18〜19行目)。

  1. function initialize() {
  1.   myShape.addEventListener("mousedown", startDrag);
  1. }
  2. function startDrag(eventObject) {
  1.   eventObject.addEventListener("mousemove", drag);
  1. }
  2. function drag(eventObject) {
  3.   var instance = eventObject.target;
  4.   instance.x = eventObject.stageX;
  5.   instance.y = eventObject.stageY;
  6.   stage.update();
  7. }

リスナー関数を除くには、加えたオブジェクトに対してEventDispatcher.removeEventListener()メソッドを呼出す。

オブジェクト.removeEventListener(イベント, リスナー関数)

マウスボタンを放す"mouseup"イベントで、リスナーを除いて初めの状態に戻す(第14行目)。リスナーを加えたのはMouseEventオブジェクトなので、その参照をドラッグするインスタンスに加えた(第11〜12行目)。

"mouseup"イベントのリスナー関数(stopDrag())は、引数のMouseEventオブジェクトのMouseEvent.targetプロパティからドラッグしているインスタンスの参照を得て(第23行目)、さらにその変数からリスナーを除くMouseEventオブジェクトの参照を取出している(第24行目)。そのMouseEventオブジェクトからEventDispatcher.removeEventListener()メソッドでリスナーを除く(第25〜26行目)。

  1. function startDrag(eventObject) {
  2.   var instance = eventObject.target;
  3.   instance.dispatcher = eventObject;
  1.   eventObject.addEventListener("mouseup", stopDrag);
  2. }
  1. function stopDrag(eventObject) {
  2.   var instance = eventObject.target;
  3.   var dispatcher = instance.dispatcher;
  4.   dispatcher.removeEventListener("mousemove", drag);
  5.   dispatcher.removeEventListener("mouseup", stopDrag);
  6. }

つぎのコード005は、インスタンス上でマウスボタンを押すと、マウスを動かす操作にリスナー関数が加えられて、インスタンスの位置をマウスポインタに追随させる。マウスボタンを放すと、マウスを動かす操作とボタンを放したときのリスナーはともに除かれる。

コード005■オブジェクトをドラッグ&ドロップする
  1. var stage;
  2. function initialize() {
  3.   var canvasElement = document.getElementById("myCanvas");
  4.   stage = new createjs.Stage(canvasElement);
  5.   var myShape = createShape(canvasElement.width / 2, canvasElement.height / 2);
  6.   myShape.addEventListener("mousedown", startDrag);
  7.   stage.addChild(myShape);
  8.   stage.update();
  9. }
  10. function startDrag(eventObject) {
  11.   var instance = eventObject.target;
  12.   instance.dispatcher = eventObject;
  13.   eventObject.addEventListener("mousemove", drag);
  14.   eventObject.addEventListener("mouseup", stopDrag);
  15. }
  16. function drag(eventObject) {
  17.   var instance = eventObject.target;
  18.   instance.x = eventObject.stageX;
  19.   instance.y = eventObject.stageY;
  20.   stage.update();
  21. }
  22. function stopDrag(eventObject) {
  23.   var instance = eventObject.target;
  24.   var dispatcher = instance.dispatcher;
  25.   dispatcher.removeEventListener("mousemove", drag);
  26.   dispatcher.removeEventListener("mouseup", stopDrag);
  27. }
  28. function createShape(nX, nY) {
  29.   var myShape = new createjs.Shape();
  30.   myShape.x = nX;
  31.   myShape.y = nY;
  32.   drawStar(myShape.graphics);
  33.   return myShape;
  34. }
  35. function drawStar(myGraphics) {
  36.   myGraphics.beginFill("#0000FF");
  37.   myGraphics.drawPolyStar(0, 0, 40, 5, 0.6, -90);
  38. }

作成者: 野中文雄
更新日: 2013年2月25日 注[*1]に、Ticker.addEventListener()メソッドの第2引数としてStageオブジェクトを渡す手法追加。
更新日: 2013年2月21日「Stage3D勉強会(第3回) 活動レポート」へのリンクを追加。
作成日: 2013年2月15日


Copyright © 2001-2013 Fumio Nonaka.  All rights reserved.