Flashを使わずに、スマートフォン向けサイトでアニメーションを実装する際、いくつか選択肢があると思います。
その中でもCreateJSを使った際に、いくつか気を付けなければいけないポイントがあったので、まとめました。
気をつけるポイント
- 最新のCreateJSを使う
- タッチ操作に反応させる
- CSSのtransformを使ってcanvasを縮小させると、Android4.x系のデフォルトブラウザで表示がおかしくなる
- canvasが画面サイズより大きいと、CSSで
overflow:hidden
などとしても余計な余白が生成されてしまうので、JSで動的にサイズを設定してあげる - 一部のAndroid4.x系のデフォルトブラウザで、PreloadJSのcompleteイベントが2回コールされる
最新のCreateJSを使う
通信負荷を分散させるために、CDN (Content Delivery Network) でホスティングされているCreateJSを使います。
バージョン情報は下記サイトで確認します。
以下のように、EaselJS, TweenJS, SoundJS, PreloadJSを一括で読み込める記述方法もあります。
<head>
<script src="http://code.createjs.com/createjs-2013.09.25.min.js"></script>
</head>
タッチ操作に反応させる
CreateJSのイベント処理は、PCでのイベントがベースになっています。(mousedownやclickなど)
clickイベントなどは、何もしなくてもタッチ操作に反応してくれますが、mousedownなどは反応してくれません。mousedownなどをタッチ操作に反応させるには、ステージ生成後に下記処理を行います。
<body>
<canvas id="canvas" width=320 height=320></canvas>
</body>
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);
createjs.Touch.enable(stage);
CSSのtransformを使ってcanvasを縮小させない
画像をcanvas上に描画する際、解像度の高いスマートフォンでより綺麗に見せるために、倍のサイズで描画したものを縮小して表示させる方法が有効です。
例えば以下のように、CSSのtransformを使って実現する方法があります。この方法だと、画像を描画する座標などもそのままスケールしてくれるため、簡単に調整出来ます。
#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ではなく描画する画像を、以下のように縮小して使うことで、解像度の高いスマートフォンで画像を綺麗に見せることが出来ます。
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サイズを合わせる方法です。
var canvas = document.getElementById("canvas");
var stage = new createjs.Stage(canvas);
stage.canvas.width = window.innerWidth;
stage.canvas.height = window.innerHeight;
以下は、例えば640x320のcanvasに描画したものを、画面中央に表示してはみ出た部分は切り捨てる、というようなことをしてます。
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;
}
#canvas {
position: absolute;
left: 50%;
}
stage.x = -(650 - windowWidth) / 2;
としているのは、切り捨てた部分の領域分、canvas上の描画位置をずらしています。
PreloadJSのcompleteイベント
CreateJSには画像や音声といったアセットファイルを簡単にプリロードしてくれる、PreloadJSというライブラリがあります。
例えば、画像ファイルを読み込んでcanvasに表示するようなサンプルコードは、以下のようになります。
公式のドキュメントも、だいたい同じです。
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では起きません。
個人的にはあまり気持ちのよい解決策ではなかったのですが、以下とすることで解決出来ました。
function handleComplete() {
loader.removeEventListener("fileload", handleFileLoad);
loader.removeEventListener("complete", handleComplete);
// 何かしらの処理
...
}
まとめ
スマートフォンでCreateJSを使ってアニメーションを実装する際、chromeやsafariなどはPC版とほぼ同じような挙動をしてくれました。Android2.3系のデフォルトブラウザも、パフォーマンスはかなり落ちますが、挙動はまあまあ安定してます。
しかしAndroid4.x系のデフォルトブラウザは別です。とてもユニークな挙動をしてくれますので、特に念入りな動作確認が必須だと思いました。
この記事で触れたこと以外にも、以下のような記事もあります。
CreateJS x Android でハマったこと