1 /**
  2  * The MIT License (MIT)
  3  *
  4  * Copyright (c) 2016 DeNA Co., Ltd.
  5  *
  6  * Permission is hereby granted, free of charge, to any person obtaining a copy
  7  * of this software and associated documentation files (the "Software"), to deal
  8  * in the Software without restriction, including without limitation the rights
  9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 10  * copies of the Software, and to permit persons to whom the Software is
 11  * furnished to do so, subject to the following conditions:
 12  *
 13  * The above copyright notice and this permission notice shall be included in
 14  * all copies or substantial portions of the Software.
 15  *
 16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 22  * SOFTWARE.
 23  */
 24 
 25 /// <reference path="base.js"/>
 26 /// <reference path="event_dispatcher.js"/>
 27 /// <reference path="tick_event.js"/>
 28 /// <reference path="tick_listener.js"/>
 29 /// <reference path="object_list.js"/>
 30 /// <reference path="user_agent.js"/>
 31 
 32 /**
 33  * A singleton class that provides a tick.
 34  * @extends {createjs.EventDispatcher}
 35  * @constructor
 36  */
 37 createjs.Ticker = function() {
 38   createjs.EventDispatcher.call(this);
 39 };
 40 createjs.inherits('Ticker', createjs.Ticker, createjs.EventDispatcher);
 41 
 42 /**
 43  * The global instance of the createjs.Ticker object.
 44  * @type {createjs.Ticker}
 45  * @private
 46  */
 47 createjs.Ticker.instance_ = null;
 48 
 49 /**
 50  * Represents the mode that the Ticker object uses the requestAnimationFrame API
 51  * with synchronization to the target frame-rate.
 52  * @const {string}
 53  */
 54 createjs.Ticker.RAF_SYNCHED = 'synched';
 55 
 56 /**
 57  * Represents the mode that the Ticker object uses the requestAnimationFrame API
 58  * without synchronization to the target frame-rate.
 59  * @const {string}
 60  */
 61 createjs.Ticker.RAF = 'raf';
 62 
 63 /**
 64  * The mode representing the Ticker object uses the setTimeout API.
 65  * @const {string}
 66  */
 67 createjs.Ticker.TIMEOUT = 'timeout';
 68 
 69 /**
 70  * The mode representing the Ticker object chooses the best API for it.
 71  * @const {string}
 72  */
 73 createjs.Ticker.AUTO = 'auto';
 74 
 75 /**
 76  * The requestAnimationFrame() method used by the createjs.Ticker object.
 77  * @const {Function}
 78  */
 79 createjs.Ticker.requestAnimationFrame =
 80     createjs.global['requestAnimationFrame'] ||
 81     createjs.global['webkitRequestAnimationFrame'];
 82 
 83 /** 
 84  * The cancelAnimationFrame() method used by the createjs.Ticker object.
 85  * @const {Function}
 86  */
 87 createjs.Ticker.cancelAnimationFrame =
 88     createjs.global['cancelAnimationFrame'] ||
 89     createjs.global['webkitCancelAnimationFrame'];
 90 
 91 /**
 92  * The maximum number of times to measure animation intervals.
 93  * @const {number}
 94  */
 95 createjs.Ticker.RETRY = 10;
 96 
 97 /** 
 98  * Whether this ticker is not running now.
 99  * @type {boolean}
100  * @protected
101  */
102 createjs.Ticker.prototype.paused_ = false;
103 
104 /**
105  * Whether this ticker has been initialized. (This does not mean the ticker is
106  * currently running or not.)
107  * @type {boolean}
108  * @protected
109  */
110 createjs.Ticker.prototype.initialized_ = false;
111 
112 /**
113  * The time when this ticker starts dispatching tick events.
114  * @type {number}
115  * @protected
116  */
117 createjs.Ticker.prototype.startTime_ = 0;
118 
119 /**
120  * The total period of time that this ticker stops dispatching tick events.
121  * @type {number}
122  * @protected
123  */
124 createjs.Ticker.prototype.pausedTime_ = 0;
125 
126 /**
127  * The interrupt interval for calling the 'tick_()' method repeatedly in
128  * milliseconds.
129  * @type {number}
130  * @protected
131  */
132 createjs.Ticker.prototype.interval_ = 50;
133 
134 /**
135  * The last time when this ticker has dispatched tick events.
136  * @type {number}
137  * @protected
138  */
139 createjs.Ticker.prototype.lastTime_ = 0;
140 
141 /**
142  * The list of times when this ticker has dispatched tick events.
143  * @type {createjs.Ticker.PerformanceCounter}
144  * @protected
145  */
146 createjs.Ticker.prototype.times_ = null;
147 
148 /**
149  * Stores the timeout or requestAnimationFrame id.
150  * @type {number}
151  * @protected
152  */
153 createjs.Ticker.prototype.timerId_ = 0;
154 
155 /**
156  * True if currently using requestAnimationFrame, false if using setTimeout.
157  * @type {boolean}
158  * @protected
159  */
160 createjs.Ticker.prototype.useRAF_ = false;
161 
162 /**
163  * The listeners which listens tick events. This ticker adds createjs.Stage
164  * objects and createjs.Tween objects to update them without dispatching 'tick'
165  * events. (There is some overhead for the createjs.EventDispatcher class to
166  * dispatch a 'tick' event.)
167  * @type {createjs.ObjectList}
168  * @private
169  */
170 createjs.Ticker.prototype.tickListeners_ = null;
171 
172 /**
173  * The 'tick' event used by this ticker.
174  * @type {createjs.TickEvent}
175  * @private
176  */
177 createjs.Ticker.prototype.tickEvent_ = null;
178 
179 /**
180  * The remaining number of times to measure animation intervals.
181  * @type {number}
182  * @private
183  */
184 createjs.Ticker.prototype.retry_ = createjs.Ticker.RETRY;
185 
186 /**
187  * The timestamp used in measuring the interval of the requestAnimationFrame()
188  * API.
189  * @type {number}
190  * @private
191  */
192 createjs.Ticker.prototype.timestamp_ = 0;
193 
194 /**
195  * A class that collects the specified number of values.
196  * @constructor
197  */
198 createjs.Ticker.PerformanceCounter = function() {
199   /**
200    * @type {number}
201    */
202   this.offset_ = 0;
203 
204   /**
205    * @type {Array.<number>}
206    */
207   this.values_ = [
208     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
209     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
211     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
212   ];
213 };
214 
215 /**
216  * @const {number}
217  * @private
218  */
219 createjs.Ticker.PerformanceCounter.SIZE = 64;
220  
221 /**
222  * @const {number}
223  * @private
224  */
225 createjs.Ticker.PerformanceCounter.MASK =
226     createjs.Ticker.PerformanceCounter.SIZE - 1;
227 
228 
229 /**
230  * Adds a value to this object.
231  * @param {number} value
232  */
233 createjs.Ticker.PerformanceCounter.prototype.addValue = function(value) {
234   /// <param type="number" name="value"/>
235   var offset = this.offset_ & createjs.Ticker.PerformanceCounter.MASK;
236   this.values_[offset] = value;
237   ++this.offset_;
238 };
239 
240 /**
241  * Returns the average of the values stored in this object.
242  * @return {number}
243  */
244 createjs.Ticker.PerformanceCounter.prototype.getAverage = function() {
245   /// <returns type="number"/>
246   if (!this.offset_) {
247     return 0;
248   }
249   var total = 0;
250   var size = createjs.min(this.offset_,
251                           createjs.Ticker.PerformanceCounter.SIZE);
252   for (var i = 0; i < size; ++i) {
253     total += this.values_[i]
254   }
255   return total / size;
256 };
257 
258 /**
259  * Returns the frames per second.
260  * @return {number}
261  */
262 createjs.Ticker.PerformanceCounter.prototype.getFPS = function() {
263   /// <returns type="number"/>
264   var size = createjs.min(this.offset_,
265                           createjs.Ticker.PerformanceCounter.SIZE);
266   var head = (this.offset_ - size) & createjs.Ticker.PerformanceCounter.MASK;
267   var tail = (this.offset_ - 1) & createjs.Ticker.PerformanceCounter.MASK;
268   return 1000 * size / (this.values_[tail] - this.values_[head]);
269 };
270 
271 /**
272  * Returns the instance of the createjs.Ticker object.
273  * @return {createjs.Ticker}
274  */
275 createjs.Ticker.getInstance_ = function() {
276   /// <returns type="createjs.Ticker"/>
277   if (!createjs.Ticker.instance_) {
278     createjs.Ticker.instance_ = new createjs.Ticker();
279   }
280   return createjs.Ticker.instance_;
281 };
282 
283 /**
284  * Returns the instance of the createjs.Ticker object.
285  * @param {number} delta
286  * @param {boolean} paused
287  * @param {number} time
288  * @param {number} runTime
289  * @return {createjs.TickEvent}
290  */
291 createjs.Ticker.getEvent_ = function(delta, paused, time, runTime) {
292   /// <param type="number" name="delta"/>
293   /// <param type="boolean" name="paused"/>
294   /// <param type="number" name="time"/>
295   /// <param type="number" name="runTime"/>
296   /// <returns type="createjs.TickEvent"/>
297   var ticker = createjs.Ticker.getInstance_();
298   if (!ticker.tickEvent_) {
299     ticker.tickEvent_ = new createjs.TickEvent(
300         'tick', false, false, delta, paused, time, runTime);
301   } else {
302     ticker.tickEvent_.reset(delta, paused, time, runTime);
303   }
304   return ticker.tickEvent_;
305 };
306 
307 /**
308  * Called when the browser sends a system tick event. This method is called
309  * either by a requestAnimationFrame() callback or by a setTimeout() callback.
310  * @param {number} timestamp
311  * @private
312  */
313 createjs.Ticker.tick_ = function(timestamp) {
314   /// <param type="number" name="timestamp"/>
315   var ticker = createjs.Ticker.getInstance_();
316   if (!ticker.startTime_) {
317     ticker.startTime_ = timestamp;
318   }
319   var elapsedTime = timestamp - ticker.lastTime_;
320   ticker.lastTime_ = timestamp;
321   var paused = ticker.paused_;
322   if (paused) {
323     ticker.pausedTime_ += elapsedTime;
324   } else {
325     var time = timestamp - ticker.startTime_;
326     var runTime = time - ticker.pausedTime_;
327     var tickListeners = ticker.tickListeners_;
328     if (tickListeners) {
329       var listeners = ticker.tickListeners_.lock();
330       for (var i = 0; i < listeners.length; ++i) {
331         var listener = /** @type {createjs.TickListener} */ (listeners[i]);
332         listener.handleTick(runTime);
333       }
334       tickListeners.unlock();
335     }
336     if (ticker.hasListener('tick')) {
337       var event = createjs.Ticker.getEvent_(elapsedTime, paused, time, runTime);
338       ticker.dispatchRawEvent(event);
339     }
340   }
341 
342   if (!ticker.times_) {
343     ticker.times_ = new createjs.Ticker.PerformanceCounter();
344   }
345   ticker.times_.addValue(timestamp);
346 };
347 
348 /**
349  * A callback function for the window.requestAnimationFrame() method. This
350  * function sends a tick event only when it takes at least |ticker.internal_|
351  * milliseconds since the last time when it sends the event.
352  * @param {number} timestamp
353  * @private
354  */
355 createjs.Ticker.handleSynchronizedRAF_ = function(timestamp) {
356   /// <param type="number" name="timestamp"/>
357   var ticker = createjs.Ticker.getInstance_();
358   ticker.timerId_ = createjs.Ticker.requestAnimationFrame.call(
359       createjs.global, createjs.Ticker.handleSynchronizedRAF_);
360   var elapsed = timestamp - ticker.lastTime_;
361   // Some browsers truncates the given timestamp to ms (e.g. 33.3 ms -> 33 ms)
362   // and it prevents calling the 'tick_()' method at its expected frequency if
363   // the interval is not an integer. To work around such truncated timestamps,
364   // this method compares with 'ticker.interval_ - 1' instead of comparing with
365   // 'ticker.interval_'.
366   if (elapsed >= ticker.interval_ - 1) {
367     createjs.Ticker.tick_(timestamp);
368   }
369 };
370 
371 /**
372  * A callback function for the window.setInterval() method.
373  * @private
374  */
375 createjs.Ticker.handleInterval_ = function() {
376   var ticker = createjs.Ticker.getInstance_();
377   var timestamp = Date.now();
378   createjs.Ticker.tick_(timestamp);
379 };
380 
381 /**
382  * Stops the global ticker.
383  * @param {createjs.Ticker} ticker
384  * @private
385  */
386 createjs.Ticker.stopTick_ = function(ticker) {
387   /// <param type="createjs.Ticker" name="ticker"/>
388   if (ticker.timerId_) {
389     if (ticker.useRAF_) {
390       if (createjs.Ticker.cancelAnimationFrame) {
391         createjs.Ticker.cancelAnimationFrame.call(
392             createjs.global, ticker.timerId_);
393       }
394     } else {
395       createjs.global.clearInterval(ticker.timerId_);
396     }
397     ticker.timerId_ = 0;
398   }
399 };
400 
401 /**
402  * Starts the global ticker.
403  * @private
404  */
405 createjs.Ticker.setupTick_ = function() {
406   var ticker = createjs.Ticker.getInstance_();
407   createjs.Ticker.stopTick_(ticker);
408   // There are lots of browser issues and it is not so trivial to choose a tick
409   // method for a game to render its frames at 60 fps as listed in the following
410   // table.
411   //   +---------+------------------------+---------+---------+
412   //   | Browser | OS                     | timeout | synched |
413   //   +---------+------------------------+---------+---------+
414   //   | WebView | Android 4.0 or 4.1     | OK      | N/A     |
415   //   |         | Android 4.2            | (3)     | OK      |
416   //   |         | Android 4.3            | OK      | OK      |
417   //   |         | Android 4.4 or later   | OK      | (1)     |
418   //   +---------+------------------------+---------+---------+
419   //   | Chrome  | Android                | OK      | (1)     |
420   //   |         | Win                    | (2)     | OK      |
421   //   |         | Mac                    | (2)     | OK      |
422   //   +---------+------------------------+---------+---------+
423   //   | Safari  | iOS                    | OK      | OK      |
424   //   |         | Mac                    | OK      | OK      |
425   //   +---------+------------------------+---------+---------+
426   //   | IE11    | Win                    | OK      | OK      |
427   //   +---------+------------------------+---------+---------+
428   //   | Edge    | Win                    | OK      | OK      |
429   //   +---------+------------------------+---------+---------+
430   // (1) The requestAnimationFrame() method does not guarantee calling its
431   //     callbacks at 60 fps.
432   // (2) Chrome skips frames rendered by setInterval() callbacks
433   //     <http://crbug.com/436021>.
434   // (3) An eval() call clears setInterval() callbacks on Android 4.2
435   //     <http://stackoverflow.com/questions/17617608>.
436   var mode = /** @type {string} */ (createjs.Ticker.exports['timingMode']);
437   if (mode != createjs.Ticker.TIMEOUT) {
438     if (createjs.Ticker.requestAnimationFrame) {
439       var callback = createjs.Ticker.handleSynchronizedRAF_;
440       ticker.timerId_ =
441           createjs.Ticker.requestAnimationFrame.call(createjs.global, callback);
442       ticker.useRAF_ = true;
443       return;
444     }
445   }
446   ticker.useRAF_ = false;
447   ticker.timerId_ = createjs.global.setInterval(
448       createjs.Ticker.handleInterval_,
449       ticker.interval_);
450 };
451 
452 /**
453  * Stops the global ticker and removes all listeners.
454  * @param {boolean=} opt_destroy
455  */
456 createjs.Ticker.reset = function(opt_destroy) {
457   /// <param type="boolean" optional="true" name="opt_destroy"/>
458   var ticker = createjs.Ticker.getInstance_();
459   ticker.removeAllListeners();
460   ticker.tickListeners_ = null;
461   if (opt_destroy) {
462     createjs.Ticker.stopTick_(ticker);
463   }
464 };
465   
466 /**
467  * Kicks the global ticker. This method explicitly calls the setInterval()
468  * callback added by the ticker if it uses the setInterval() method. (This is a
469  * workaround for Android Chrome, which does not call setInterval() callbacks
470  * while it dispatches touch events.)
471  */
472 createjs.Ticker.kick = function() {
473   var ticker = createjs.Ticker.getInstance_();
474   if (!ticker.useRAF_ && ticker.timerId_) {
475     var timestamp = Date.now();
476     var elapsed = timestamp - ticker.lastTime_;
477     if (elapsed >= ticker.interval_ - 1) {
478       createjs.Ticker.tick_(timestamp);
479     }
480   }
481 };
482 
483 /**
484  * Sets the tick interval (in milliseconds).
485  * @param {number} interval
486  */
487 createjs.Ticker.setInterval = function(interval) {
488   /// <param type="number" name="value"/>
489   var ticker = createjs.Ticker.getInstance_();
490   ticker.interval_ = interval;
491   if (ticker.initialized_) {
492     createjs.Ticker.setupTick_();
493   }
494 };
495 
496 /**
497  * Returns the current tick interval.
498  * @return {number}
499  */
500 createjs.Ticker.getInterval = function() {
501   /// <returns type="number"/>
502   var ticker = createjs.Ticker.getInstance_();
503   return ticker.interval_;
504 };
505 
506 /**
507  * Sets the target frame-rate in frames per second (FPS).
508  * @param {number} value
509  * @param {boolean=} opt_noClip
510  */
511 createjs.Ticker.setFPS = function(value, opt_noClip) {
512   /// <param type="number" name="value"/>
513   /// <param type="number" optional="true" name="opt_noClip"/>
514   // Round up the input FPS so it becomes a divisor of 60.
515   value = 60 / createjs.truncate(60 / value);
516   createjs.Ticker.setInterval(createjs.truncate(1000 / value));
517 };
518 
519 /**
520  * Returns the target frame-rate in frames per second (FPS).
521  * @return {number}
522  */
523 createjs.Ticker.getFPS = function() {
524   /// <returns type="number"/>
525   var ticker = createjs.Ticker.getInstance_();
526   return 1000 / ticker.interval_;
527 };
528 
529 /**
530  * Returns the time elapsed since the last tick in frames.
531  * @return {number}
532  */
533 createjs.Ticker.getFrames = function() {
534   /// <returns type="number"/>
535   return 1;
536 };
537 
538 /**
539  * Returns the average time spent within a tick.
540  * @param {number=} opt_ticks
541  * @return {number}
542  */
543 createjs.Ticker.getMeasuredTickTime = function(opt_ticks) {
544   /// <param type="number" optional="true" name="opt_ticks"/>
545   /// <returns type="number"/>
546   return 0;
547 };
548 
549 /**
550  * Returns the actual frames per second.
551  * @param {number=} opt_ticks
552  * @return {number}
553  */
554 createjs.Ticker.getMeasuredFPS = function(opt_ticks) {
555   /// <param type="number" optional="true" name="opt_ticks"/>
556   /// <returns type="number"/>
557   var ticker = createjs.Ticker.getInstance_();
558   return ticker.times_.getFPS();
559 };
560 
561 /**
562  * Starts the Ticker object or stops it.
563  * @param {boolean} value
564  */
565 createjs.Ticker.setPaused = function(value) {
566   /// <param type="boolean" name="value"/>
567   var ticker = createjs.Ticker.getInstance_();
568   ticker.paused_ = value;
569 };
570 
571 /**
572  * Returns whether the Ticker object is paused.
573  * @return {boolean}
574  */
575 createjs.Ticker.getPaused = function() {
576   /// <returns type="boolean"/>
577   var ticker = createjs.Ticker.getInstance_();
578   return ticker.paused_;
579 };
580 
581 /**
582  * Returns the last time when this object dispatches a tick event.
583  * @return {number}
584  */
585 createjs.Ticker.getRunTime = function() {
586   /// <returns type="number"/>
587   var ticker = createjs.Ticker.getInstance_();
588   return ticker.lastTime_ - ticker.startTime_ - ticker.pausedTime_;
589 };
590 
591 /**
592  * Returns the last tick time.
593  * @param {boolean=} opt_runTime
594  * @returns {number}
595  */
596 createjs.Ticker.getEventTime = function(opt_runTime) {
597   /// <param type="boolean" optional="true" name="opt_runTime"/>
598   /// <returns type="number"/>
599   var ticker = createjs.Ticker.getInstance_();
600   var time = ticker.lastTime_;
601   if (!!opt_runTime) {
602     time -= ticker.pausedTime_;
603   }
604   return time;
605 };
606   
607 /**
608  * Returns the number of ticks that have been broadcast by Ticker.
609  * @param {boolean} pauseable
610  * @return {number}
611  */
612 createjs.Ticker.getTicks = function(pauseable) {
613   /// <param type="boolean" name="pausable"/>
614   /// <returns type="number"/>
615   return 0;
616 };
617 
618 /**
619  * Adds an event listener.
620  * @param {string} type
621  * @param {Function|Object} listener
622  * @param {boolean=} opt_useCapture
623  * @return {Function|Object}
624  */
625 createjs.Ticker.addListener = function(type, listener, opt_useCapture) {
626   /// <param type="string" name="type"/>
627   /// <param type="Function" name="listener"/>
628   /// <param type="boolean" optional="true" name="opt_useCapture"/>
629   /// <returns type="Function"/>
630   createjs.assert(type == 'tick');
631   var ticker = createjs.Ticker.getInstance_();
632   if (!ticker.initialized_) {
633     ticker.initialized_ = true;
634     createjs.Ticker.setupTick_();
635   }
636   if (listener.handleTick) {
637     if (!ticker.tickListeners_) {
638       ticker.tickListeners_ = new createjs.ObjectList();
639     }
640     ticker.tickListeners_.pushUniqueItem(listener);
641     return listener;
642   }
643   return ticker.on(type, listener);
644 };
645 
646 /**
647  * Removes the specified event listener.
648  * @param {string} type
649  * @param {Function|Object} listener
650  * @param {boolean=} opt_useCapture
651  */
652 createjs.Ticker.removeListener = function(type, listener, opt_useCapture) {
653   /// <param type="string" name="type"/>
654   /// <param type="Function" name="listener"/>
655   /// <param type="boolean" optional="true" name="opt_useCapture"/>
656   createjs.assert(type == 'tick');
657   if (!listener) {
658     return;
659   }
660   var ticker = createjs.Ticker.getInstance_();
661   if (listener.handleTick) {
662     var listeners = ticker.tickListeners_;
663     if (listeners) {
664       listeners.removeItem(listener);
665     }
666     return;
667   }
668   ticker.off(type, listener);
669 };
670 
671 /**
672  * Removes all listeners for the specified type, or all listeners of all types.
673  * @param {string=} opt_type
674  */
675 createjs.Ticker.removeAllListeners = function(opt_type) {
676   /// <param type="string" optional="true" name="type"/>
677   createjs.assert(opt_type == null || opt_type == 'tick');
678   var ticker = createjs.Ticker.getInstance_();
679   var listeners = ticker.tickListeners_;
680   if (listeners) {
681     listeners.removeAllItems();
682   }
683   ticker.removeAllListeners(opt_type || '');
684 };
685 
686 /**
687  * Dispatches the specified event to all listeners.
688  * @param {Object|string|Event} event
689  * @param {Object=} opt_target
690  * @return {boolean}
691  */
692 createjs.Ticker.dispatch = function(event, opt_target) {
693   /// <param name="event"/>
694   /// <param type="Object" optional="true" name="opt_target"/>
695   /// <returns type="boolean"/>
696   var ticker = createjs.Ticker.getInstance_();
697   return ticker.dispatch(event, opt_target || null);
698 };
699 
700 /**
701  * Returns whether there is at least one listener for the specified event type.
702  * @param {string} type
703  * @return {boolean}
704  */
705 createjs.Ticker.hasListener = function(type) {
706   /// <param name="event"/>
707   /// <returns type="boolean"/>
708   createjs.assert(type == 'tick');
709   var ticker = createjs.Ticker.getInstance_();
710   return ticker.hasListener(type);
711 };
712 
713 /**
714  * A table of exported functions.
715  * @type {Object.<string,Function|string>}
716  * @const
717  */
718 createjs.Ticker.exports = createjs.exportStatic('createjs.Ticker', {
719   'reset': createjs.Ticker.reset,
720   'setInterval': createjs.Ticker.setInterval,
721   'getInterval': createjs.Ticker.getInterval,
722   'setFPS': createjs.Ticker.setFPS,
723   'getFPS': createjs.Ticker.getFPS,
724   'getMeasuredTickTime': createjs.Ticker.getMeasuredTickTime,
725   'getMeasuredFPS': createjs.Ticker.getMeasuredFPS,
726   'setPaused': createjs.Ticker.setPaused,
727   'getPaused': createjs.Ticker.getPaused,
728   'getTime': createjs.Ticker.getEventTime,
729   'getEventTime': createjs.Ticker.getEventTime,
730   'getTicks': createjs.Ticker.getTicks,
731   'addEventListener': createjs.Ticker.addListener,
732   'removeEventListener': createjs.Ticker.removeListener,
733   'removeAllEventListeners': createjs.Ticker.removeAllListeners,
734   'dispatchEvent': createjs.Ticker.dispatch,
735   'hasEventListener': createjs.Ticker.hasListener,
736   'timingMode': createjs.Ticker.RAF_SYNCHED
737 });
738