2013/06/21更新

[JS] アニメーションを行うのに、setTimeoutよりもrequestAnimationFrameを使ってみよう

このエントリーをはてなブックマークに追加            

こんにちは、@yoheiMuneです。
JavaScriptを用いてアニメーションを行う際に、setTimeoutやsetIntervalを使ってアニメーションループを実装することが多いと思いますが、 最近使えるようになってきたrequestAnimationFrameを使うと、よりいい感じにアニメーションを行うことが出来ます。
今日は、requestAnimationFrameという機能についてブログを書きたいと思います。

画像


requestAnimationFrameとは

requestAnimationFrameとは、setTimeoutと似たような機能で、ブラウザの次の描画の際に実行したい関数を指定することで、 ブラウザが次回描画時に呼び出してくれる機能です。
以下のように使うことが出来ます。
winodow.requestAnimationFrame(function() {
  // アニメーションで実行したい処理
});

// setTimeoutの場合はこんな感じで使うかと思います。
setTimeout(function() {
  // アニメーションで実行したい処理
}, 50);
上記2つのコードで大きく違うところは、次回呼び出しをいつ行うかを指定できるか否かです。 setTimeoutでは第2引数にミリ秒単位で次回呼び出し時間を指定できますが、requestAnimationFrameでは指定できず、次回呼び出しはブラウザに依存します。

「それ困るんじゃない?」と感じるかと思いますが、ブラウザの実行速度を意識したfpsの設定をわざわざしなくて良いという点で便利です。 例えば実行速度が速い環境ではfpsを60に、遅い場合にはfpsを12にしたいといった実装をsetTimeoutでは行う必要がありますが、requestAnimationFrameでは行う必要がありません。ブラウザ任せです。

またrequestAnimationFrameを使うと、アニメーションが滑らかになります。setTimeoutでアニメーションする際には、プログラムが指定したFPSでアニメーションしようとしますが、そのFPSがブラウザのFPSと合っていないことも多く、アニメーションが飛んだり角付いたりする原因となっています。
requestAnimationFrameでは、アニメーションのFPSとブラウザのFPSが一致するので、滑らかなアニメーションになります。


requestAnimationFrameは非アクティブウインドウでは手を抜く

requestAnimationFrameは、対象ウインドウが非活性時(違うタブを開いているとか)の場合には、処理が間引かれたり止まったりして、PCのCPUに負荷を掛けないようになってい(るようです)ます。setTimeoutだと非活性時にも動いちゃってPCに負荷を掛けるので、この動きは良いですね。



requestAnimationFrameの実装状況

Webで便利なものは、各ブラウザの実装状況が気になります。「Can i use」サイトによると、以下のような実装状況のようです。
画像 http://caniuse.com/#search=requestAnimation

Androidは全滅、IEは10から、iOS/Chrome/Firefoxはいい感じに使えるって所でしょうか。 サポート状況がまばらですので、setTimeoutとの使い分けが必要です。以下ではsetTimeoutとの使い分ける実装方法を記載しました。



requestAnimationFrameを使える場合には、setTimeoutよりも優先して使う

requestAnimationFrameとsetTimeoutは、メソッドシグニチャや使い方が近しいので、使い分けが簡単です。 以下のように実装することで、使い分けをすることが出来ます。
// アニメーションループに使うメソッドを決める
var animationFrame
   = window.requestAnimationFrame
     || window.webkitRequestAnimationFrame
     || window.mozRequestAnimationFrame
     || window.setTimeout;

// アニメーションを行うメソッドを定義する。
var animation = function() {
  
  // 描画する
  draw();

  // 次描画の計算を行う
  calc();

  // 次呼び出しを予約する
  // 第2引数は、setTimeoutの場合のみ使われる
  animationFrame(animation, 1000 / 24);
};

// アニメーションを行う
animation();
requestAnimationFrameはベンダープレフィックス付きの場合もあるので、色々と試しながらanimationFrame変数に代入します。 その後は、setTimeoutを使うのと同じように、アニメーションを実装します。
こんな感じで、requestAnimationFrameとsetTimeoutを使い分けることが出来ます。



参考資料

requestAnimationFrameについては、以下のサイトの情報が役立ちました。

- window.requestAnimationFrame - Web API リファレンス | MDN
- W3C Timing control for script-based animations
- Timing control for script-based animations ("requestAnimationFrame") (Windows)



最後に

Web世界は便利なものがドンドン出てきますね。新しいことを学ぶのは楽しい限りです。
今後も面白い技術がありましたら、このブログで紹介出来ればと思います。

最後までご覧頂きましてありがとうございました。





こんな記事もいかがですか?

RSS画像

もしご興味をお持ち頂けましたら、ぜひRSSへの登録をお願い致します。