JSXでrequestAnimationFrameを使う

<追記>
現在requestAnimationFrame()はJSX標準ライブラリの timer.jsx に組み込まれています。

W3Canimation-timingで定義されているrequestAnimatioFrame()を使うと、JavaScriptでアニメーションをするときに良い感じのフレームレートで実行してくれる、ということになっています。

This document defines an API web page authors can use to write script-based animations where the user agent is in control of limiting the update rate of the animation. The user agent is in a better position to determine the ideal animation rate based on whether the page is currently in a foreground or background tab, what the current load on the CPU is, and so on. Using this API should therefore result in more appropriate utilization of the CPU by the browser.

適当訳:

この文書ではスクリプトでアニメーションを作るときのAPIを定義するよ。ブラウザは、そのページが表にあるか否かとかCPUの負荷とかを元に良い感じにフレームレートを決めるよ。CPUの無駄使いとかよくないからね。

当然JSXでもrequetAnimationFrame()を使いたいのですが、問題はこれをこのままの名前で提供しているブラウザがほとんどないということです。ベンダプレフィクスがついてwebkitRequestAnimationFrame()とかmozRequestAnimationFrame()とかなってます。これは静的型付けなJSXからはとても使いにくい。

そこでやや反則気味ですが、js.jsxを使ってメソッドの有無をチェックして事前準備をすることで、JSXでもrequestAnimationFrame()を使うことができます。

実際の使用例は web/example/sakura.jsx にあります*1

  // 実際に使えるものを探す。
  // 存在していなければsetTimeout()で代用する

  static function getRequestAnimationFrame() : function(tick : function(:number) : void) : void {

    if(js.global["requestAnimationFrame"] != undefined) {
      return function (tick : function(:number) : void) : void {
        dom.window.requestAnimationFrame(tick);
      };
    }
    else if(js.global["webkitRequestAnimationFrame"] != undefined) {
      return function (tick : function(:number) : void) : void {
        dom.window.webkitRequestAnimationFrame(tick);
      };
    }
    else if(js.global["mozRequestAnimationFrame"] != undefined) {
      return function (tick : function(:number) : void) : void {
        dom.window.mozRequestAnimationFrame(tick);
      };
    }
    else {
      return function (tick : function(:number) : void) : void {
        dom.window.setTimeout(function() : void { tick(0); }, 1000 / 60);
      };
    }

  }

  static const requestAnimationFrame = _Main.getRequestAnimationFrame();

呼び出す際は以下のようにします。

      var callTick = function(elapsed : number) : void {
        stage.tick();

        _Main.requestAnimationFrame(callTick);
      };

      // start animation
      _Main.requestAnimationFrame(callTick);

これでとりあえず使えるようになりました。なお、メソッドの有無の識別は現実のプログラミングには頻繁に必要になるため、js.jsxを使わずにもできるようにする予定です。

*1:なお webkit- と moz- 以外は定義していないので使用できません