Edited at

Canvasアニメーションの要点

More than 3 years have passed since last update.


はじめに

いまさらですがHTML5 Canvasの勉強をはじめました。

Canvas APIを使ったアニメーションの実装は、jQuery animate()css3 keyframesといったものとは考え方が異なります。はじめて調べた時には結構戸惑ったので、同じような方のためにメモしたいと思います。


アニメーション = 再描画

Canvasでは便利なアニメーションメソッドはなく、単純に描画自体を繰り返すことでアニメーションを実現させます。イメージとしては、パラパラまんがのように画面自体が次々と差し替わっていくようなものでしょうか。


アニメーションサンプル

canvas-anim.gif


なお↓ページで実際の動きを確認できます

http://nekoneko-wanwan.github.io/demo/canvas/animation/



Canvasアニメーションの手順

ざっくりと以下のような流れになります


  1. 要素を削除

  2. 要素を描画

  3. 要素を動かす(動かす位置座標を再定義)

  4. 終了フラグが無ければ1.へ戻る


サンプルコード


index.html

<canvas id="myCanvas" width="100" height="100"></canvas>



script.js

function drawLoopSquare() {

/* Canvas要素の定義など */
var cs = document.getElementById('myCanvas');
var ctx = cs.getContext('2d');
var w = cs.width;
var h = cs.height;
var x = 0;

/* 描画フロー */
function render() {
// Canvas全体をクリア
ctx.clearRect(0, 0, w, h);

// 要素を描画する
ctx.beginPath();
ctx.strokeRect(x, 0, 10, 10);

// 要素を動かす
// 四角形のx座標がCanvasの横幅を超えたら初期位置(x座標を0)へ
// そうでなければ、x座標を1増やす
if (x > cs.width) {
x = 0;
} else {
x += 1;
}

// このrender関数を繰り返す
// 下記どちらかを使った場合は、外側でrender()を実行する※1(もしくは即時実行)
// setTimeout(render, 100);
// requestAnimationFrame(render);
}
/* ※1 */
// render();

/* render()関数を繰り返す */
/* setTimeout、requestAnimationFrameではなく、setIntervalを使う場合 */
setInterval(render, 100);
}
drawLoopSquare();


再描画を行うためのループメソッドとして、


  • setInterval()

  • setTimeout()

  • requestAnimationFrame()

がよく使用されます。それぞれ以下のように使い分けることができます。


  • 決まった時間でループを行ないたい: setInterval(), setTimeout()

  • 描画負荷を抑えたい・なるべくヌルヌルさせたい: requestAnimationFrame()


requestAnimationFrame()について

requestAnimationFrame()は高速でCPUにやさしいですが、未対応ブラウザも存在します。

対応するためのpolyfillは以下になります。

window.requestAnimFrame = (function() {

return (
window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback, time) {
var time = time ? time: 1000 / 60;
window.setTimeout(callback, time);
}
);
})();

またrequestAnimationFrameはグローバルなため、場合によってはbindでthisを束縛してやる必要があります。

{

update: function() {
// 座標を変更する処理など
},
draw: function() {
// 要素を描画する処理など
},
render: function() {
this.update();
this.draw();
requestAnimationFrame(this.render.bind(this)); // 引数にthisを使うためにbind
}
}


おわりに

まだまだ分かっていないことばかりなので、不正確なところがあればコメントや編集リクエストをお願いします


追記: 2015年5月19日

Canvasイベントについて別途記事を書きました。

http://qiita.com/nekoneko-wanwan/items/9af7fb34d0fb7f9fc870)