サイトトップ

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

HTML5テクニカルノート

EaselJS 0.7.1: 他のオブジェクトの後ろに置いたインスタンスがマウスイベントを受取らない

ID: FN1312002 Technique: HTML5 and JavaScript Library: EaselJS 0.7.1

EaselJS 0.7.0から、ほとんどのマウスイベントはバブリングするようになりました(「EaselJS 0.7.0: Eventクラスでイベントの流れを扱うメソッド」参照)。すると、子インスタンスで起こったマウスイベントが、親インスタンスのリスナーで扱えます。ただし、そのためにこれまでと動きが変わってくるところもあります。


01 マウスイベントの流れ

EaselJS 0.7.0以降では、ほとんどのマウスイベントが表示リストの親子の間を伝わるようになります。この流れは「イベントフロー」と呼ばれます(図001)。インスタンスにマウス操作をして、イベントが起こったときを「ターゲット段階」といいます。バブリングするマウスイベントは、表示リストの親インスタンスに順に伝わり、Stageオブジェクトにまで達します。これが「バブリング段階」です。

さらに、ターゲット段階に先立ち、親から子への流れとしてイベントを捉えることもできます。これは「キャプチャ段階」と呼ばれます。キャプチャ段階のイベントをリスナーで先取りするには、EventDispatcher.addEventListener()メソッドの第3引数にtrueを渡します(デフォルト値はfalse)。

図001■イベントフローのバブリングとキャプチャ
図001

このようなイベントフローが採り入れられたことにより、インスタンスのマウスイベントの受取り方がEaselJS 0.6.1までとは変わってきます。また、EaselJS 0.7.0と0.7.1でも少し違いがあります。DisplayObject.clickイベントを例にして、簡単にご説明しましょう。


02 EaselJS 0.6.1のDisplayObjectインスタンスのマウスクリックの受取り方

まずは、EaselJS 0.6.1の場合です。サンプルとしてつくるscript要素は、後にコード001として全体を掲げます。抜書きするスクリプトの行番号は、コード001にもとづきます。

  1. <script src="http://code.createjs.com/easeljs-0.6.1.min.js"></script>

初めに呼出される関数(initialize())は、矩形のShapeインスタンスをつぎのようにふたつつくり(instanceとno_listener)、一部重ねてステージに置きます(第8〜12行目)。

  1. var stage;
  2. function initialize() {
  1.   var instance = createShape(centerX, centerY);
  2.   var no_listener = createShape(centerX + 25, centerY + 25);
  3.   stage = new createjs.Stage(canvasElement);
  4.   stage.addChild(instance);
  5.   stage.addChild(no_listener);
  1. }
  1. function createShape(x, y) {
  2.   var instance = new createjs.Shape();
  3.   instance.x = x;
  4.   instance.y = y;
  5.   drawRectangle(instance.graphics);
  6.   return instance;
  7. }
  8. function drawRectangle(myGraphics) {
  9.   var randomNumber = Math.floor(Math.random() * 0xFFFFFF);
  10.   myGraphics.beginFill(createjs.Graphics.getRGB(randomNumber));
  11.   myGraphics.drawRect(-25, -25, 50, 50);
  12. }

ふたつのShapeインスタンスのうち、後ろ側にのみDisplayObject.clickイベントのリスナー(rotate())を加えます(第14行目)。リスナー関数はインスタンスをクリックするたびに、その角度を15度回します(第16〜20行目)。ここで注目していただきたいのは、手前にインスタンスが重なった部分をクリックしても、リスナー関数が呼出されるということです(図002)。

図002■ふたつ重ねた後ろのインスタンスにマウスイベントのリスナーを加えた
図002

  1. function initialize() {
  1.   var instance = createShape(centerX, centerY);
  1.   stage.addChild(instance);
  1.   instance.addEventListener("click", rotate);
  2. }
  3. function rotate(eventObject) {
  4.   var instance = eventObject.target;
  5.   instance.rotation += 30;
  6.   stage.update();
  7. }

