サイトトップ

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

HTML5テクニカルノート

EaselJSでインスタンスをクリックした座標で回しながらドラッグする

ID: FN1205001 Technique: HTML5 and JavaScript

EaselJSで外部から読込んだビットマップファイルをCanvasに表示し、初めにクリックした座標で回しながらドラッグしてみます。本稿の解説は、(1)外部ビットマップファイルの読込みと(2)マウスクリックおよびドラッグのイベントの扱いについて、基本的な知識をおもちの方が対象です。不足あるいは不安がある場合には、先につぎのノートをお読みください。

  1. EaselJSで外部ビットマップファイルを読込んで回す
  2. EaselJSのマウスクリックとドラッグ&ドロップ

01 外部画像ファイルを読込んでCanvasの中央に表示する
ビットマップはPNGファイル(Pen.png)で用意しました。HTMLドキュメントと同じ場所に画像用のフォルダ(images)をつくり、その中に納めます(図001)。そして、HTMLドキュメントの<body>要素には<canvas>要素("myCanvas")が記述され、描画のためのJavaScriptの関数(xInitialize())を呼出しているものとします。

<body onload="xInitialize()">
  <canvas id="myCanvas" width="240" height="180"></canvas>
</body>

図001■PNGファイルを画像用フォルダに納める
図001

以下のコード001をHTMLドキュメントの<script>要素として加えると、外部から読込まれたPNGファイルの画像が画面の真ん中に表示されます(図002)。

図002■外部から読込んだファイルの画像がCanvasの中央に表示された
図002

コード001■PNGファイルを読込んでCanvasの中央に表示する
  1. <script src="easeljs/utils/UID.js"></script>
  2. <script src="easeljs/geom/Matrix2D.js"></script>
  3. <script src="easeljs/display/DisplayObject.js"></script>
  4. <script src="easeljs/display/Container.js"></script>
  5. <script src="easeljs/display/Stage.js"></script>
  6. <script src="easeljs/display/Bitmap.js"></script>
  7. <script type="text/javascript">
  8.   var stage;
  9.   var myBitmap;
  10.   function xInitialize() {
  11.     var canvasObject = document.getElementById('myCanvas');
  12.     stage = new Stage(canvasObject);
  13.     xDraw(canvasObject.width / 2, canvasObject.height / 2);
  14.   }
  15.   function xDraw(nX, nY) {
  16.     myBitmap = new Bitmap("images/Pen.png");
  17.     myBitmap.x = nX - myBitmap.image.width / 2;
  18.     myBitmap.y = nY - myBitmap.image.height / 2;
  19.     stage.addChild(myBitmap);
  20.     stage.update();
  21.   }
  22. </script>

外部画像ファイルを読込んで表示する関数(xDraw())は、表示するxy座標を引数(nXとnY)に受取ります(コード001第15行目)。その座標が読込んだ画像(myBitmap)の中心になるよう、その幅と高さの半分を指定座標から差引いています(第17〜18行目)[*1]

[*1] 前出「EaselJSで外部ビットマップファイルを読込んで回す」のコード002と異なり、プロパティDisplayObject.regXDisplayObject.regYでBitmapインスタンスの基準点を変えることはしませんでした。それは、次項でインスタンスを任意の座標で回すため、基準点を予め定めておく意味がないからです。


02 インスタンスのクリックした座標を中心に回す
インスタンスは、DisplayObject.rotationプロパティで回せます(「EaselJSで描いた星形を回す」参照)。ただし、回転の中心は、インスタンスの基準点です。本稿のお題は、この中心座標を任意に決めようというものです。この項では、インスタンスのクリックした座標を中心に、予め定めた角度回します。

そのためには、前掲コード001につぎのコードを加えます。なお、でき上がった<script>属性の全体は後にコード002として掲げました。頭に添えた行番号は、後掲コード002にもとづきます。

  1. <script src="easeljs/events/MouseEvent.js"></script>
  2. <script src="easeljs/geom/Point.js"></script>
  1. <script type="text/javascript">
  1.   function xDraw(nX, nY) {
  1.     myBitmap.onClick = clickHandler;
  1.   }
  2.   function clickHandler(eventObject) {
  3.     var mouseX = eventObject.stageX;
  4.     var mouseY = eventObject.stageY;
  5.     var mousePoint = this.globalToLocal(mouseX, mouseY);
  6.     this.rotation += 15;
  7.     var offsetPoint = this.localToGlobal(mousePoint.x, mousePoint.y);
  8.     this.x += mouseX - offsetPoint.x;
  9.     this.y += mouseY - offsetPoint.y;
  10.     stage.update();
  11.   }
  12. </script>

