サイトトップ

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

HTML5 / Flash ActionScript講座
Webクリエイターのための
CreateJSスタイルブック
gihyo.jp連載
「HTML5のCanvasでつくる
ダイナミックな表現
―CreateJSを使う」
■Twitter: @FumioNonaka / Facebook Page: CreateJS

Creators MeetUp

EaselJS 0.7.0と0.7.1のマウスドラッグとマウスイベントのバブリング

本稿は、2013年12月21日土曜日に催された第11回「Creators MeetUp」で務めた一席「新しいCreateJSのマウスイベント」のまとめとして書いた。サンプルコードはjsdo.itに掲げている。また、当日の映像はUSTREAM録画として公開された。


Video streaming by Ustream

CreateJSのライブラリは2013年9月にアップグレードされ、12月17日付CreateJS Blogで+0.0.1のマイナーアップデートがリリースされた(図001)。とくに大きな変更が加えられたのはEaselJSのイベントモデルだ。EaselJS 0.7.0と0.7.1を併せて、とくにマウスイベントの扱いについて説明する(詳しくは、「EaselJS 0.7.0の改訂」および「EaselJS 0.7.1が公開される」参照)。

図001■2013年12月にリリースされたCreateJSの最新版ライブラリ
図001


01 ドラッグ&ドロップ

ドラッグ&ドロップでは、3つのマウス操作についてマウスイベントの扱いを考える。

    ドラッグ&ドロップで扱うマウスイベント
  1. インスタンスの上でマウスボタンが押されたらドラッグを始める
  2. ボタンを押したままマウスを動かしたらインスタンスが追いかける
  3. マウスボタンを放したらドラッグは終える

EaselJS 0.7.0では、マウスイベントのリスナーを加えるインスタンスはDisplayObjectにまとめられた。リスナーを除くために、イベントオブジェクトの参照を保たなくて済む。ただし、EaselJS 0.6.1からイベント名が変わったことに注意しなければならない(表001)。

表001■EaselJS 0.7.0からドラッグ&ドロップに用いるマウスイベント
MouseEventクラスの
イベント
(0.6.1)
DisplayObjectクラスの
イベント
(0.7.0)
マウス操作
mousedown インスタンス上でマウスボタンが押された。
mousemove pressmove インスタンス上でマウスボタンが押されたまま、ポインタが動かされた。
mouseup pressup インスタンス上で押されたマウスボタンが放された。

コード001■EaselJS 0.7.1でインスタンスをドラッグ&ドロップする
  1. instance.addEventListener("mousedown", startDrag);
  2. function startDrag(eventObject) {
  3.   var instance = eventObject.target;
  4.   instance.addEventListener("pressmove", drag);
  5.   instance.addEventListener("pressup", stopDrag);
  6. }
  7. function drag(eventObject) {
  8.   var instance = eventObject.target;
  9.   instance.x = eventObject.stageX;
  10.   instance.y = eventObject.stageY;
  11.   stage.update();
  12. }
  13. function stopDrag(eventObject) {
  14.   var instance = eventObject.target;
  15.   instance.removeEventListener("pressmove", drag);
  16.   instance.removeEventListener("pressup", stopDrag);
  17. }

サンプル001■EaselJS 0.7.1でShapeインスタンスをドラッグ&ドロップする

02 マウスイベントのバブリングとその停止

バブリングというのは、泡のように上っていくこと。EaselJS 0.7.0から、ほとんどのマウスイベントは、イベントが起こったインスタンス(ターゲット)から表示リストの階層を上って伝わるようになった。その流れに先立って、表示リストの頂点からターゲットに向かって伝わることをキャプチャという(図002)。

図002■イベントのバブリングとキャプチャ
図002

サンプルとして後にコード002を掲げた。ボタンにするShape(button)と背景画像のBitmapインスタンスを、Containerオブジェクト(container)に入れ子にした。そして、ボタンをクリックするとURLが開き、親Containerオブジェクトは画像とボタンをまとめてドラッグできるようにしたい(図003)。

図003■ボタンのクリックと背景画像のドラッグ
図003左
ボタンはクリック
図003右
画像とボタンは親がまとめてドラッグ

ドラッグのスクリプトは、基本的に前掲コード001と変わらない。ただし、ドラッグするのは、ふたつのインスタンスを入れ子にした親Containerオブジェクト(container)だ。そして、リスナーが加えられてイベントを処理しているインスタンスはEvent.currentTargetプロパティで参照する(第6、第13、および第19行目)。