この例のscript要素をまとめると、つぎのコード001のとおりです。ご参考までにjsdo.itのサンプルコードをリンクしています。

コード001■EaselJS 0.6.1で重ねたインスタンスの後ろ側にマウスイベントのリスナーを加える
  1. <script src="http://code.createjs.com/easeljs-0.6.1.min.js"></script>
  2. <script>
  3. var stage;
  4. function initialize() {
  5.   var canvasElement = document.getElementById("myCanvas");
  6.   var centerX = canvasElement.width / 2;
  7.   var centerY = canvasElement.height / 2;
  8.   var instance = createShape(centerX, centerY);
  9.   var no_listener = createShape(centerX + 25, centerY + 25);
  10.   stage = new createjs.Stage(canvasElement);
  11.   stage.addChild(instance);
  12.   stage.addChild(no_listener);
  13.   stage.update();
  14.   instance.addEventListener("click", rotate);
  15. }
  16. function rotate(eventObject) {
  17.   var instance = eventObject.target;
  18.   instance.rotation += 30;
  19.   stage.update();
  20. }
  21. function createShape(x, y) {
  22.   var instance = new createjs.Shape();
  23.   instance.x = x;
  24.   instance.y = y;
  25.   drawRectangle(instance.graphics);
  26.   return instance;
  27. }
  28. function drawRectangle(myGraphics) {
  29.   var randomNumber = Math.floor(Math.random() * 0xFFFFFF);
  30.   myGraphics.beginFill(createjs.Graphics.getRGB(randomNumber));
  31.   myGraphics.drawRect(-25, -25, 50, 50);
  32. }
  33. </script>

03 EaselJS 0.7.0のDisplayObjectインスタンスのマウスクリックの受取り方

前掲コード001でscript要素に読込むEaselJSのバージョンを0.7.0に書替えます。リファレンスのDisplayObject.clickイベントの説明は、0.6.1と変わっていません。コードもとくにエラーが起こることなく、マウスイベントにリスナーを加えたインスタンスは、クリックすれば回ります。

    <!--
    <script src="http://code.createjs.com/easeljs-0.6.1.min.js"></script>
    -->
  1. <script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>

ただし、ふたつのインスタンスが重なった部分をクリックしたときは、リスナー関数が呼出されなくなります(図003)。これは、マウスイベントがバブリングするようになったためと考えられます。これまでは、手前のインスタンスは自分にイベントリスナーがなければやることはありませんでした。ところが、EaselJS 0.7.0では、親インスタンスにそのイベントリスナーが加えられているかもしれず、バブリングで送らなければなりません。そこで、手前のインスタンスがマウスイベントを奪う結果となったのでしょう。

図003■ふたつ重ねた後ろのインスタンスに加えたマウスイベントのリスナーが呼出されない
図002

EaselJS 0.6.1と同じ動きにするには、ステートメントを1行加えます(script要素全体は、後にコード002として掲げました)。DisplayObjectインスタンスをマウスインタラクションから外すには、DisplayObject.mouseEnabledプロパティをfalseに定めます(第10行目)。

  1. function initialize() {
  1.   var instance = createShape(centerX, centerY);
  2.   var no_listener = createShape(centerX + 25, centerY + 25);
  3.   no_listener.mouseEnabled = false;
  1.   stage.addChild(instance);
  2.   stage.addChild(no_listener);
  1.   instance.addEventListener("click", rotate);
  2. }

これで、手前にインスタンスが重なった部分をクリックしても、後ろのインスタンスのイベントリスナーが呼出されます。script要素全体は、つぎのコード002のとおりです。また、jsdo.itのサンプルコードもリンクに加えてあります。

