diff --git a/src/extras/MovieClip.js b/src/extras/MovieClip.js index 6a34990..b604386 100644 --- a/src/extras/MovieClip.js +++ b/src/extras/MovieClip.js @@ -1,5 +1,5 @@ var core = require('../core'), - Ticker = require('./Ticker'); + ticker = require('../ticker'); /** * A MovieClip is a simple way to display an animation depicted by a list of textures. @@ -129,7 +129,7 @@ } this.playing = false; - Ticker.sharedTicker.remove(this.update); + ticker.shared.remove(this.update); }; /** @@ -144,7 +144,7 @@ } this.playing = true; - Ticker.sharedTicker.add(this.update, this); + ticker.shared.add(this.update, this); }; /** diff --git a/src/extras/MovieClip.js b/src/extras/MovieClip.js index 6a34990..b604386 100644 --- a/src/extras/MovieClip.js +++ b/src/extras/MovieClip.js @@ -1,5 +1,5 @@ var core = require('../core'), - Ticker = require('./Ticker'); + ticker = require('../ticker'); /** * A MovieClip is a simple way to display an animation depicted by a list of textures. @@ -129,7 +129,7 @@ } this.playing = false; - Ticker.sharedTicker.remove(this.update); + ticker.shared.remove(this.update); }; /** @@ -144,7 +144,7 @@ } this.playing = true; - Ticker.sharedTicker.add(this.update, this); + ticker.shared.add(this.update, this); }; /** diff --git a/src/extras/Ticker.js b/src/extras/Ticker.js deleted file mode 100644 index 8504185..0000000 --- a/src/extras/Ticker.js +++ /dev/null @@ -1,332 +0,0 @@ -var core = require('../core'), - EventEmitter = require('eventemitter3').EventEmitter, - // Internal event used by composed emitter - TICK = 'tick'; - -/** - * Yes, this is accessing an internal module:eventemitter3 api. - * Ugly, but calling module:eventemitter3.EventEmitter#listeners - * does a bit too much for what this is for. - * This is simple enough to keep track of and contribute - * back to the eventemitter3 project in the near future. - * - * @private - */ -function hasListeners(emitter) -{ - return !!(emitter._events && emitter._events[TICK]); -} - -/** - * A Ticker class that runs an update loop that other objects listen to. - * This class is composed around an EventEmitter object to add listeners - * meant for execution on the next requested animation frame. - * Animation frames are requested only when necessary, - * e.g. When the ticker is started and the emitter has listeners. - * - * @class - * @memberof PIXI.extras - */ -function Ticker() -{ - var _this = this; - /** - * Internal tick method bound to ticker instance. - * This is because in early 2015, Function.bind - * is still 60% slower in high performance scenarios. - * Also separating frame requests from update method - * so listeners may be called at any time and with - * any animation API, just invoke ticker.update(time). - * - * @private - */ - this._tick = function _tick(time) { - - _this._requestId = null; - - if (_this.started) - { - _this.update(time); - } - // Check here because listeners could have side effects - // and may have modified state during frame execution. - // A new frame may have been requested or listeners removed. - if (_this.started && _this._requestId === null && hasListeners(_this._emitter)) - { - _this._requestId = requestAnimationFrame(_this._tick); - } - }; - /** - * Internal emitter used to fire 'tick' event - * @private - */ - this._emitter = new EventEmitter(); - /** - * Internal current frame request ID - * @private - */ - this._requestId = null; - /** - * Internal value managed by minFPS property setter and getter. - * This is the maximum allowed millseconds between updates. - * @private - */ - this._maxElapsedMS = 100; - - /** - * Whether or not this ticker should - * start automatically when a listener is added. - * - * @member {boolean} - */ - this.autoStart = false; - - /** - * The current percentage of the - * target FPS with speed factored in. - * - * @member {number} - */ - this.deltaTime = 1; - - /** - * The last time {@link PIXI.extras.Ticker#update} - * was invoked by animation frame callback or manually. - * - * @member {number} - */ - this.lastTime = 0; - - /** - * Factor of current FPS. - * @example - * ticker.speed = 2; // Approximately 120 FPS, or 0.12 FPMS. - * - * @member {number} - */ - this.speed = 1; - - /** - * Whether or not this ticker has been started. - * `true` if {@link PIXI.extras.Ticker.start} has been called. - * `false` if {@link PIXI.extras.Ticker.stop} has been called. - * - * @member {boolean} - */ - this.started = false; -} - -Object.defineProperties(Ticker.prototype, { - /** - * Gets the frames per second for which this - * ticker is running. The default is appoximately - * 60 FPS in modern browsers, but may vary. - * This also factors in the property value of - * {@link PIXI.extras.Ticker#speed}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @readonly - */ - FPS: { - get: function() - { - return core.TARGET_FPMS * 1000 * this.deltaTime; - } - }, - - /** - * This property manages the maximum amount - * of time allowed to elapse between ticks, - * or calls to {@link PIXI.extras.Ticker#update}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @default 10 - */ - minFPS: { - get: function() - { - return 1000 / this._maxElapsedMS; - }, - set: function(fps) - { - // Clamp: 0 to TARGET_FPMS - var minFPMS = Math.min(Math.max(0, fps) / 1000, core.TARGET_FPMS); - this._maxElapsedMS = 1 / minFPMS; - } - } -}); - -/** - * Conditionally requests a new animation frame. - * If a frame has not already been requested, and if the internal - * emitter has listeners, a new frame is requested. - * - * @private - */ -Ticker.prototype._requestIfNeeded = function _requestIfNeeded() -{ - if (this._requestId === null && hasListeners(this._emitter)) - { - // ensure callbacks get correct delta - this.lastTime = performance.now(); - this._requestId = requestAnimationFrame(this._tick); - } -}; - -/** - * Conditionally cancels a pending animation frame. - * - * @private - */ -Ticker.prototype._cancelIfNeeded = function _cancelIfNeeded() -{ - if (this._requestId !== null) - { - cancelAnimationFrame(this._requestId); - this._requestId = null; - } -}; - -/** - * Conditionally requests a new animation frame. - * If the ticker has been started it checks if a frame has not already - * been requested, and if the internal emitter has listeners. If these - * conditions are met, a new frame is requested. If the ticker has not - * been started, but autoStart is `true`, then the ticker starts now, - * and continues with the previous conditions to request a new frame. - * - * @private - */ -Ticker.prototype._startIfPossible = function _startIfPossible() -{ - if (this.started) - { - this._requestIfNeeded(); - } - else if (this.autoStart) - { - this.start(); - } -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#on} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.add = function add(fn, context) -{ - this._emitter.on(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#once} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.addOnce = function addOnce(fn, context) -{ - this._emitter.once(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. - * It checks if the emitter has listeners for 'tick' event. - * If it does, then it cancels the animation frame. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.remove = function remove(fn, once) -{ - this._emitter.off(TICK, fn, once); - - if (!hasListeners(this._emitter)) - { - this._cancelIfNeeded(); - } - - return this; -}; - -/** - * Starts the ticker. If the ticker has listeners - * a new animation frame is requested at this point. - */ -Ticker.prototype.start = function start() -{ - if (!this.started) - { - this.started = true; - this._requestIfNeeded(); - } -}; - -/** - * Stops the ticker. If the ticker has requested - * an animation frame it is canceled at this point. - */ -Ticker.prototype.stop = function stop() -{ - if (this.started) - { - this.started = false; - this._cancelIfNeeded(); - } -}; - -/** - * Triggers an update, setting deltaTime, lastTime, and - * firing the internal 'tick' event invoking all listeners. - * - * @param [currentTime=performance.now()] {number} the current time of execution - */ -Ticker.prototype.update = function update(currentTime) -{ - var elapsedMS; - - // Allow calling update directly with default currentTime. - currentTime = currentTime || performance.now(); - elapsedMS = currentTime - this.lastTime; - - // cap the milliseconds elapsed - if (elapsedMS > this._maxElapsedMS) - { - elapsedMS = this._maxElapsedMS; - } - - this.deltaTime = (elapsedMS * core.TARGET_FPMS); - // Factor in speed - this.deltaTime *= this.speed; - - // Invoke listeners added to internal emitter - this._emitter.emit(TICK, this.deltaTime); - - this.lastTime = currentTime; -}; - -/** - * The shared ticker instance used by {@link PIXI.extras.MovieClip}. - * The property {@link PIXI.extras.Ticker#autoStart} is set to true - * for this instance. - * - * @type {PIXI.extras.Ticker} - * @memberof PIXI.extras.Ticker - */ -Ticker.sharedTicker = new Ticker(); -Ticker.sharedTicker.autoStart = true; - -module.exports = Ticker; diff --git a/src/extras/MovieClip.js b/src/extras/MovieClip.js index 6a34990..b604386 100644 --- a/src/extras/MovieClip.js +++ b/src/extras/MovieClip.js @@ -1,5 +1,5 @@ var core = require('../core'), - Ticker = require('./Ticker'); + ticker = require('../ticker'); /** * A MovieClip is a simple way to display an animation depicted by a list of textures. @@ -129,7 +129,7 @@ } this.playing = false; - Ticker.sharedTicker.remove(this.update); + ticker.shared.remove(this.update); }; /** @@ -144,7 +144,7 @@ } this.playing = true; - Ticker.sharedTicker.add(this.update, this); + ticker.shared.add(this.update, this); }; /** diff --git a/src/extras/Ticker.js b/src/extras/Ticker.js deleted file mode 100644 index 8504185..0000000 --- a/src/extras/Ticker.js +++ /dev/null @@ -1,332 +0,0 @@ -var core = require('../core'), - EventEmitter = require('eventemitter3').EventEmitter, - // Internal event used by composed emitter - TICK = 'tick'; - -/** - * Yes, this is accessing an internal module:eventemitter3 api. - * Ugly, but calling module:eventemitter3.EventEmitter#listeners - * does a bit too much for what this is for. - * This is simple enough to keep track of and contribute - * back to the eventemitter3 project in the near future. - * - * @private - */ -function hasListeners(emitter) -{ - return !!(emitter._events && emitter._events[TICK]); -} - -/** - * A Ticker class that runs an update loop that other objects listen to. - * This class is composed around an EventEmitter object to add listeners - * meant for execution on the next requested animation frame. - * Animation frames are requested only when necessary, - * e.g. When the ticker is started and the emitter has listeners. - * - * @class - * @memberof PIXI.extras - */ -function Ticker() -{ - var _this = this; - /** - * Internal tick method bound to ticker instance. - * This is because in early 2015, Function.bind - * is still 60% slower in high performance scenarios. - * Also separating frame requests from update method - * so listeners may be called at any time and with - * any animation API, just invoke ticker.update(time). - * - * @private - */ - this._tick = function _tick(time) { - - _this._requestId = null; - - if (_this.started) - { - _this.update(time); - } - // Check here because listeners could have side effects - // and may have modified state during frame execution. - // A new frame may have been requested or listeners removed. - if (_this.started && _this._requestId === null && hasListeners(_this._emitter)) - { - _this._requestId = requestAnimationFrame(_this._tick); - } - }; - /** - * Internal emitter used to fire 'tick' event - * @private - */ - this._emitter = new EventEmitter(); - /** - * Internal current frame request ID - * @private - */ - this._requestId = null; - /** - * Internal value managed by minFPS property setter and getter. - * This is the maximum allowed millseconds between updates. - * @private - */ - this._maxElapsedMS = 100; - - /** - * Whether or not this ticker should - * start automatically when a listener is added. - * - * @member {boolean} - */ - this.autoStart = false; - - /** - * The current percentage of the - * target FPS with speed factored in. - * - * @member {number} - */ - this.deltaTime = 1; - - /** - * The last time {@link PIXI.extras.Ticker#update} - * was invoked by animation frame callback or manually. - * - * @member {number} - */ - this.lastTime = 0; - - /** - * Factor of current FPS. - * @example - * ticker.speed = 2; // Approximately 120 FPS, or 0.12 FPMS. - * - * @member {number} - */ - this.speed = 1; - - /** - * Whether or not this ticker has been started. - * `true` if {@link PIXI.extras.Ticker.start} has been called. - * `false` if {@link PIXI.extras.Ticker.stop} has been called. - * - * @member {boolean} - */ - this.started = false; -} - -Object.defineProperties(Ticker.prototype, { - /** - * Gets the frames per second for which this - * ticker is running. The default is appoximately - * 60 FPS in modern browsers, but may vary. - * This also factors in the property value of - * {@link PIXI.extras.Ticker#speed}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @readonly - */ - FPS: { - get: function() - { - return core.TARGET_FPMS * 1000 * this.deltaTime; - } - }, - - /** - * This property manages the maximum amount - * of time allowed to elapse between ticks, - * or calls to {@link PIXI.extras.Ticker#update}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @default 10 - */ - minFPS: { - get: function() - { - return 1000 / this._maxElapsedMS; - }, - set: function(fps) - { - // Clamp: 0 to TARGET_FPMS - var minFPMS = Math.min(Math.max(0, fps) / 1000, core.TARGET_FPMS); - this._maxElapsedMS = 1 / minFPMS; - } - } -}); - -/** - * Conditionally requests a new animation frame. - * If a frame has not already been requested, and if the internal - * emitter has listeners, a new frame is requested. - * - * @private - */ -Ticker.prototype._requestIfNeeded = function _requestIfNeeded() -{ - if (this._requestId === null && hasListeners(this._emitter)) - { - // ensure callbacks get correct delta - this.lastTime = performance.now(); - this._requestId = requestAnimationFrame(this._tick); - } -}; - -/** - * Conditionally cancels a pending animation frame. - * - * @private - */ -Ticker.prototype._cancelIfNeeded = function _cancelIfNeeded() -{ - if (this._requestId !== null) - { - cancelAnimationFrame(this._requestId); - this._requestId = null; - } -}; - -/** - * Conditionally requests a new animation frame. - * If the ticker has been started it checks if a frame has not already - * been requested, and if the internal emitter has listeners. If these - * conditions are met, a new frame is requested. If the ticker has not - * been started, but autoStart is `true`, then the ticker starts now, - * and continues with the previous conditions to request a new frame. - * - * @private - */ -Ticker.prototype._startIfPossible = function _startIfPossible() -{ - if (this.started) - { - this._requestIfNeeded(); - } - else if (this.autoStart) - { - this.start(); - } -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#on} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.add = function add(fn, context) -{ - this._emitter.on(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#once} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.addOnce = function addOnce(fn, context) -{ - this._emitter.once(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. - * It checks if the emitter has listeners for 'tick' event. - * If it does, then it cancels the animation frame. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.remove = function remove(fn, once) -{ - this._emitter.off(TICK, fn, once); - - if (!hasListeners(this._emitter)) - { - this._cancelIfNeeded(); - } - - return this; -}; - -/** - * Starts the ticker. If the ticker has listeners - * a new animation frame is requested at this point. - */ -Ticker.prototype.start = function start() -{ - if (!this.started) - { - this.started = true; - this._requestIfNeeded(); - } -}; - -/** - * Stops the ticker. If the ticker has requested - * an animation frame it is canceled at this point. - */ -Ticker.prototype.stop = function stop() -{ - if (this.started) - { - this.started = false; - this._cancelIfNeeded(); - } -}; - -/** - * Triggers an update, setting deltaTime, lastTime, and - * firing the internal 'tick' event invoking all listeners. - * - * @param [currentTime=performance.now()] {number} the current time of execution - */ -Ticker.prototype.update = function update(currentTime) -{ - var elapsedMS; - - // Allow calling update directly with default currentTime. - currentTime = currentTime || performance.now(); - elapsedMS = currentTime - this.lastTime; - - // cap the milliseconds elapsed - if (elapsedMS > this._maxElapsedMS) - { - elapsedMS = this._maxElapsedMS; - } - - this.deltaTime = (elapsedMS * core.TARGET_FPMS); - // Factor in speed - this.deltaTime *= this.speed; - - // Invoke listeners added to internal emitter - this._emitter.emit(TICK, this.deltaTime); - - this.lastTime = currentTime; -}; - -/** - * The shared ticker instance used by {@link PIXI.extras.MovieClip}. - * The property {@link PIXI.extras.Ticker#autoStart} is set to true - * for this instance. - * - * @type {PIXI.extras.Ticker} - * @memberof PIXI.extras.Ticker - */ -Ticker.sharedTicker = new Ticker(); -Ticker.sharedTicker.autoStart = true; - -module.exports = Ticker; diff --git a/src/extras/index.js b/src/extras/index.js index aa08e38..1f85635 100644 --- a/src/extras/index.js +++ b/src/extras/index.js @@ -13,7 +13,6 @@ * @namespace PIXI.extras */ module.exports = { - Ticker: require('./Ticker'), MovieClip: require('./MovieClip'), TilingSprite: require('./TilingSprite'), BitmapText: require('./BitmapText'), diff --git a/src/extras/MovieClip.js b/src/extras/MovieClip.js index 6a34990..b604386 100644 --- a/src/extras/MovieClip.js +++ b/src/extras/MovieClip.js @@ -1,5 +1,5 @@ var core = require('../core'), - Ticker = require('./Ticker'); + ticker = require('../ticker'); /** * A MovieClip is a simple way to display an animation depicted by a list of textures. @@ -129,7 +129,7 @@ } this.playing = false; - Ticker.sharedTicker.remove(this.update); + ticker.shared.remove(this.update); }; /** @@ -144,7 +144,7 @@ } this.playing = true; - Ticker.sharedTicker.add(this.update, this); + ticker.shared.add(this.update, this); }; /** diff --git a/src/extras/Ticker.js b/src/extras/Ticker.js deleted file mode 100644 index 8504185..0000000 --- a/src/extras/Ticker.js +++ /dev/null @@ -1,332 +0,0 @@ -var core = require('../core'), - EventEmitter = require('eventemitter3').EventEmitter, - // Internal event used by composed emitter - TICK = 'tick'; - -/** - * Yes, this is accessing an internal module:eventemitter3 api. - * Ugly, but calling module:eventemitter3.EventEmitter#listeners - * does a bit too much for what this is for. - * This is simple enough to keep track of and contribute - * back to the eventemitter3 project in the near future. - * - * @private - */ -function hasListeners(emitter) -{ - return !!(emitter._events && emitter._events[TICK]); -} - -/** - * A Ticker class that runs an update loop that other objects listen to. - * This class is composed around an EventEmitter object to add listeners - * meant for execution on the next requested animation frame. - * Animation frames are requested only when necessary, - * e.g. When the ticker is started and the emitter has listeners. - * - * @class - * @memberof PIXI.extras - */ -function Ticker() -{ - var _this = this; - /** - * Internal tick method bound to ticker instance. - * This is because in early 2015, Function.bind - * is still 60% slower in high performance scenarios. - * Also separating frame requests from update method - * so listeners may be called at any time and with - * any animation API, just invoke ticker.update(time). - * - * @private - */ - this._tick = function _tick(time) { - - _this._requestId = null; - - if (_this.started) - { - _this.update(time); - } - // Check here because listeners could have side effects - // and may have modified state during frame execution. - // A new frame may have been requested or listeners removed. - if (_this.started && _this._requestId === null && hasListeners(_this._emitter)) - { - _this._requestId = requestAnimationFrame(_this._tick); - } - }; - /** - * Internal emitter used to fire 'tick' event - * @private - */ - this._emitter = new EventEmitter(); - /** - * Internal current frame request ID - * @private - */ - this._requestId = null; - /** - * Internal value managed by minFPS property setter and getter. - * This is the maximum allowed millseconds between updates. - * @private - */ - this._maxElapsedMS = 100; - - /** - * Whether or not this ticker should - * start automatically when a listener is added. - * - * @member {boolean} - */ - this.autoStart = false; - - /** - * The current percentage of the - * target FPS with speed factored in. - * - * @member {number} - */ - this.deltaTime = 1; - - /** - * The last time {@link PIXI.extras.Ticker#update} - * was invoked by animation frame callback or manually. - * - * @member {number} - */ - this.lastTime = 0; - - /** - * Factor of current FPS. - * @example - * ticker.speed = 2; // Approximately 120 FPS, or 0.12 FPMS. - * - * @member {number} - */ - this.speed = 1; - - /** - * Whether or not this ticker has been started. - * `true` if {@link PIXI.extras.Ticker.start} has been called. - * `false` if {@link PIXI.extras.Ticker.stop} has been called. - * - * @member {boolean} - */ - this.started = false; -} - -Object.defineProperties(Ticker.prototype, { - /** - * Gets the frames per second for which this - * ticker is running. The default is appoximately - * 60 FPS in modern browsers, but may vary. - * This also factors in the property value of - * {@link PIXI.extras.Ticker#speed}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @readonly - */ - FPS: { - get: function() - { - return core.TARGET_FPMS * 1000 * this.deltaTime; - } - }, - - /** - * This property manages the maximum amount - * of time allowed to elapse between ticks, - * or calls to {@link PIXI.extras.Ticker#update}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @default 10 - */ - minFPS: { - get: function() - { - return 1000 / this._maxElapsedMS; - }, - set: function(fps) - { - // Clamp: 0 to TARGET_FPMS - var minFPMS = Math.min(Math.max(0, fps) / 1000, core.TARGET_FPMS); - this._maxElapsedMS = 1 / minFPMS; - } - } -}); - -/** - * Conditionally requests a new animation frame. - * If a frame has not already been requested, and if the internal - * emitter has listeners, a new frame is requested. - * - * @private - */ -Ticker.prototype._requestIfNeeded = function _requestIfNeeded() -{ - if (this._requestId === null && hasListeners(this._emitter)) - { - // ensure callbacks get correct delta - this.lastTime = performance.now(); - this._requestId = requestAnimationFrame(this._tick); - } -}; - -/** - * Conditionally cancels a pending animation frame. - * - * @private - */ -Ticker.prototype._cancelIfNeeded = function _cancelIfNeeded() -{ - if (this._requestId !== null) - { - cancelAnimationFrame(this._requestId); - this._requestId = null; - } -}; - -/** - * Conditionally requests a new animation frame. - * If the ticker has been started it checks if a frame has not already - * been requested, and if the internal emitter has listeners. If these - * conditions are met, a new frame is requested. If the ticker has not - * been started, but autoStart is `true`, then the ticker starts now, - * and continues with the previous conditions to request a new frame. - * - * @private - */ -Ticker.prototype._startIfPossible = function _startIfPossible() -{ - if (this.started) - { - this._requestIfNeeded(); - } - else if (this.autoStart) - { - this.start(); - } -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#on} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.add = function add(fn, context) -{ - this._emitter.on(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#once} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.addOnce = function addOnce(fn, context) -{ - this._emitter.once(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. - * It checks if the emitter has listeners for 'tick' event. - * If it does, then it cancels the animation frame. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.remove = function remove(fn, once) -{ - this._emitter.off(TICK, fn, once); - - if (!hasListeners(this._emitter)) - { - this._cancelIfNeeded(); - } - - return this; -}; - -/** - * Starts the ticker. If the ticker has listeners - * a new animation frame is requested at this point. - */ -Ticker.prototype.start = function start() -{ - if (!this.started) - { - this.started = true; - this._requestIfNeeded(); - } -}; - -/** - * Stops the ticker. If the ticker has requested - * an animation frame it is canceled at this point. - */ -Ticker.prototype.stop = function stop() -{ - if (this.started) - { - this.started = false; - this._cancelIfNeeded(); - } -}; - -/** - * Triggers an update, setting deltaTime, lastTime, and - * firing the internal 'tick' event invoking all listeners. - * - * @param [currentTime=performance.now()] {number} the current time of execution - */ -Ticker.prototype.update = function update(currentTime) -{ - var elapsedMS; - - // Allow calling update directly with default currentTime. - currentTime = currentTime || performance.now(); - elapsedMS = currentTime - this.lastTime; - - // cap the milliseconds elapsed - if (elapsedMS > this._maxElapsedMS) - { - elapsedMS = this._maxElapsedMS; - } - - this.deltaTime = (elapsedMS * core.TARGET_FPMS); - // Factor in speed - this.deltaTime *= this.speed; - - // Invoke listeners added to internal emitter - this._emitter.emit(TICK, this.deltaTime); - - this.lastTime = currentTime; -}; - -/** - * The shared ticker instance used by {@link PIXI.extras.MovieClip}. - * The property {@link PIXI.extras.Ticker#autoStart} is set to true - * for this instance. - * - * @type {PIXI.extras.Ticker} - * @memberof PIXI.extras.Ticker - */ -Ticker.sharedTicker = new Ticker(); -Ticker.sharedTicker.autoStart = true; - -module.exports = Ticker; diff --git a/src/extras/index.js b/src/extras/index.js index aa08e38..1f85635 100644 --- a/src/extras/index.js +++ b/src/extras/index.js @@ -13,7 +13,6 @@ * @namespace PIXI.extras */ module.exports = { - Ticker: require('./Ticker'), MovieClip: require('./MovieClip'), TilingSprite: require('./TilingSprite'), BitmapText: require('./BitmapText'), diff --git a/src/index.js b/src/index.js index a149f72..a6e9ca7 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ core.loaders = require('./loaders'); core.mesh = require('./mesh'); core.spine = require('pixi-spine'); +core.ticker = require('./ticker'); // export a premade loader instance core.loader = new core.loaders.Loader(); diff --git a/src/extras/MovieClip.js b/src/extras/MovieClip.js index 6a34990..b604386 100644 --- a/src/extras/MovieClip.js +++ b/src/extras/MovieClip.js @@ -1,5 +1,5 @@ var core = require('../core'), - Ticker = require('./Ticker'); + ticker = require('../ticker'); /** * A MovieClip is a simple way to display an animation depicted by a list of textures. @@ -129,7 +129,7 @@ } this.playing = false; - Ticker.sharedTicker.remove(this.update); + ticker.shared.remove(this.update); }; /** @@ -144,7 +144,7 @@ } this.playing = true; - Ticker.sharedTicker.add(this.update, this); + ticker.shared.add(this.update, this); }; /** diff --git a/src/extras/Ticker.js b/src/extras/Ticker.js deleted file mode 100644 index 8504185..0000000 --- a/src/extras/Ticker.js +++ /dev/null @@ -1,332 +0,0 @@ -var core = require('../core'), - EventEmitter = require('eventemitter3').EventEmitter, - // Internal event used by composed emitter - TICK = 'tick'; - -/** - * Yes, this is accessing an internal module:eventemitter3 api. - * Ugly, but calling module:eventemitter3.EventEmitter#listeners - * does a bit too much for what this is for. - * This is simple enough to keep track of and contribute - * back to the eventemitter3 project in the near future. - * - * @private - */ -function hasListeners(emitter) -{ - return !!(emitter._events && emitter._events[TICK]); -} - -/** - * A Ticker class that runs an update loop that other objects listen to. - * This class is composed around an EventEmitter object to add listeners - * meant for execution on the next requested animation frame. - * Animation frames are requested only when necessary, - * e.g. When the ticker is started and the emitter has listeners. - * - * @class - * @memberof PIXI.extras - */ -function Ticker() -{ - var _this = this; - /** - * Internal tick method bound to ticker instance. - * This is because in early 2015, Function.bind - * is still 60% slower in high performance scenarios. - * Also separating frame requests from update method - * so listeners may be called at any time and with - * any animation API, just invoke ticker.update(time). - * - * @private - */ - this._tick = function _tick(time) { - - _this._requestId = null; - - if (_this.started) - { - _this.update(time); - } - // Check here because listeners could have side effects - // and may have modified state during frame execution. - // A new frame may have been requested or listeners removed. - if (_this.started && _this._requestId === null && hasListeners(_this._emitter)) - { - _this._requestId = requestAnimationFrame(_this._tick); - } - }; - /** - * Internal emitter used to fire 'tick' event - * @private - */ - this._emitter = new EventEmitter(); - /** - * Internal current frame request ID - * @private - */ - this._requestId = null; - /** - * Internal value managed by minFPS property setter and getter. - * This is the maximum allowed millseconds between updates. - * @private - */ - this._maxElapsedMS = 100; - - /** - * Whether or not this ticker should - * start automatically when a listener is added. - * - * @member {boolean} - */ - this.autoStart = false; - - /** - * The current percentage of the - * target FPS with speed factored in. - * - * @member {number} - */ - this.deltaTime = 1; - - /** - * The last time {@link PIXI.extras.Ticker#update} - * was invoked by animation frame callback or manually. - * - * @member {number} - */ - this.lastTime = 0; - - /** - * Factor of current FPS. - * @example - * ticker.speed = 2; // Approximately 120 FPS, or 0.12 FPMS. - * - * @member {number} - */ - this.speed = 1; - - /** - * Whether or not this ticker has been started. - * `true` if {@link PIXI.extras.Ticker.start} has been called. - * `false` if {@link PIXI.extras.Ticker.stop} has been called. - * - * @member {boolean} - */ - this.started = false; -} - -Object.defineProperties(Ticker.prototype, { - /** - * Gets the frames per second for which this - * ticker is running. The default is appoximately - * 60 FPS in modern browsers, but may vary. - * This also factors in the property value of - * {@link PIXI.extras.Ticker#speed}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @readonly - */ - FPS: { - get: function() - { - return core.TARGET_FPMS * 1000 * this.deltaTime; - } - }, - - /** - * This property manages the maximum amount - * of time allowed to elapse between ticks, - * or calls to {@link PIXI.extras.Ticker#update}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @default 10 - */ - minFPS: { - get: function() - { - return 1000 / this._maxElapsedMS; - }, - set: function(fps) - { - // Clamp: 0 to TARGET_FPMS - var minFPMS = Math.min(Math.max(0, fps) / 1000, core.TARGET_FPMS); - this._maxElapsedMS = 1 / minFPMS; - } - } -}); - -/** - * Conditionally requests a new animation frame. - * If a frame has not already been requested, and if the internal - * emitter has listeners, a new frame is requested. - * - * @private - */ -Ticker.prototype._requestIfNeeded = function _requestIfNeeded() -{ - if (this._requestId === null && hasListeners(this._emitter)) - { - // ensure callbacks get correct delta - this.lastTime = performance.now(); - this._requestId = requestAnimationFrame(this._tick); - } -}; - -/** - * Conditionally cancels a pending animation frame. - * - * @private - */ -Ticker.prototype._cancelIfNeeded = function _cancelIfNeeded() -{ - if (this._requestId !== null) - { - cancelAnimationFrame(this._requestId); - this._requestId = null; - } -}; - -/** - * Conditionally requests a new animation frame. - * If the ticker has been started it checks if a frame has not already - * been requested, and if the internal emitter has listeners. If these - * conditions are met, a new frame is requested. If the ticker has not - * been started, but autoStart is `true`, then the ticker starts now, - * and continues with the previous conditions to request a new frame. - * - * @private - */ -Ticker.prototype._startIfPossible = function _startIfPossible() -{ - if (this.started) - { - this._requestIfNeeded(); - } - else if (this.autoStart) - { - this.start(); - } -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#on} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.add = function add(fn, context) -{ - this._emitter.on(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#once} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.addOnce = function addOnce(fn, context) -{ - this._emitter.once(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. - * It checks if the emitter has listeners for 'tick' event. - * If it does, then it cancels the animation frame. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.remove = function remove(fn, once) -{ - this._emitter.off(TICK, fn, once); - - if (!hasListeners(this._emitter)) - { - this._cancelIfNeeded(); - } - - return this; -}; - -/** - * Starts the ticker. If the ticker has listeners - * a new animation frame is requested at this point. - */ -Ticker.prototype.start = function start() -{ - if (!this.started) - { - this.started = true; - this._requestIfNeeded(); - } -}; - -/** - * Stops the ticker. If the ticker has requested - * an animation frame it is canceled at this point. - */ -Ticker.prototype.stop = function stop() -{ - if (this.started) - { - this.started = false; - this._cancelIfNeeded(); - } -}; - -/** - * Triggers an update, setting deltaTime, lastTime, and - * firing the internal 'tick' event invoking all listeners. - * - * @param [currentTime=performance.now()] {number} the current time of execution - */ -Ticker.prototype.update = function update(currentTime) -{ - var elapsedMS; - - // Allow calling update directly with default currentTime. - currentTime = currentTime || performance.now(); - elapsedMS = currentTime - this.lastTime; - - // cap the milliseconds elapsed - if (elapsedMS > this._maxElapsedMS) - { - elapsedMS = this._maxElapsedMS; - } - - this.deltaTime = (elapsedMS * core.TARGET_FPMS); - // Factor in speed - this.deltaTime *= this.speed; - - // Invoke listeners added to internal emitter - this._emitter.emit(TICK, this.deltaTime); - - this.lastTime = currentTime; -}; - -/** - * The shared ticker instance used by {@link PIXI.extras.MovieClip}. - * The property {@link PIXI.extras.Ticker#autoStart} is set to true - * for this instance. - * - * @type {PIXI.extras.Ticker} - * @memberof PIXI.extras.Ticker - */ -Ticker.sharedTicker = new Ticker(); -Ticker.sharedTicker.autoStart = true; - -module.exports = Ticker; diff --git a/src/extras/index.js b/src/extras/index.js index aa08e38..1f85635 100644 --- a/src/extras/index.js +++ b/src/extras/index.js @@ -13,7 +13,6 @@ * @namespace PIXI.extras */ module.exports = { - Ticker: require('./Ticker'), MovieClip: require('./MovieClip'), TilingSprite: require('./TilingSprite'), BitmapText: require('./BitmapText'), diff --git a/src/index.js b/src/index.js index a149f72..a6e9ca7 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ core.loaders = require('./loaders'); core.mesh = require('./mesh'); core.spine = require('pixi-spine'); +core.ticker = require('./ticker'); // export a premade loader instance core.loader = new core.loaders.Loader(); diff --git a/src/ticker/Ticker.js b/src/ticker/Ticker.js new file mode 100644 index 0000000..4b2311f --- /dev/null +++ b/src/ticker/Ticker.js @@ -0,0 +1,321 @@ +var core = require('../core'), + EventEmitter = require('eventemitter3').EventEmitter, + // Internal event used by composed emitter + TICK = 'tick'; + +/** + * Yes, this is accessing an internal module:eventemitter3 api. + * Ugly, but calling module:eventemitter3.EventEmitter#listeners + * does a bit too much for what this is for. + * This is simple enough to keep track of and contribute + * back to the eventemitter3 project in the near future. + * + * @private + */ +function hasListeners(emitter) +{ + return !!(emitter._events && emitter._events[TICK]); +} + +/** + * A Ticker class that runs an update loop that other objects listen to. + * This class is composed around an EventEmitter object to add listeners + * meant for execution on the next requested animation frame. + * Animation frames are requested only when necessary, + * e.g. When the ticker is started and the emitter has listeners. + * + * @class + * @memberof PIXI.ticker + */ +function Ticker() +{ + var _this = this; + /** + * Internal tick method bound to ticker instance. + * This is because in early 2015, Function.bind + * is still 60% slower in high performance scenarios. + * Also separating frame requests from update method + * so listeners may be called at any time and with + * any animation API, just invoke ticker.update(time). + * + * @private + */ + this._tick = function _tick(time) { + + _this._requestId = null; + + if (_this.started) + { + _this.update(time); + } + // Check here because listeners could have side effects + // and may have modified state during frame execution. + // A new frame may have been requested or listeners removed. + if (_this.started && _this._requestId === null && hasListeners(_this._emitter)) + { + _this._requestId = requestAnimationFrame(_this._tick); + } + }; + /** + * Internal emitter used to fire 'tick' event + * @private + */ + this._emitter = new EventEmitter(); + /** + * Internal current frame request ID + * @private + */ + this._requestId = null; + /** + * Internal value managed by minFPS property setter and getter. + * This is the maximum allowed millseconds between updates. + * @private + */ + this._maxElapsedMS = 100; + + /** + * Whether or not this ticker should + * start automatically when a listener is added. + * + * @member {boolean} + */ + this.autoStart = false; + + /** + * The current percentage of the + * target FPS with speed factored in. + * + * @member {number} + */ + this.deltaTime = 1; + + /** + * The last time {@link PIXI.ticker.Ticker#update} + * was invoked by animation frame callback or manually. + * + * @member {number} + */ + this.lastTime = 0; + + /** + * Factor of current FPS. + * @example + * ticker.speed = 2; // Approximately 120 FPS, or 0.12 FPMS. + * + * @member {number} + */ + this.speed = 1; + + /** + * Whether or not this ticker has been started. + * `true` if {@link PIXI.ticker.Ticker.start} has been called. + * `false` if {@link PIXI.ticker.Ticker.stop} has been called. + * + * @member {boolean} + */ + this.started = false; +} + +Object.defineProperties(Ticker.prototype, { + /** + * Gets the frames per second for which this + * ticker is running. The default is appoximately + * 60 FPS in modern browsers, but may vary. + * This also factors in the property value of + * {@link PIXI.ticker.Ticker#speed}. + * + * @member + * @memberof PIXI.ticker.Ticker# + * @readonly + */ + FPS: { + get: function() + { + return core.TARGET_FPMS * 1000 * this.deltaTime; + } + }, + + /** + * This property manages the maximum amount + * of time allowed to elapse between ticks, + * or calls to {@link PIXI.ticker.Ticker#update}. + * + * @member + * @memberof PIXI.ticker.Ticker# + * @default 10 + */ + minFPS: { + get: function() + { + return 1000 / this._maxElapsedMS; + }, + set: function(fps) + { + // Clamp: 0 to TARGET_FPMS + var minFPMS = Math.min(Math.max(0, fps) / 1000, core.TARGET_FPMS); + this._maxElapsedMS = 1 / minFPMS; + } + } +}); + +/** + * Conditionally requests a new animation frame. + * If a frame has not already been requested, and if the internal + * emitter has listeners, a new frame is requested. + * + * @private + */ +Ticker.prototype._requestIfNeeded = function _requestIfNeeded() +{ + if (this._requestId === null && hasListeners(this._emitter)) + { + // ensure callbacks get correct delta + this.lastTime = performance.now(); + this._requestId = requestAnimationFrame(this._tick); + } +}; + +/** + * Conditionally cancels a pending animation frame. + * + * @private + */ +Ticker.prototype._cancelIfNeeded = function _cancelIfNeeded() +{ + if (this._requestId !== null) + { + cancelAnimationFrame(this._requestId); + this._requestId = null; + } +}; + +/** + * Conditionally requests a new animation frame. + * If the ticker has been started it checks if a frame has not already + * been requested, and if the internal emitter has listeners. If these + * conditions are met, a new frame is requested. If the ticker has not + * been started, but autoStart is `true`, then the ticker starts now, + * and continues with the previous conditions to request a new frame. + * + * @private + */ +Ticker.prototype._startIfPossible = function _startIfPossible() +{ + if (this.started) + { + this._requestIfNeeded(); + } + else if (this.autoStart) + { + this.start(); + } +}; + +/** + * Calls {@link module:eventemitter3.EventEmitter#on} internally for the + * internal 'tick' event. It checks if the emitter has listeners, + * and if so it requests a new animation frame at this point. + * + * @returns {PIXI.ticker.Ticker} this + */ +Ticker.prototype.add = function add(fn, context) +{ + this._emitter.on(TICK, fn, context); + + this._startIfPossible(); + + return this; +}; + +/** + * Calls {@link module:eventemitter3.EventEmitter#once} internally for the + * internal 'tick' event. It checks if the emitter has listeners, + * and if so it requests a new animation frame at this point. + * + * @returns {PIXI.ticker.Ticker} this + */ +Ticker.prototype.addOnce = function addOnce(fn, context) +{ + this._emitter.once(TICK, fn, context); + + this._startIfPossible(); + + return this; +}; + +/** + * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. + * It checks if the emitter has listeners for 'tick' event. + * If it does, then it cancels the animation frame. + * + * @returns {PIXI.ticker.Ticker} this + */ +Ticker.prototype.remove = function remove(fn, once) +{ + this._emitter.off(TICK, fn, once); + + if (!hasListeners(this._emitter)) + { + this._cancelIfNeeded(); + } + + return this; +}; + +/** + * Starts the ticker. If the ticker has listeners + * a new animation frame is requested at this point. + */ +Ticker.prototype.start = function start() +{ + if (!this.started) + { + this.started = true; + this._requestIfNeeded(); + } +}; + +/** + * Stops the ticker. If the ticker has requested + * an animation frame it is canceled at this point. + */ +Ticker.prototype.stop = function stop() +{ + if (this.started) + { + this.started = false; + this._cancelIfNeeded(); + } +}; + +/** + * Triggers an update, setting deltaTime, lastTime, and + * firing the internal 'tick' event invoking all listeners. + * + * @param [currentTime=performance.now()] {number} the current time of execution + */ +Ticker.prototype.update = function update(currentTime) +{ + var elapsedMS; + + // Allow calling update directly with default currentTime. + currentTime = currentTime || performance.now(); + elapsedMS = currentTime - this.lastTime; + + // cap the milliseconds elapsed + if (elapsedMS > this._maxElapsedMS) + { + elapsedMS = this._maxElapsedMS; + } + + this.deltaTime = (elapsedMS * core.TARGET_FPMS); + // Factor in speed + this.deltaTime *= this.speed; + + // Invoke listeners added to internal emitter + this._emitter.emit(TICK, this.deltaTime); + + this.lastTime = currentTime; +}; + +module.exports = Ticker; diff --git a/src/extras/MovieClip.js b/src/extras/MovieClip.js index 6a34990..b604386 100644 --- a/src/extras/MovieClip.js +++ b/src/extras/MovieClip.js @@ -1,5 +1,5 @@ var core = require('../core'), - Ticker = require('./Ticker'); + ticker = require('../ticker'); /** * A MovieClip is a simple way to display an animation depicted by a list of textures. @@ -129,7 +129,7 @@ } this.playing = false; - Ticker.sharedTicker.remove(this.update); + ticker.shared.remove(this.update); }; /** @@ -144,7 +144,7 @@ } this.playing = true; - Ticker.sharedTicker.add(this.update, this); + ticker.shared.add(this.update, this); }; /** diff --git a/src/extras/Ticker.js b/src/extras/Ticker.js deleted file mode 100644 index 8504185..0000000 --- a/src/extras/Ticker.js +++ /dev/null @@ -1,332 +0,0 @@ -var core = require('../core'), - EventEmitter = require('eventemitter3').EventEmitter, - // Internal event used by composed emitter - TICK = 'tick'; - -/** - * Yes, this is accessing an internal module:eventemitter3 api. - * Ugly, but calling module:eventemitter3.EventEmitter#listeners - * does a bit too much for what this is for. - * This is simple enough to keep track of and contribute - * back to the eventemitter3 project in the near future. - * - * @private - */ -function hasListeners(emitter) -{ - return !!(emitter._events && emitter._events[TICK]); -} - -/** - * A Ticker class that runs an update loop that other objects listen to. - * This class is composed around an EventEmitter object to add listeners - * meant for execution on the next requested animation frame. - * Animation frames are requested only when necessary, - * e.g. When the ticker is started and the emitter has listeners. - * - * @class - * @memberof PIXI.extras - */ -function Ticker() -{ - var _this = this; - /** - * Internal tick method bound to ticker instance. - * This is because in early 2015, Function.bind - * is still 60% slower in high performance scenarios. - * Also separating frame requests from update method - * so listeners may be called at any time and with - * any animation API, just invoke ticker.update(time). - * - * @private - */ - this._tick = function _tick(time) { - - _this._requestId = null; - - if (_this.started) - { - _this.update(time); - } - // Check here because listeners could have side effects - // and may have modified state during frame execution. - // A new frame may have been requested or listeners removed. - if (_this.started && _this._requestId === null && hasListeners(_this._emitter)) - { - _this._requestId = requestAnimationFrame(_this._tick); - } - }; - /** - * Internal emitter used to fire 'tick' event - * @private - */ - this._emitter = new EventEmitter(); - /** - * Internal current frame request ID - * @private - */ - this._requestId = null; - /** - * Internal value managed by minFPS property setter and getter. - * This is the maximum allowed millseconds between updates. - * @private - */ - this._maxElapsedMS = 100; - - /** - * Whether or not this ticker should - * start automatically when a listener is added. - * - * @member {boolean} - */ - this.autoStart = false; - - /** - * The current percentage of the - * target FPS with speed factored in. - * - * @member {number} - */ - this.deltaTime = 1; - - /** - * The last time {@link PIXI.extras.Ticker#update} - * was invoked by animation frame callback or manually. - * - * @member {number} - */ - this.lastTime = 0; - - /** - * Factor of current FPS. - * @example - * ticker.speed = 2; // Approximately 120 FPS, or 0.12 FPMS. - * - * @member {number} - */ - this.speed = 1; - - /** - * Whether or not this ticker has been started. - * `true` if {@link PIXI.extras.Ticker.start} has been called. - * `false` if {@link PIXI.extras.Ticker.stop} has been called. - * - * @member {boolean} - */ - this.started = false; -} - -Object.defineProperties(Ticker.prototype, { - /** - * Gets the frames per second for which this - * ticker is running. The default is appoximately - * 60 FPS in modern browsers, but may vary. - * This also factors in the property value of - * {@link PIXI.extras.Ticker#speed}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @readonly - */ - FPS: { - get: function() - { - return core.TARGET_FPMS * 1000 * this.deltaTime; - } - }, - - /** - * This property manages the maximum amount - * of time allowed to elapse between ticks, - * or calls to {@link PIXI.extras.Ticker#update}. - * - * @member - * @memberof PIXI.extras.Ticker# - * @default 10 - */ - minFPS: { - get: function() - { - return 1000 / this._maxElapsedMS; - }, - set: function(fps) - { - // Clamp: 0 to TARGET_FPMS - var minFPMS = Math.min(Math.max(0, fps) / 1000, core.TARGET_FPMS); - this._maxElapsedMS = 1 / minFPMS; - } - } -}); - -/** - * Conditionally requests a new animation frame. - * If a frame has not already been requested, and if the internal - * emitter has listeners, a new frame is requested. - * - * @private - */ -Ticker.prototype._requestIfNeeded = function _requestIfNeeded() -{ - if (this._requestId === null && hasListeners(this._emitter)) - { - // ensure callbacks get correct delta - this.lastTime = performance.now(); - this._requestId = requestAnimationFrame(this._tick); - } -}; - -/** - * Conditionally cancels a pending animation frame. - * - * @private - */ -Ticker.prototype._cancelIfNeeded = function _cancelIfNeeded() -{ - if (this._requestId !== null) - { - cancelAnimationFrame(this._requestId); - this._requestId = null; - } -}; - -/** - * Conditionally requests a new animation frame. - * If the ticker has been started it checks if a frame has not already - * been requested, and if the internal emitter has listeners. If these - * conditions are met, a new frame is requested. If the ticker has not - * been started, but autoStart is `true`, then the ticker starts now, - * and continues with the previous conditions to request a new frame. - * - * @private - */ -Ticker.prototype._startIfPossible = function _startIfPossible() -{ - if (this.started) - { - this._requestIfNeeded(); - } - else if (this.autoStart) - { - this.start(); - } -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#on} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.add = function add(fn, context) -{ - this._emitter.on(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#once} internally for the - * internal 'tick' event. It checks if the emitter has listeners, - * and if so it requests a new animation frame at this point. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.addOnce = function addOnce(fn, context) -{ - this._emitter.once(TICK, fn, context); - - this._startIfPossible(); - - return this; -}; - -/** - * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. - * It checks if the emitter has listeners for 'tick' event. - * If it does, then it cancels the animation frame. - * - * @returns {PIXI.extras.Ticker} this - */ -Ticker.prototype.remove = function remove(fn, once) -{ - this._emitter.off(TICK, fn, once); - - if (!hasListeners(this._emitter)) - { - this._cancelIfNeeded(); - } - - return this; -}; - -/** - * Starts the ticker. If the ticker has listeners - * a new animation frame is requested at this point. - */ -Ticker.prototype.start = function start() -{ - if (!this.started) - { - this.started = true; - this._requestIfNeeded(); - } -}; - -/** - * Stops the ticker. If the ticker has requested - * an animation frame it is canceled at this point. - */ -Ticker.prototype.stop = function stop() -{ - if (this.started) - { - this.started = false; - this._cancelIfNeeded(); - } -}; - -/** - * Triggers an update, setting deltaTime, lastTime, and - * firing the internal 'tick' event invoking all listeners. - * - * @param [currentTime=performance.now()] {number} the current time of execution - */ -Ticker.prototype.update = function update(currentTime) -{ - var elapsedMS; - - // Allow calling update directly with default currentTime. - currentTime = currentTime || performance.now(); - elapsedMS = currentTime - this.lastTime; - - // cap the milliseconds elapsed - if (elapsedMS > this._maxElapsedMS) - { - elapsedMS = this._maxElapsedMS; - } - - this.deltaTime = (elapsedMS * core.TARGET_FPMS); - // Factor in speed - this.deltaTime *= this.speed; - - // Invoke listeners added to internal emitter - this._emitter.emit(TICK, this.deltaTime); - - this.lastTime = currentTime; -}; - -/** - * The shared ticker instance used by {@link PIXI.extras.MovieClip}. - * The property {@link PIXI.extras.Ticker#autoStart} is set to true - * for this instance. - * - * @type {PIXI.extras.Ticker} - * @memberof PIXI.extras.Ticker - */ -Ticker.sharedTicker = new Ticker(); -Ticker.sharedTicker.autoStart = true; - -module.exports = Ticker; diff --git a/src/extras/index.js b/src/extras/index.js index aa08e38..1f85635 100644 --- a/src/extras/index.js +++ b/src/extras/index.js @@ -13,7 +13,6 @@ * @namespace PIXI.extras */ module.exports = { - Ticker: require('./Ticker'), MovieClip: require('./MovieClip'), TilingSprite: require('./TilingSprite'), BitmapText: require('./BitmapText'), diff --git a/src/index.js b/src/index.js index a149f72..a6e9ca7 100644 --- a/src/index.js +++ b/src/index.js @@ -10,6 +10,7 @@ core.loaders = require('./loaders'); core.mesh = require('./mesh'); core.spine = require('pixi-spine'); +core.ticker = require('./ticker'); // export a premade loader instance core.loader = new core.loaders.Loader(); diff --git a/src/ticker/Ticker.js b/src/ticker/Ticker.js new file mode 100644 index 0000000..4b2311f --- /dev/null +++ b/src/ticker/Ticker.js @@ -0,0 +1,321 @@ +var core = require('../core'), + EventEmitter = require('eventemitter3').EventEmitter, + // Internal event used by composed emitter + TICK = 'tick'; + +/** + * Yes, this is accessing an internal module:eventemitter3 api. + * Ugly, but calling module:eventemitter3.EventEmitter#listeners + * does a bit too much for what this is for. + * This is simple enough to keep track of and contribute + * back to the eventemitter3 project in the near future. + * + * @private + */ +function hasListeners(emitter) +{ + return !!(emitter._events && emitter._events[TICK]); +} + +/** + * A Ticker class that runs an update loop that other objects listen to. + * This class is composed around an EventEmitter object to add listeners + * meant for execution on the next requested animation frame. + * Animation frames are requested only when necessary, + * e.g. When the ticker is started and the emitter has listeners. + * + * @class + * @memberof PIXI.ticker + */ +function Ticker() +{ + var _this = this; + /** + * Internal tick method bound to ticker instance. + * This is because in early 2015, Function.bind + * is still 60% slower in high performance scenarios. + * Also separating frame requests from update method + * so listeners may be called at any time and with + * any animation API, just invoke ticker.update(time). + * + * @private + */ + this._tick = function _tick(time) { + + _this._requestId = null; + + if (_this.started) + { + _this.update(time); + } + // Check here because listeners could have side effects + // and may have modified state during frame execution. + // A new frame may have been requested or listeners removed. + if (_this.started && _this._requestId === null && hasListeners(_this._emitter)) + { + _this._requestId = requestAnimationFrame(_this._tick); + } + }; + /** + * Internal emitter used to fire 'tick' event + * @private + */ + this._emitter = new EventEmitter(); + /** + * Internal current frame request ID + * @private + */ + this._requestId = null; + /** + * Internal value managed by minFPS property setter and getter. + * This is the maximum allowed millseconds between updates. + * @private + */ + this._maxElapsedMS = 100; + + /** + * Whether or not this ticker should + * start automatically when a listener is added. + * + * @member {boolean} + */ + this.autoStart = false; + + /** + * The current percentage of the + * target FPS with speed factored in. + * + * @member {number} + */ + this.deltaTime = 1; + + /** + * The last time {@link PIXI.ticker.Ticker#update} + * was invoked by animation frame callback or manually. + * + * @member {number} + */ + this.lastTime = 0; + + /** + * Factor of current FPS. + * @example + * ticker.speed = 2; // Approximately 120 FPS, or 0.12 FPMS. + * + * @member {number} + */ + this.speed = 1; + + /** + * Whether or not this ticker has been started. + * `true` if {@link PIXI.ticker.Ticker.start} has been called. + * `false` if {@link PIXI.ticker.Ticker.stop} has been called. + * + * @member {boolean} + */ + this.started = false; +} + +Object.defineProperties(Ticker.prototype, { + /** + * Gets the frames per second for which this + * ticker is running. The default is appoximately + * 60 FPS in modern browsers, but may vary. + * This also factors in the property value of + * {@link PIXI.ticker.Ticker#speed}. + * + * @member + * @memberof PIXI.ticker.Ticker# + * @readonly + */ + FPS: { + get: function() + { + return core.TARGET_FPMS * 1000 * this.deltaTime; + } + }, + + /** + * This property manages the maximum amount + * of time allowed to elapse between ticks, + * or calls to {@link PIXI.ticker.Ticker#update}. + * + * @member + * @memberof PIXI.ticker.Ticker# + * @default 10 + */ + minFPS: { + get: function() + { + return 1000 / this._maxElapsedMS; + }, + set: function(fps) + { + // Clamp: 0 to TARGET_FPMS + var minFPMS = Math.min(Math.max(0, fps) / 1000, core.TARGET_FPMS); + this._maxElapsedMS = 1 / minFPMS; + } + } +}); + +/** + * Conditionally requests a new animation frame. + * If a frame has not already been requested, and if the internal + * emitter has listeners, a new frame is requested. + * + * @private + */ +Ticker.prototype._requestIfNeeded = function _requestIfNeeded() +{ + if (this._requestId === null && hasListeners(this._emitter)) + { + // ensure callbacks get correct delta + this.lastTime = performance.now(); + this._requestId = requestAnimationFrame(this._tick); + } +}; + +/** + * Conditionally cancels a pending animation frame. + * + * @private + */ +Ticker.prototype._cancelIfNeeded = function _cancelIfNeeded() +{ + if (this._requestId !== null) + { + cancelAnimationFrame(this._requestId); + this._requestId = null; + } +}; + +/** + * Conditionally requests a new animation frame. + * If the ticker has been started it checks if a frame has not already + * been requested, and if the internal emitter has listeners. If these + * conditions are met, a new frame is requested. If the ticker has not + * been started, but autoStart is `true`, then the ticker starts now, + * and continues with the previous conditions to request a new frame. + * + * @private + */ +Ticker.prototype._startIfPossible = function _startIfPossible() +{ + if (this.started) + { + this._requestIfNeeded(); + } + else if (this.autoStart) + { + this.start(); + } +}; + +/** + * Calls {@link module:eventemitter3.EventEmitter#on} internally for the + * internal 'tick' event. It checks if the emitter has listeners, + * and if so it requests a new animation frame at this point. + * + * @returns {PIXI.ticker.Ticker} this + */ +Ticker.prototype.add = function add(fn, context) +{ + this._emitter.on(TICK, fn, context); + + this._startIfPossible(); + + return this; +}; + +/** + * Calls {@link module:eventemitter3.EventEmitter#once} internally for the + * internal 'tick' event. It checks if the emitter has listeners, + * and if so it requests a new animation frame at this point. + * + * @returns {PIXI.ticker.Ticker} this + */ +Ticker.prototype.addOnce = function addOnce(fn, context) +{ + this._emitter.once(TICK, fn, context); + + this._startIfPossible(); + + return this; +}; + +/** + * Calls {@link module:eventemitter3.EventEmitter#off} internally for 'tick' event. + * It checks if the emitter has listeners for 'tick' event. + * If it does, then it cancels the animation frame. + * + * @returns {PIXI.ticker.Ticker} this + */ +Ticker.prototype.remove = function remove(fn, once) +{ + this._emitter.off(TICK, fn, once); + + if (!hasListeners(this._emitter)) + { + this._cancelIfNeeded(); + } + + return this; +}; + +/** + * Starts the ticker. If the ticker has listeners + * a new animation frame is requested at this point. + */ +Ticker.prototype.start = function start() +{ + if (!this.started) + { + this.started = true; + this._requestIfNeeded(); + } +}; + +/** + * Stops the ticker. If the ticker has requested + * an animation frame it is canceled at this point. + */ +Ticker.prototype.stop = function stop() +{ + if (this.started) + { + this.started = false; + this._cancelIfNeeded(); + } +}; + +/** + * Triggers an update, setting deltaTime, lastTime, and + * firing the internal 'tick' event invoking all listeners. + * + * @param [currentTime=performance.now()] {number} the current time of execution + */ +Ticker.prototype.update = function update(currentTime) +{ + var elapsedMS; + + // Allow calling update directly with default currentTime. + currentTime = currentTime || performance.now(); + elapsedMS = currentTime - this.lastTime; + + // cap the milliseconds elapsed + if (elapsedMS > this._maxElapsedMS) + { + elapsedMS = this._maxElapsedMS; + } + + this.deltaTime = (elapsedMS * core.TARGET_FPMS); + // Factor in speed + this.deltaTime *= this.speed; + + // Invoke listeners added to internal emitter + this._emitter.emit(TICK, this.deltaTime); + + this.lastTime = currentTime; +}; + +module.exports = Ticker; diff --git a/src/ticker/index.js b/src/ticker/index.js new file mode 100644 index 0000000..448b323 --- /dev/null +++ b/src/ticker/index.js @@ -0,0 +1,24 @@ +/** + * @file Main export of the PIXI extras library + * @author Mat Groves + * @copyright 2013-2015 GoodBoyDigital + * @license {@link https://github.com/GoodBoyDigital/pixi.js/blob/master/LICENSE|MIT License} + */ +var Ticker = require('./Ticker'); + +/** + * The shared ticker instance used by {@link PIXI.extras.MovieClip}. + * and by {@link PIXI.interaction.InteractionManager}. + * The property {@link PIXI.ticker.Ticker#autoStart} is set to true + * for this instance. + * + * @type {PIXI.ticker.Ticker} + * @memberof PIXI.ticker + */ +var shared = new Ticker(); +shared.autoStart = true; + +module.exports = { + shared: shared, + Ticker: Ticker +};