Phaser Source: src/utils/RequestAnimationFrame.js

# Source: src/utils/RequestAnimationFrame.js

    /**
    * @author       Richard Davey <rich@photonstorm.com>
    * @copyright    2016 Photon Storm Ltd.
    * @license      {@link https://github.com/photonstorm/phaser/blob/master/license.txt|MIT License}
    */

    /**
    * Abstracts away the use of RAF or setTimeOut for the core game update loop.
    *
    * @class Phaser.RequestAnimationFrame
    * @constructor
    * @param {Phaser.Game} game - A reference to the currently running game.
    * @param {boolean} [forceSetTimeOut=false] - Tell Phaser to use setTimeOut even if raf is available.
    */
    Phaser.RequestAnimationFrame = function(game, forceSetTimeOut) {

        if (forceSetTimeOut === undefined) { forceSetTimeOut = false; }

        /**
        * @property {Phaser.Game} game - The currently running game.
        */
        this.game = game;

        /**
        * @property {boolean} isRunning - true if RequestAnimationFrame is running, otherwise false.
        * @default
        */
        this.isRunning = false;

        /**
        * @property {boolean} forceSetTimeOut - Tell Phaser to use setTimeOut even if raf is available.
        */
        this.forceSetTimeOut = forceSetTimeOut;

        var vendors = [
            'ms',
            'moz',
            'webkit',
            'o'
        ];

        for (var x = 0; x < vendors.length && !window.requestAnimationFrame; x++)
        {
            window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
            window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'];
        }

        /**
        * @property {boolean} _isSetTimeOut  - true if the browser is using setTimeout instead of raf.
        * @private
        */
        this._isSetTimeOut = false;

        /**
        * @property {function} _onLoop - The function called by the update.
        * @private
        */
        this._onLoop = null;

        /**
        * @property {number} _timeOutID - The callback ID used when calling cancel.
        * @private
        */
        this._timeOutID = null;

    };

    Phaser.RequestAnimationFrame.prototype = {

        /**
        * Starts the requestAnimationFrame running or setTimeout if unavailable in browser
        * @method Phaser.RequestAnimationFrame#start
        */
        start: function () {

            this.isRunning = true;

            var _this = this;

            if (!window.requestAnimationFrame || this.forceSetTimeOut)
            {
                this._isSetTimeOut = true;

                this._onLoop = function () {
                    return _this.updateSetTimeout();
                };

                this._timeOutID = window.setTimeout(this._onLoop, 0);
            }
            else
            {
                this._isSetTimeOut = false;

                this._onLoop = function (time) {
                    return _this.updateRAF(time);
                };

                this._timeOutID = window.requestAnimationFrame(this._onLoop);
            }

        },

        /**
        * The update method for the requestAnimationFrame
        * @method Phaser.RequestAnimationFrame#updateRAF
        */
        updateRAF: function (rafTime) {

            if (this.isRunning)
            {
                // floor the rafTime to make it equivalent to the Date.now() provided by updateSetTimeout (just below)
                this.game.update(Math.floor(rafTime));

                this._timeOutID = window.requestAnimationFrame(this._onLoop);
            }

        },

        /**
        * The update method for the setTimeout.
        * @method Phaser.RequestAnimationFrame#updateSetTimeout
        */
        updateSetTimeout: function () {

            if (this.isRunning)
            {
                this.game.update(Date.now());

                this._timeOutID = window.setTimeout(this._onLoop, this.game.time.timeToCall);
            }

        },

        /**
        * Stops the requestAnimationFrame from running.
        * @method Phaser.RequestAnimationFrame#stop
        */
        stop: function () {

            if (this._isSetTimeOut)
            {
                clearTimeout(this._timeOutID);
            }
            else
            {
                window.cancelAnimationFrame(this._timeOutID);
            }

            this.isRunning = false;

        },

        /**
        * Is the browser using setTimeout?
        * @method Phaser.RequestAnimationFrame#isSetTimeOut
        * @return {boolean}
        */
        isSetTimeOut: function () {
            return this._isSetTimeOut;
        },

        /**
        * Is the browser using requestAnimationFrame?
        * @method Phaser.RequestAnimationFrame#isRAF
        * @return {boolean}
        */
        isRAF: function () {
            return (this._isSetTimeOut === false);
        }

    };

    Phaser.RequestAnimationFrame.prototype.constructor = Phaser.RequestAnimationFrame;