1 /**
  2  * Hilo
  3  * Copyright 2015 alibaba.com
  4  * Licensed under the MIT License
  5  */
  6 
  7 /**
  8  * @language=en
  9  * @class Ticker is a Timer. It can run the code at specified framerate.
 10  * @param {Number} fps The fps of ticker.
 11  * @module hilo/util/Ticker
 12  * @requires hilo/core/Class
 13  * @requires hilo/core/Hilo
 14  */
 15 var Ticker = Class.create(/** @lends Ticker.prototype */{
 16     constructor: function(fps){
 17         this._targetFPS = fps || 30;
 18         this._interval = 1000 / this._targetFPS;
 19         this._tickers = [];
 20     },
 21 
 22     _paused: false,
 23     _targetFPS: 0,
 24     _interval: 0,
 25     _intervalId: null,
 26     _tickers: null,
 27     _lastTime: 0,
 28     _tickCount: 0,
 29     _tickTime: 0,
 30     _measuredFPS: 0,
 31 
 32     /**
 33      * @language=en
 34      * Start the ticker.
 35      * @param {Boolean} userRAF Whether or not use requestAnimationFrame, default is not.
 36      */
 37     start: function(useRAF){
 38         if(this._intervalId) return;
 39         this._lastTime = +new Date();
 40 
 41         var self = this, interval = this._interval,
 42             raf = window.requestAnimationFrame ||
 43                   window[Hilo.browser.jsVendor + 'RequestAnimationFrame'];
 44 
 45         if(useRAF && raf){
 46             var tick = function(){
 47                 self._tick();
 48             }
 49             var runLoop = function(){
 50                 self._intervalId = setTimeout(runLoop, interval);
 51                 raf(tick);
 52             };
 53         }else{
 54             runLoop = function(){
 55                 self._intervalId = setTimeout(runLoop, interval);
 56                 self._tick();
 57             };
 58         }
 59 
 60         runLoop();
 61     },
 62 
 63     /**
 64      * @language=en
 65      * Stop the ticker.
 66      */
 67     stop: function(){
 68         clearTimeout(this._intervalId);
 69         this._intervalId = null;
 70         this._lastTime = 0;
 71     },
 72 
 73     /**
 74      * @language=en
 75      * Pause the ticker.
 76      */
 77     pause: function(){
 78         this._paused = true;
 79     },
 80 
 81     /**
 82      * @language=en
 83      * Resume the ticker.
 84      */
 85     resume: function(){
 86         this._paused = false;
 87     },
 88 
 89     /**
 90      * @private
 91      */
 92     _tick: function(){
 93         if(this._paused) return;
 94         var startTime = +new Date(),
 95             deltaTime = startTime - this._lastTime,
 96             tickers = this._tickers;
 97 
 98         //calculates the real fps
 99         if(++this._tickCount >= this._targetFPS){
100             this._measuredFPS = 1000 / (this._tickTime / this._tickCount) + 0.5 >> 0;
101             this._tickCount = 0;
102             this._tickTime = 0;
103         }else{
104             this._tickTime += startTime - this._lastTime;
105         }
106         this._lastTime = startTime;
107 
108         for(var i = 0, len = tickers.length; i < len; i++){
109             tickers[i].tick(deltaTime);
110         }
111     },
112 
113     /**
114      * @language=en
115      * Get the fps.
116      */
117     getMeasuredFPS: function(){
118         return this._measuredFPS;
119     },
120 
121     /**
122      * @language=en
123      * Add tickObject. The tickObject must implement the tick method.
124      * @param {Object} tickObject The tickObject to add.It must implement the tick method.
125      */
126     addTick: function(tickObject){
127         if(!tickObject || typeof(tickObject.tick) != 'function'){
128             throw new Error('Ticker: The tick object must implement the tick method.');
129         }
130         this._tickers.push(tickObject);
131     },
132 
133     /**
134      * @language=en
135      * Remove the tickObject
136      * @param {Object} tickObject The tickObject to remove.
137      */
138     removeTick: function(tickObject){
139         var tickers = this._tickers,
140             index = tickers.indexOf(tickObject);
141         if(index >= 0){
142             tickers.splice(index, 1);
143         }
144     }
145 
146 });