EaselJSのライブラリからは、MouseEventとPointのふたつのクラスを加えました(後掲コード002第2〜3行目)。Bitmapインスタンスのクリックで回転させますので、DisplayObject.onClickイベントにハンドラの関数(clickHandler)を定めています(第21行目)。イベントハンドラは、引数のイベントオブジェクトからMouseEvent.stageXMouseEvent.stageYプロパティでマウス座標を調べ(第26〜27行目)、DisplayObject.rotationプロパティでインスタンスを回します(第29行目)。

問題は回転の中心を、マウスクリックした座標にすることです。そのためには、DisplayObject.globalToLocal()DisplayObject.localToGlobal()メソッドを用います。ふたつのメソッドには、引数としてともにxy座標値を渡します。

DisplayObjectオブジェクト.globalToLocal(x座標, y座標)
DisplayObjectオブジェクト.localToGlobal(x座標, y座標)

DisplayObject.globalToLocal()メソッドはそれがステージ上の座標とみなして、インスタンスから見た座標に変換します。DisplayObject.localToGlobal()メソッドは、逆に座標がインスタンスから見た値と捉えて、ステージ上の座標に直します。戻り値の座標はともにPointオブジェクトで返されます。では、ふたつのメソッドを使って、どうやって回転の中心を変えるかです。手順はつぎのようになります。

  1. クリックしたステージ上の座標を調べる(第26〜27行目)
  2. クリック座標をインスタンス上の座標に変換する(第28行目)
  3. インスタンスを回転する(第29行目)
  4. 回転後のインスタンスから見たクリック座標をステージ上の座標に変換する(第30行目)
  5. 2と4の座標の差を補正する(第31〜32行目)

つまり、初めにクリックした位置を覚えたうえで、インスタンスから見た座標に変えます。そして、回転後その座標がどうずれたか、ステージを基準にして調べます。そのずれを直せば、インスタンスの角度は回転しつつ、クリックした座標が動かないということです(図003)。

図003■回転した後クリック座標の位置を戻す
図003
クリック座標を記録
図003
インスタンスを基準点で回転
図003
クリック座標の位置を戻す

前掲コード001に以上の修正を加えたのが、以下のコード002です。インスタンスをクリックするたびに、その座標を中心にして角度が回ります。

コード002■インスタンスのクリックした座標を中心にして回す
  1. <script src="easeljs/utils/UID.js"></script>
  2. <script src="easeljs/events/MouseEvent.js"></script>
  3. <script src="easeljs/geom/Point.js"></script>
  4. <script src="easeljs/geom/Matrix2D.js"></script>
  5. <script src="easeljs/display/DisplayObject.js"></script>
  6. <script src="easeljs/display/Container.js"></script>
  7. <script src="easeljs/display/Stage.js"></script>
  8. <script src="easeljs/display/Bitmap.js"></script>
  9. <script type="text/javascript">
  10.   var stage;
  11.   var myBitmap;
  12.   function xInitialize() {
  13.     var canvasObject = document.getElementById('myCanvas');
  14.     stage = new Stage(canvasObject);
  15.     xDraw(canvasObject.width / 2, canvasObject.height / 2);
  16.   }
  17.   function xDraw(nX, nY) {
  18.     myBitmap = new Bitmap("images/Pen.png");
  19.     myBitmap.x = nX - myBitmap.image.width / 2;
  20.     myBitmap.y = nY - myBitmap.image.height / 2;
  21.     myBitmap.onClick = clickHandler;
  22.     stage.addChild(myBitmap);
  23.     stage.update();
  24.   }
  25.   function clickHandler(eventObject) {
  26.     var mouseX = eventObject.stageX;
  27.     var mouseY = eventObject.stageY;
  28.     var mousePoint = this.globalToLocal(mouseX, mouseY);
  29.     this.rotation += 15;
  30.     var offsetPoint = this.localToGlobal(mousePoint.x, mousePoint.y);
  31.     this.x += mouseX - offsetPoint.x;
  32.     this.y += mouseY - offsetPoint.y;
  33.     stage.update();
  34.   }
  35. </script>

