Help us understand the problem. What is going on with this article?

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)

nekoneko-wanwan
Webデザイン、フロントエンド開発を主にやっています。真面目なものから、変なものまで。色々な記事を投稿していければと思います。
hotstartupinc
「ペライチ」を開発する会社です。
https://peraichi.com/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした