1 
  2 /**
  3  * @class Ticker是一个定时器类。它可以按指定帧率重复运行,从而按计划执行代码。
  4  * @param {Number} fps 指定定时器的运行帧率。
  5  * @module hilo/util/Ticker
  6  * @requires hilo/core/Class
  7  * @requires hilo/core/Hilo
  8  */
  9 var Ticker = Class.create(/** @lends Ticker.prototype */{
 10     constructor: function Ticker(fps){
 11         this._targetFPS = fps || 30;
 12         this._interval = 1000 / this._targetFPS;
 13         this._tickers = [];
 14     },
 15 
 16     _paused: false,
 17     _targetFPS: 0,
 18     _interval: 0,
 19     _intervalId: null,
 20     _tickers: null,
 21     _lastTime: 0,
 22     _tickCount: 0,
 23     _tickTime: 0,
 24     _measuredFPS: 0,
 25 
 26     /**
 27      * 启动定时器。
 28      * @param {Boolean} userRAF 是否使用requestAnimationFrame,默认为false。
 29      */
 30     start: function(useRAF){
 31         if(this._intervalId) return;
 32         this._lastTime = +new Date();
 33 
 34         var self = this, interval = this._interval,
 35             raf = window.requestAnimationFrame || 
 36                   window[Hilo.browser.jsVendor + 'RequestAnimationFrame'];
 37         
 38         if(useRAF && raf){
 39             var tick = function(){
 40                 self._tick();
 41             }
 42             var runLoop = function(){
 43                 self._intervalId = setTimeout(runLoop, interval);
 44                 raf(tick);
 45             };
 46         }else{
 47             runLoop = function(){
 48                 self._intervalId = setTimeout(runLoop, interval);
 49                 self._tick();
 50             };
 51         }
 52         
 53         runLoop();
 54     },
 55 
 56     /**
 57      * 停止定时器。
 58      */
 59     stop: function(){
 60         clearTimeout(this._intervalId);
 61         this._intervalId = null;
 62         this._lastTime = 0;
 63     },
 64 
 65     /**
 66      * 暂停定时器。
 67      */
 68     pause: function(){
 69         this._paused = true;
 70     },
 71 
 72     /**
 73      * 恢复定时器。
 74      */
 75     resume: function(){
 76         this._paused = false;
 77     },
 78 
 79     /**
 80      * @private
 81      */
 82     _tick: function(){
 83         if(this._paused) return;
 84         var startTime = +new Date(),
 85             deltaTime = startTime - this._lastTime,
 86             tickers = this._tickers;
 87 
 88         for(var i = 0, len = tickers.length; i < len; i++){
 89             tickers[i].tick(deltaTime);
 90         }
 91 
 92         //calculates the real fps
 93         var endTime = +new Date();
 94         if(++this._tickCount >= this._targetFPS){
 95             this._measuredFPS = 1000 / (this._tickTime / this._tickCount) + 0.5 >> 0;
 96             this._tickCount = 0;
 97             this._tickTime = 0;
 98         }else{
 99             this._tickTime += endTime - this._lastTime;
100         }
101         this._lastTime = endTime;
102     },
103 
104     /**
105      * 获得测定的运行时帧率。
106      */
107     getMeasuredFPS: function(){
108         return this._measuredFPS;
109     },
110 
111     /**
112      * 添加定时器对象。定时器对象必须实现 tick 方法。
113      * @param {Object} tickObject 要添加的定时器对象。此对象必须包含 tick 方法。
114      */
115     addTick: function(tickObject){
116         if(!tickObject || typeof(tickObject.tick) != 'function'){
117             throw new Error('Ticker: The tick object must implement the tick method.');
118         }
119         this._tickers.push(tickObject);
120     },
121 
122     /**
123      * 删除定时器对象。
124      * @param {Object} tickObject 要删除的定时器对象。
125      */
126     removeTick: function(tickObject){
127         var tickers = this._tickers,
128             index = tickers.indexOf(tickObject);
129         if(index >= 0){
130             tickers.splice(index, 1);
131         }
132     }
133 
134 });