Canvasでアニメーションの巻。
Canvasアニメーションのライフサイクル
描画をクリア(clearRect) -> アニメーション計算 -> 描画、を繰返します。
CanvasはFlashのように変更になったものだけを描画する機能は無く、毎回全て再描画を行わないといけません。
再描画前にクリアしておかないと追加で描画され位置が変わったものは重なってしまいます。
ライフサイクルを維持するために定期的に関数を実行させないといけません。
JavaScriptでそのような目的に使える関数は1つだけです。
追記しました、requestAnimationFrame
と言う名の関数が HTML5 Working Draft にありました。
setInterval
setInterval(callback:Function, delay:int(ms))
*setTimeout
でも同じように作ることは可能ですが、効率などの点からもdelayなどで1回しか時間管理が必要な時だけに使用を限定すべきです。
HTML
<canvas id='canvas'></canvas> |
JavaScript
var canvas = document.getElementById('canvas'); var context = canvas.getContext('2d'); context.fillStyle = "#ff0000"; var speed=20, pos={x:20,y:20}, angle=35, radians=0, moveX=0, moveY=0, ball={x:pos.x,y:pos.y}, PI2=Math.PI / 180; function loop () { context.clearRect(0,0,canvas.width,canvas.height); ball.x += moveX; ball.y += moveY; context.beginPath(); context.arc(ball.x,ball.y,15,0,Math.PI*2,true); context.closePath(); context.fill(); if (ball.x > canvas.width || ball.x < 0) { angle = 180 - angle; if (ball.x < 0) { ball.x = 0; } else { ball.x = canvas.width; }; } else if (ball.y > canvas.height || ball.y < 0) { angle = 360 - angle; if (ball.y < 0) { ball.y = 0; } else { ball.y = canvas.height; }; }; radians = angle * PI2; moveX = Math.cos(radians) * speed; moveY = Math.sin(radians) * speed; }; setInterval(loop,33); |
ボールがキャンバスの中をバウンドします。
動きはリニア(加減速しない)です。
Flashって良くできてる
こうやってCanvasでアニメーションさせてみるとFlashが良くできていることをあらためて痛感させられます。
レイヤー機能があるので重なり順を変えたりすることが簡単に実現できます。
オブジェクト(DisplayObject)それぞれにMatrixプロパティがあるので、それぞれのMatrixを操作できます。
CanvasはMatrixが1つしか無いので複数のものを動かす時はかなりめんどくさい。
enterFrame, exitFrameが無いので自前で仕組みを作らないといけない。
しかも毎回(毎フレームごと)画面をクリアして全画面を再描画しないといけない、この負荷はどれくらいなんだろう?
FlashはPlugin, ActiveXのFlash Playerが描画だけどCanvasはブラウザが直接レンダリングするのでこの点はCanvasの方が有利に働くかも。
update 2012-05-07
よく調べてみると requestAnimationFrame
てのがあった。
http://www.w3.org/TR/2012/WD-animation-timing-20120221/
Working Draftなんで採用される率高いよね。
で、caniuse.comで調べてみたら…
http://caniuse.com/#search=requestAnimationFrame
現状で使うのは厳しそう。
window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame |
使うならこうやって調べておいて、どれにも該当しないときは setTimeout
で代用するのが良さそう。
setIntervalだとコードの置き換えがメンドいのでsetTimeoutの方が良さげでした。
update 2012-05-09
requestAnimationFrame に関して以下のようなステキなコードを知りました。
(function (w, r) { w['r'+r] = w['r'+r] || w['webkitR'+r] || w['mozR'+r] || w['msR'+r] || w['oR'+r] || function(c){ w.setTimeout(c, 1000 / 60); }; })(window, 'equestAnimationFrame'); |
これを先頭に挿入しておけばどのブラウザでもrequestAnimationFrameが使えることになります。
http://0-9.sakura.ne.jp/pub/lt/modest/start.html
この「jQueryで破棄されたrequestAnimationFrameとJSでのアニメーション実装で注意すること」でも触れられているように何も無理して使う必要はなさそうです。
もう一つ、setTimeoutでも大丈夫なんですね。
勉強になりました。
ピンバック: Canvas始めました – マウスを追っかけるアニメーション - イナヅマtvログ