Animate CC 2018のカメラをJavaScriptで操作する

Adobe Animate CC 2018はカメラがスクリプトで操作できるようになりました。基本的なズームとパン(移動)を使った作例でご紹介します。jsdo.itに掲げたサンプル001は、カメラがマウスポインタの動きに応じてパンし、水平ドラッグでズームします。

###サンプル001■Controlling camera in Animate CC 2018
[![1710003_003.png](https://qiita-image-store.s3.amazonaws.com/0/128949/48267e0b-9b3d-3422-b8e1-5b2e29313482.png)
\>\> jsdo.itへ](http://jsdo.it/FumioNonaka/CbDU)

#カメラとレイヤー深度を設定する
Animate CC 2018のHTML5 Canvasドキュメントでカメラを操作するには、タイムラインで[カメラを追加]しなければなりません(図001)。また、遠近の視差を表現しないとつまらないでしょう。そのためには、高度なレイヤーでレイヤー深度を調整してください(「[高度なレイヤーを使用したレイヤー深度の作成](https://helpx.adobe.com/jp/animate/using/timeline-layers.html#advanced-layers)」および「[高度なレイヤーとレイヤー深度](https://www.lynda.jp/lessons/42682)」参照)。

####図001■カメラを追加して高度なレイヤーはオンにする
![1710003_001.png](https://qiita-image-store.s3.amazonaws.com/0/128949/6f3d594a-6284-b149-9426-78ca0fcbff95.png)


#カメラを取得する
カメラを操作するには、カメラのオブジェクトを取得しなければなりません。そのためのメソッドが`AdobeAn.VirtualCamera.getCamera()`です。引数にはメインタイムライン(exportRoot)を渡します。

```js
var camera = AdobeAn.VirtualCamera.getCamera(exportRoot);
```

カメラをコントロールするためのAPIは、「[実行時のインタラクティブカメラの使用](https://helpx.adobe.com/jp/animate/using/working-with-camera-in-animate-cc.html#runtime-camera)」をご参照ください。また、[コードスニペット]に[カメラ]のコードが加わりましたので、そちらを参考にしてもよいでしょう(図002)。

####図002■[コードスニペット]パネルの[カメラ]の項目(HTML5 Canvas)
![1710003_002.png](https://qiita-image-store.s3.amazonaws.com/0/128949/5f9c8105-6247-4a27-a3fc-de03a318b8ba.png)


#カメラのズームを操作する
カメラのズームは、メソッド`getZoom()`と`setZoom()`によりそれぞれパーセンテージで取得・設定します。

```js
// ズームのパーセンテージを得る
var zoom = camera.getZoom();
// ズームのパーセンテージを定める
camera.setZoom(zoom);
```

ステージ上の水平ドラッグでズームイン/ズームアウトさせるのがつぎのコードです。[`Stage.stagemousedown`イベント](https://createjs.com/docs/easeljs/classes/Stage.html#event_stagemousedown)でドラッグ開始の座標(mouseDown)を得て、ドラッグの[`DisplayObject.pressmove`イベント](https://createjs.com/docs/easeljs/classes/DisplayObject.html#event_pressmove)によりカメラのズームを変えています。

```js
var mouseDown = new createjs.Point();

stage.addEventListener('stagemousedown', function(event) {
	mouseDown.x = event.stageX;
	mouseDown.y = event.stageY;
});
stage.addEventListener('pressmove', function(event) {
	var zoom = camera.getZoom() + (event.stageX - mouseDown.x) * 0.02;
	if (100 < zoom && zoom < 250) {
		camera.setZoom(zoom);
	}
});
```

#カメラの位置を操作する
カメラの位置は、メソッド`getPosition()`と`setPosition()`でそれぞれ取得・設定します。`getPosition()`メソッドの戻り値は、`x`と`y`および`z`のプロパティをもったオブジェクトです。`setPosition()`メソッドには、座標値を3つの引数として渡します。

```js
// カメラの位置を得る
var position = camera.getPosition();
// カメラの位置を定める
camera.setPosition(x, y, z);
```

つぎのコードは、マウスポインタがステージ中央から上下左右どちらにあるかによって、カメラの位置を動かします。アニメーションは[`Ticker.tick`イベント](https://createjs.com/docs/easeljs/classes/Ticker.html#event_tick)のリスナー関数で扱います。そうすると、マウスポインタの座標が取れませんので、[`Stage.stagemousemove`イベント](https://createjs.com/docs/easeljs/classes/Stage.html#event_stagemousemove)で座標を変数に納めました。なお、ステージ(Canvas)の大きさを調べるとき注意すべきことについて、「[HTML5 Canvasで書き出したCanvasの大きさが倍になる](http://www.fumiononaka.com/TechNotes/Flash/FN1702004.html)」をご参照ください。

```js
var stageCenter = new createjs.Point(
	canvas.width / stage.scaleX / 2,
	canvas.height / stage.scaleY / 2
);
var mouseMove = new createjs.Point();
var mouseDown = new createjs.Point();
stage.addEventListener('stagemousemove', function(event) {
	mouseMove.x = event.stageX;
	mouseMove.y = event.stageY;
});
createjs.Ticker.addEventListener('tick', function(event) {
	var position = camera.getPosition();
	var positionX = (mouseMove.x > stageCenter.x) ? position.x - 1 : position.x + 1;
	var positionY = (mouseMove.y > stageCenter.y) ? position.y - 1 : position.y + 1;
	if (-90 < positionX && positionX < 90) {
		position.x = positionX;
	}
	if (-40 < positionY && positionY < 0) {
		position.y = positionY;
	}
	camera.setPosition(position.x, position.y, position.z);
});
```

ここでひとつ、ECMAScript 6の新しい`Math`クラスのメソッドをご紹介します。引数の符号(sign)つまり正か負か0かを、それぞれ+1、-1、0で返す[`Math.sign()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Math/sign)です。このメソッドを使うと、上記コードでカメラの動く方向を決める条件(3項)演算子の式が、つぎのように書き替えられます。

```js
// var positionX = (mouseMove.x > stageCenter.x) ? position.x - 1 : position.x + 1;
// var positionY = (mouseMove.y > stageCenter.y) ? position.y - 1 : position.y + 1;
var positionX = position.x + Math.sign(stageCenter.x - mouseMove.x);
var positionY = position.y + Math.sign(stageCenter.y - mouseMove.y);
```

以上のスクリプトをまとめたのが、つぎのコード001です。冒頭のサンプル001は、FLAファイルのメインタイムラインにこのコードを書いてパブリッシュしました。

####コード001■カメラをマウスポインタの移動でパン/ドラッグでズームする
```js
var camera = AdobeAn.VirtualCamera.getCamera(exportRoot);
var stageCenter = new createjs.Point(
	canvas.width / stage.scaleX / 2,
	canvas.height / stage.scaleY / 2
);
var mouseMove = new createjs.Point();
var mouseDown = new createjs.Point();
stage.addEventListener('stagemousemove', function(event) {
	mouseMove.x = event.stageX;
	mouseMove.y = event.stageY;
});
createjs.Ticker.addEventListener('tick', function(event) {
	var position = camera.getPosition();
	var positionX = position.x + Math.sign(stageCenter.x - mouseMove.x);
	var positionY = position.y + Math.sign(stageCenter.y - mouseMove.y);
	if (-90 < positionX && positionX < 90) {
		position.x = positionX;
	}
	if (-40 < positionY && positionY < 0) {
		position.y = positionY;
	}
	camera.setPosition(position.x, position.y, position.z);
});
stage.addEventListener('stagemousedown', function(event) {
	mouseDown.x = event.stageX;
	mouseDown.y = event.stageY;
});
stage.addEventListener('pressmove', function(event) {
	var zoom = camera.getZoom() + (event.stageX - mouseDown.x) * 0.02;
	if (100 < zoom && zoom < 250) {
		camera.setZoom(zoom);
	}
});
```

[追記: 2017年10月29日]「[カメラの位置を操作する](https://qiita.com/FumioNonaka/items/33d4515a82f590e67045#%E3%82%AB%E3%83%A1%E3%83%A9%E3%81%AE%E4%BD%8D%E7%BD%AE%E3%82%92%E6%93%8D%E4%BD%9C%E3%81%99%E3%82%8B)」に、`Math.sign()`メソッドによるコードの書き替えを追加。