ボタンのShapeインスタンス(button)については、DisplayObject.clickイベントに加えたリスナー関数(navigateToURL())でURLを開けばよい(第3および第23〜25行目)。

  1. container.addEventListener("mousedown", startDrag);
  2. button.addEventListener("click", navigateToURL);
  1. function startDrag(eventObject) {
  2.   var instance = eventObject.currentTarget;
  1.   instance.addEventListener("pressmove", drag);
  2.   instance.addEventListener("pressup", stopDrag);
  3. }
  4. function drag(eventObject) {
  5.   var instance = eventObject.currentTarget;
  6.   instance.x = eventObject.stageX;
  7.   instance.y = eventObject.stageY;
  8.   stage.update();
  9. }
  10. function stopDrag(eventObject) {
  11.   var instance = eventObject.currentTarget;
  12.   instance.removeEventListener("pressmove", drag);
  13.   instance.removeEventListener("pressup", stopDrag);
  14. }
  15. function navigateToURL(eventObject) {
  16.   window.open("http://plus.adobe-adc.jp/2_10/", "_blank");
  17. }

ただし、このスクリプトだけでは、Shapeインスタンスの上でマウスボタンを押すと、イベントはバブリングして親Containerオブジェクト(container)に伝わる。すると、リスナー関数(startDrag())が呼出され、ドラッグを始めたことになってしまう。

そこで、マウスイベントのバブリングを止めよう。ボタンのShapeインスタンス(button)にも、DisplayObject.mousedownイベントのリスナー(stopEvent())を加える(第4行目)。そして、リスナー関数は、Event.stopPropagation()メソッドで親オブジェクトへのイベントを止める(第26〜28行目)。

Eventオブジェクト.stopPropagation()
コード002■EaselJS 0.7.1で入れ子インスタンスのマウスイベントがバブリングするのを止める
  1. var offset = new createjs.Point();
  2. container.addEventListener("mousedown", startDrag);
  3. button.addEventListener("click", navigateToURL);
  4. button.addEventListener("mousedown", stopEvent);
  5. function startDrag(eventObject) {
  6.   var instance = eventObject.currentTarget;
  7.   offset.x = instance.x - eventObject.stageX;
  8.   offset.y = instance.y - eventObject.stageY;
  9.   instance.addEventListener("pressmove", drag);
  10.   instance.addEventListener("pressup", stopDrag);
  11. }
  12. function drag(eventObject) {
  13.   var instance = eventObject.currentTarget;
  14.   instance.x = eventObject.stageX + offset.x;
  15.   instance.y = eventObject.stageY + offset.y;
  16.   stage.update();
  17. }
  18. function stopDrag(eventObject) {
  19.   var instance = eventObject.currentTarget;
  20.   instance.removeEventListener("pressmove", drag);
  21.   instance.removeEventListener("pressup", stopDrag);
  22. }
  23. function navigateToURL(eventObject) {
  24.   window.open("http://plus.adobe-adc.jp/2_10/", "_blank");
  25. }
  26. function stopEvent(eventObject) {
  27.   eventObject.stopPropagation();
  28. }

サンプル002■EaselJS 0.7.1で入れ子インスタンスのマウスイベントのバブリングを止める

03 マスクをドラッグする

EaselJSでは、マスクをドラッグすることもできる。ただし、バブリングするマウスイベントには気をつけなければならない。サンプル003はEaselJS 0.6.1でつくられているため、マウスイベントはバブリングしない。

サンプル003■EaselJS 0.6.1でインスタンスにフィルタとマスクをかける

同じつくり方でEaselJS 0.7.0を用いると、マスクがドラッグできなくなる。手前のBitmapインスタンスがマウスイベントを奪ってしまうためだ。それを防ぐには、手前に重なるインスタンスすべてのDisplayObject.mouseEnabledプロパティfalseに定めなければならない。

サンプル004■EaselJS 0.7.0でインスタンスにフィルタとマスクをかける


04 EaselJS 0.7.1のマウスイベントのバブリング

EaselJS 0.7.1では、インスタンスのイベントのフロー(バブリング)の中にマウスイベントのリスナーをもつインスタンスがないかぎり、マウスイベントは奪わない。

サンプル005■EaselJS 0.7.1でインスタンスにフィルタとマスクをかける

だが、ひとたび上司(親インスタンス)がリスナーをもつと、部下(子インスタンス)にはリスナーがなくても、報告責任(マウスイベント)が生じてバブリングする。つまり、「部下のイベントは上司のモノ」。その裏返しとして、背面のインスタンスはイベントを横取りされる。悔しかったら「倍返しだ!」。

図004■親インスタンスがリスナーをもつと子インスタンスのマウスイベントはバブリングする
図004

コード003■EaselJS 0.7.1で親インスタンスがリスナーをもつと入れ子のマウスイベントはバブリングする
  1. stage.addChild(container);
  2. container.addChild(instance);
  3. container.addChild(no_listener);
  4. container.addEventListener("mousedown", function() {});
  5. instance.addEventListener("click", rotate);
  6. function rotate(eventObject) {
  7.   var instance = eventObject.currentTarget;
  8.   instance.rotation += 30;
  9.   stage.update();
  10. }

作成者: 野中文雄
更新日: 2014年1月10日 USTREAM動画を追加。
作成日: 2013年12月21日


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