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="tween_object.js"/>
 28 /// <reference path="tick_listener.js"/>
 29 /// <reference path="ticker.js"/>
 30 
 31 /**
 32  * A class that contains multiple createjs.Tween objects and updates them
 33  * synchronously.
 34  * @param {Array.<createjs.TweenObject>} tweens
 35  * @param {Object.<string,number>} labels
 36  * @param {Object.<string,boolean|number>=} opt_properties
 37  * @extends {createjs.EventDispatcher}
 38  * @implements {createjs.TickListener}
 39  * @constructor
 40  */
 41 createjs.Timeline = function(tweens, labels, opt_properties) {
 42   createjs.EventDispatcher.call(this);
 43 
 44   if (createjs.DEBUG) {
 45     /**
 46      * An ID for this timeline.
 47      * @type {number}
 48      */
 49     this.id = createjs.Timeline.id_++;
 50   }
 51 
 52   /**
 53    * The tweens controlled by this timeline.
 54    * @type {Array.<createjs.TweenObject>}
 55    * @private
 56    */
 57   this.tweens_ = [];
 58 
 59   /**
 60    * A mapping table from a label name to its position.
 61    * @type {Object.<string,number>}
 62    * @private
 63    */
 64   this.labels_ = labels;
 65 
 66   if (opt_properties) {
 67     this.loop_ = !!opt_properties['loop'];
 68     this.paused_ = !!opt_properties['paused'];
 69     this.position_ = /** @type {number} */ (opt_properties['position']) || -1;
 70   }
 71   this.addTweens_(tweens, tweens.length);
 72 
 73   // Over-write the 'paused_' property to force the 'setPaused()' method to
 74   // start this tween if an application likes to start it now. The 'setPaused()'
 75   // method starts this timeline or stops it only when its state has been
 76   // changed from the current one.
 77   if (!this.paused_) {
 78     this.paused_ = true;
 79     this.setPaused(false);
 80   }
 81 };
 82 createjs.inherits('Timeline', createjs.Timeline, createjs.EventDispatcher);
 83 
 84 if (createjs.DEBUG) {
 85   /**
 86    * IDs assigned to timelines.
 87    * @type {number}
 88    */
 89   createjs.Timeline.id_ = 0;
 90 }
 91 
 92 /**
 93  * The total duration of this timeline in milliseconds (or ticks).
 94  * @type {number}
 95  */
 96 createjs.Timeline.prototype['duration'] = 0;
 97 
 98 /**
 99  * Whether this timeline loops when it reaches its end.
100  * @type {boolean}
101  * @private
102  */
103 createjs.Timeline.prototype.loop_ = false;
104 
105 /**
106  * Whether this timeline is playing its tweens.
107  * @type {boolean}
108  * @private
109  */
110 createjs.Timeline.prototype.paused_ = false;
111 
112 /**
113  * Adds an array tweens to this timeline.
114  * @param {Array.<createjs.TweenObject>} tweens
115  * @param {number} length
116  * @private
117  */
118 createjs.Timeline.prototype.addTweens_ = function(tweens, length) {
119   var targets = [];
120   for (var i = 0; i < length; ++i) {
121     var tween = tweens[i];
122     for (var j = 0; j < this.tweens_.length; ++j) {
123       if (tween === this.tweens_[j]) {
124         tween = null;
125         break;
126       }
127     }
128     if (tween) {
129       var duration = tween.setProxy(null, targets);
130       if (this['duration'] < duration) {
131         this['duration'] = duration;
132       }
133       tween.setProperties(this.loop_, this.position_, false);
134       this.tweens_.push(tween);
135     }
136   }
137 };
138 
139 /**
140  * Adds one or more tweens to this timeline.
141  * @param {...createjs.TweenObject} var_args
142  * @return {createjs.TweenObject}
143  * @const
144  */
145 createjs.Timeline.prototype.addTween = function(var_args) {
146   /// <param type="createjs.TweenObject" name="var_args"/>
147   /// <returns type="createjs.TweenObject"/>
148   var args = arguments;
149   var length = args.length;
150   createjs.assert(length > 0);
151   this.addTweens_(
152       /** @type {Array.<createjs.TweenObject>} */ (/** @type {*} */ (args)),
153       length);
154   return args[0];
155 };
156 
157 /**
158  * Removes one or more tweens from this timeline.
159  * @param {...createjs.TweenObject} var_args
160  * @return {boolean}
161  * @const
162  */
163 createjs.Timeline.prototype.removeTween = function(var_args) {
164   /// <param type="createjs.TweenObject" name="var_args"/>
165   /// <returns type="boolean"/>
166   createjs.notImplemented();
167   return false;
168 };
169 
170 /**
171  * Adds a label that can be used with the gotoAndPlay() method.
172  * @param {string} label
173  * @param {number} position
174  * @const
175  */
176 createjs.Timeline.prototype.addLabel = function(label, position) {
177   /// <param type="string" name="label"/>
178   /// <param type="number" name="position"/>
179   createjs.notImplemented();
180   this.labels_[label] = position;
181 };
182 
183 /**
184  * Sets labels for this timeline.
185  * @param {Object.<string,number>=} opt_labels
186  * @const
187  */
188 createjs.Timeline.prototype.setLabels = function(opt_labels) {
189   /// <param type="Object" name="labels"/>
190   createjs.notImplemented();
191 };
192 
193 /**
194  * Returns the sorted list of the labels added to this timeline.
195  * @return {Array.<createjs.MovieClip.Label>}
196  * @const
197  */
198 createjs.Timeline.prototype.getLabels = function() {
199   /// <returns type="Array" elementType="createjs.MovieClip.Label"/>
200   createjs.notImplemented();
201   return null;
202 };
203   
204 /**
205  * Returns the name of the label on or immediately before the current position.
206  * @return {string}
207  * @const
208  */
209 createjs.Timeline.prototype.getCurrentLabel = function() {
210   /// <returns type="string"/>
211   createjs.notImplemented();
212   return '';
213 };
214 
215 /**
216  * Pauses or plays this timeline.
217  * @param {boolean} value
218  * @const
219  */
220 createjs.Timeline.prototype.setPaused = function(value) {
221   /// <param type="boolean" name="value"/>
222   var paused = !!value;
223   if (this.paused_ == paused) {
224     return;
225   }
226   this.paused_ = paused;
227   var time = createjs.Ticker.getRunTime();
228   if (paused) {
229     for (var i = 0; i < this.tweens_.length; ++i) {
230       this.tweens_[i].stopTween(time);
231     }
232     createjs.Ticker.removeListener('tick', this);
233   } else {
234     for (var i = 0; i < this.tweens_.length; ++i) {
235       this.tweens_[i].playTween(time);
236     }
237     createjs.Ticker.addListener('tick', this);
238   }
239 };
240 
241 /**
242  * Starts playing this timeline from the specified position.
243  * @param {string|number} value
244  */
245 createjs.Timeline.prototype.gotoAndPlay = function(value) {
246   /// <param name="value"/>
247   createjs.notImplemented();
248 };
249 
250 /**
251  * Stops playing this timeline and jumps to the specified position.
252  * @param {string|number} value
253  */
254 createjs.Timeline.prototype.gotoAndStop = function(value) {
255   /// <param name="value"/>
256   createjs.notImplemented();
257 };
258 
259 /** @override */
260 createjs.Timeline.prototype.handleTick = function(time) {
261   var playing = 0;
262   for (var i = 0; i < this.tweens_.length; ++i) {
263     var tween = this.tweens_[i];
264     tween.updateTween(time, createjs.TweenTarget.PlayMode.INDEPENDENT, -1);
265     playing |= tween.isEnded() ? 0 : 1;
266   }
267   if (!playing) {
268     createjs.Ticker.removeListener('tick', this);
269   }
270 };
271 
272 // Export the createjs.Timeline object to the global namespace.
273 createjs.exportObject('createjs.Timeline',
274                       createjs.Timeline, {
275   // createjs.Timeline methods.
276   'addTween': createjs.Timeline.prototype.addTween,
277   'removeTween': createjs.Timeline.prototype.removeTween,
278   'addLabel': createjs.Timeline.prototype.addLabel,
279   'setLabels': createjs.Timeline.prototype.setLabels,
280   'getLabels': createjs.Timeline.prototype.getLabels,
281   'getCurrentLabel': createjs.Timeline.prototype.getCurrentLabel,
282   'setPaused': createjs.Timeline.prototype.setPaused,
283   'gotoAndPlay': createjs.Timeline.prototype.gotoAndPlay,
284   'gotoAndStop': createjs.Timeline.prototype.gotoAndStop
285 });
286