03 インスタンスをクリックした座標で回しながらドラッグする
もう少しバリエーションをつけます。インスタンスを回しながらドラッグできるようにしましょう。前掲コード002に、以下のような手を加えます。でき上がりのJavaScriptは後にコード003として掲げますので、各ステートメント頭の番号はその行を示します。

  1. var mousePoint;
  1. function xDraw(nX, nY) {
      // myBitmap.onClick = clickHandler;
  1.   myBitmap.onPress = clickHandler;
  1. }
  2. function clickHandler(eventObject) {
  3.   var mouseX = eventObject.stageX;
  4.   var mouseY = eventObject.stageY;
      // var mousePoint = this.globalToLocal(mouseX, mouseY);
  5.   mousePoint = this.globalToLocal(mouseX, mouseY);
  6.   eventObject.onMouseMove = mouseMoveHandler;
  7.   eventObject.onMouseUp = mouseUpHandler;
  8.   eventObject.instance = this;
      /*
      this.rotation += 15;
      var offsetPoint = this.localToGlobal(mousePoint.x, mousePoint.y);
      this.x += mouseX - offsetPoint.x;
      this.y += mouseY - offsetPoint.y;
      stage.update();
      */
  9. }
  10. function mouseMoveHandler(eventObject) {
  11.   var instance = this.instance;
  12.   var mouseX = eventObject.stageX;
  13.   var mouseY = eventObject.stageY;
  14.   instance.rotation += 15;
  15.   var offsetPoint = instance.localToGlobal(mousePoint.x, mousePoint.y);
  16.   instance.x += mouseX - offsetPoint.x;
  17.   instance.y += mouseY - offsetPoint.y;
  18.   stage.update();
  19. }
  20. function mouseUpHandler(eventObject) {
  21.   this.onMouseMove = this.onMouseUp = null;
  22. }

ドラッグの始まりはBitmapインスタンスの上でマウスボタンを押したときですので、ハンドラの関数(clickHandler())はDisplayObject.onPressイベントに加えます(コード003第13行目)。ドラッグのアニメーションはMouseEvent.onMouseMove、ドラッグの終了はMouseEvent.onMouseUpイベントにハンドラの関数(mouseMoveHandler()とmouseUpHandler())として定めます(第21〜22行目)。

気をつけなければならないのは、MouseEvent.onMouseMoveイベントのハンドラがMouseEventオブジェクトに加えられることです。そのため、ドラッグするBitmapインスタンスの参照(this)を、MouseEventオブジェクトに変数(instance)として与えています(コード003第23行目)。詳しくは、前出「EaselJSのマウスクリックとドラッグ&ドロップ」をお読みください。

マウスポインタの現行座標を調べ、Bitmapインスタンスを回転してから、クリック座標のずれを直す処理は、MouseEvent.onMouseMoveイベントのハンドラ(mouseMoveHandler())で行います(コード003第27〜32行目)。初めにインスタンスをクリックした位置はDisplayObject.onPressイベントで捉えますので、その座標を納めたPointオブジェクト(mousePoint)はローカル変数でなく、グローバル変数として宣言しました(第3行目)。

コード003■インスタンスを初めにクリックした座標で回しながらドラッグする
  1. var stage;
  2. var myBitmap;
  3. var mousePoint;
  4. function xInitialize() {
  5.   var canvasObject = document.getElementById('myCanvas');
  6.   stage = new Stage(canvasObject);
  7.   xDraw(canvasObject.width / 2, canvasObject.height / 2);
  8. }
  9. function xDraw(nX, nY) {
  10.   myBitmap = new Bitmap("images/Pen.png");
  11.   myBitmap.x = nX - myBitmap.image.width / 2;
  12.   myBitmap.y = nY - myBitmap.image.height / 2;
  13.   myBitmap.onPress = clickHandler;
  14.   stage.addChild(myBitmap);
  15.   stage.update();
  16. }
  17. function clickHandler(eventObject) {
  18.   var mouseX = eventObject.stageX;
  19.   var mouseY = eventObject.stageY;
  20.   mousePoint = this.globalToLocal(mouseX, mouseY);
  21.   eventObject.onMouseMove = mouseMoveHandler;
  22.   eventObject.onMouseUp = mouseUpHandler;
  23.   eventObject.instance = this;
  24. }
  25. function mouseMoveHandler(eventObject) {
  26.   var instance = this.instance;
  27.   var mouseX = eventObject.stageX;
  28.   var mouseY = eventObject.stageY;
  29.   instance.rotation += 15;
  30.   var offsetPoint = instance.localToGlobal(mousePoint.x, mousePoint.y);
  31.   instance.x += mouseX - offsetPoint.x;
  32.   instance.y += mouseY - offsetPoint.y;
  33.   stage.update();
  34. }
  35. function mouseUpHandler(eventObject) {
  36.   this.onMouseMove = this.onMouseUp = null;
  37. }

これでBitmapインスタンスは、初めにマウスボタンを押された座標で回りながら移動します(図004)。ただし、回転とドラッグのアニメーションは、MouseEvent.onMouseMoveイベントのハンドラ(mouseMoveHandler())に定めましたので、マウスボタンを押していてもポインタを動かさなければインスタンスは回りません。

図004■インスタンスがマウスボタンを押した座標で回りながら移動する
図004


作成者: 野中文雄
作成日: 2012年5月1日


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