コード002■EaselJS 0.7.0で重ねたインスタンスの後ろ側でマウスイベントのリスナーを呼出す
  1. <script src="http://code.createjs.com/easeljs-0.7.0.min.js"></script>
  2. <script>
  3. var stage;
  4. function initialize() {
  5.   var canvasElement = document.getElementById("myCanvas");
  6.   var centerX = canvasElement.width / 2;
  7.   var centerY = canvasElement.height / 2;
  8.   var instance = createShape(centerX, centerY);
  9.   var no_listener = createShape(centerX + 25, centerY + 25);
  10.   no_listener.mouseEnabled = false;
  11.   stage = new createjs.Stage(canvasElement);
  12.   stage.addChild(instance);
  13.   stage.addChild(no_listener);
  14.   stage.update();
  15.   instance.addEventListener("click", rotate);
  16. }
  17. function rotate(eventObject) {
  18.   var instance = eventObject.target;
  19.   instance.rotation += 30;
  20.   stage.update();
  21. }
  22. function createShape(x, y) {
  23.   var instance = new createjs.Shape();
  24.   instance.x = x;
  25.   instance.y = y;
  26.   drawRectangle(instance.graphics);
  27.   return instance;
  28. }
  29. function drawRectangle(myGraphics) {
  30.   var randomNumber = Math.floor(Math.random() * 0xFFFFFF);
  31.   myGraphics.beginFill(createjs.Graphics.getRGB(randomNumber));
  32.   myGraphics.drawRect(-25, -25, 50, 50);
  33. }
  34. </script>

EaselJS 0.7.0のイベントモデルについて、ひとつ補っておきます。すべてのイベントの基本クラスとしてEventクラスが新たに備わりました。そのプロパティのEvent.currentTargetは、イベントリスナーが加えられたインスタンスを参照します。これまで述べたとおり、マウスイベントは基本的にバブリングします。そのとき、親インスタンスに加えたイベントリスナーから、Event.currentTargetプロパティで親インスタンス自身が参照できます。

前掲コード002のリスナー関数(rotate())は、Event.currentTargetプロパティを用いてつぎのように書替えても動きます(第18行目)。

  1. function rotate(eventObject) {
      // var instance = eventObject.target;
  2.   var instance = eventObject.currentTarget;
  3.   instance.rotation += 30;
  4.   stage.update();
  5. }

04 EaselJS 0.7.1のDisplayObjectインスタンスのマウスクリックの受取り方

ところが、前掲コード001でscript要素に読込むEaselJSのバージョンを0.7.1に書替えると、後ろのインスタンスのリスナーは重なりをクリックしても0.6.1と同じように呼出されます。リスナーがないインスタンスは、マウスイベントを確かめる対象から外されたためです(「EaselJS 0.7.1が公開される」参照)。ご参考までに、jsdo.itのサンプルも掲げました。

<!--
<script src="http://code.createjs.com/easeljs-0.6.1.min.js"></script>
-->

<script src="http://code.createjs.com/easeljs-0.7.1.min.js"></script>

ただし、バブリングするイベントは、親オブジェクトのリスナーが受取ります。つまり、親オブジェクトがリスナーをもっていれば、リスナーのない子オブジェクトであってもマウスイベントが起こってバブリングさせるのです。

たとえば、前掲コード001にさらに手を加えて、以下のように親Containerオブジェクト(container)の入れ子としてふたつのShapeインスタンスを加えたとします。そして、親オブジェクトにマウスイベントのリスナーを加えると、リスナーのない手前のインスタンス(no_listener)がマウスイベントを奪うようになります。

親オブジェクト(container)にリスナーを定めたイベント(DisplayObject.mousedown)が子オブジェクト(instance)とは異なり、しかもリスナーにnullを与えていることにご注目ください。動きを確かめたい方は、jsdo.itのサンプルをご覧ください。

function initialize() {

  var container = new createjs.Container();
  var instance = createShape(centerX, centerY);
  var no_listener = createShape(centerX + 25, centerY + 25);

  stage.addChild(container);
  // stage.addChild(instance);
  container.addChild(instance);
  // stage.addChild(no_listener);
  container.addChild(no_listener);
  stage.update();
  container.addEventListener("mousedown", null);
  instance.addEventListener("click", rotate);
}



作成者: 野中文雄
作成日: 2013年12月29日


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