JavaScriptによるアニメーション

HTMLとJavaScript を使ったシンプルなアニメーションの例を紹介します。具体的には画面上でボールが跳ねるプログラムです。

サンプルアプリの動作:ボールが枠の中で跳ねるアニメ

このプログラムは、おおまかに以下の部分に分けることができます。

HTMLとCSS、JavaScript(キャンバスを準備する、ボールの最初の状態を決める、円を描く関数drawBall()の定義、関数animate()の定義、そして呼び出し)です。

アプリとソースコードのインポート

以下のボタンをクリックすると、Monaca Educationにプロジェクトをインポートできます。

Monaca Educationにインポートする(要ログイン)

HTMLとCSS

HTMLファイルindex.htmlでは、タグ<canvas>を使って、アニメーションを表示するためのエリア(キャンバス)を定義しています。

キャンバス要素には”myCanvas” というIDが付けてあり、JavaScriptからこのキャンバスを操作するために使用できます。以下はindex.htmlの中の、タグ<body>の内容です。

…
<body>
    <canvas id="myCanvas" width="320" height="320"></canvas>
</body>
…

CSSファイル(フォルダcssの中のstyle.css)では、キャンバスの背景色を灰色に設定し、ページの中央に配置しています。

canvas { 
    background: #eee; 
    display: block; 
    margin: 0 auto; 
}

JavaScript

JavaScriptファイルmain.js(※フォルダjsにあります)に、プログラムの本体があります。60行あまりのプログラムです。

5つに分けて説明します。

(1)キャンバスの準備をする

最初の部分では、キャンバスとその描画コンテキストを設定しています。

var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');

ここで言う「描画コンテキスト」は、画家が使うキャンバスと絵の具、または学校の黒板とチョークの関係にたとえることができます。

キャンバスは絵を描く先(背景やスペース)です。HTMLのキャンバスも、絵を描く先です。

一方、描画コンテキスト(※getContext(‘2d’) で取得されるオブジェクト。変数ctxに代入されている)は、そのキャンバス上に絵を描くためのツールや色(絵の具やチョーク)を表します。

つまり、ここで、プログラムの中で絵を描く先と、絵を描く道具を準備したわけです。プログラムの続きの部分で、描画コンテキスト(ctx)を使って、キャンバス上に図形を描いていきます。

(2)ボールの最初の状態を決める

続いて、ボールの初期位置(x, y)、ボールの動き(dx, dy)、そしてボールの半径(ballRadius)を定義しています。これらの変数はボールを画面上で動かすために使います。

var x = canvas.width / 2;
var y = canvas.height - 30;
var dx = 2;
var dy = -2;
var ballRadius = 10;

ボールの初期位置(x, y)は、ボールの中心の座標です。

なお、HTMLキャンバスでは、座標の原点(0, 0)は、キャンバスの左上の端にあります。キャンバスの一番上のY座標の値は0、一番下のY座標の値は「キャンバスの高さ」と同じになります。

キャンバスの幅を2で割ると、左右中央が分かります。

キャンバスの高さを2で割ると、上下中央が分かります。例のプログラムでは、画面の高さ-30としてありますから、キャンバスの高さから30引いた値になり、画面の一番下から少し(30だけ)画面中央寄りの位置になります。

ボールの動きの値は、横軸(X)方向と、縦軸(Y)方向の2つに分けて用意されています。

Xの値が正の値なら、ボールは画面右の方に移動していきます。負の値なら、画面左方向です。

Yの値が正の値なら、ボールは画面下の方に移動していきます。負の値なら、画面上方向です。

(3)円を描く関数drawBall()の定義

drawBall 関数では、キャンバス上にボールを描いています。

function drawBall() {
  ctx.beginPath();
  ctx.arc(x, y, ballRadius, 0, Math.PI*2);
  ctx.fillStyle = "#0095DD";
  ctx.fill();
  ctx.closePath();
}

ctx.beginPath() と ctx.closePath() で描画の開始と終了を示します。その間に描きたい図形のための処理を書きます。

ctx.arc() を使って円を描いています。円は (x, y) の位置に描かれ、ballRadius でサイズ(半径)が指定されています。ctx.fillStyle でボールの色を設定し、ctx.fill() でその色でボールを塗りつぶしています。

(4)関数animate()の定義

関数animate()では、アニメーションの手順が実装されています。

function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  drawBall();
  if(x + dx > canvas.width-ballRadius || x + dx < ballRadius) {
    dx = -dx; 
  }
  if(y + dy > canvas.height-ballRadius || y + dy < ballRadius) {
    dy = -dy;
  }

  x += dx;
  y += dy;
  requestAnimationFrame(animate);
}

まず、ctx.clearRect() を使ってキャンバスをきれいにしています。これは初めて関数animate()が実行されるときはあまり意味がある動作ではありません。2回目以降に、「前回描いた絵を消す」という意味のある動作になります。

次に、関数drawBall()を呼び出してボールを描きます。

その後、ボールがキャンバスの端に達したかどうかをチェックし、端に達していればボールの移動方向を反転させます。符号の+、ーを入れ替えると、キャンバス上を移動する方向が逆になります(dx = -dx、dy = -dy)。

最後に、ボールの位置を更新し、requestAnimationFrame(animate) を呼び出して、次のフレーム(=次の瞬間の画面表示)で、再びこの関数(animate)が呼ばれるようにします。

以上により、ボールが動いているように見えるアニメーションが実現されます。

(5)処理を始める

ここまでのJavaScriptファイルでは、変数に値を代入し、関数を定義してきました。ここまででは、まだ、アニメーション動作を開始していません。
JavaScriptファイルの最後の、animate();で、関数animate()を呼び出し、関数の定義に従って動作が起きて、アニメーションになります。

animate();

プログラムの記述の順序と、実行の順序

JavaScriptファイルmain.jsに書いてある順序と、実際に処理が実行されるときの実行順序は異なります。次に概念図を示します。

水色の番号の順に実行されていきます。

最後の行のanimate();が、関数animate()を呼び出し、関数animate()の中からrequestAnimationFrame()が呼び出され、以後animate() -> requestAnimationFrame() -> animate() … という無限に続く繰り返しが実行されることになります。