TweenCore.as
21.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
/**
* VERSION: 1.382
* DATE: 2010-05-25
* ACTIONSCRIPT VERSION: 3.0 (AS2 version is also available)
* UPDATES AND DOCUMENTATION AT: http://www.TweenLite.com
**/
package com.greensock.core {
import com.greensock.*;
/**
* TweenCore is the base class for all TweenLite, TweenMax, TimelineLite, and TimelineMax classes and
* provides core functionality and properties. There is no reason to use this class directly.<br /><br />
*
* <b>Copyright 2010, GreenSock. All rights reserved.</b> This work is subject to the terms in <a href="http://www.greensock.com/terms_of_use.html">http://www.greensock.com/terms_of_use.html</a> or for corporate Club GreenSock members, the software agreement that was issued with the corporate membership.
*
* @author Jack Doyle, jack@greensock.com
*/
public class TweenCore {
/** @private **/
public static const version:Number = 1.382;
/** @private **/
protected static var _classInitted:Boolean;
/** @private Delay in seconds (or frames for frames-based tweens/timelines) **/
protected var _delay:Number;
/** @private Has onUpdate. Tracking this as a Boolean value is faster than checking this.vars.onUpdate != null. **/
protected var _hasUpdate:Boolean;
/** @private Primarily used for zero-duration tweens to determine the direction/momentum of time which controls whether the starting or ending values should be rendered. For example, if a zero-duration tween renders and then its timeline reverses and goes back before the startTime, the zero-duration tween must render the starting values. Otherwise, if the render time is zero or later, it should always render the ending values. **/
protected var _rawPrevTime:Number = -1;
/** @private **/
protected var _pauseTime:Number;
/** Stores variables (things like alpha, y or whatever we're tweening as well as special properties like "onComplete"). **/
public var vars:Object;
/** @private The tween has begun and is now active **/
public var active:Boolean;
/** @private Flagged for garbage collection **/
public var gc:Boolean;
/** @private Indicates whether or not init() has been called (where all the tween property start/end value information is recorded) **/
public var initted:Boolean;
/** The parent timeline on which the tween/timeline is placed. By default, it uses the TweenLite.rootTimeline (or TweenLite.rootFramesTimeline for frames-based tweens/timelines). **/
public var timeline:SimpleTimeline;
/** @private Start time in seconds (or frames for frames-based tweens/timelines), according to its position on its parent timeline **/
public var cachedStartTime:Number;
/** @private The last rendered currentTime of this TweenCore. If a tween is going to repeat, its cachedTime will reset even though the cachedTotalTime continues linearly (or if it yoyos, the cachedTime may go forwards and backwards several times over the course of the tween). The cachedTime reflects the tween's "local" (which can never exceed the duration) time whereas the cachedTotalTime reflects the overall time. These will always match if the tween doesn't repeat/yoyo.**/
public var cachedTime:Number;
/** @private The last rendered totalTime of this TweenCore. It is prefaced with "cached" because using a public property like this is faster than using the getter which is essentially a function call. If you want to update the value, you should always use the normal property, like myTween.totalTime = 0.5.**/
public var cachedTotalTime:Number;
/** @private Prefaced with "cached" because using a public property like this is faster than using the getter which is essentially a function call. If you want to update the value, you should always use the normal property, like myTween.duration = 0.5.**/
public var cachedDuration:Number;
/** @private Prefaced with "cached" because using a public property like this is faster than using the getter which is essentially a function call. If you want to update the value, you should always use the normal property, like myTween.totalDuration = 0.5.**/
public var cachedTotalDuration:Number;
/** @private timeScale allows you to slow down or speed up a tween/timeline. 1 = normal speed, 0.5 = half speed, 2 = double speed, etc. It is prefaced with "cached" because using a public property like this is faster than using the getter which is essentially a function call. If you want to update the value, you should always use the normal property, like myTween.timeScale = 2**/
public var cachedTimeScale:Number;
/** @private Indicates whether or not the tween is reversed. **/
public var cachedReversed:Boolean;
/** @private Next TweenCore object in the linked list.**/
public var nextNode:TweenCore;
/** @private Previous TweenCore object in the linked list**/
public var prevNode:TweenCore;
/** @private When a TweenCore has been removed from its timeline, it is considered an orphan. When it it added to a timeline, it is no longer an orphan. We don't just set its "timeline" property to null because we need to always keep track of the timeline in case the TweenCore is enabled again by restart() or basically any operation that would cause it to become active again. "cachedGC" is different in that a TweenCore could be eligible for gc yet not removed from its timeline, like when a TimelineLite completes for example. **/
public var cachedOrphan:Boolean;
/** @private Indicates that the duration or totalDuration may need refreshing (like if a TimelineLite's child had a change in duration or startTime). This is another performance booster because if the cache isn't dirty, we can quickly read from the cachedDuration and/or cachedTotalDuration **/
public var cacheIsDirty:Boolean;
/** @private Quicker way to read the paused property. It is public for speed purposes. When setting the paused state, always use the regular "paused" property.**/
public var cachedPaused:Boolean;
/** Place to store any data you want.**/
public var data:*;
public function TweenCore(duration:Number=0, vars:Object=null) {
this.vars = (vars != null) ? vars : {};
this.cachedDuration = this.cachedTotalDuration = duration;
_delay = (this.vars.delay) ? Number(this.vars.delay) : 0;
this.cachedTimeScale = (this.vars.timeScale) ? Number(this.vars.timeScale) : 1;
this.active = Boolean(duration == 0 && _delay == 0 && this.vars.immediateRender != false);
this.cachedTotalTime = this.cachedTime = 0;
this.data = this.vars.data;
if (!_classInitted) {
if (isNaN(TweenLite.rootFrame)) {
TweenLite.initClass();
_classInitted = true;
} else {
return;
}
}
var tl:SimpleTimeline = (this.vars.timeline is SimpleTimeline) ? this.vars.timeline : (this.vars.useFrames) ? TweenLite.rootFramesTimeline : TweenLite.rootTimeline;
this.cachedStartTime = tl.cachedTotalTime + _delay;
tl.addChild(this);
if (this.vars.reversed) {
this.cachedReversed = true;
}
if (this.vars.paused) {
this.paused = true;
}
}
/** Starts playing forward from the current position. (essentially unpauses and makes sure that it is not reversed) **/
public function play():void {
this.reversed = false;
this.paused = false;
}
/** Pauses the tween/timeline **/
public function pause():void {
this.paused = true;
}
/** Starts playing from the current position without altering direction (forward or reversed). **/
public function resume():void {
this.paused = false;
}
/**
* Restarts and begins playing forward.
*
* @param includeDelay Determines whether or not the delay (if any) is honored in the restart()
* @param suppressEvents If true, no events or callbacks will be triggered as the "virtual playhead" moves to the new position (onComplete, onUpdate, onReverseComplete, etc. of this tween/timeline and any of its child tweens/timelines won't be triggered, nor will any of the associated events be dispatched)
*/
public function restart(includeDelay:Boolean=false, suppressEvents:Boolean=true):void {
this.reversed = false;
this.paused = false;
this.setTotalTime((includeDelay) ? -_delay : 0, suppressEvents);
}
/**
* Reverses smoothly, adjusting the startTime to avoid any skipping. After being reversed,
* it will play backwards, exactly opposite from its forward orientation, meaning that, for example, a
* tween's easing equation will appear reversed as well. If a tween/timeline plays for 2 seconds and gets
* reversed, it will play for another 2 seconds to return to the beginning.
*
* @param forceResume If true, it will resume() immediately upon reversing. Otherwise its paused state will remain unchanged.
*/
public function reverse(forceResume:Boolean=true):void {
this.reversed = true;
if (forceResume) {
this.paused = false;
} else if (this.gc) {
this.setEnabled(true, false);
}
}
/**
* @private
* Renders the tween/timeline at a particular time (or frame number for frames-based tweens)
* WITHOUT changing its startTime. For example, if a tween's duration
* is 3, <code>renderTime(1.5)</code> would render it at the halfway finished point.
*
* @param time time in seconds (or frame number for frames-based tweens/timelines) to render.
* @param suppressEvents If true, no events or callbacks will be triggered for this render (like onComplete, onUpdate, onReverseComplete, etc.)
* @param force Normally the tween will skip rendering if the time matches the cachedTotalTime (to improve performance), but if force is true, it forces a render. This is primarily used internally for tweens with durations of zero in TimelineLite/Max instances.
*/
public function renderTime(time:Number, suppressEvents:Boolean=false, force:Boolean=false):void {
}
/**
* Forces the tween/timeline to completion.
*
* @param skipRender to skip rendering the final state of the tween, set skipRender to true.
* @param suppressEvents If true, no events or callbacks will be triggered for this render (like onComplete, onUpdate, onReverseComplete, etc.)
*/
public function complete(skipRender:Boolean=false, suppressEvents:Boolean=false):void {
if (!skipRender) {
renderTime(this.totalDuration, suppressEvents, false); //just to force the final render
return; //renderTime() will call complete() again, so just return here.
}
if (this.timeline.autoRemoveChildren) {
this.setEnabled(false, false);
} else {
this.active = false;
}
if (!suppressEvents) {
if (this.vars.onComplete && this.cachedTotalTime == this.cachedTotalDuration && !this.cachedReversed) { //note: remember that tweens can have a duration of zero in which case their cachedTime and cachedDuration would always match.
this.vars.onComplete.apply(null, this.vars.onCompleteParams);
} else if (this.cachedReversed && this.cachedTotalTime == 0 && this.vars.onReverseComplete) {
this.vars.onReverseComplete.apply(null, this.vars.onReverseCompleteParams);
}
}
}
/**
* Clears any initialization data (like starting values in tweens) which can be useful if, for example,
* you want to restart it without reverting to any previously recorded starting values. When you invalidate()
* a tween/timeline, it will be re-initialized the next time it renders and its <code>vars</code> object will be re-parsed.
* The timing of the tween/timeline (duration, startTime, delay) will NOT be affected. Another example would be if you
* have a <code>TweenMax(mc, 1, {x:100, y:100})</code> that ran when mc.x and mc.y were initially at 0, but now mc.x
* and mc.y are 200 and you want them tween to 100 again, you could simply <code>invalidate()</code> the tween and
* <code>restart()</code> it. Without invalidating first, restarting it would cause the values jump back to 0 immediately
* (where they started when the tween originally began). When you invalidate a timeline, it automatically invalidates
* all of its children.
**/
public function invalidate():void {
}
/**
* @private
* If a tween/timeline is enabled, it is eligible to be rendered (unless it is paused). Setting enabled to
* false essentially removes it from its parent timeline and stops protecting it from garbage collection.
*
* @param enabled Enabled state of the tween/timeline
* @param ignoreTimeline By default, the tween/timeline will remove itself from its parent timeline when it is disabled, and add itself when it is enabled, but this parameter allows you to override that behavior.
* @return Boolean value indicating whether or not important properties may have changed when the TweenCore was enabled/disabled. For example, when a motionBlur (plugin) is disabled, it swaps out a BitmapData for the target and may alter the alpha. We need to know this in order to determine whether or not a new tween that is overwriting this one should be re-initted() with the changed properties.
**/
public function setEnabled(enabled:Boolean, ignoreTimeline:Boolean=false):Boolean {
this.gc = !enabled;
if (enabled) {
this.active = Boolean(!this.cachedPaused && this.cachedTotalTime > 0 && this.cachedTotalTime < this.cachedTotalDuration);
if (!ignoreTimeline && this.cachedOrphan) {
this.timeline.addChild(this);
}
} else {
this.active = false;
if (!ignoreTimeline && !this.cachedOrphan) {
this.timeline.remove(this, true);
}
}
return false;
}
/** Kills the tween/timeline, stopping it immediately. **/
public function kill():void {
setEnabled(false, false);
}
/**
* @private
* Sets the cacheIsDirty property of all anscestor timelines (and optionally this tween/timeline too). Setting
* the cacheIsDirty property to true forces any necessary recalculation of its cachedDuration and cachedTotalDuration
* properties and sorts the affected timelines' children TweenCores so that they're in the proper order
* next time the duration or totalDuration is requested. We don't just recalculate them immediately because
* it can be much faster to do it this way.
*
* @param includeSelf indicates whether or not this tween's cacheIsDirty property should be affected.
*/
protected function setDirtyCache(includeSelf:Boolean=true):void {
var tween:TweenCore = (includeSelf) ? this : this.timeline;
while (tween) {
tween.cacheIsDirty = true;
tween = tween.timeline;
}
}
/**
* @private
* Sort of like placing the local "playhead" at a particular totalTime and then aligning it with
* the parent timeline's "playhead" so that rendering continues from that point smoothly. This
* changes the cachedStartTime.
*
* @param time Time that should be rendered (includes any repeats and repeatDelays for TimelineMax)
* @param suppressEvents If true, no events or callbacks will be triggered for this render (like onComplete, onUpdate, onReverseComplete, etc.)
**/
protected function setTotalTime(time:Number, suppressEvents:Boolean=false):void {
if (this.timeline) {
var tlTime:Number = (_pauseTime || _pauseTime == 0) ? _pauseTime : this.timeline.cachedTotalTime;
if (this.cachedReversed) {
var dur:Number = (this.cacheIsDirty) ? this.totalDuration : this.cachedTotalDuration;
this.cachedStartTime = tlTime - ((dur - time) / this.cachedTimeScale);
} else {
this.cachedStartTime = tlTime - (time / this.cachedTimeScale);
}
if (!this.timeline.cacheIsDirty) { //for performance improvement. If the parent's cache is already dirty, it already took care of marking the anscestors as dirty too, so skip the function call here.
setDirtyCache(false);
}
if (this.cachedTotalTime != time) {
renderTime(time, suppressEvents, false);
}
}
}
//---- GETTERS / SETTERS ------------------------------------------------------------
/**
* Length of time in seconds (or frames for frames-based tweens/timelines) before the tween should begin.
* The tween's starting values are not determined until after the delay has expired (except in from() tweens)
**/
public function get delay():Number {
return _delay;
}
public function set delay(n:Number):void {
this.startTime += (n - _delay);
_delay = n;
}
/**
* Duration of the tween in seconds (or frames for frames-based tweens/timelines) not including any repeats
* or repeatDelays. <code>totalDuration</code>, by contrast, does include repeats and repeatDelays.
**/
public function get duration():Number {
return this.cachedDuration;
}
public function set duration(n:Number):void {
this.cachedDuration = this.cachedTotalDuration = n;
setDirtyCache(false);
}
/**
* Duration of the tween in seconds (or frames for frames-based tweens/timelines) including any repeats
* or repeatDelays (which are only available on TweenMax and TimelineMax). <code>duration</code>, by contrast, does
* <b>NOT</b> include repeats and repeatDelays. So if a TweenMax's <code>duration</code> is 1 and it has a repeat of 2, the <code>totalDuration</code> would be 3.
**/
public function get totalDuration():Number {
return this.cachedTotalDuration;
}
public function set totalDuration(n:Number):void {
this.duration = n;
}
/**
* Most recently rendered time (or frame for frames-based tweens/timelines) according to its
* <code>duration</code>. <code>totalTime</code>, by contrast, is based on its <code>totalDuration</code>
* which includes repeats and repeatDelays. Since TweenLite and TimelineLite don't offer
* <code>repeat</code> and <code>repeatDelay</code> functionality, <code>currentTime</code>
* and <code>totalTime</code> will always be the same but in TweenMax or TimelineMax, they
* could be different. For example, if a TimelineMax instance has a duration
* of 5 a repeat of 1 (meaning its <code>totalDuration</code> is 10), at the end of the second cycle,
* <code>currentTime</code> would be 5 whereas <code>totalTime</code> would be 10. If you tracked both
* properties over the course of the tween, you'd see <code>currentTime</code> go from 0 to 5 twice (one for each
* cycle) in the same time it takes <code>totalTime</code> go from 0 to 10.
**/
public function get currentTime():Number {
return this.cachedTime;
}
public function set currentTime(n:Number):void {
setTotalTime(n, false);
}
/**
* Most recently rendered time (or frame for frames-based tweens/timelines) according to its
* <code>totalDuration</code>. <code>currentTime</code>, by contrast, is based on its <code>duration</code>
* which does NOT include repeats and repeatDelays. Since TweenLite and TimelineLite don't offer
* <code>repeat</code> and <code>repeatDelay</code> functionality, <code>currentTime</code>
* and <code>totalTime</code> will always be the same but in TweenMax or TimelineMax, they
* could be different. For example, if a TimelineMax instance has a duration
* of 5 a repeat of 1 (meaning its <code>totalDuration</code> is 10), at the end of the second cycle,
* <code>currentTime</code> would be 5 whereas <code>totalTime</code> would be 10. If you tracked both
* properties over the course of the tween, you'd see <code>currentTime</code> go from 0 to 5 twice (one for each
* cycle) in the same time it takes <code>totalTime</code> go from 0 to 10.
**/
public function get totalTime():Number {
return this.cachedTotalTime;
}
public function set totalTime(n:Number):void {
setTotalTime(n, false);
}
/** Start time in seconds (or frames for frames-based tweens/timelines), according to its position on its parent timeline **/
public function get startTime():Number {
return this.cachedStartTime;
}
public function set startTime(n:Number):void {
var adjust:Boolean = Boolean(this.timeline != null && (n != this.cachedStartTime || this.gc));
this.cachedStartTime = n;
if (adjust) {
this.timeline.addChild(this); //ensures that any necessary re-sequencing of TweenCores in the timeline occurs to make sure the rendering order is correct.
}
}
/** Indicates the reversed state of the tween/timeline. This value is not affected by <code>yoyo</code> repeats and it does not take into account the reversed state of anscestor timelines. So for example, a tween that is not reversed might appear reversed if its parent timeline (or any ancenstor timeline) is reversed. **/
public function get reversed():Boolean {
return this.cachedReversed;
}
public function set reversed(b:Boolean):void {
if (b != this.cachedReversed) {
this.cachedReversed = b;
setTotalTime(this.cachedTotalTime, true);
}
}
/** Indicates the paused state of the tween/timeline. This does not take into account anscestor timelines. So for example, a tween that is not paused might appear paused if its parent timeline (or any ancenstor timeline) is paused. **/
public function get paused():Boolean {
return this.cachedPaused;
}
public function set paused(b:Boolean):void {
if (b != this.cachedPaused && this.timeline) {
if (b) {
_pauseTime = this.timeline.rawTime;
} else {
this.cachedStartTime += this.timeline.rawTime - _pauseTime;
_pauseTime = NaN;
setDirtyCache(false);
}
this.cachedPaused = b;
this.active = Boolean(!this.cachedPaused && this.cachedTotalTime > 0 && this.cachedTotalTime < this.cachedTotalDuration);
}
if (!b && this.gc) {
this.setTotalTime(this.cachedTotalTime, false);
this.setEnabled(true, false);
}
}
}
}