CreateJSでスマートフォン向けサイトのアニメーションを実装するときに気をつけるポイント


Flashを使わずに、スマートフォン向けサイトでアニメーションを実装する際、いくつか選択肢があると思います。
その中でもCreateJSを使った際に、いくつか気を付けなければいけないポイントがあったので、まとめました。

## 気をつけるポイント

* 最新のCreateJSを使う
* タッチ操作に反応させる
* CSSのtransformを使ってcanvasを縮小させると、Android4.x系のデフォルトブラウザで表示がおかしくなる
* canvasが画面サイズより大きいと、CSSで `overflow:hidden` などとしても余計な余白が生成されてしまうので、JSで動的にサイズを設定してあげる
* 一部のAndroid4.x系のデフォルトブラウザで、PreloadJSのcompleteイベントが2回コールされる

## 最新のCreateJSを使う

通信負荷を分散させるために、CDN (Content Delivery Network) でホスティングされているCreateJSを使います。
バージョン情報は下記サイトで確認します。

[CreateJS CDN Libraries](http://code.createjs.com/)

以下のように、EaselJS, TweenJS, SoundJS, PreloadJSを一括で読み込める記述方法もあります。

```html:HTML
<head>
<script src="http://code.createjs.com/createjs-2013.09.25.min.js"></script>
</head>
```

## タッチ操作に反応させる

CreateJSのイベント処理は、PCでのイベントがベースになっています。（mousedownやclickなど）
clickイベントなどは、何もしなくてもタッチ操作に反応してくれますが、mousedownなどは反応してくれません。mousedownなどをタッチ操作に反応させるには、ステージ生成後に下記処理を行います。

```html:HTML
<body>
    <canvas id="canvas" width=320 height=320></canvas>
</body>
```

```javascript:JavaScript
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);
createjs.Touch.enable(stage);
```

## CSSのtransformを使ってcanvasを縮小させない

画像をcanvas上に描画する際、解像度の高いスマートフォンでより綺麗に見せるために、倍のサイズで描画したものを縮小して表示させる方法が有効です。
例えば以下のように、CSSのtransformを使って実現する方法があります。この方法だと、画像を描画する座標などもそのままスケールしてくれるため、簡単に調整出来ます。

```css:CSS
#canvas {
		-webkit-transform: scale(0.5, 0.5);
		   -moz-transform: scale(0.5, 0.5);
		    -ms-transform: scale(0.5, 0.5);
		     -o-transform: scale(0.5, 0.5);
		        transform: scale(0.5, 0.5);
}
```

ところが、 **Android4.x系のデフォルトブラウザで上記canvasを表示させると、縮小前と縮小後の両方の画像が一緒に描画されてしまいます。** （chromeやsafariは問題ありません。）

解決策として、canvasではなく描画する画像を、以下のように縮小して使うことで、解像度の高いスマートフォンで画像を綺麗に見せることが出来ます。

```javascript:JavaScript
var bitmap = new createjs.Bitmap("img/xxx.png");
bitmap.setTransform(0, 0, 0.5, 0.5);
stage.addChild(bitmap);
```

## canvasサイズはJSで動的に設定してあげる

画面サイズが大きいスマートフォンに合わせて、大きいサイズで設定したcanvasを、画面サイズが小さいスマートフォンでは、はみ出た部分をマスクしてしまえばいいかと考えていました。
しかし **canvasが画面サイズより大きいと、親の要素でCSSで `overflow:hidden` などとしても余計な余白が生成されてしまいました。** 他にもいろいろとCSSで解決しようとしたのですが、よい方法が見つかりませんでした。

結局、画面サイズより大きいcanvasがそもそもの原因なので、JSで動的にサイズを設定してあげる方法が、シンプルな解決策でした。

以下は、単純に画面サイズにcanvasサイズを合わせる方法です。

```javascript:JavaScript
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);

stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
```

以下は、例えば640x320のcanvasに描画したものを、画面中央に表示してはみ出た部分は切り捨てる、というようなことをしてます。

```javascript:JavaScript
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;

if (windowWidth < 640) {
    $('#canvas').css({"margin-left":-windowWidth/2+"px"});
    stage.canvas.width = windowWidth;
    stage.x = -(640 - windowWidth) / 2;
} else {
    $('#canvas').css({"margin-left":-640/2+"px"});
    stage.canvas.width = 640;
}
```

```css:CSS
#canvas {
    position: absolute;
    left: 50%;
}
```

`stage.x = -(650 - windowWidth) / 2;` としているのは、切り捨てた部分の領域分、canvas上の描画位置をずらしています。

## PreloadJSのcompleteイベント

CreateJSには画像や音声といったアセットファイルを簡単にプリロードしてくれる、PreloadJSというライブラリがあります。
例えば、画像ファイルを読み込んでcanvasに表示するようなサンプルコードは、以下のようになります。
[公式のドキュメント](http://www.createjs.com/Docs/PreloadJS/classes/LoadQueue.html)も、だいたい同じです。

```javascript:JavaScript
var manifest = [{src:"img/xxx.png", id:"image"}];

var loader = new createjs.LoadQueue(false);
loader.addEventListener("fileload", handleFileLoad);
loader.addEventListener("complete", handleComplete);
loader.loadManifest(manifest);

function handleFileLoad(event) {
    var type = event.item.type;  // 読み込んだファイルのタイプ
    var data = event.result;     // 読み込んだデータ
}

function handleComplete() {
    // 何かしらの処理
    ...
}
```

fileloadイベントはファイルを読み込む度に発生し、completeイベントは全てのファイルを読み込んだ後に発生します。
ところが **一部のAndroid4.x系のデフォルトブラウザで、PreloadJSのcompleteイベントが2回コールされていました。** このケースでも、chromeやsafariでは起きません。

個人的にはあまり気持ちのよい解決策ではなかったのですが、以下とすることで解決出来ました。

```javascript:JavaScript
function handleComplete() {
    loader.removeEventListener("fileload", handleFileLoad);
    loader.removeEventListener("complete", handleComplete);
    
    // 何かしらの処理
    ...
}
```

## まとめ

スマートフォンでCreateJSを使ってアニメーションを実装する際、chromeやsafariなどはPC版とほぼ同じような挙動をしてくれました。Android2.3系のデフォルトブラウザも、パフォーマンスはかなり落ちますが、挙動はまあまあ安定してます。
しかしAndroid4.x系のデフォルトブラウザは別です。とてもユニークな挙動をしてくれますので、特に念入りな動作確認が必須だと思いました。

この記事で触れたこと以外にも、以下のような記事もあります。
[CreateJS x Android でハマったこと](http://qiita.com/calmbooks/items/6df5e01a7a29417e55c6)