1/*! 2 * VERSION: 1.18.0 3 * DATE: 2015-09-05 4 * UPDATES AND DOCS AT: http://greensock.com 5 * 6 * Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin 7 * 8 * @license Copyright (c) 2008-2015, GreenSock. All rights reserved. 9 * This work is subject to the terms at http://greensock.com/standard-license or for 10 * Club GreenSock members, the software agreement that was issued with your membership. 11 * 12 * @author: Jack Doyle, [email protected] 13 **/ 14var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node 15(_gsScope._gsQueue || (_gsScope._gsQueue = [])).push( function() { 16 17 "use strict"; 18 19 _gsScope._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) { 20 21 var _slice = function(a) { //don't use [].slice because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll() 22 var b = [], 23 l = a.length, 24 i; 25 for (i = 0; i !== l; b.push(a[i++])); 26 return b; 27 }, 28 _applyCycle = function(vars, targets, i) { 29 var alt = vars.cycle, 30 p, val; 31 for (p in alt) { 32 val = alt[p]; 33 vars[p] = (typeof(val) === "function") ? val.call(targets[i], i) : val[i % val.length]; 34 } 35 delete vars.cycle; 36 }, 37 TweenMax = function(target, duration, vars) { 38 TweenLite.call(this, target, duration, vars); 39 this._cycle = 0; 40 this._yoyo = (this.vars.yoyo === true); 41 this._repeat = this.vars.repeat || 0; 42 this._repeatDelay = this.vars.repeatDelay || 0; 43 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it. 44 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method) 45 }, 46 _tinyNum = 0.0000000001, 47 TweenLiteInternals = TweenLite._internals, 48 _isSelector = TweenLiteInternals.isSelector, 49 _isArray = TweenLiteInternals.isArray, 50 p = TweenMax.prototype = TweenLite.to({}, 0.1, {}), 51 _blankArray = []; 52 53 TweenMax.version = "1.18.0"; 54 p.constructor = TweenMax; 55 p.kill()._gc = false; 56 TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf; 57 TweenMax.getTweensOf = TweenLite.getTweensOf; 58 TweenMax.lagSmoothing = TweenLite.lagSmoothing; 59 TweenMax.ticker = TweenLite.ticker; 60 TweenMax.render = TweenLite.render; 61 62 p.invalidate = function() { 63 this._yoyo = (this.vars.yoyo === true); 64 this._repeat = this.vars.repeat || 0; 65 this._repeatDelay = this.vars.repeatDelay || 0; 66 this._uncache(true); 67 return TweenLite.prototype.invalidate.call(this); 68 }; 69 70 p.updateTo = function(vars, resetDuration) { 71 var curRatio = this.ratio, 72 immediate = this.vars.immediateRender || vars.immediateRender, 73 p; 74 if (resetDuration && this._startTime < this._timeline._time) { 75 this._startTime = this._timeline._time; 76 this._uncache(false); 77 if (this._gc) { 78 this._enabled(true, false); 79 } else { 80 this._timeline.insert(this, this._startTime - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct. 81 } 82 } 83 for (p in vars) { 84 this.vars[p] = vars[p]; 85 } 86 if (this._initted || immediate) { 87 if (resetDuration) { 88 this._initted = false; 89 if (immediate) { 90 this.render(0, true, true); 91 } 92 } else { 93 if (this._gc) { 94 this._enabled(true, false); 95 } 96 if (this._notifyPluginsOfEnabled && this._firstPT) { 97 TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks 98 } 99 if (this._time / this._duration > 0.998) { //if the tween has finished (or come extremely close to finishing), we just need to rewind it to 0 and then render it again at the end which forces it to re-initialize (parsing the new vars). We allow tweens that are close to finishing (but haven't quite finished) to work this way too because otherwise, the values are so small when determining where to project the starting values that binary math issues creep in and can make the tween appear to render incorrectly when run backwards. 100 var prevTime = this._time; 101 this.render(0, true, false); 102 this._initted = false;
103 this.render(prevTime, true, false); 104 } else if (this._time > 0 || immediate) { 105 this._initted = false; 106 this._init(); 107 var inv = 1 / (1 - curRatio), 108 pt = this._firstPT, endValue; 109 while (pt) { 110 endValue = pt.s + pt.c; 111 pt.c *= inv; 112 pt.s = endValue - pt.c; 113 pt = pt._next; 114 } 115 } 116 } 117 } 118 return this; 119 }; 120 121 p.render = function(time, suppressEvents, force) { 122 if (!this._initted) if (this._duration === 0 && this.vars.repeat) { //zero duration tweens that render immediately have render() called from TweenLite's constructor, before TweenMax's constructor has finished setting _repeat, _repeatDelay, and _yoyo which are critical in determining totalDuration() so we need to call invalidate() which is a low-kb way to get those set properly. 123 this.invalidate(); 124 } 125 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(), 126 prevTime = this._time, 127 prevTotalTime = this._totalTime, 128 prevCycle = this._cycle, 129 duration = this._duration, 130 prevRawPrevTime = this._rawPrevTime, 131 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime; 132 if (time >= totalDur) { 133 this._totalTime = totalDur; 134 this._cycle = this._repeat; 135 if (this._yoyo && (this._cycle & 1) !== 0) { 136 this._time = 0; 137 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0; 138 } else { 139 this._time = duration; 140 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1; 141 } 142 if (!this._reversed) { 143 isComplete = true; 144 callback = "onComplete"; 145 force = (force || this._timeline.autoRemoveChildren); //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline. 146 } 147 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered. 148 if (this._startTime === this._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent rounding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate. 149 time = 0; 150 } 151 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) { 152 force = true; 153 if (prevRawPrevTime > _tinyNum) { 154 callback = "onReverseComplete"; 155 } 156 } 157 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 158 } 159 160 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 161 this._totalTime = this._time = this._cycle = 0; 162 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0; 163 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0)) { 164 callback = "onReverseComplete"; 165 isComplete = this._reversed; 166 } 167 if (time < 0) { 168 this._active = false;
169 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered. 170 if (prevRawPrevTime >= 0) { 171 force = true; 172 } 173 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 174 } 175 } 176 if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately. 177 force = true; 178 } 179 } else { 180 this._totalTime = this._time = time; 181 182 if (this._repeat !== 0) { 183 cycleDuration = duration + this._repeatDelay; 184 this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but Flash reports it as 0.79999999!) 185 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) { 186 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning) 187 } 188 this._time = this._totalTime - (this._cycle * cycleDuration); 189 if (this._yoyo) if ((this._cycle & 1) !== 0) { 190 this._time = duration - this._time; 191 } 192 if (this._time > duration) { 193 this._time = duration; 194 } else if (this._time < 0) { 195 this._time = 0; 196 } 197 } 198 199 if (this._easeType) { 200 r = this._time / duration; 201 type = this._easeType; 202 pow = this._easePower; 203 if (type === 1 || (type === 3 && r >= 0.5)) { 204 r = 1 - r; 205 } 206 if (type === 3) { 207 r *= 2; 208 } 209 if (pow === 1) { 210 r *= r; 211 } else if (pow === 2) { 212 r *= r * r; 213 } else if (pow === 3) { 214 r *= r * r * r; 215 } else if (pow === 4) { 216 r *= r * r * r * r; 217 } 218 219 if (type === 1) { 220 this.ratio = 1 - r; 221 } else if (type === 2) { 222 this.ratio = r; 223 } else if (this._time / duration < 0.5) { 224 this.ratio = r / 2; 225 } else { 226 this.ratio = 1 - (r / 2); 227 } 228 229 } else { 230 this.ratio = this._ease.getRatio(this._time / duration); 231 } 232 233 } 234 235 if (prevTime === this._time && !force && prevCycle === this._cycle) { 236 if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate. 237 this._callback("onUpdate"); 238 } 239 return; 240 } else if (!this._initted) { 241 this._init(); 242 if (!this._initted || this._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that over
242writing occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example. 243 return; 244 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) { //we stick it in the queue for rendering at the very end of the tick - this is a performance optimization because browsers invalidate styles and force a recalculation if you read, write, and then read style data (so it's better to read/read/read/write/write/write than read/write/read/write/read/write). The down side, of course, is that usually you WANT things to render immediately because you may have code running right after that which depends on the change. Like imagine running TweenLite.set(...) and then immediately after that, creating a nother tween that animates the same property to another value; the starting values of that 2nd tween wouldn't be accurate if lazy is true. 245 this._time = prevTime; 246 this._totalTime = prevTotalTime; 247 this._rawPrevTime = prevRawPrevTime; 248 this._cycle = prevCycle; 249 TweenLiteInternals.lazyTweens.push(this); 250 this._lazy = [time, suppressEvents]; 251 return; 252 } 253 //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently. 254 if (this._time && !isComplete) { 255 this.ratio = this._ease.getRatio(this._time / duration); 256 } else if (isComplete && this._ease._calcEnd) { 257 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1); 258 } 259 } 260 if (this._lazy !== false) { 261 this._lazy = false; 262 } 263 264 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) { 265 this._active = true; //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done. 266 } 267 if (prevTotalTime === 0) { 268 if (this._initted === 2 && time > 0) { 269 //this.invalidate(); 270 this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true 271 } 272 if (this._startAt) { 273 if (time >= 0) { 274 this._startAt.render(time, suppressEvents, force); 275 } else if (!callback) { 276 callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area. 277 } 278 } 279 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) { 280 this._callback("onStart"); 281 } 282 } 283 284 pt = this._firstPT; 285 while (pt) { 286 if (pt.f) { 287 pt.t[pt.p](pt.c * this.ratio + pt.s); 288 } else { 289 pt.t[pt.p] = pt.c * this.ratio + pt.s; 290 } 291 pt = pt._next; 292 } 293 294 if (this._onUpdate) { 295 if (time < 0) if (this._startAt && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values. 296 this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete. 297 } 298 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
299 this._callback("onUpdate"); 300 } 301 } 302 if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) { 303 this._callback("onRepeat"); 304 } 305 if (callback) if (!this._gc || force) { //check gc because there's a chance that kill() could be called in an onUpdate 306 if (time < 0 && this._startAt && !this._onUpdate && this._startTime) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values. 307 this._startAt.render(time, suppressEvents, force); 308 } 309 if (isComplete) { 310 if (this._timeline.autoRemoveChildren) { 311 this._enabled(false, false); 312 } 313 this._active = false; 314 } 315 if (!suppressEvents && this.vars[callback]) { 316 this._callback(callback); 317 } 318 if (duration === 0 && this._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon sce
318nario, but possible nonetheless. 319 this._rawPrevTime = 0; 320 } 321 } 322 }; 323 324//---- STATIC FUNCTIONS ----------------------------------------------------------------------------------------------------------- 325 326 TweenMax.to = function(target, duration, vars) { 327 return new TweenMax(target, duration, vars); 328 }; 329 330 TweenMax.from = function(target, duration, vars) { 331 vars.runBackwards = true; 332 vars.immediateRender = (vars.immediateRender != false); 333 return new TweenMax(target, duration, vars); 334 }; 335 336 TweenMax.fromTo = function(target, duration, fromVars, toVars) { 337 toVars.startAt = fromVars; 338 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 339 return new TweenMax(target, duration, toVars); 340 }; 341 342 TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 343 stagger = stagger || 0; 344 var delay = vars.delay || 0, 345 a = [], 346 finalComplete = function() { 347 if (vars.onComplete) { 348 vars.onComplete.apply(vars.onCompleteScope || this, arguments); 349 } 350 onCompleteAll.apply(onCompleteAllScope || vars.callbackScope || this, onCompleteAllParams || _blankArray); 351 }, 352 cycle = vars.cycle, 353 fromCycle = (vars.startAt && vars.startAt.cycle), 354 l, copy, i, p; 355 if (!_isArray(targets)) { 356 if (typeof(targets) === "string") { 357 targets = TweenLite.selector(targets) || targets; 358 } 359 if (_isSelector(targets)) { 360 targets = _slice(targets); 361 } 362 } 363 targets = targets || []; 364 if (stagger < 0) { 365 targets = _slice(targets); 366 targets.reverse(); 367 stagger *= -1; 368 } 369 l = targets.length - 1; 370 for (i = 0; i <= l; i++) { 371 copy = {}; 372 for (p in vars) { 373 copy[p] = vars[p]; 374 } 375 if (cycle) { 376 _applyCycle(copy, targets, i); 377 } 378 if (fromCycle) { 379 fromCycle = copy.startAt = {}; 380 for (p in vars.startAt) { 381 fromCycle[p] = vars.startAt[p]; 382 } 383 _applyCycle(copy.startAt, targets, i); 384 } 385 copy.delay = delay; 386 if (i === l && onCompleteAll) { 387 copy.onComplete = finalComplete; 388 } 389 a[i] = new TweenMax(targets[i], duration, copy); 390 delay += stagger; 391 } 392 return a; 393 }; 394 395 TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 396 vars.runBackwards = true; 397 vars.immediateRender = (vars.immediateRender != false); 398 return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 399 }; 400 401 TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 402 toVars.startAt = fromVars; 403 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 404 return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 405 }; 406 407 TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) { 408 return new TweenMax(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, callbackScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, immediateRender:false, useFrames:useFrames, overwrite:0}); 409 }; 410 411 TweenMax.set = function(target, vars) { 412 return new TweenMax(target, 0, vars); 413 }; 414 415 TweenMax.isTweening = function(target) { 416 return (TweenLite.getTweensOf(target, true).length > 0); 417 }; 418 419 var _getChildrenOf = function(timeline, includeTimelines) { 420 var a = [], 421 cnt = 0, 422 tween = timeline._first; 423 while (tween) { 424 if (tween instanceof TweenLite) { 425 a[cnt++] = tween; 426 } else { 427 if (includeTimelines) { 428 a[cnt++] = tween; 429 } 430 a = a.concat(_getChildrenOf(tween, includeTimelines)); 431 cnt = a.length; 432 } 433 tween = tween._next; 434 } 435 return a; 436 }, 437 getAllTweens = TweenMax.getAllTweens = function(includeTimelines) { 438 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) ); 439 }; 440 441 TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) { 442 if (tweens == null) { 443 tweens = true; 444 } 445 if (delayedCalls == null) { 446 delayedCalls = true; 447 } 448 var a = getAllTweens((timelines != false)), 449 l = a.length, 450 allTrue = (tweens && delayedCalls && timelines), 451 isDC, tween, i; 452 for (i = 0; i < l; i++) { 453 tween = a[i]; 454 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) { 455 if (complete) { 456 tween.totalTime(tween._reversed ? 0 : tween.totalDuration()); 457 } else { 458 tween._enabled(false, false); 459 } 460 } 461 } 462 }; 463 464 TweenMax.killChildTweensOf = function(parent, complete) { 465 if (parent == null) { 466 return; 467 } 468 var tl = TweenLiteInternals.tweenLookup, 469 a, curParent, p, i, l; 470 if (typeof(parent) === "string") { 471 parent = TweenLite.selector(parent) || parent; 472 } 473 if (_isSelector(parent)) { 474 parent = _slice(parent); 475 } 476 if (_isArray(parent)) { 477 i = parent.length; 478 while (--i > -1) { 479 TweenMax.killChildTweensOf(parent[i], complete); 480 } 481 return; 482 } 483 a = []; 484 for (p in tl) { 485 curParent = tl[p].target.parentNode; 486 while (curParent) { 487 if (curParent === parent) { 488 a = a.concat(tl[p].tweens); 489 } 490 curParent = curParent.parentNode; 491 } 492 } 493 l = a.length; 494 for (i = 0; i < l; i++) { 495 if (complete) { 496 a[i].totalTime(a[i].totalDuration()); 497 } 498 a[i]._enabled(false, false); 499 } 500 }; 501 502 var _changePause = function(pause, tweens, delayedCalls, timelines) { 503 tweens = (tweens !== false); 504 delayedCalls = (delayedCalls !== false); 505 timelines = (timelines !== false); 506 var a = getAllTweens(timelines), 507 allTrue = (tweens && delayedCalls && timelines), 508 i = a.length, 509 isDC, tween; 510 while (--i > -1) { 511 tween = a[i]; 512 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) { 513 tween.paused(pause); 514 } 515 } 516 }; 517 518 TweenMax.pauseAll = function(tweens, delayedCalls, timelines) { 519 _changePause(true, tweens, delayedCalls, timelines); 520 }; 521
522 TweenMax.resumeAll = function(tweens, delayedCalls, timelines) { 523 _changePause(false, tweens, delayedCalls, timelines); 524 }; 525 526 TweenMax.globalTimeScale = function(value) { 527 var tl = Animation._rootTimeline, 528 t = TweenLite.ticker.time; 529 if (!arguments.length) { 530 return tl._timeScale; 531 } 532 value = value || _tinyNum; //can't allow zero because it'll throw the math off 533 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value); 534 tl = Animation._rootFramesTimeline; 535 t = TweenLite.ticker.frame; 536 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value); 537 tl._timeScale = Animation._rootTimeline._timeScale = value; 538 return value; 539 }; 540 541 542//---- GETTERS / SETTERS ---------------------------------------------------------------------------------------------------------- 543 544 p.progress = function(value) { 545 return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), false); 546 }; 547 548 p.totalProgress = function(value) { 549 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false); 550 }; 551 552 p.time = function(value, suppressEvents) { 553 if (!arguments.length) { 554 return this._time; 555 } 556 if (this._dirty) { 557 this.totalDuration(); 558 } 559 if (value > this._duration) { 560 value = this._duration; 561 } 562 if (this._yoyo && (this._cycle & 1) !== 0) { 563 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay)); 564 } else if (this._repeat !== 0) { 565 value += this._cycle * (this._duration + this._repeatDelay); 566 } 567 return this.totalTime(value, suppressEvents); 568 }; 569 570 p.duration = function(value) { 571 if (!arguments.length) { 572 return this._duration; //don't set _dirty = false because there could be repeats that haven't been factored into the _totalDuration yet. Otherwise, if you create a repeated TweenMax and then immediately check its duration(), it would cache the value and the totalDuration would not be correct, thus repeats wouldn't take effect. 573 } 574 return Animation.prototype.duration.call(this, value); 575 }; 576 577 p.totalDuration = function(value) { 578 if (!arguments.length) { 579 if (this._dirty) { 580 //instead of Infinity, we use 999999999999 so that we can accommodate reverses 581 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat); 582 this._dirty = false; 583 } 584 return this._totalDuration; 585 } 586 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) ); 587 }; 588 589 p.repeat = function(value) { 590 if (!arguments.length) { 591 return this._repeat; 592 } 593 this._repeat = value; 594 return this._uncache(true); 595 }; 596 597 p.repeatDelay = function(value) { 598 if (!arguments.length) { 599 return this._repeatDelay; 600 } 601 this._repeatDelay = value; 602 return this._uncache(true); 603 }; 604 605 p.yoyo = function(value) { 606 if (!arguments.length) { 607 return this._yoyo; 608 } 609 this._yoyo = value; 610 return this; 611 }; 612 613 614 return TweenMax; 615 616 }, true); 617 618 619 620 621 622 623 624 625/* 626 * ---------------------------------------------------------------- 627 * TimelineLite 628 * ---------------------------------------------------------------- 629 */ 630 _gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) { 631 632 var TimelineLite = function(vars) { 633 SimpleTimeline.call(this, vars); 634 this._labels = {}; 635 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true); 636 this.smoothChildTiming = (this.vars.smoothChildTiming === true); 637 this._sortChildren = true; 638 this._onUpdate = this.vars.onUpdate; 639 var v = this.vars, 640 val, p; 641 for (p in v) { 642 val = v[p]; 643 if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) { 644 v[p] = this._swapSelfInParams(val); 645 } 646 } 647 if (_isArray(v.tweens)) { 648 this.add(v.tweens, 0, v.align, v.stagger); 649 } 650 }, 651 _tinyNum = 0.0000000001, 652 TweenLiteInternals = TweenLite._internals, 653 _internals = TimelineLite._internals = {}, 654 _isSelector = TweenLiteInternals.isSelector, 655 _isArray = TweenLiteInternals.isArray, 656 _lazyTweens = TweenLiteInternals.lazyTweens, 657 _lazyRender = TweenLiteInternals.lazyRender, 658 _globals = _gsScope._gsDefine.globals, 659 _copy = function(vars) { 660 var copy = {}, p; 661 for (p in vars) { 662 copy[p] = vars[p]; 663 } 664 return copy; 665 }, 666 _applyCycle = function(vars, targets, i) { 667 var alt = vars.cycle, 668 p, val; 669 for (p in alt) { 670 val = alt[p]; 671 vars[p] = (typeof(val) === "function") ? val.call(targets[i], i) : val[i % val.length]; 672 } 673 delete vars.cycle; 674 }, 675 _pauseCallback = _internals.pauseCallback = function() {}, 676 _slice = function(a) { //don't use [].slice because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll() 677 var b = [], 678 l = a.length, 679 i; 680 for (i = 0; i !== l; b.push(a[i++])); 681 return b; 682 }, 683 p = TimelineLite.prototype = new SimpleTimeline(); 684
685 TimelineLite.version = "1.18.0"; 686 p.constructor = TimelineLite; 687 p.kill()._gc = p._forcingPlayhead = p._hasPause = false; 688 689 /* might use later... 690 //translates a local time inside an animation to the corresponding time on the root/global timeline, factoring in all nesting and timeScales. 691 function localToGlobal(time, animation) { 692 while (animation) { 693 time = (time / animation._timeScale) + animation._startTime; 694 animation = animation.timeline; 695 } 696 return time; 697 } 698 699 //translates the supplied time on the root/global timeline into the corresponding local time inside a particular animation, factoring in all nesting and timeScales 700 function globalToLocal(time, animation) { 701 var scale = 1; 702 time -= localToGlobal(0, animation); 703 while (animation) { 704 scale *= animation._timeScale; 705 animation = animation.timeline; 706 } 707 return time * scale; 708 } 709 */ 710 711 p.to = function(target, duration, vars, position) { 712 var Engine = (vars.repeat && _globals.TweenMax) || TweenLite; 713 return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position); 714 }; 715 716 p.from = function(target, duration, vars, position) { 717 return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position); 718 }; 719 720 p.fromTo = function(target, duration, fromVars, toVars, position) { 721 var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite; 722 return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position); 723 }; 724 725 p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 726 var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, callbackScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}), 727 cycle = vars.cycle, 728 copy, i; 729 if (typeof(targets) === "string") { 730 targets = TweenLite.selector(targets) || targets; 731 } 732 targets = targets || []; 733 if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array. 734 targets = _slice(targets); 735 } 736 stagger = stagger || 0; 737 if (stagger < 0) { 738 targets = _slice(targets); 739 targets.reverse(); 740 stagger *= -1; 741 } 742 for (i = 0; i < targets.length; i++) { 743 copy = _copy(vars); 744 if (copy.startAt) { 745 copy.startAt = _copy(copy.startAt); 746 if (copy.startAt.cycle) { 747 _applyCycle(copy.startAt, targets, i); 748 } 749 } 750 if (cycle) { 751 _applyCycle(copy, targets, i); 752 } 753 tl.to(targets[i], duration, copy, i * stagger); 754 } 755 return this.add(tl, position); 756 }; 757 758 p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 759 vars.immediateRender = (vars.immediateRender != false); 760 vars.runBackwards = true; 761 return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 762 }; 763 764 p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 765 toVars.startAt = fromVars; 766 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 767 return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 768 }; 769 770 p.call = function(callback, params, scope, position) { 771 return this.add( TweenLite.delayedCall(0, callback, params, scope), position); 772 }; 773 774 p.set = function(target, vars, position) { 775 position = this._parseTimeOrLabel(position, 0, true); 776 if (vars.immediateRender == null) { 777 vars.immediateRender = (position === this._time && !this._paused); 778 } 779 return this.add( new TweenLite(target, 0, vars), position); 780 }; 781 782 TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) { 783 vars = vars || {}; 784 if (vars.smoothChildTiming == null) { 785 vars.smoothChildTiming = true; 786 } 787 var tl = new TimelineLite(vars), 788 root = tl._timeline, 789 tween, next; 790 if (ignoreDelayedCalls == null) { 791 ignoreDelayedCalls = true; 792 } 793 root._remove(tl, true); 794 tl._startTime = 0; 795 tl._rawPrevTime = tl._time = tl._totalTime = root._time; 796 tween = root._first; 797 while (tween) { 798 next = tween._next; 799 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) { 800 tl.add(tween, tween._startTime - tween._delay); 801 } 802 tween = next; 803 } 804 root.add(tl, 0); 805 return tl; 806 }; 807 808 p.add = function(value, position, align, stagger) { 809 var curTime, l, i, child, tl, beforeRawTime; 810 if (typeof(position) !== "number") { 811 position = this._parseTimeOrLabel(position, 0, true, value); 812 } 813 if (!(value instanceof Animation)) { 814 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
815 align = align || "normal"; 816 stagger = stagger || 0; 817 curTime = position; 818 l = value.length; 819 for (i = 0; i < l; i++) { 820 if (_isArray(child = value[i])) { 821 child = new TimelineLite({tweens:child}); 822 } 823 this.add(child, curTime); 824 if (typeof(child) !== "string" && typeof(child) !== "function") { 825 if (align === "sequence") { 826 curTime = child._startTime + (child.totalDuration() / child._timeScale); 827 } else if (align === "start") { 828 child._startTime -= child.delay(); 829 } 830 } 831 curTime += stagger; 832 } 833 return this._uncache(true); 834 } else if (typeof(value) === "string") { 835 return this.addLabel(value, position); 836 } else if (typeof(value) === "function") { 837 value = TweenLite.delayedCall(0, value); 838 } else { 839 throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string."); 840 } 841 } 842 843 SimpleTimeline.prototype.add.call(this, value, position); 844 845 //if the timeline has already ended but the inserted tween/timeline extends the duration, we should enable this timeline again so that it renders properly. We should also align the playhead with the parent timeline's when appropriate. 846 if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) { 847 //in case any of the ancestors had completed but should now be enabled... 848 tl = this; 849 beforeRawTime = (tl.rawTime() > value._startTime); //if the tween is placed on the timeline so that it starts BEFORE the current rawTime, we should align the playhead (move the timeline). This is because sometimes users will create a timeline, let it finish, and much later append a tween and expect it to run instead of jumping to its end state. While technically one could argue that it should jump to its end state, that's not what users intuitively expect. 850 while (tl._timeline) { 851 if (beforeRawTime && tl._timeline.smoothChildTiming) { 852 tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it. 853 } else if (tl._gc) { 854 tl._enabled(true, false); 855 } 856 tl = tl._timeline; 857 } 858 } 859 860 return this; 861 }; 862 863 p.remove = function(value) { 864 if (value instanceof Animation) { 865 this._remove(value, false); 866 var tl = value._timeline = value.vars.useFrames ? Animation._rootFramesTimeline : Animation._rootTimeline; //now that it's removed, default it to the root timeline so that if it gets played again, it doesn't jump back into this timeline. 867 value._startTime = (value._paused ? value._pauseTime : tl._time) - ((!value._reversed ? value._totalTime : value.totalDuration() - value._totalTime) / value._timeScale); //ensure that if it gets played again, the timing is correct. 868 return this; 869 } else if (value instanceof Array || (value && value.push && _isArray(value))) { 870 var i = value.length; 871 while (--i > -1) { 872 this.remove(value[i]); 873 } 874 return this; 875 } else if (typeof(value) === "string") { 876 return this.removeLabel(value); 877 } 878 return this.kill(null, value); 879 }; 880 881 p._remove = function(tween, skipDisable) { 882 SimpleTimeline.prototype._remove.call(this, tween, skipDisable); 883 var last = this._last; 884 if (!last) { 885 this._time = this._totalTime = this._duration = this._totalDuration = 0; 886 } else if (this._time > last._startTime + last._totalDuration / last._timeScale) { 887 this._time = this.duration(); 888 this._totalTime = this._totalDuration; 889 } 890 return this; 891 }; 892 893 p.append = function(value, offsetOrLabel) { 894 return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value)); 895 }; 896 897 p.insert = p.insertMultiple = function(value, position, align, stagger) { 898 return this.add(value, position || 0, align, stagger); 899 }; 900 901 p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) { 902 return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger); 903 }; 904 905 p.addLabel = function(label, position) { 906 this._labels[label] = this._parseTimeOrLabel(position); 907 return this; 908 }; 909 910 p.addPause = function(position, callback, params, scope) { 911 var t = TweenLite.delayedCall(0, _pauseCallback, params, scope || this); 912 t.vars.onComplete = t.vars.onReverseComplete = callback;
913 t.data = "isPause"; 914 this._hasPause = true; 915 return this.add(t, position); 916 }; 917 918 p.removeLabel = function(label) { 919 delete this._labels[label]; 920 return this; 921 }; 922 923 p.getLabelTime = function(label) { 924 return (this._labels[label] != null) ? this._labels[label] : -1; 925 }; 926 927 p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) { 928 var i; 929 //if we're about to add a tween/timeline (or an array of them) that's already a child of this timeline, we should remove it first so that it doesn't contaminate the duration(). 930 if (ignore instanceof Animation && ignore.timeline === this) { 931 this.remove(ignore); 932 } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) { 933 i = ignore.length; 934 while (--i > -1) { 935 if (ignore[i] instanceof Animation && ignore[i].timeline === this) { 936 this.remove(ignore[i]); 937 } 938 } 939 } 940 if (typeof(offsetOrLabel) === "string") { 941 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent); 942 } 943 offsetOrLabel = offsetOrLabel || 0; 944 if (typeof(timeOrLabel) === "string" && (isNaN(timeOrLabel) || this._labels[timeOrLabel] != null)) { //if the string is a number like "1", check to see if there's a label with that name, otherwise interpret it as a number (absolute value). 945 i = timeOrLabel.indexOf("="); 946 if (i === -1) { 947 if (this._labels[timeOrLabel] == null) { 948 return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel; 949 } 950 return this._labels[timeOrLabel] + offsetOrLabel; 951 } 952 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1)); 953 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration(); 954 } else if (timeOrLabel == null) { 955 timeOrLabel = this.duration(); 956 } 957 return Number(timeOrLabel) + offsetOrLabel; 958 }; 959 960 p.seek = function(position, suppressEvents) { 961 return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false)); 962 }; 963 964 p.stop = function() { 965 return this.paused(true); 966 }; 967 968 p.gotoAndPlay = function(position, suppressEvents) { 969 return this.play(position, suppressEvents); 970 }; 971 972 p.gotoAndStop = function(position, suppressEvents) { 973 return this.pause(position, suppressEvents); 974 }; 975 976 p.render = function(time, suppressEvents, force) { 977 if (this._gc) { 978 this._enabled(true, false); 979 } 980 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(), 981 prevTime = this._time, 982 prevStart = this._startTime, 983 prevTimeScale = this._timeScale, 984 prevPaused = this._paused, 985 tween, isComplete, next, callback, internalForce, pauseTween; 986 if (time >= totalDur) { 987 this._totalTime = this._time = totalDur; 988 if (!this._reversed) if (!this._hasPausedChild()) { 989 isComplete = true; 990 callback = "onComplete"; 991 internalForce = !!this._timeline.autoRemoveChildren; //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline. 992 if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) { 993 internalForce = true; 994 if (this._rawPrevTime > _tinyNum) { 995 callback = "onReverseComplete"; 996 } 997 } 998 } 999 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 1000 time = totalDur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7. 1001 1002 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 1003 this._totalTime = this._time = 0; 1004 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) { 1005 callback = "onReverseComplete"; 1006 isComplete = this._reversed; 1007 } 1008 if (time < 0) { 1009 this._active = false;
1010 if (this._timeline.autoRemoveChildren && this._reversed) { //ensures proper GC if a timeline is resumed after it's finished reversing. 1011 internalForce = isComplete = true; 1012 callback = "onReverseComplete"; 1013 } else if (this._rawPrevTime >= 0 && this._first) { //when going back beyond the start, force a render so that zero-duration tweens that sit at the very beginning render their start values properly. Otherwise, if the parent timeline's playhead lands exactly at this timeline's startTime, and then moves backwards, the zero-duration tweens at the beginning would still be at their end state. 1014 internalForce = true; 1015 } 1016 this._rawPrevTime = time; 1017 } else { 1018 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 1019 if (time === 0 && isComplete) { //if there's a zero-duration tween at the very beginning of a timeline and the playhead lands EXACTLY at time 0, that tween will correctly render its end values, but we need to keep the timeline alive for one more render so that the beginning values render properly as the parent's playhead keeps moving beyond the begining. Imagine obj.x starts at 0 and then we do tl.set(obj, {x:100}).to(obj, 1, {x:200}) and then later we tl.reverse()...the goal is to have obj.x revert to 0. If the playhead happens to land on exactly 0, without this chunk of code, it'd complete the timeline and remove it from the rendering queue (not good). 1020 tween = this._first; 1021 while (tween && tween._startTime === 0) { 1022 if (!tween._duration) { 1023 isComplete = false; 1024 } 1025 tween = tween._next; 1026 } 1027 } 1028 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline) 1029 if (!this._initted) { 1030 internalForce = true; 1031 } 1032 } 1033 1034 } else { 1035 1036 if (this._hasPause && !this._forcingPlayhead && !suppressEvents) { 1037 if (time >= prevTime) { 1038 tween = this._first; 1039 while (tween && tween._startTime <= time && !pauseTween) { 1040 if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && this._rawPrevTime === 0)) { 1041 pauseTween = tween; 1042 } 1043 tween = tween._next; 1044 } 1045 } else { 1046 tween = this._last; 1047 while (tween && tween._startTime >= time && !pauseTween) { 1048 if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) { 1049 pauseTween = tween; 1050 } 1051 tween = tween._prev; 1052 } 1053 } 1054 if (pauseTween) { 1055 this._time = time = pauseTween._startTime; 1056 this._totalTime = time + (this._cycle * (this._totalDuration + this._repeatDelay)); 1057 } 1058 } 1059 1060 this._totalTime = this._time = this._rawPrevTime = time; 1061 } 1062 if ((this._time === prevTime || !this._first) && !force && !internalForce && !pauseTween) { 1063 return; 1064 } else if (!this._initted) { 1065 this._initted = true; 1066 } 1067 1068 if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) { 1069 this._active = true; //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example. 1070 } 1071 1072 if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) { 1073 this._callback("onStart"); 1074 } 1075 1076 if (this._time >= prevTime) { 1077 tween = this._first; 1078 while (tween) { 1079 next = tween._next; //record it here because the value could change after rendering... 1080 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1081 break; 1082 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) { 1083 if (pauseTween === tween) { 1084 this.pause(); 1085 } 1086 if (!tween._reversed) { 1087 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1088 } else { 1089 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1090 } 1091 } 1092 tween = next; 1093 } 1094 } else { 1095 tween = this._last; 1096 while (tween) { 1097 next = tween._prev; //record it here because the value could change after rendering... 1098 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1099 break; 1100 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) { 1101 if (pauseTween === tween) { 1102 pauseTween = tween._prev; //the linked list is organized by _startTime, thus it's possible that a tween could start BEFORE the pause and end after it, in which case it would be positioned before the pause tween in the linked list, but we should render it before we pause() the timeline and cease rendering. This is only a concern when going in reverse. 1103 while (pauseTween && pauseTween.endTime() > this._time) { 1104 pauseTween.render( (pauseTween._reversed ? pauseTween.totalDuration() - ((time - pauseTween._startTime) * pauseTween._timeScale) : (time - pauseTween._startTime) * pauseTween._timeScale), suppressEvents, force); 1105 pauseTween = pauseTween._prev; 1106 } 1107 pauseTween = null; 1108 this.pause(); 1109 } 1110 if (!tween._reversed) { 1111 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1112 } else { 1113 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1114 } 1115 } 1116 tween = next; 1117 } 1118 } 1119 1120 if (this._onUpdate) if (!suppressEvents) { 1121 if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onUpdate on a timeline that reports/checks tweened values. 1122 _lazyRender(); 1123 }
1124 this._callback("onUpdate"); 1125 } 1126 1127 if (callback) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate 1128 if (isComplete) { 1129 if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onComplete on a timeline that reports/checks tweened values. 1130 _lazyRender(); 1131 } 1132 if (this._timeline.autoRemoveChildren) { 1133 this._enabled(false, false); 1134 } 1135 this._active = false; 1136 } 1137 if (!suppressEvents && this.vars[callback]) { 1138 this._callback(callback); 1139 } 1140 } 1141 }; 1142 1143 p._hasPausedChild = function() { 1144 var tween = this._first; 1145 while (tween) { 1146 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) { 1147 return true; 1148 } 1149 tween = tween._next; 1150 } 1151 return false; 1152 }; 1153 1154 p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) { 1155 ignoreBeforeTime = ignoreBeforeTime || -9999999999; 1156 var a = [], 1157 tween = this._first, 1158 cnt = 0; 1159 while (tween) { 1160 if (tween._startTime < ignoreBeforeTime) { 1161 //do nothing 1162 } else if (tween instanceof TweenLite) { 1163 if (tweens !== false) { 1164 a[cnt++] = tween; 1165 } 1166 } else { 1167 if (timelines !== false) { 1168 a[cnt++] = tween; 1169 } 1170 if (nested !== false) { 1171 a = a.concat(tween.getChildren(true, tweens, timelines)); 1172 cnt = a.length; 1173 } 1174 } 1175 tween = tween._next; 1176 } 1177 return a; 1178 }; 1179 1180 p.getTweensOf = function(target, nested) { 1181 var disabled = this._gc, 1182 a = [], 1183 cnt = 0, 1184 tweens, i; 1185 if (disabled) { 1186 this._enabled(true, true); //getTweensOf() filters out disabled tweens, and we have to mark them as _gc = true when the timeline completes in order to allow clean garbage collection, so temporarily re-enable the timeline here. 1187 } 1188 tweens = TweenLite.getTweensOf(target); 1189 i = tweens.length; 1190 while (--i > -1) { 1191 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) { 1192 a[cnt++] = tweens[i]; 1193 } 1194 } 1195 if (disabled) { 1196 this._enabled(false, true); 1197 } 1198 return a; 1199 }; 1200 1201 p.recent = function() { 1202 return this._recent; 1203 }; 1204 1205 p._contains = function(tween) { 1206 var tl = tween.timeline; 1207 while (tl) { 1208 if (tl === this) { 1209 return true; 1210 } 1211 tl = tl.timeline; 1212 } 1213 return false; 1214 }; 1215 1216 p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) { 1217 ignoreBeforeTime = ignoreBeforeTime || 0; 1218 var tween = this._first, 1219 labels = this._labels, 1220 p; 1221 while (tween) { 1222 if (tween._startTime >= ignoreBeforeTime) { 1223 tween._startTime += amount; 1224 } 1225 tween = tween._next; 1226 }
1227 if (adjustLabels) { 1228 for (p in labels) { 1229 if (labels[p] >= ignoreBeforeTime) { 1230 labels[p] += amount; 1231 } 1232 } 1233 } 1234 return this._uncache(true); 1235 }; 1236 1237 p._kill = function(vars, target) { 1238 if (!vars && !target) { 1239 return this._enabled(false, false); 1240 } 1241 var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target), 1242 i = tweens.length, 1243 changed = false; 1244 while (--i > -1) { 1245 if (tweens[i]._kill(vars, target)) { 1246 changed = true; 1247 } 1248 } 1249 return changed; 1250 }; 1251 1252 p.clear = function(labels) { 1253 var tweens = this.getChildren(false, true, true), 1254 i = tweens.length; 1255 this._time = this._totalTime = 0; 1256 while (--i > -1) { 1257 tweens[i]._enabled(false, false); 1258 } 1259 if (labels !== false) { 1260 this._labels = {}; 1261 } 1262 return this._uncache(true); 1263 }; 1264 1265 p.invalidate = function() { 1266 var tween = this._first; 1267 while (tween) { 1268 tween.invalidate(); 1269 tween = tween._next; 1270 } 1271 return Animation.prototype.invalidate.call(this);; 1272 }; 1273 1274 p._enabled = function(enabled, ignoreTimeline) { 1275 if (enabled === this._gc) { 1276 var tween = this._first; 1277 while (tween) { 1278 tween._enabled(enabled, true); 1279 tween = tween._next; 1280 } 1281 } 1282 return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline); 1283 }; 1284 1285 p.totalTime = function(time, suppressEvents, uncapped) { 1286 this._forcingPlayhead = true; 1287 var val = Animation.prototype.totalTime.apply(this, arguments); 1288 this._forcingPlayhead = false; 1289 return val; 1290 }; 1291 1292 p.duration = function(value) { 1293 if (!arguments.length) { 1294 if (this._dirty) { 1295 this.totalDuration(); //just triggers recalculation 1296 } 1297 return this._duration; 1298 } 1299 if (this.duration() !== 0 && value !== 0) { 1300 this.timeScale(this._duration / value); 1301 } 1302 return this; 1303 }; 1304 1305 p.totalDuration = function(value) { 1306 if (!arguments.length) { 1307 if (this._dirty) { 1308 var max = 0, 1309 tween = this._last, 1310 prevStart = 999999999999, 1311 prev, end; 1312 while (tween) { 1313 prev = tween._prev; //record it here in case the tween changes position in the sequence... 1314 if (tween._dirty) { 1315 tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it. 1316 } 1317 if (tween._startTime > prevStart && this._sortChildren && !tween._paused) { //in case one of the tweens shifted out of order, it needs to be re-inserted into the correct position in the sequence 1318 this.add(tween, tween._startTime - tween._delay); 1319 } else { 1320 prevStart = tween._startTime; 1321 } 1322 if (tween._startTime < 0 && !tween._paused) { //children aren't allowed to have negative startTimes unless smoothChildTiming is true, so adjust here if one is found. 1323 max -= tween._startTime; 1324 if (this._timeline.smoothChildTiming) { 1325 this._startTime += tween._startTime / this._timeScale; 1326 } 1327 this.shiftChildren(-tween._startTime, false, -9999999999); 1328 prevStart = 0; 1329 } 1330 end = tween._startTime + (tween._totalDuration / tween._timeScale); 1331 if (end > max) { 1332 max = end; 1333 } 1334 tween = prev; 1335 } 1336 this._duration = this._totalDuration = max; 1337 this._dirty = false; 1338 } 1339 return this._totalDuration; 1340 } 1341 if (this.totalDuration() !== 0) if (value !== 0) { 1342 this.timeScale(this._totalDuration / value); 1343 } 1344 return this; 1345 }; 1346 1347 p.paused = function(value) { 1348 if (!value) { //if there's a pause directly at the spot from where we're unpausing, skip it. 1349 var tween = this._first, 1350 time = this._time; 1351 while (tween) { 1352 if (tween._startTime === time && tween.data === "isPause") { 1353 tween._rawPrevTime = 0; //remember, _rawPrevTime is how zero-duration tweens/callbacks sense directionality and determine whether or not to fire. If _rawPrevTime is the same as _startTime on the next render, it won't fire. 1354 } 1355 tween = tween._next; 1356 } 1357 } 1358 return Animation.prototype.paused.apply(this, arguments); 1359 }; 1360 1361 p.usesFrames = function() { 1362 var tl = this._timeline; 1363 while (tl._timeline) { 1364 tl = tl._timeline; 1365 } 1366 return (tl === Animation._rootFramesTimeline); 1367 }; 1368 1369 p.rawTime = function() { 1370 return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale; 1371 }; 1372 1373 return TimelineLite; 1374 1375 }, true); 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389/* 1390 * ---------------------------------------------------------------- 1391 * TimelineMax 1392 * ---------------------------------------------------------------- 1393 */ 1394 _gsScope._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) { 1395 1396 var TimelineMax = function(vars) { 1397 TimelineLite.call(this, vars); 1398 this._repeat = this.vars.repeat || 0; 1399 this._repeatDelay = this.vars.repeatDelay || 0; 1400 this._cycle = 0; 1401 this._yoyo = (this.vars.yoyo === true); 1402 this._dirty = true; 1403 }, 1404 _tinyNum = 0.0000000001, 1405 TweenLiteInternals = TweenLite._internals, 1406 _lazyTweens = TweenLiteInternals.lazyTweens, 1407 _lazyRender = TweenLiteInternals.lazyRender,
1408 _easeNone = new Ease(null, null, 1, 0), 1409 p = TimelineMax.prototype = new TimelineLite(); 1410 1411 p.constructor = TimelineMax; 1412 p.kill()._gc = false; 1413 TimelineMax.version = "1.18.0"; 1414 1415 p.invalidate = function() { 1416 this._yoyo = (this.vars.yoyo === true); 1417 this._repeat = this.vars.repeat || 0; 1418 this._repeatDelay = this.vars.repeatDelay || 0; 1419 this._uncache(true); 1420 return TimelineLite.prototype.invalidate.call(this); 1421 }; 1422 1423 p.addCallback = function(callback, position, params, scope) { 1424 return this.add( TweenLite.delayedCall(0, callback, params, scope), position); 1425 }; 1426 1427 p.removeCallback = function(callback, position) { 1428 if (callback) { 1429 if (position == null) { 1430 this._kill(null, callback); 1431 } else { 1432 var a = this.getTweensOf(callback, false), 1433 i = a.length, 1434 time = this._parseTimeOrLabel(position); 1435 while (--i > -1) { 1436 if (a[i]._startTime === time) { 1437 a[i]._enabled(false, false); 1438 } 1439 } 1440 } 1441 } 1442 return this; 1443 }; 1444 1445 p.removePause = function(position) { 1446 return this.removeCallback(TimelineLite._internals.pauseCallback, position); 1447 }; 1448 1449 p.tweenTo = function(position, vars) { 1450 vars = vars || {}; 1451 var copy = {ease:_easeNone, useFrames:this.usesFrames(), immediateRender:false}, 1452 duration, p, t; 1453 for (p in vars) { 1454 copy[p] = vars[p]; 1455 } 1456 copy.time = this._parseTimeOrLabel(position); 1457 duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001; 1458 t = new TweenLite(this, duration, copy); 1459 copy.onStart = function() { 1460 t.target.paused(true); 1461 if (t.vars.time !== t.target.time() && duration === t.duration()) { //don't make the duration zero - if it's supposed to be zero, don't worry because it's already initting the tween and will complete immediately, effectively making the duration zero anyway. If we make duration zero, the tween won't run at all. 1462 t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale ); 1463 } 1464 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it. 1465 t._callback("onStart"); 1466 } 1467 }; 1468 return t; 1469 }; 1470 1471 p.tweenFromTo = function(fromPosition, toPosition, vars) { 1472 vars = vars || {}; 1473 fromPosition = this._parseTimeOrLabel(fromPosition); 1474 vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], callbackScope:this}; 1475 vars.immediateRender = (vars.immediateRender !== false); 1476 var t = this.tweenTo(toPosition, vars); 1477 return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001); 1478 }; 1479 1480 p.render = function(time, suppressEvents, force) { 1481 if (this._gc) { 1482 this._enabled(true, false); 1483 } 1484 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(), 1485 dur = this._duration, 1486 prevTime = this._time, 1487 prevTotalTime = this._totalTime, 1488 prevStart = this._startTime, 1489 prevTimeScale = this._timeScale, 1490 prevRawPrevTime = this._rawPrevTime, 1491 prevPaused = this._paused, 1492 prevCycle = this._cycle, 1493 tween, isComplete, next, callback, internalForce, cycleDuration, pauseTween; 1494 if (time >= totalDur) { 1495 if (!this._locked) { 1496 this._totalTime = totalDur; 1497 this._cycle = this._repeat; 1498 } 1499 if (!this._reversed) if (!this._hasPausedChild()) { 1500 isComplete = true; 1501 callback = "onComplete"; 1502 internalForce = !!this._timeline.autoRemoveChildren; //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline. 1503 if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) { 1504 internalForce = true; 1505 if (prevRawPrevTime > _tinyNum) { 1506 callback = "onReverseComplete"; 1507 } 1508 } 1509 } 1510 this._rawPrevTime = (this._duration || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 1511 if (this._yoyo && (this._cycle & 1) !== 0) { 1512 this._time = time = 0; 1513 } else { 1514 this._time = dur; 1515 time = dur + 0.0001; //to avoid occasional floating point rounding errors - sometimes child tweens/timelines were not being fully completed (their progress might be 0.999999999999998 instead of 1 because when _time - tween._startTime is performed, floating point errors would return a value that was SLIGHTLY off). Try (999999999999.7 - 999999999999) * 1 = 0.699951171875 instead of 0.7. We cannot do less then 0.0001 because the same issue can occur when the duration is extremely large like 999999999999 in
1515which case adding 0.00000001, for example, causes it to act like nothing was added. 1516 } 1517 1518 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 1519 if (!this._locked) { 1520 this._totalTime = this._cycle = 0; 1521 } 1522 this._time = 0; 1523 if (prevTime !== 0 || (dur === 0 && prevRawPrevTime !== _tinyNum && (prevRawPrevTime > 0 || (time < 0 && prevRawPrevTime >= 0)) && !this._locked)) { //edge case for checking time < 0 && prevRawPrevTime >= 0: a zero-duration fromTo() tween inside a zero-duration timeline (yeah, very rare) 1524 callback = "onReverseComplete"; 1525 isComplete = this._reversed; 1526 } 1527 if (time < 0) { 1528 this._active = false; 1529 if (this._timeline.autoRemoveChildren && this._reversed) { 1530 internalForce = isComplete = true; 1531 callback = "onReverseComplete"; 1532 } else if (prevRawPrevTime >= 0 && this._first) { //when going back beyond the start, force a render so that zero-duration tweens that sit at the very beginning render their start values properly. Otherwise, if the parent timeline's playhead lands exactly at this timeline's startTime, and then moves backwards, the zero-duration tweens at the beginning would still be at their end state. 1533 internalForce = true; 1534 } 1535 this._rawPrevTime = time; 1536 } else { 1537 this._rawPrevTime = (dur || !suppressEvents || time || this._rawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration timeline or tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 1538 if (time === 0 && isComplete) { //if there's a zero-duration tween at the very beginning of a timeline and the playhead lands EXACTLY at time 0, that tween will correctly render its end values, but we need to keep the timeline alive for one more render so that the beginning values render properly as the parent's playhead keeps moving beyond the begining. Imagine obj.x starts at 0 and then we do tl.set(obj, {x:100}).to(obj, 1, {x:200}) and then later we tl.reverse()...the goal is to have obj.x revert to 0. If the playhead happens to land on exactly 0, without this chunk of code, it'd complete the timeline and remove it from the rendering queue (not good). 1539 tween = this._first; 1540 while (tween && tween._startTime === 0) { 1541 if (!tween._duration) { 1542 isComplete = false; 1543 } 1544 tween = tween._next; 1545 } 1546 } 1547 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline) 1548 if (!this._initted) { 1549 internalForce = true; 1550 } 1551 } 1552 1553 } else { 1554 if (dur === 0 && prevRawPrevTime < 0) { //without this, zero-duration repeating timelines (like with a simple callback nested at the very beginning and a repeatDelay) wouldn't render the first time through. 1555 internalForce = true; 1556 } 1557 this._time = this._rawPrevTime = time; 1558 if (!this._locked) { 1559 this._totalTime = time; 1560 if (this._repeat !== 0) { 1561 cycleDuration = dur + this._repeatDelay; 1562 this._cycle = (this._totalTime / cycleDuration) >> 0; //originally _totalTime % cycleDuration but floating point errors caused problems, so I normalized it. (4 % 0.8 should be 0 but it gets reported as 0.79999999!) 1563 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) { 1564 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning) 1565 } 1566 this._time = this._totalTime - (this._cycle * cycleDuration); 1567 if (this._yoyo) if ((this._cycle & 1) !== 0) { 1568 this._time = dur - this._time; 1569 } 1570 if (this._time > dur) { 1571 this._time = dur; 1572 time = dur + 0.0001; //to avoid occasional floating point rounding error 1573 } else if (this._time < 0) { 1574 this._time = time = 0; 1575 } else { 1576 time = this._time; 1577 } 1578 } 1579 } 1580 1581 if (this._hasPause && !this._forcingPlayhead && !suppressEvents) { 1582 time = this._time; 1583 if (time >= prevTime) { 1584 tween = this._first; 1585 while (tween && tween._startTime <= time && !pauseTween) { 1586 if (!tween._duration) if (tween.data === "isPause" && !tween.ratio && !(tween._startTime === 0 && this._rawPrevTime === 0)) { 1587 pauseTween = tween; 1588 } 1589 tween = tween._next; 1590 } 1591 } else { 1592 tween = this._last; 1593 while (tween && tween._startTime >= time && !pauseTween) { 1594 if (!tween._duration) if (tween.data === "isPause" && tween._rawPrevTime > 0) { 1595 pauseTween = tween; 1596 } 1597 tween = tween._prev; 1598 } 1599 } 1600 if (pauseTween) { 1601 this._time = time = pauseTween._startTime; 1602 this._totalTime = time + (this._cycle * (this._totalDuration + this._repeatDelay)); 1603 } 1604 } 1605 1606 } 1607 1608 if (this._cycle !== prevCycle) if (!this._locked) { 1609 /* 1610 make sure children at the end/beginning of the timeline are rendered properly. If, for example, 1611 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which
1612 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there 1613 could be a callback or a short tween that's at 2.95 or 3 seconds in which wouldn't render. So 1614 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must 1615 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work. 1616 */ 1617 var backwards = (this._yoyo && (prevCycle & 1) !== 0), 1618 wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)), 1619 recTotalTime = this._totalTime, 1620 recCycle = this._cycle, 1621 recRawPrevTime = this._rawPrevTime, 1622 recTime = this._time; 1623 1624 this._totalTime = prevCycle * dur; 1625 if (this._cycle < prevCycle) { 1626 backwards = !backwards; 1627 } else { 1628 this._totalTime += dur; 1629 } 1630 this._time = prevTime; //temporarily revert _time so that render() renders the children in the correct order. Without this, tweens won't rewind correctly. We could arhictect things in a "cleaner" way by splitting out the rendering queue into a separate method but for performance reasons, we kept it all inside this method. 1631 1632 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime; 1633 this._cycle = prevCycle; 1634 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render() 1635 prevTime = (backwards) ? 0 : dur; 1636 this.render(prevTime, suppressEvents, (dur === 0)); 1637 if (!suppressEvents) if (!this._gc) { 1638 if (this.vars.onRepeat) { 1639 this._callback("onRepeat"); 1640 } 1641 } 1642 if (wrap) { 1643 prevTime = (backwards) ? dur + 0.0001 : -0.0001; 1644 this.render(prevTime, true, false); 1645 } 1646 this._locked = false; 1647 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible) 1648 return; 1649 } 1650 this._time = recTime; 1651 this._totalTime = recTotalTime; 1652 this._cycle = recCycle; 1653 this._rawPrevTime = recRawPrevTime; 1654 } 1655 1656 if ((this._time === prevTime || !this._first) && !force && !internalForce && !pauseTween) { 1657 if (prevTotalTime !== this._totalTime) if (this._onUpdate) if (!suppressEvents) { //so that onUpdate fires even during the repeatDelay - as long as the totalTime changed, we should trigger onUpdate. 1658 this._callback("onUpdate"); 1659 } 1660 return; 1661 } else if (!this._initted) { 1662 this._initted = true; 1663 } 1664 1665 if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) { 1666 this._active = true; //so that if the user renders the timeline (as opposed to the parent timeline rendering it), it is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the timeline already finished but the user manually re-renders it as halfway done, for example. 1667 } 1668 1669 if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) { 1670 this._callback("onStart"); 1671 } 1672 1673 if (this._time >= prevTime) { 1674 tween = this._first; 1675 while (tween) { 1676 next = tween._next; //record it here because the value could change after rendering... 1677 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1678 break; 1679 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) { 1680 if (pauseTween === tween) { 1681 this.pause(); 1682 } 1683 if (!tween._reversed) { 1684 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1685 } else { 1686 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1687 } 1688 } 1689 tween = next; 1690 } 1691 } else { 1692 tween = this._last; 1693 while (tween) { 1694 next = tween._prev; //record it here because the value could change after rendering... 1695 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1696 break; 1697 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) { 1698 if (pauseTween === tween) { 1699 pauseTween = tween._prev; //the linked list is organized by _startTime, thus it's possible that a tween could start BEFORE the pause and end after it, in which case it would be positioned before the pause tween in the linked list, but we should render it before we pause() the timeline and cease rendering. This is only a concern when going in reverse. 1700 while (pauseTween && pauseTween.endTime() > this._time) { 1701 pauseTween.render( (pauseTween._reversed ? pauseTween.totalDuration() - ((time - pauseTween._startTime) * pauseTween._timeScale) : (time - pauseTween._startTime) * pauseTween._timeScale), suppressEvents, force); 1702 pauseTween = pauseTween._prev; 1703 } 1704 pauseTween = null; 1705 this.pause(); 1706 } 1707 if (!tween._reversed) { 1708 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1709 } else { 1710 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1711 } 1712 } 1713 tween = next; 1714 } 1715 } 1716 1717 if (this._onUpdate) if (!suppressEvents) { 1718 if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onUpdate on a timeline that reports/checks tweened values. 1719 _lazyRender(); 1720 }
1721 this._callback("onUpdate"); 1722 } 1723 if (callback) if (!this._locked) if (!this._gc) if (prevStart === this._startTime || prevTimeScale !== this._timeScale) if (this._time === 0 || totalDur >= this.totalDuration()) { //if one of the tweens that was rendered altered this timeline's startTime (like if an onComplete reversed the timeline), it probably isn't complete. If it is, don't worry, because whatever call altered the startTime would complete if it was necessary at the new time. The only exception is the timeScale property. Also check _gc because there's a chance that kill() could be called in an onUpdate 1724 if (isComplete) { 1725 if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when a timeline finishes, users expect things to have rendered fully. Imagine an onComplete on a timeline that reports/checks tweened values. 1726 _lazyRender(); 1727 } 1728 if (this._timeline.autoRemoveChildren) { 1729 this._enabled(false, false); 1730 } 1731 this._active = false; 1732 } 1733 if (!suppressEvents && this.vars[callback]) { 1734 this._callback(callback); 1735 } 1736 } 1737 }; 1738 1739 p.getActive = function(nested, tweens, timelines) { 1740 if (nested == null) { 1741 nested = true; 1742 } 1743 if (tweens == null) { 1744 tweens = true; 1745 } 1746 if (timelines == null) { 1747 timelines = false; 1748 } 1749 var a = [], 1750 all = this.getChildren(nested, tweens, timelines), 1751 cnt = 0, 1752 l = all.length, 1753 i, tween; 1754 for (i = 0; i < l; i++) { 1755 tween = all[i]; 1756 if (tween.isActive()) { 1757 a[cnt++] = tween; 1758 } 1759 } 1760 return a; 1761 }; 1762 1763 1764 p.getLabelAfter = function(time) { 1765 if (!time) if (time !== 0) { //faster than isNan() 1766 time = this._time; 1767 } 1768 var labels = this.getLabelsArray(), 1769 l = labels.length, 1770 i; 1771 for (i = 0; i < l; i++) { 1772 if (labels[i].time > time) { 1773 return labels[i].name; 1774 } 1775 } 1776 return null; 1777 }; 1778 1779 p.getLabelBefore = function(time) { 1780 if (time == null) { 1781 time = this._time; 1782 } 1783 var labels = this.getLabelsArray(), 1784 i = labels.length; 1785 while (--i > -1) { 1786 if (labels[i].time < time) { 1787 return labels[i].name; 1788 } 1789 } 1790 return null; 1791 }; 1792 1793 p.getLabelsArray = function() { 1794 var a = [], 1795 cnt = 0, 1796 p; 1797 for (p in this._labels) { 1798 a[cnt++] = {time:this._labels[p], name:p}; 1799 } 1800 a.sort(function(a,b) { 1801 return a.time - b.time; 1802 }); 1803 return a; 1804 }; 1805 1806 1807//---- GETTERS / SETTERS ------------------------------------------------------------------------------------------------------- 1808 1809 p.progress = function(value, suppressEvents) { 1810 return (!arguments.length) ? this._time / this.duration() : this.totalTime( this.duration() * ((this._yoyo && (this._cycle & 1) !== 0) ? 1 - value : value) + (this._cycle * (this._duration + this._repeatDelay)), suppressEvents); 1811 }; 1812 1813 p.totalProgress = function(value, suppressEvents) { 1814 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, suppressEvents); 1815 }; 1816 1817 p.totalDuration = function(value) { 1818 if (!arguments.length) { 1819 if (this._dirty) { 1820 TimelineLite.prototype.totalDuration.call(this); //just forces refresh 1821 //Instead of Infinity, we use 999999999999 so that we can accommodate reverses. 1822 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat); 1823 } 1824 return this._totalDuration; 1825 } 1826 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) ); 1827 }; 1828 1829 p.time = function(value, suppressEvents) { 1830 if (!arguments.length) { 1831 return this._time; 1832 } 1833 if (this._dirty) { 1834 this.totalDuration(); 1835 } 1836 if (value > this._duration) { 1837 value = this._duration; 1838 } 1839 if (this._yoyo && (this._cycle & 1) !== 0) { 1840 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay)); 1841 } else if (this._repeat !== 0) { 1842 value += this._cycle * (this._duration + this._repeatDelay); 1843 } 1844 return this.totalTime(value, suppressEvents); 1845 }; 1846 1847 p.repeat = function(value) { 1848 if (!arguments.length) { 1849 return this._repeat; 1850 } 1851 this._repeat = value; 1852 return this._uncache(true); 1853 }; 1854 1855 p.repeatDelay = function(value) { 1856 if (!arguments.length) { 1857 return this._repeatDelay; 1858 } 1859 this._repeatDelay = value; 1860 return this._uncache(true); 1861 }; 1862 1863 p.yoyo = function(value) { 1864 if (!arguments.length) { 1865 return this._yoyo; 1866 } 1867 this._yoyo = value; 1868 return this; 1869 }; 1870 1871 p.currentLabel = function(value) { 1872 if (!arguments.length) { 1873 return this.getLabelBefore(this._time + 0.00000001); 1874 } 1875 return this.seek(value, true); 1876 }; 1877 1878 return TimelineMax; 1879 1880 }, true); 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893/* 1894 * ---------------------------------------------------------------- 1895 * BezierPlugin 1896 * ---------------------------------------------------------------- 1897 */ 1898 (function() { 1899 1900 var _RAD2DEG = 180 / Math.PI, 1901 _r1 = [], 1902 _r2 = [], 1903 _r3 = [], 1904 _corProps = {}, 1905 _globals = _gsScope._gsDefine.globals, 1906 Segment = function(a, b, c, d) { 1907 this.a = a; 1908 this.b = b; 1909 this.c = c; 1910 this.d = d; 1911 this.da = d - a; 1912 this.ca = c - a; 1913 this.ba = b - a; 1914 }, 1915 _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,", 1916 cubicToQuadratic = function(a, b, c, d) { 1917 var q1 = {a:a}, 1918 q2 = {}, 1919 q3 = {}, 1920 q4 = {c:d}, 1921 mab = (a + b) / 2, 1922 mbc = (b + c) / 2, 1923 mcd = (c + d) / 2, 1924 mabc = (mab + mbc) / 2, 1925 mbcd = (mbc + mcd) / 2, 1926 m8 = (mbcd - mabc) / 8; 1927 q1.b = mab + (a - mab) / 4; 1928 q2.b = mabc + m8; 1929 q1.c = q2.a = (q1.b + q2.b) / 2; 1930 q2.c = q3.a = (mabc + mbcd) / 2; 1931 q3.b = mbcd - m8; 1932 q4.b = mcd + (d - mcd) / 4; 1933 q3.c = q4.a = (q3.b + q4.b) / 2; 1934 return [q1, q2, q3, q4]; 1935 }, 1936 _calculateControlPoints = function(a, curviness, quad, basic, correlate) { 1937 var l = a.length - 1, 1938 ii = 0, 1939 cp1 = a[0].a, 1940 i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl; 1941 for (i = 0; i < l; i++) { 1942 seg = a[ii]; 1943 p1 = seg.a; 1944 p2 = seg.d; 1945 p3 = a[ii+1].d; 1946 1947 if (correlate) { 1948 r1 = _r1[i]; 1949 r2 = _r2[i]; 1950 tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5); 1951 m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0)); 1952 m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0)); 1953 mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0)); 1954 } else { 1955 m1 = p2 - (p2 - p1) * curviness * 0.5; 1956 m2 = p2 + (p3 - p2) * curviness * 0.5; 1957 mm = p2 - (m1 + m2) / 2; 1958 } 1959 m1 += mm; 1960 m2 += mm; 1961 1962 seg.c = cp2 = m1; 1963 if (i !== 0) { 1964 seg.b = cp1; 1965 } else { 1966 seg.b = cp1 = seg.a + (seg.c - seg.a) * 0.6; //instead of placing b on a exactly, we move it inline with c so that if the user specifies an ease like Back.easeIn or Elastic.easeIn which goes BEYOND the beginning, it will do so smoothly. 1967 } 1968 1969 seg.da = p2 - p1; 1970 seg.ca = cp2 - p1; 1971 seg.ba = cp1 - p1; 1972 1973 if (quad) { 1974 qb = cubicToQuadratic(p1, cp1, cp2, p2); 1975 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]); 1976 ii += 4; 1977 } else { 1978 ii++; 1979 } 1980 1981 cp1 = m2; 1982 } 1983 seg = a[ii]; 1984 seg.b = cp1; 1985 seg.c = cp1 + (seg.d - cp1) * 0.4; //instead of placing c on d exactly, we move it inline with b so that if the user specifies an ease like Back.easeOut or Elastic.easeOut which goes BEYOND the end, it will do so smoothly. 1986 seg.da = seg.d - seg.a; 1987 seg.ca = seg.c - seg.a; 1988 seg.ba = cp1 - seg.a; 1989 if (quad) { 1990 qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d); 1991 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]); 1992 } 1993 }, 1994 _parseAnchors = function(values, p, correlate, prepend) { 1995 var a = [], 1996 l, i, p1, p2, p3, tmp; 1997 if (prepend) {
1998 values = [prepend].concat(values); 1999 i = values.length; 2000 while (--i > -1) { 2001 if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") { 2002 values[i][p] = prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)); //accommodate relative values. Do it inline instead of breaking it out into a function for speed reasons 2003 } 2004 } 2005 } 2006 l = values.length - 2; 2007 if (l < 0) { 2008 a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]); 2009 return a; 2010 } 2011 for (i = 0; i < l; i++) { 2012 p1 = values[i][p]; 2013 p2 = values[i+1][p]; 2014 a[i] = new Segment(p1, 0, 0, p2); 2015 if (correlate) { 2016 p3 = values[i+2][p]; 2017 _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1); 2018 _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2); 2019 } 2020 } 2021 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]); 2022 return a; 2023 }, 2024 bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) { 2025 var obj = {}, 2026 props = [], 2027 first = prepend || values[0], 2028 i, p, a, j, r, l, seamless, last; 2029 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate; 2030 if (curviness == null) { 2031 curviness = 1; 2032 } 2033 for (p in values[0]) { 2034 props.push(p); 2035 } 2036 //check to see if the last and first values are identical (well, within 0.05). If so, make seamless by appending the second element to the very end of the values array and the 2nd-to-last element to the very beginning (we'll remove those segments later) 2037 if (values.length > 1) { 2038 last = values[values.length - 1]; 2039 seamless = true; 2040 i = props.length; 2041 while (--i > -1) { 2042 p = props[i]; 2043 if (Math.abs(first[p] - last[p]) > 0.05) { //build in a tolerance of +/-0.05 to accommodate rounding errors. For example, if you set an object's position to 4.945, Flash will make it 4.9 2044 seamless = false; 2045 break; 2046 } 2047 } 2048 if (seamless) { 2049 values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens 2050 if (prepend) { 2051 values.unshift(prepend); 2052 } 2053 values.push(values[1]); 2054 prepend = values[values.length - 3]; 2055 } 2056 } 2057 _r1.length = _r2.length = _r3.length = 0; 2058 i = props.length; 2059 while (--i > -1) { 2060 p = props[i]; 2061 _corProps[p] = (correlate.indexOf(","+p+",") !== -1); 2062 obj[p] = _parseAnchors(values, p, _corProps[p], prepend); 2063 } 2064 i = _r1.length; 2065 while (--i > -1) { 2066 _r1[i] = Math.sqrt(_r1[i]); 2067 _r2[i] = Math.sqrt(_r2[i]); 2068 } 2069 if (!basic) { 2070 i = props.length; 2071 while (--i > -1) { 2072 if (_corProps[p]) { 2073 a = obj[props[i]]; 2074 l = a.length - 1; 2075 for (j = 0; j < l; j++) { 2076 r = a[j+1].da / _r2[j] + a[j].da / _r1[j]; 2077 _r3[j] = (_r3[j] || 0) + r * r; 2078 } 2079 } 2080 } 2081 i = _r3.length; 2082 while (--i > -1) { 2083 _r3[i] = Math.sqrt(_r3[i]); 2084 } 2085 } 2086 i = props.length; 2087 j = quadratic ? 4 : 1; 2088 while (--i > -1) { 2089 p = props[i]; 2090 a = obj[p]; 2091 _calculateControlPoints(a, curviness, quadratic, basic, _corProps[p]); //this method requires that _parseAnchors() and _setSegmentRatios() ran first so that _r1, _r2, and _r3 values are populated for all properties 2092 if (seamless) { 2093 a.splice(0, j); 2094 a.splice(a.length - j, j); 2095 } 2096 } 2097 return obj; 2098 }, 2099 _parseBezierData = function(values, type, prepend) { 2100 type = type || "soft"; 2101 var obj = {}, 2102 inc = (type === "cubic") ? 3 : 2, 2103 soft = (type === "soft"), 2104 props = [], 2105 a, b, c, d, cur, i, j, l, p, cnt, tmp; 2106 if (soft && prepend) { 2107 values = [prepend].concat(values); 2108 } 2109 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; } 2110 for (p in values[0]) { 2111 props.push(p); 2112 } 2113 i = props.length; 2114 while (--i > -1) { 2115 p = props[i]; 2116 obj[p] = cur = []; 2117 cnt = 0; 2118 l = values.length; 2119 for (j = 0; j < l; j++) { 2120 a = (prepend == null) ? values[j][p] : (typeof( (tmp = values[j][p]) ) === "string" && tmp.charAt(1) === "=") ? prepend[p] + Number(tmp.charAt(0) + tmp.substr(2)) : Number(tmp); 2121 if (soft) if (j > 1) if (j < l - 1) { 2122 cur[cnt++] = (a + cur[cnt-2]) / 2; 2123 } 2124 cur[cnt++] = a; 2125 } 2126 l = cnt - inc + 1; 2127 cnt = 0; 2128 for (j = 0; j < l; j += inc) { 2129 a = cur[j]; 2130 b = cur[j+1]; 2131 c = cur[j+2]; 2132 d = (inc === 2) ? 0 : cur[j+3]; 2133 cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c); 2134 } 2135 cur.length = cnt; 2136 } 2137 return obj; 2138 }, 2139 _addCubicLengths = function(a, steps, resolution) { 2140 var inc = 1 / resolution, 2141 j = a.length, 2142 d, d1, s, da, ca, ba, p, i, inv, bez, index; 2143 while (--j > -1) { 2144 bez = a[j]; 2145 s = bez.a; 2146 da = bez.d - s; 2147 ca = bez.c - s; 2148 ba = bez.b - s; 2149 d = d1 = 0; 2150 for (i = 1; i <= resolution; i++) { 2151 p = inc * i; 2152 inv = 1 - p; 2153 d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p); 2154 index = j * resolution + i - 1; 2155 steps[index] = (steps[index] || 0) + d * d; 2156 } 2157 } 2158 }, 2159 _parseLengthData = function(obj, resolution) { 2160 resolution = resolution >> 0 || 6; 2161 var a = [], 2162 lengths = [], 2163 d = 0, 2164 total = 0, 2165 threshold = resolution - 1, 2166 segments = [], 2167 curLS = [], //current length segments array 2168 p, i, l, index; 2169 for (p in obj) { 2170 _addCubicLengths(obj[p], a, resolution); 2171 } 2172 l = a.length; 2173 for (i = 0; i < l; i++) { 2174 d += Math.sqrt(a[i]); 2175 index = i % resolution; 2176 curLS[index] = d; 2177 if (index === threshold) { 2178 total += d; 2179 index = (i / resolution) >> 0; 2180 segments[index] = curLS; 2181 lengths[index] = total; 2182 d = 0; 2183 curLS = []; 2184 } 2185 } 2186 return {length:total, lengths:lengths, segments:segments}; 2187 }, 2188 2189 2190 2191 BezierPlugin = _gsScope._gsDefine.plugin({ 2192 propName: "bezier", 2193 priority: -1, 2194 version: "1.3.4", 2195 API: 2, 2196 global:true, 2197 2198 //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 2199 init: function(target, vars, tween) { 2200 this._target = target; 2201 if (vars instanceof Array) { 2202 vars = {values:vars}; 2203 } 2204 this._func = {}; 2205 this._round = {}; 2206 this._props = []; 2207 this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10); 2208 var values = vars.values || [], 2209 first = {}, 2210 second = values[0], 2211 autoRotate = vars.autoRotate || tween.vars.orientToBezier, 2212 p, isFunc, i, j, prepend; 2213 2214 this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null; 2215 for (p in second) { 2216 this._props.push(p); 2217 } 2218 2219 i = this._props.length; 2220 while (--i > -1) { 2221 p = this._props[i]; 2222 2223 this._overwriteProps.push(p); 2224 isFunc = this._func[p] = (typeof(target[p]) === "function"); 2225 first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ](); 2226 if (!prepend) if (first[p] !== values[0][p]) { 2227 prepend = first; 2228 } 2229 } 2230 this._beziers = (vars.type !== "cubic" && vars.type !== "quadratic" && vars.type !== "soft") ? bezierThrough(values, isNaN(vars.curviness) ? 1 : vars.curviness, false, (vars.type === "thruBasic"), vars.correlate, prepend) : _parseBezierData(values, vars.type, first); 2231 this._segCount = this._beziers[p].length; 2232 2233 if (this._timeRes) { 2234 var ld = _parseLengthData(this._beziers, this._timeRes); 2235 this._length = ld.length; 2236 this._lengths = ld.lengths; 2237 this._segments = ld.segments; 2238 this._l1 = this._li = this._s1 = this._si = 0; 2239 this._l2 = this._lengths[0]; 2240 this._curSeg = this._segments[0]; 2241 this._s2 = this._curSeg[0]; 2242 this._prec = 1 / this._curSeg.length; 2243 } 2244 2245 if ((autoRotate = this._autoRotate)) { 2246 this._initialRotations = []; 2247 if (!(autoRotate[0] instanceof Array)) { 2248 this._autoRotate = autoRotate = [autoRotate]; 2249 } 2250 i = autoRotate.length; 2251 while (--i > -1) { 2252 for (j = 0; j < 3; j++) { 2253 p = autoRotate[i][j]; 2254 this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
2255 } 2256 p = autoRotate[i][2]; 2257 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p]; 2258 } 2259 } 2260 this._startRatio = tween.vars.runBackwards ? 1 : 0; //we determine the starting ratio when the tween inits which is always 0 unless the tween has runBackwards:true (indicating it's a from() tween) in which case it's 1. 2261 return true; 2262 }, 2263 2264 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.) 2265 set: function(v) { 2266 var segments = this._segCount, 2267 func = this._func, 2268 target = this._target, 2269 notStart = (v !== this._startRatio), 2270 curIndex, inv, i, p, b, t, val, l, lengths, curSeg; 2271 if (!this._timeRes) { 2272 curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0; 2273 t = (v - (curIndex * (1 / segments))) * segments; 2274 } else { 2275 lengths = this._lengths; 2276 curSeg = this._curSeg; 2277 v *= this._length; 2278 i = this._li; 2279 //find the appropriate segment (if the currently cached one isn't correct) 2280 if (v > this._l2 && i < segments - 1) { 2281 l = segments - 1; 2282 while (i < l && (this._l2 = lengths[++i]) <= v) { } 2283 this._l1 = lengths[i-1]; 2284 this._li = i; 2285 this._curSeg = curSeg = this._segments[i]; 2286 this._s2 = curSeg[(this._s1 = this._si = 0)]; 2287 } else if (v < this._l1 && i > 0) { 2288 while (i > 0 && (this._l1 = lengths[--i]) >= v) { } 2289 if (i === 0 && v < this._l1) { 2290 this._l1 = 0; 2291 } else { 2292 i++; 2293 } 2294 this._l2 = lengths[i]; 2295 this._li = i; 2296 this._curSeg = curSeg = this._segments[i]; 2297 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0; 2298 this._s2 = curSeg[this._si]; 2299 } 2300 curIndex = i; 2301 //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one) 2302 v -= this._l1; 2303 i = this._si; 2304 if (v > this._s2 && i < curSeg.length - 1) { 2305 l = curSeg.length - 1; 2306 while (i < l && (this._s2 = curSeg[++i]) <= v) { } 2307 this._s1 = curSeg[i-1]; 2308 this._si = i; 2309 } else if (v < this._s1 && i > 0) { 2310 while (i > 0 && (this._s1 = curSeg[--i]) >= v) { } 2311 if (i === 0 && v < this._s1) { 2312 this._s1 = 0; 2313 } else { 2314 i++; 2315 } 2316 this._s2 = curSeg[i]; 2317 this._si = i; 2318 } 2319 t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec; 2320 } 2321 inv = 1 - t; 2322 2323 i = this._props.length; 2324 while (--i > -1) { 2325 p = this._props[i]; 2326 b = this._beziers[p][curIndex]; 2327 val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a; 2328 if (this._round[p]) { 2329 val = Math.round(val); 2330 } 2331 if (func[p]) { 2332 target[p](val); 2333 } else { 2334 target[p] = val; 2335 } 2336 } 2337 2338 if (this._autoRotate) { 2339 var ar = this._autoRotate, 2340 b2, x1, y1, x2, y2, add, conv; 2341 i = ar.length; 2342 while (--i > -1) { 2343 p = ar[i][2]; 2344 add = ar[i][3] || 0; 2345 conv = (ar[i][4] === true) ? 1 : _RAD2DEG; 2346 b = this._beziers[ar[i][0]]; 2347 b2 = this._beziers[ar[i][1]]; 2348 2349 if (b && b2) { //in case one of the properties got overwritten. 2350 b = b[curIndex]; 2351 b2 = b2[curIndex]; 2352 2353 x1 = b.a + (b.b - b.a) * t; 2354 x2 = b.b + (b.c - b.b) * t; 2355 x1 += (x2 - x1) * t; 2356 x2 += ((b.c + (b.d - b.c) * t) - x2) * t; 2357 2358 y1 = b2.a + (b2.b - b2.a) * t; 2359 y2 = b2.b + (b2.c - b2.b) * t; 2360 y1 += (y2 - y1) * t; 2361 y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t; 2362 2363 val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i]; 2364 2365 if (func[p]) { 2366 target[p](val); 2367 } else { 2368 target[p] = val; 2369 } 2370 } 2371 } 2372 } 2373 } 2374 }), 2375 p = BezierPlugin.prototype; 2376 2377 2378 BezierPlugin.bezierThrough = bezierThrough; 2379 BezierPlugin.cubicToQuadratic = cubicToQuadratic; 2380 BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite 2381 BezierPlugin.quadraticToCubic = function(a, b, c) { 2382 return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c); 2383 }; 2384 2385 BezierPlugin._cssRegister = function() { 2386 var CSSPlugin = _globals.CSSPlugin; 2387 if (!CSSPlugin) { 2388 return; 2389 } 2390 var _internals = CSSPlugin._internals, 2391 _parseToProxy = _internals._parseToProxy, 2392 _setPluginRatio = _internals._setPluginRatio, 2393 CSSPropTween = _internals.CSSPropTween; 2394 _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) { 2395 if (e instanceof Array) { 2396 e = {values:e}; 2397 } 2398 plugin = new BezierPlugin(); 2399 var values = e.values, 2400 l = values.length - 1, 2401 pluginValues = [], 2402 v = {}, 2403 i, p, data; 2404 if (l < 0) { 2405 return pt; 2406 } 2407 for (i = 0; i <= l; i++) { 2408 data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i)); 2409 pluginValues[i] = data.end; 2410 } 2411 for (p in e) { 2412 v[p] = e[p]; //duplicate the vars object because we need to alter some things which w
2412ould cause problems if the user plans to reuse the same vars object for another tween. 2413 } 2414 v.values = pluginValues; 2415 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2); 2416 pt.data = data; 2417 pt.plugin = plugin; 2418 pt.setRatio = _setPluginRatio; 2419 if (v.autoRotate === 0) { 2420 v.autoRotate = true; 2421 } 2422 if (v.autoRotate && !(v.autoRotate instanceof Array)) { 2423 i = (v.autoRotate === true) ? 0 : Number(v.autoRotate); 2424 v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false; 2425 } 2426 if (v.autoRotate) { 2427 if (!cssp._transform) { 2428 cssp._enableTransforms(false); 2429 } 2430 data.autoRotate = cssp._target._gsTransform; 2431 } 2432 plugin._onInitTween(data.proxy, v, cssp._tween); 2433 return pt; 2434 }}); 2435 }; 2436 2437 p._roundProps = function(lookup, value) { 2438 var op = this._overwriteProps, 2439 i = op.length; 2440 while (--i > -1) { 2441 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) { 2442 this._round[op[i]] = value; 2443 } 2444 } 2445 }; 2446 2447 p._kill = function(lookup) { 2448 var a = this._props, 2449 p, i; 2450 for (p in this._beziers) { 2451 if (p in lookup) { 2452 delete this._beziers[p]; 2453 delete this._func[p]; 2454 i = a.length; 2455 while (--i > -1) { 2456 if (a[i] === p) { 2457 a.splice(i, 1); 2458 } 2459 } 2460 } 2461 } 2462 return this._super._kill.call(this, lookup); 2463 }; 2464 2465 }()); 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480/* 2481 * ---------------------------------------------------------------- 2482 * CSSPlugin 2483 * ---------------------------------------------------------------- 2484 */ 2485 _gsScope._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) { 2486 2487 /** @constructor **/ 2488 var CSSPlugin = function() { 2489 TweenPlugin.call(this, "css"); 2490 this._overwriteProps.length = 0; 2491 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method) 2492 }, 2493 _globals = _gsScope._gsDefine.globals, 2494 _hasPriority, //turns true whenever a CSSPropTween instance is created that has a priority other than 0. This helps us discern whether or not we should spend the time organizing the linked list or not after a CSSPlugin's _onInitTween() method is called. 2495 _suffixMap, //we set this in _onInitTween() each time as a way to have a persistent variable we can use in other methods like _parse() without having to pass it around as a parameter and we keep _parse() decoupled from a particular CSSPlugin instance 2496 _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter 2497 _overwriteProps, //alias to the currently instantiating CSSPlugin's _overwriteProps array. We use this closure in order to avoid having to pass a reference around from method to method and aid in minification. 2498 _specialProps = {}, 2499 p = CSSPlugin.prototype = new TweenPlugin("css"); 2500 2501 p.constructor = CSSPlugin; 2502 CSSPlugin.version = "1.18.0"; 2503 CSSPlugin.API = 2; 2504 CSSPlugin.defaultTransformPerspective = 0; 2505 CSSPlugin.defaultSkewType = "compensated"; 2506 CSSPlugin.defaultSmoothOrigin = true; 2507 p = "px"; //we'll reuse the "p" variable to keep file size down 2508 CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""}; 2509 2510 2511 var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g, 2512 _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g, 2513 _valuesExp = /(?:\+=|\-=|\-|\b)[\d\-\.]+[a-zA-Z0-9]*(?:%|\b)/gi, //finds all the values that begin with numbers or += or -= and then a number. Includes suffixes. We use this to split complex values apart like "1px 5px 20px rgb(255,102,51)" 2514 _NaNExp = /(?![+-]?\d*\.?\d+|[+-]|e[+-]\d+)[^0-9]/g, //also allows scientific notation and doesn't kill the leading -/+ in -= and += 2515 _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g, 2516 _opacityExp = /opacity *= *([^)]*)/i, 2517 _opacityValExp = /opacity:([^;]*)/i, 2518 _alphaFilterExp = /alpha\(opacity *=.+?\)/i, 2519 _rgbhslExp = /^(rgb|hsl)/, 2520 _capsExp = /([A-Z])/g, 2521 _camelExp = /-([a-z])/gi, 2522 _urlExp = /(^(?:url\(\"|url\())|(?:(\"\))$|\)$)/gi, //for pulling out urls from url(...) or url("...") strings (some browsers wrap urls in quotes, some don't when reporting things like backgroundImage) 2523 _camelFunc = function(s, g) { return g.toUpperCase(); }, 2524 _horizExp = /(?:Left|Right|Width)/i, 2525 _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
2526 _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i, 2527 _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis 2528 _DEG2RAD = Math.PI / 180, 2529 _RAD2DEG = 180 / Math.PI, 2530 _forcePT = {}, 2531 _doc = document, 2532 _createElement = function(type) { 2533 return _doc.createElementNS ? _doc.createElementNS("http://www.w3.org/1999/xhtml", type) : _doc.createElement(type); 2534 }, 2535 _tempDiv = _createElement("div"), 2536 _tempImg = _createElement("img"), 2537 _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins 2538 _agent = navigator.userAgent, 2539 _autoRound, 2540 _reqSafariFix, //we won't apply the Safari transform fix until we actually come across a tween that affects a transform property (to maintain best performance). 2541 2542 _isSafari, 2543 _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element. 2544 _isSafariLT6, //Safari (and Android 4 which uses a flavor of Safari) has a bug that prevents changes to "top" and "left" properties from rendering properly if changed on the same frame as a transform UNLESS we set the element's WebkitBackfaceVisibility to hidden (weird, I know). Doing this for Android 3 and earlier seems to actually cause other problems, though (fun!) 2545 _ieVers, 2546 _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version. 2547 var i = _agent.indexOf("Android"), 2548 a = _createElement("a"); 2549 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3)); 2550 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6)); 2551 _isFirefox = (_agent.indexOf("Firefox") !== -1); 2552 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent) || (/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) { 2553 _ieVers = parseFloat( RegExp.$1 ); 2554 } 2555 if (!a) { 2556 return false; 2557 } 2558 a.style.cssText = "top:1px;opacity:.55;"; 2559 return /^0.55/.test(a.style.opacity); 2560 }()), 2561 _getIEOpacity = function(v) { 2562 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1); 2563 }, 2564 _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE. 2565 if (window.console) { 2566 console.log(s); 2567 } 2568 }, 2569 2570 _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-" 2571 _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz". 2572 2573 // @private feed in a camelCase property name like "transform" and it will check to see if it is valid as-is or if it needs a vendor prefix. It returns the corrected camelCase property name (i.e. "WebkitTransform" or "MozTransform" or "transform" or null if no such property is found, like if the browser is IE8 or before, "transform" won't be found at all) 2574 _checkPropPrefix = function(p, e) { 2575 e = e || _tempDiv; 2576 var s = e.style, 2577 a, i; 2578 if (s[p] !== undefined) { 2579 return p; 2580 } 2581 p = p.charAt(0).toUpperCase() + p.substr(1); 2582 a = ["O","Moz","ms","Ms","Webkit"]; 2583 i = 5; 2584 while (--i > -1 && s[a[i]+p] === undefined) { } 2585 if (i >= 0) { 2586 _prefix = (i === 3) ? "ms" : a[i]; 2587 _prefixCSS = "-" + _prefix.toLowerCase() + "-"; 2588 return _prefix + p; 2589 } 2590 return null; 2591 }, 2592 2593 _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {}, 2594 2595 /** 2596 * @private Returns the css style for a particular property of an element. For example, to get whatever the current "left" css value for an element with an ID of "myElement", you could do: 2597 * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left"); 2598 * 2599 * @param {!Object} t Target element whose style property you want to query 2600 * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.) 2601 * @param {Object=} cs Computed style object. This just provides a way to speed processing if you're going to get several properties on the same element in quick succession - you can reuse the result of the getComputedStyle() call. 2602 * @param {boolean=} calc If true, the value will not be read directly from the element's "style" property (if it exists there), but instead the getComputedStyle() result will be used. This can be useful when you want to ensure that the browser itself is interpreting the value. 2603 * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto". 2604 * @return {?string} The current property value 2605 */ 2606 _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) { 2607 var rv; 2608 if (!_supportsOpacity) if (p === "opacity") { //several versions of IE don't use the standard "opacity" property - they use things like filter:alpha(opacity=50), so we parse that here. 2609 return _getIEOpacity(t); 2610 } 2611 if (!calc && t.style[p]) { 2612 rv = t.style[p]; 2613 } else if ((cs = cs || _getComputedStyle(t))) { 2614 rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase()); 2615 } else if (t.currentStyle) { 2616 rv = t.currentStyle[p]; 2617 } 2618 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv; 2619 }, 2620 2621 /** 2622 * @private Pass the target element, the property name, the numeric value, and the suffix (like "%", "em", "px", etc.) and it will spit back the equivalent pixel number. 2623 * @param {!Object} t Target element 2624 * @param {!string} p Property name (like "left", "top", "marginLeft", etc.) 2625 * @param {!number} v Value 2626 * @param {string=} sfx Suffix (like "px" or "%" or "em") 2627 * @param {boolean=} recurse If true, the call is a recursive one. In some browsers (like IE7/8), occasionally the value isn't accurately reported initially, but if we run the function again it will take effect. 2628 * @return {number} value in pixels 2629 */ 2630 _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) { 2631 if (sfx === "px" || !sfx) { return v; } 2632 if (sfx === "auto" || !v) { return 0; } 2633 var horiz = _horizExp.test(p), 2634 node = t, 2635 style = _tempDiv.style, 2636 neg = (v < 0), 2637 pix, cache, time; 2638 if (neg) { 2639 v = -v; 2640 } 2641 if (sfx === "%" && p.indexOf("border") !== -1) { 2642 pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight); 2643 } else { 2644 style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;"; 2645 if (sfx === "%" || !node.appendChild || sfx.charAt(0) === "v" || sfx === "rem") { 2646 node = t.parentNode || _doc.body; 2647 cache = node._gsCache; 2648 time = TweenLite.ticker.frame; 2649 if (cache && horiz && cache.time === time) { //performance optimization: we record the width of elements along with the ticker frame so that we can quickly get it again on the same tick (seems relatively safe to assume it wouldn't change on the same tick) 2650 return cache.width * v / 100; 2651 } 2652 style[(horiz ? "width" : "height")] = v + sfx; 2653 } else { 2654 style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx; 2655 } 2656 node.appendChild(_tempDiv); 2657 pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]); 2658 node.removeChild(_tempDiv); 2659 if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) { 2660 cache = node._gsCache = node._gsCache || {}; 2661 cache.time = time; 2662 cache.width = pix / v * 100; 2663 } 2664 if (pix === 0 && !recurse) { 2665 pix = _convertToPixels(t, p, v, sfx, true); 2666 } 2667 } 2668 return neg ? -pix : pix; 2669 }, 2670 _calculateOffset = _internals.calculateOffset = function(t, p, cs) { //for figuring out "top" or "left" in px when it's "auto". We need to factor in margin with the offsetLeft/offsetTop 2671 if (_getStyle(t, "position", cs) !== "absolute") { return 0; } 2672 var dim = ((p === "left") ? "Left" : "Top"),
2673 v = _getStyle(t, "margin" + dim, cs); 2674 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0); 2675 }, 2676 2677 // @private returns at object containing ALL of the style properties in camelCase and their associated values. 2678 _getAllStyles = function(t, cs) { 2679 var s = {}, 2680 i, tr, p; 2681 if ((cs = cs || _getComputedStyle(t, null))) { 2682 if ((i = cs.length)) { 2683 while (--i > -1) { 2684 p = cs[i]; 2685 if (p.indexOf("-transform") === -1 || _transformPropCSS === p) { //Some webkit browsers duplicate transform values, one non-prefixed and one prefixed ("transform" and "WebkitTransform"), so we must weed out the extra one here. 2686 s[p.replace(_camelExp, _camelFunc)] = cs.getPropertyValue(p); 2687 } 2688 } 2689 } else { //some browsers behave differently - cs.length is always 0, so we must do a for...in loop. 2690 for (i in cs) { 2691 if (i.indexOf("Transform") === -1 || _transformProp === i) { //Some webkit browsers duplicate transform values, one non-prefixed and one prefixed ("transform" and "WebkitTransform"), so we must weed out the extra one here. 2692 s[i] = cs[i]; 2693 } 2694 } 2695 } 2696 } else if ((cs = t.currentStyle || t.style)) { 2697 for (i in cs) { 2698 if (typeof(i) === "string" && s[i] === undefined) { 2699 s[i.replace(_camelExp, _camelFunc)] = cs[i]; 2700 } 2701 } 2702 } 2703 if (!_supportsOpacity) { 2704 s.opacity = _getIEOpacity(t); 2705 } 2706 tr = _getTransform(t, cs, false); 2707 s.rotation = tr.rotation; 2708 s.skewX = tr.skewX; 2709 s.scaleX = tr.scaleX; 2710 s.scaleY = tr.scaleY; 2711 s.x = tr.x; 2712 s.y = tr.y; 2713 if (_supports3D) { 2714 s.z = tr.z; 2715 s.rotationX = tr.rotationX; 2716 s.rotationY = tr.rotationY; 2717 s.scaleZ = tr.scaleZ; 2718 } 2719 if (s.filters) { 2720 delete s.filters; 2721 } 2722 return s; 2723 }, 2724 2725 // @private analyzes two style objects (as returned by _getAllStyles()) and only looks for differences between them that contain tweenable values (like a number or color). It returns an object with a "difs" property which refers to an object c
2725ontaining only those isolated properties and values for tweening, and a "firstMPT" property which refers to the first MiniPropTween instance in a linked list that recorded all the starting values of the different properties so that we can revert to them at the end or beginning of the tween - we don't want the cascading to get messed up. The forceLookup parameter is an optional generic object with properties that should be forced into the results - this is necessary for className tweens that are overwriting others because imagine a scenario where a rollover/rollout adds/removes a class and the user swipes the mouse over the target SUPER fast, thus nothing actually changed yet and the subsequent comparison of the properties would indicate they match (especially when px rounding is taken into consideration), thus no tweening is necessary even though it SHOULD tween and remove those properties after the tween (otherwise the inline styles will contaminate things). See the className SpecialProp code for details. 2726 _cssDif = function(t, s1, s2, vars, forceLookup) { 2727 var difs = {}, 2728 style = t.style, 2729 val, p, mpt; 2730 for (p in s2) { 2731 if (p !== "cssText") if (p !== "length") if (isNaN(p)) if (s1[p] !== (val = s2[p]) || (forceLookup && forceLookup[p])) if (p.indexOf("Origin") === -1) if (typeof(val) === "number" || typeof(val) === "string") { 2732 difs[p] = (val === "auto" && (p === "left" || p === "top")) ? _calculateOffset(t, p) : ((val === "" || val === "auto" || val === "none") && typeof(s1[p]) === "string" && s1[p].replace(_NaNExp, "") !== "") ? 0 : val; //if the ending value is defaulting ("" or "auto"), we check the starting value and if it can be parsed into a number (a string which could have a suffix too, like 700px), then we swap in 0 for "" or "auto" so that things actually tween. 2733 if (style[p] !== undefined) { //for className tweens, we must remember which properties already existed inline - the ones that didn't should be removed when the tween isn't in progress because they were only introduced to facilitate the transition between classes. 2734 mpt = new MiniPropTween(style, p, style[p], mpt); 2735 } 2736 } 2737 } 2738 if (vars) { 2739 for (p in vars) { //copy properties (except className) 2740 if (p !== "className") { 2741 difs[p] = vars[p]; 2742 } 2743 } 2744 } 2745 return {difs:difs, firstMPT:mpt}; 2746 }, 2747 _dimensions = {width:["Left","Right"], height:["Top","Bottom"]}, 2748 _margins = ["marginLeft","marginRight","marginTop","marginBottom"], 2749 2750 /** 2751 * @private Gets the width or height of an element 2752 * @param {!Object} t Target element 2753 * @param {!string} p Property name ("width" or "height") 2754 * @param {Object=} cs Computed style object (if one exists). Just a speed optimization. 2755 * @return {number} Dimension (in pixels) 2756 */ 2757 _getDimension = function(t, p, cs) { 2758 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight), 2759 a = _dimensions[p], 2760 i = a.length; 2761 cs = cs || _getComputedStyle(t, null); 2762 while (--i > -1) { 2763 v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0; 2764 v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0; 2765 } 2766 return v; 2767 }, 2768 2769 // @private Parses position-related complex strings like "top left" or "50px 10px" or "70% 20%", etc. which are used for things like transformOrigin or backgroundPosition. Optionally decorates a supplied object (recObj) with the following properties: "ox" (offsetX), "oy" (offsetY), "oxp" (if true, "ox" is a percentage not a pixel value), and "oxy" (if true, "oy" is a percentage not a pixel value) 2770 _parsePosition = function(v, recObj) { 2771 if (v === "contain" || v === "auto" || v === "auto auto") { 2772 return v + " "; 2773 } 2774 if (v == null || v === "") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto". 2775 v = "0 0"; 2776 } 2777 var a = v.split(" "), 2778 x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0], 2779 y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1]; 2780 if (y == null) { 2781 y = (x === "center") ? "50%" : "0"; 2782 } else if (y === "center") { 2783 y = "50%"; 2784 } 2785 if (x === "center" || (isNaN(parseFloat(x)) && (x + "").indexOf("=") === -1)) { //remember, the user could flip-flop the values and say "bottom center" or "center bottom", etc. "center" is ambiguous because it c
2785ould be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative. 2786 x = "50%"; 2787 } 2788 v = x + " " + y + ((a.length > 2) ? " " + a[2] : ""); 2789 if (recObj) { 2790 recObj.oxp = (x.indexOf("%") !== -1); 2791 recObj.oyp = (y.indexOf("%") !== -1); 2792 recObj.oxr = (x.charAt(1) === "="); 2793 recObj.oyr = (y.charAt(1) === "="); 2794 recObj.ox = parseFloat(x.replace(_NaNExp, "")); 2795 recObj.oy = parseFloat(y.replace(_NaNExp, "")); 2796 recObj.v = v; 2797 } 2798 return recObj || v; 2799 }, 2800 2801 /** 2802 * @private Takes an ending value (typically a string, but can be a number) and a starting value and returns the change between the two, looking for relative value indicators like += and -= and it also ignores suffixes (but make sure the ending value starts with a number or +=/-= and that the starting value is a NUMBER!) 2803 * @param {(number|string)} e End value which is typically a string, but could be a number 2804 * @param {(number|string)} b Beginning value which is typically a string but could be a number 2805 * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized) 2806 */ 2807 _parseChange = function(e, b) { 2808 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b); 2809 }, 2810 2811 /** 2812 * @private Takes a value and a default number, checks if the value is relative, null, or numeric and spits back a normalized number accordingly. Primarily used in the _parseTransform() function. 2813 * @param {Object} v Value to be parsed 2814 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter) 2815 * @return {number} Parsed value 2816 */ 2817 _parseVal = function(v, d) { 2818 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * parseFloat(v.substr(2)) + d : parseFloat(v); 2819 }, 2820 2821 /** 2822 * @private Translates strings like "40deg" or "40" or 40rad" or "+=40deg" or "270_short" or "-90_cw" or "+=45_ccw" to a numeric radian angle. Of course a starting/default value must be fed in too so that relative values can be calculated properly. 2823 * @param {Object} v Value to be parsed 2824 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter) 2825 * @param {string=} p property name for directionalEnd (optional - only used when the parsed value is directional ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation). Property name would be "rotation", "rotationX", or "rotationY" 2826 * @param {Object=} directionalEnd An object that will store the raw end values for directional angles ("_short", "_cw", or "_ccw" suffix). We need a way to store the uncompensated value so that at the end of the tween, we set it to exactly what was requested with no directional compensation. 2827 * @return {number} parsed angle in radians 2828 */ 2829 _parseAngle = function(v, d, p, directionalEnd) { 2830 var min = 0.000001, 2831 cap, split, dif, result, isRelative; 2832 if (v == null) { 2833 result = d; 2834 } else if (typeof(v) === "number") { 2835 result = v; 2836 } else { 2837 cap = 360; 2838 split = v.split("_"); 2839 isRelative = (v.charAt(1) === "="); 2840 dif = (isRelative ? parseInt(v.charAt(0) + "1", 10) * parseFloat(split[0].substr(2)) : parseFloat(split[0])) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - (isRelative ? 0 : d); 2841 if (split.length) { 2842 if (directionalEnd) { 2843 directionalEnd[p] = d + dif; 2844 } 2845 if (v.indexOf("short") !== -1) { 2846 dif = dif % cap; 2847 if (dif !== dif % (cap / 2)) { 2848 dif = (dif < 0) ? dif + cap : dif - cap; 2849 } 2850 } 2851 if (v.indexOf("_cw") !== -1 && dif < 0) { 2852 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 2853 } else if (v.indexOf("ccw") !== -1 && dif > 0) { 2854 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 2855 } 2856 } 2857 result = d + dif; 2858 } 2859 if (result < min && result > -min) { 2860 result = 0; 2861 } 2862 return result; 2863 }, 2864 2865 _colorLookup = {aqua:[0,255,255], 2866 lime:[0,255,0], 2867 silver:[192,192,192], 2868 black:[0,0,0], 2869 maroon:[128,0,0], 2870 teal:[0,128,128], 2871 blue:[0,0,255], 2872 navy:[0,0,128], 2873 white:[255,255,255], 2874 fuchsia:[255,0,255], 2875 olive:[128,128,0], 2876 yellow:[255,255,0], 2877 orange:[255,165,0], 2878 gray:[128,128,128], 2879 purple:[128,0,128], 2880 green:[0,128,0], 2881 red:[255,0,0], 2882 pink:[255,192,203], 2883 cyan:[0,255,255], 2884 transparent:[255,255,255,0]}, 2885 2886 _hue = function(h, m1, m2) { 2887 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h; 2888 return ((((h * 6 < 1) ? m1 + (m2 - m1) * h * 6 : (h < 0.5) ? m2 : (h * 3 < 2) ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * 255) + 0.5) | 0; 2889 }, 2890 2891 /** 2892 * @private Parses a color (like #9F0, #FF9900, rgb(255,51,153) or hsl(108, 50%, 10%)) into an array with 3 elements for red, green, and blue or if toHSL parameter is true, it will populate the array with hue, saturation, and lightness values. If a relative value is found in an hsl() or hsla() string, it will preserve those relative prefixes and all the values in the array will be strings instead of numbers (in all other cases it will be populated with numbers). 2893 * @param {(string|number)} v The value the should be parsed which could be a string like #9F0 or rgb(255,102,51) or rgba(255,0,0,0.5) or it could be a number like 0xFF00CC or even a named color like red, blue, purple, etc. 2894 * @param {(boolean)} toHSL If true, an hsl() or hsla() value will be returned instead of rgb() or rgba() 2895 * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order, or if the toHSL parameter was true, the array will contain hue, saturation and lightness (and optionally alpha) in that order. Always numbers unless there's a relative prefix found in an hsl() or hsla() string and toHSL is true. 2896 */ 2897 _parseColor = CSSPlugin.parseColor = function(v, toHSL) { 2898 var a, r, g, b, h, s, l, max, min, d, wasHSL; 2899 if (!v) { 2900 a = _colorLookup.black; 2901 } else if (typeof(v) === "number") { 2902 a = [v >> 16, (v >> 8) & 255, v & 255]; 2903 } else { 2904 if (v.charAt(v.length - 1) === ",") { //sometimes a trailing comma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)" - in this example "blue," has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value. 2905 v = v.substr(0, v.length - 1); 2906 } 2907 if (_colorLookup[v]) { 2908 a = _colorLookup[v]; 2909 } else if (v.charAt(0) === "#") { 2910 if (v.length === 4) { //for shorthand like #9F0 2911 r = v.charAt(1); 2912 g = v.charAt(2); 2913 b = v.charAt(3); 2914 v = "#" + r + r + g + g + b + b; 2915 } 2916 v = parseInt(v.substr(1), 16); 2917 a = [v >> 16, (v >> 8) & 255, v & 255]; 2918 } else if (v.substr(0, 3) === "hsl") { 2919 a = wasHSL = v.match(_numExp); 2920 if (!toHSL) { 2921 h = (Number(a[0]) % 360) / 360;
2922 s = Number(a[1]) / 100; 2923 l = Number(a[2]) / 100; 2924 g = (l <= 0.5) ? l * (s + 1) : l + s - l * s; 2925 r = l * 2 - g; 2926 if (a.length > 3) { 2927 a[3] = Number(v[3]); 2928 } 2929 a[0] = _hue(h + 1 / 3, r, g); 2930 a[1] = _hue(h, r, g); 2931 a[2] = _hue(h - 1 / 3, r, g); 2932 } else if (v.indexOf("=") !== -1) { //if relative values are found, just return the raw strings with the relative prefixes in place. 2933 return v.match(_relNumExp); 2934 } 2935 } else { 2936 a = v.match(_numExp) || _colorLookup.transparent; 2937 } 2938 a[0] = Number(a[0]); 2939 a[1] = Number(a[1]); 2940 a[2] = Number(a[2]); 2941 if (a.length > 3) { 2942 a[3] = Number(a[3]); 2943 } 2944 } 2945 if (toHSL && !wasHSL) { 2946 r = a[0] / 255; 2947 g = a[1] / 255; 2948 b = a[2] / 255; 2949 max = Math.max(r, g, b); 2950 min = Math.min(r, g, b); 2951 l = (max + min) / 2; 2952 if (max === min) { 2953 h = s = 0; 2954 } else { 2955 d = max - min; 2956 s = l > 0.5 ? d / (2 - max - min) : d / (max + min); 2957 h = (max === r) ? (g - b) / d + (g < b ? 6 : 0) : (max === g) ? (b - r) / d + 2 : (r - g) / d + 4; 2958 h *= 60; 2959 } 2960 a[0] = (h + 0.5) | 0; 2961 a[1] = (s * 100 + 0.5) | 0; 2962 a[2] = (l * 100 + 0.5) | 0; 2963 } 2964 return a; 2965 }, 2966 _formatColors = function(s, toHSL) { 2967 var colors = s.match(_colorExp) || [], 2968 charIndex = 0, 2969 parsed = colors.length ? "" : s, 2970 i, color, temp; 2971 for (i = 0; i < colors.length; i++) { 2972 color = colors[i]; 2973 temp = s.substr(charIndex, s.indexOf(color, charIndex)-charIndex); 2974 charIndex += temp.length + color.length; 2975 color = _parseColor(color, toHSL); 2976 if (color.length === 3) { 2977 color.push(1); 2978 } 2979 parsed += temp + (toHSL ? "hsla(" + color[0] + "," + color[1] + "%," + color[2] + "%," + color[3] : "rgba(" + color.join(",")) + ")"; 2980 } 2981 return parsed; 2982 }, 2983 _colorExp = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#.+?\\b"; //we'll dynamically build this Regular Expression to conserve file size. After building it, it will be able to find rgb(), rgba(), # (hexadecimal), and named color values like red, blue, purple, etc. 2984 2985 for (p in _colorLookup) { 2986 _colorExp += "|" + p + "\\b"; 2987 } 2988 _colorExp = new RegExp(_colorExp+")", "gi"); 2989 2990 CSSPlugin.colorStringFilter = function(a) { 2991 var combined = a[0] + a[1], 2992 toHSL; 2993 _colorExp.lastIndex = 0; 2994 if (_colorExp.test(combined)) { 2995 toHSL = (combined.indexOf("hsl(") !== -1 || combined.indexOf("hsla(") !== -1); 2996 a[0] = _formatColors(a[0], toHSL); 2997 a[1] = _formatColors(a[1], toHSL); 2998 } 2999 }; 3000 3001 if (!TweenLite.defaultStringFilter) { 3002 TweenLite.defaultStringFilter = CSSPlugin.colorStringFilter; 3003 } 3004 3005 /** 3006 * @private Returns a formatter function that handles taking a string (or number in some cases) and returning a consistently formatted one in terms of delimiters, quantity of values, etc. For example, we may get boxShadow values defined as "0px red" or "0px 0px 10px rgb(255,0,0)" or "0px 0px 20px 20px #F00" and we need to ensure that what we get back is described with 4 numbers and a color. This allows us to feed it into the _parseComplex() method and split the values up appropriately. The neat thing about this _getFormatter() function is that the dflt defines a pattern as well as a default, so for example, _getFormatter("0px 0px 0px 0px #777", true) not only sets the default as 0px for all distances and #777 for the color, but also sets the pattern such that 4 numbers and a color will always get returned. 3007 * @param {!string} dflt The default value and pattern to follow. So "0px 0px 0px 0px #777" will ensure that 4 numbers and a color will always get returned. 3008 * @param {boolean=} clr If true, the values should be searched for color-related data. For example, boxShadow values typically contain a color whereas borderRadius don't. 3009 * @param {boolean=} collapsible If true, the value is a top/left/right/bottom style one that acts like margin or padding, where if only one value is received, it's used for all 4; if 2 are received, the first is duplicated for 3rd (bottom) and the 2nd is duplicated for the 4th spot (left), etc. 3010 * @return {Function} formatter function 3011 */ 3012 var _getFormatter = function(dflt, clr, collapsible, multi) { 3013 if (dflt == null) { 3014 return function(v) {return v;}; 3015 } 3016 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "", 3017 dVals = dflt.split(dColor).join("").match(_valuesExp) || [], 3018 pfx = dflt.substr(0, dflt.indexOf(dVals[0])), 3019 sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "", 3020 delim = (dflt.indexOf(" ") !== -1) ? " " : ",", 3021 numVals = dVals.length, 3022 dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "", 3023 formatter; 3024 if (!numVals) { 3025 return function(v) {return v;}; 3026 } 3027 if (clr) { 3028 formatter = function(v) { 3029 var color, vals, i, a; 3030 if (typeof(v) === "number") { 3031 v += dSfx; 3032 } else if (multi && _commasOutsideParenExp.test(v)) { 3033 a = v.replace(_commasOutsideParenExp, "|").split("|"); 3034 for (i = 0; i < a.length; i++) { 3035 a[i] = formatter(a[i]); 3036 } 3037 return a.join(","); 3038 } 3039 color = (v.match(_colorExp) || [dColor])[0]; 3040 vals = v.split(color).join("").match(_valuesExp) || []; 3041 i = vals.length; 3042 if (numVals > i--) { 3043 while (++i < numVals) { 3044 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i]; 3045 } 3046 } 3047 return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : ""); 3048 }; 3049 return formatter; 3050 3051 } 3052 formatter = function(v) { 3053 var vals, a, i; 3054 if (typeof(v) === "number") { 3055 v += dSfx; 3056 } else if (multi && _commasOutsideParenExp.test(v)) { 3057 a = v.replace(_commasOutsideParenExp, "|").split("|"); 3058 for (i = 0; i < a.length; i++) { 3059 a[i] = formatter(a[i]); 3060 } 3061 return a.join(","); 3062 } 3063 vals = v.match(_valuesExp) || []; 3064 i = vals.length; 3065 if (numVals > i--) { 3066 while (++i < numVals) { 3067 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i]; 3068 } 3069 } 3070 return pfx + vals.join(delim) + sfx; 3071 }; 3072 return formatter; 3073 }, 3074 3075 /** 3076 * @private returns a formatter function that's used for edge-related values like marginTop, marginLeft, paddingBottom, paddingRight, etc. Just pass a comma-delimited list of property names related to the edges. 3077 * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft" 3078 * @return {Function} a formatter function 3079 */ 3080 _getEdgeParser = function(props) { 3081 props = props.split(","); 3082 return function(t, e, p, cssp, pt, plugin, vars) { 3083 var a = (e + "").split(" "), 3084 i; 3085 vars = {}; 3086 for (i = 0; i < 4; i++) { 3087 vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)]; 3088 } 3089 return cssp.parse(t, vars, pt, plugin); 3090 }; 3091 }, 3092 3093 // @private used when other plugins must tween values first, like BezierPlugin or ThrowPropsPlugin, etc. That plugin's setRatio() gets called first so that the values are updated, and then we loop through the MiniPropTweens which handle copying the values into their appropriate slots so that they can then be applied correctly in the main CSSPlugin setRatio() method. Remember, we typically create a proxy object that has a bunch of uniquely-named properties that we feed to the sub-plugin and it does its magic normally, and then we must interpret those values and apply them to the css because often numbers must get combined/concatenated, suffixes added, etc. to work with css, like boxShadow could have 4 values plus a color. 3094 _setPluginRatio = _internals._setPluginRatio = function(v) { 3095 this.plugin.setRatio(v); 3096 var d = this.data, 3097 proxy = d.proxy, 3098 mpt = d.firstMPT, 3099 min = 0.000001, 3100 val, pt, i, str; 3101 while (mpt) { 3102 val = proxy[mpt.v]; 3103 if (mpt.r) { 3104 val = Math.round(val); 3105 } else if (val < min && val > -min) { 3106 val = 0; 3107 } 3108 mpt.t[mpt.p] = val; 3109 mpt = mpt._next; 3110 } 3111 if (d.autoRotate) { 3112 d.autoRotate.rotation = proxy.rotation; 3113 } 3114 //at the end, we must set the CSSPropTween's "e" (end) value dynamically here because that's what is used in the final setRatio() method. 3115 if (v === 1) { 3116 mpt = d.firstMPT; 3117 while (mpt) { 3118 pt = mpt.t; 3119 if (!pt.type) { 3120 pt.e = pt.s + pt.xs0; 3121 } else if (pt.type === 1) { 3122 str = pt.xs0 + pt.s + pt.xs1; 3123 for (i = 1; i < pt.l; i++) {
3124 str += pt["xn"+i] + pt["xs"+(i+1)]; 3125 } 3126 pt.e = str; 3127 } 3128 mpt = mpt._next; 3129 } 3130 } 3131 }, 3132 3133 /** 3134 * @private @constructor Used by a few SpecialProps to hold important values for proxies. For example, _parseToProxy() creates a MiniPropTween instance for each property that must get tweened on the proxy, and we record the original property name as well as the unique one we create for the proxy, plus whether or not the value needs to be rounded plus the original value. 3135 * @param {!Object} t target object whose property we're tweening (often a CSSPropTween) 3136 * @param {!string} p property name 3137 * @param {(number|string|object)} v value 3138 * @param {MiniPropTween=} next next MiniPropTween in the linked list 3139 * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer 3140 */ 3141 MiniPropTween = function(t, p, v, next, r) { 3142 this.t = t; 3143 this.p = p; 3144 this.v = v; 3145 this.r = r; 3146 if (next) { 3147 next._prev = this; 3148 this._next = next; 3149 } 3150 }, 3151 3152 /** 3153 * @private Most other plugins (like BezierPlugin and ThrowPropsPlugin and others) can only tween numeric values, but CSSPlugin must accommodate special values that have a bunch of extra data (like a suffix or strings between numeric values, etc.). For example, boxShadow has values like "10px 10px 20px 30px rgb(255,0,0)" which would utterly confuse other plugins. This method allows us to split that data apart and grab only the numeric data and attach it to uniquely-named properties of a generic proxy object ({}) so that we can feed that to virtually any plugin to have the numbers tweened. However, we must also keep track of which properties from the proxy go with which CSSPropTween values and instances. So we create a linked list of MiniPropTweens. Each one records a target (the original CSSPropTween), property (like "s" or "xn1" or "xn2") that we're tweening and the unique property name that was used for the proxy (like "boxShadow_xn1" and "boxShadow_xn2") and whether or not they need to be rounded. That way, in the _setPluginRatio() method we can simply copy the values over from the proxy to the CSSPropTween instance(s). Then, when the main CSSPlugin setRatio() method runs and applies the CSSPropTween values accordingly, they're updated nicely. So the external plugin tweens the numbers, _setPluginRatio() copies them over, and setRatio() acts normally, applying css-specific values to the element. 3154 * This method returns an object that has the following properties:
3155 * - proxy: a generic object containing the starting values for all the properties that will be tweened by the external plugin. This is what we feed to the external _onInitTween() as the target 3156 * - end: a generic object containing the ending values for all the properties that will be tweened by the external plugin. This is what we feed to the external plugin's _onInitTween() as the destination values 3157 * - firstMPT: the first MiniPropTween in the linked list 3158 * - pt: the first CSSPropTween in the linked list that was created when parsing. If shallow is true, this linked list will NOT attach to the one passed into the _parseToProxy() as the "pt" (4th) parameter. 3159 * @param {!Object} t target object to be tweened 3160 * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed 3161 * @param {!CSSPlugin} cssp The CSSPlugin instance 3162 * @param {CSSPropTween=} pt the next CSSPropTween in the linked list 3163 * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values 3164 * @param {boolean=} shallow if true, the resulting linked list from the parse will NOT be attached to the CSSPropTween that was passed in as the "pt" (4th) parameter. 3165 * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions) 3166 */ 3167 _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) { 3168 var bpt = pt, 3169 start = {}, 3170 end = {}, 3171 transform = cssp._transform, 3172 oldForce = _forcePT, 3173 i, p, xp, mpt, firstPT; 3174 cssp._transform = null; 3175 _forcePT = vars; 3176 pt = firstPT = cssp.parse(t, vars, pt, plugin); 3177 _forcePT = oldForce; 3178 //break off from the linked list so the new ones are isolated. 3179 if (shallow) { 3180 cssp._transform = transform; 3181 if (bpt) { 3182 bpt._prev = null; 3183 if (bpt._prev) { 3184 bpt._prev._next = null; 3185 } 3186 } 3187 } 3188 while (pt && pt !== bpt) { 3189 if (pt.type <= 1) { 3190 p = pt.p; 3191 end[p] = pt.s + pt.c; 3192 start[p] = pt.s; 3193 if (!shallow) { 3194 mpt = new MiniPropTween(pt, "s", p, mpt, pt.r); 3195 pt.c = 0; 3196 } 3197 if (pt.type === 1) { 3198 i = pt.l; 3199 while (--i > 0) { 3200 xp = "xn" + i; 3201 p = pt.p + "_" + xp; 3202 end[p] = pt.data[xp]; 3203 start[p] = pt[xp]; 3204 if (!shallow) { 3205 mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]); 3206 } 3207 } 3208 } 3209 } 3210 pt = pt._next; 3211 } 3212 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT}; 3213 }, 3214 3215 3216 3217 /** 3218 * @constructor Each property that is tweened has at least one CSSPropTween associated with it. These instances store important information like the target, property, starting value, amount of change, etc. They can also optionally have a number of "extra" strings and numeric values named xs1, xn1, xs2, xn2, xs3, xn3, etc. where "s" indicates string and "n" indicates number. These can be pieced together in a complex-value tween (type:1) that has alternating types of data like a string, number, string, number, etc. For example, boxShadow could be "5px 5px 8px rgb(102, 102, 51)". In that value, there are 6 numbers that may need to tween and then pieced back together into a string again with spaces, suffixes, etc. xs0 is special in that it stores the suffix for standard (type:0) tweens, -OR- the first string (prefix) in a complex-value (type:1) CSSPropTween -OR- it can be the non-tweening value in a type:-1 CSSPropTween. We do this to conserve memory. 3219 * CSSPropTweens have the following optional properties as well (not defined through the constructor): 3220 * - l: Length in terms of the number of extra properties that the CSSPropTween has (default: 0). For example, for a boxShadow we may need to tween 5 numbers in which case l would be 5; Keep in mind that the start/end values for the first number that's tweened are always stored in the s and c properties to conserve memory. All additional values thereafter are stored in xn1, xn2, etc. 3221 * - xfirst: The first instance of any sub-CSSPropTweens that are tweening properties of this instance. For example, we may split up a boxShadow tween so that there's a main CSSPropTween of type:1 that has various xs* and xn* values associated with the h-shadow, v-shadow, blur, color, etc. Then we spawn a CSSPropTween for each of those that has a higher priority and runs BEFORE the main CSSPropTween so that the values are all set by the time it needs to re-assemble them. The xfirst gives us an easy way to identify the first one in that chain which typically ends at the main one (because they're all prepende to the linked list) 3222 * - plugin: The TweenPlugin instance that will handle the tweening of any complex values. For example, sometimes we don't want to use normal subt
3222weens (like xfirst refers to) to tween the values - we might want ThrowPropsPlugin or BezierPlugin some other plugin to do the actual tweening, so we create a plugin instance and store a reference here. We need this reference so that if we get a request to round values or disable a tween, we can pass along that request. 3223 * - data: Arbitrary data that needs to be stored with the CSSPropTween. Typically if we're going to have a plugin handle the tweening of a complex-value tween, we create a generic object that stores the END values that we're tweening to and the CSSPropTween's xs1, xs2, etc. have the starting values. We store that object as data. That way, we can simply pass that object to the plugin and use the CSSPropTween as the target. 3224 * - setRatio: Only used for type:2 tweens that require custom functionality. In this case, we call the CSSPropTween's setRatio() method and pass the ratio each time the tween updates. This isn't quite as efficient as doing things directly in the CSSPlugin's setRatio() method, but it's very convenient and flexible. 3225 * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything. 3226 * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width". 3227 * @param {number} s Starting numeric value 3228 * @param {number} c Change in numeric value over the course of the entire tween. For example, if element.width starts at 5 and should end at 100, c would be 95. 3229 * @param {CSSPropTween=} next The next CSSPropTween in the linked list. If one is defined, we will define its _prev as the new instance, and the new instance's _next will be pointed at it. 3230 * @param {number=} type The type of CSSPropTween where -1 = a non-tweening value, 0 = a standard simple tween, 1 = a complex value (like one that has multiple numbers in a comma- or space-delimited string like border:"1px solid red"), and 2 = one that uses a custom setRatio function that does all of the work of applying the values on each update. 3231 * @param {string=} n Name of the property that should be used for overwriting purposes which is typically the same as p but not always. For example, we may need to create a subtween for the 2nd part of a "clip:rect(...)" tween in which case "p" might be xs1 but "n" is still "clip" 3232 * @param {boolean=} r If true, the value(s) should be rounded 3233 * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0. 3234 * @param {string=} b Beginning value. We store this to ensure that it is EXACTLY what it was when the tween began without any risk of interpretation issues. 3235 * @param {string=} e Ending value. We store this to ensure that it is EXACTLY what the user defined at the end of the tween without any risk of interpretation issues. 3236 */ 3237 CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) { 3238 this.t = t; //target 3239 this.p = p; //property 3240 this.s = s; //starting value 3241 this.c = c; //change value 3242 this.n = n || p; //name that this CSSPropTween should be associated to (usually the same as p, but not always - n is what overwriting looks at) 3243 if (!(t instanceof CSSPropTween)) { 3244 _overwriteProps.push(this.n); 3245 } 3246 this.r = r; //round (boolean) 3247 this.type = type || 0; //0 = normal tween, -1 = non-tweening (in which case xs0 will be applied to the target's property, like tp.t[tp.p] = tp.xs0), 1 = complex-value SpecialProp, 2 = custom setRatio() that does all the work 3248 if (pr) { 3249 this.pr = pr; 3250 _hasPriority = true; 3251 } 3252 this.b = (b === undefined) ? s : b; 3253 this.e = (e === undefined) ? s + c : e; 3254 if (next) { 3255 this._next = next; 3256 next._prev = this; 3257 } 3258 }, 3259 3260 _addNonTweeningNumericPT = function(target, prop, start, end, next, overwriteProp) { //cleans up some code redundancies and helps minification. Just a fast way to add a NUMERIC non-tweening CSSPropTween
3261 var pt = new CSSPropTween(target, prop, start, end - start, next, -1, overwriteProp); 3262 pt.b = start; 3263 pt.e = pt.xs0 = end; 3264 return pt; 3265 }, 3266 3267 /** 3268 * Takes a target, the beginning value and ending value (as strings) and parses them into a CSSPropTween (possibly with child CSSPropTweens) that accommodates multiple numbers, colors, comma-delimited values, etc. For example: 3269 * sp.parseComplex(element, "boxShadow", "5px 10px 20px rgb(255,102,51)", "0px 0px 0px red", true, "0px 0px 0px rgb(0,0,0,0)", pt); 3270 * It will walk through the beginning and ending values (which should be in the same format with the same number and type of values) and figure out which parts are numbers, what strings separate the numeric/tweenable values, and then create the CSSPropTweens accordingly. If a plugin is defined, no child CSSPropTweens will be created. Instead, the ending values will be stored in the "data" property of the returned CSSPropTween like: {s:-5, xn1:-10, xn2:-20, xn3:255, xn4:0, xn5:0} so that it can be fed to any other plugin and it'll be plain numeric tweens but the recomposition of the complex value will be handled inside CSSPlugin's setRatio(). 3271 * If a setRatio is defined, the type of the CSSPropTween will be set to 2 and recomposition of the values will be the responsibility of that method. 3272 * 3273 * @param {!Object} t Target whose property will be tweened 3274 * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow") 3275 * @param {string} b Beginning value 3276 * @param {string} e Ending value 3277 * @param {boolean} clrs If true, the value could contain a color value like "rgb(255,0,0)" or "#F00" or "red". The default is false, so no colors will be recognized (a performance optimization) 3278 * @param {(string|number|Object)} dflt The default beginning value that should be used if no valid beginning value is defined or if the number of values inside the complex beginning and ending values don't match 3279 * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this). 3280 * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0. 3281 * @param {TweenPlugin=} plugin If a plugin should handle the tweening of extra properties, pass the plugin instance here. If one is defined, then NO subtweens will be created for any extra properties (the properties will be created - just not additional CSSPropTween instances to tween them) because the plugin is expected to do so. However, the end values WILL be populated in the "data" property, like {s:100, xn1:50, xn2:300} 3282 * @param {function(number)=} setRatio If values should be set in a custom function instead of being pieced together in a type:1 (complex-value) CSSPropTween, define that custom function here. 3283 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call. 3284 */ 3285 _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) { 3286 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e); 3287 b = b || dflt || ""; 3288 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e); 3289 e += ""; //ensures it's a string 3290 var ba = b.split(", ").join(",").split(" "), //beginning array 3291 ea = e.split(", ").join(",").split(" "), //ending array 3292 l = ba.length, 3293 autoRound = (_autoRound !== false), 3294 i, xi, ni, bv, ev, bnums, enums, bn, hasAlpha, temp, cv, str, useHSL; 3295 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) { 3296 ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" "); 3297 ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" "); 3298 l = ba.length; 3299 } 3300 if (l !== ea.length) { 3301 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")"); 3302 ba = (dflt || "").split(" "); 3303 l = ba.length; 3304 } 3305 pt.plugin = plugin; 3306 pt.setRatio = setRatio; 3307 _colorExp.lastIndex = 0; 3308 for (i = 0; i < l; i++) { 3309 bv = ba[i]; 3310 ev = ea[i]; 3311 bn = parseFloat(bv); 3312 //if the value begins with a number (most common). It's fine if it has a suffix like px 3313 if (bn || bn === 0) { 3314 pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true); 3315 3316 //if the value is a color 3317 } else if (clrs && _colorExp.test(bv)) { 3318 str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it. 3319 useHSL = (ev.indexOf("hsl") !== -1 && _supportsOpacity); 3320 bv = _parseColor(bv, useHSL); 3321 ev = _parseColor(ev, useHSL); 3322 hasAlpha = (bv.length + ev.length > 6); 3323 if (hasAlpha && !_supportsOpacity && ev[3] === 0) { //older versions of IE don't support rgba(), so if the destination alpha is 0, just use "transparent" for the end color 3324 pt["xs" + pt.l] += pt.l ? " transparent" : "transparent";
3325 pt.e = pt.e.split(ea[i]).join("transparent"); 3326 } else { 3327 if (!_supportsOpacity) { //old versions of IE don't support rgba(). 3328 hasAlpha = false; 3329 } 3330 if (useHSL) { 3331 pt.appendXtra((hasAlpha ? "hsla(" : "hsl("), bv[0], _parseChange(ev[0], bv[0]), ",", false, true) 3332 .appendXtra("", bv[1], _parseChange(ev[1], bv[1]), "%,", false) 3333 .appendXtra("", bv[2], _parseChange(ev[2], bv[2]), (hasAlpha ? "%," : "%" + str), false); 3334 } else { 3335 pt.appendXtra((hasAlpha ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true) 3336 .appendXtra("", bv[1], ev[1] - bv[1], ",", true) 3337 .appendXtra("", bv[2], ev[2] - bv[2], (hasAlpha ? "," : str), true); 3338 } 3339 3340 if (hasAlpha) { 3341 bv = (bv.length < 4) ? 1 : bv[3]; 3342 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false); 3343 } 3344 } 3345 _colorExp.lastIndex = 0; //otherwise the test() on the RegExp could move the lastIndex and taint future results. 3346 3347 } else { 3348 bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array 3349 3350 //if no number is found, treat it as a non-tweening value and just append the string to the current xs. 3351 if (!bnums) { 3352 pt["xs" + pt.l] += pt.l ? " " + bv : bv; 3353 3354 //loop through all the numbers that are found and construct the extra values on the pt. 3355 } else { 3356 enums = ev.match(_relNumExp); //get each group of numbers in the end value string and drop them into an array. We allow relative values too, like +=50 or -=.5 3357 if (!enums || enums.length !== bnums.length) { 3358 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")"); 3359 return pt; 3360 } 3361 ni = 0; 3362 for (xi = 0; xi < bnums.length; xi++) { 3363 cv = bnums[xi]; 3364 temp = bv.indexOf(cv, ni); 3365 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0)); 3366 ni = temp + cv.length; 3367 } 3368 pt["xs" + pt.l] += bv.substr(ni); 3369 } 3370 } 3371 } 3372 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly. 3373 if (e.indexOf("=") !== -1) if (pt.data) { 3374 str = pt.xs0 + pt.data.s; 3375 for (i = 1; i < pt.l; i++) { 3376 str += pt["xs" + i] + pt.data["xn" + i]; 3377 } 3378 pt.e = str + pt["xs" + i]; 3379 } 3380 if (!pt.l) { 3381 pt.type = -1; 3382 pt.xs0 = pt.e; 3383 } 3384 return pt.xfirst || pt; 3385 }, 3386 i = 9; 3387 3388 3389 p = CSSPropTween.prototype; 3390 p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc. 3391 while (--i > 0) { 3392 p["xn" + i] = 0; 3393 p["xs" + i] = ""; 3394 } 3395 p.xs0 = ""; 3396 p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null; 3397 3398 3399 /** 3400 * Appends and extra tweening value to a CSSPropTween and automatically manages any prefix and suffix strings. The first extra value is stored in the s and c of the main CSSPropTween instance, but thereafter any extras are stored in the xn1, xn2, xn3, etc. The prefixes and suffixes are stored in the xs0, xs1, xs2, etc. properties. For example, if I walk through a clip value like "rect(10px, 5px, 0px, 20px)", the values would be stored like this: 3401 * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)" 3402 * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method). 3403 * @param {string=} pfx Prefix (if any) 3404 * @param {!number} s Starting value 3405 * @param {!number} c Change in numeric value over the course of the entire tween. For example, if the start is 5 and the end is 100, the change would be 95. 3406 * @param {string=} sfx Suffix (if any) 3407 * @param {boolean=} r Round (if true). 3408 * @param {boolean=} pad If true, this extra value should be separated by the previous one by a space. If there is no previous extra and pad is true, it will automatically drop the space. 3409 * @return {CSSPropTween} returns itself so that multiple methods can be chained together. 3410 */ 3411 p.appendXtra = function(pfx, s, c, sfx, r, pad) { 3412 var pt = this, 3413 l = pt.l; 3414 pt["xs" + l] += (pad && l) ? " " + pfx : pfx || ""; 3415 if (!c) if (l !== 0 && !pt.plugin) { //typically we'll combine non-changing values right into the xs to optimize performance, but we don't combine them when there's a plugin that will be tweening the values because it may depend on the values being split apart, like for a bezier, if a value doesn't change between the first and second iteration but then it does on the 3rd, we'll run into trouble because there's no xn slot for that value! 3416 pt["xs" + l] += s + (sfx || ""); 3417 return pt; 3418 } 3419 pt.l++; 3420 pt.type = pt.setRatio ? 2 : 1; 3421 pt["xs" + pt.l] = sfx || ""; 3422 if (l > 0) { 3423 pt.data["xn" + l] = s + c; 3424 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method) 3425 pt["xn" + l] = s; 3426 if (!pt.plugin) { 3427 pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr); 3428 pt.xfirst.xs0 = 0; //just to ensure that the property stays numeric which helps modern browsers speed up processing. Remember, in the setRatio() method, we do pt.t[pt.p] = val + pt.xs0 so if pt.xs0 is "" (the default), it'll cast the end value as a string. When a property is a number sometimes and a string sometimes, it prevents the compiler from locking in the data type, slowing things down slightly. 3429 } 3430 return pt; 3431 } 3432 pt.data = {s:s + c}; 3433 pt.rxp = {}; 3434 pt.s = s; 3435 pt.c = c; 3436 pt.r = r; 3437 return pt; 3438 }; 3439 3440 /** 3441 * @constructor A SpecialProp is basically a css property that needs to be treated in a non-standard way, like if it may contain a complex value like boxShadow:"5px 10px 15px rgb(255, 102, 51)" or if it is associated with another plugin like ThrowPropsPlugin or BezierPlugin. Every SpecialProp is associated with a particular property name like "boxShadow" or "throwProps" or "bezier" and it will intercept those values in the vars object that's passed to the CSSPlugin and handle them accordingly. 3442 * @param {!string} p Property name (like "boxShadow" or "throwProps") 3443 * @param {Object=}
3443 options An object containing any of the following configuration options: 3444 * - defaultValue: the default value 3445 * - parser: A function that should be called when the associated property name is found in the vars. This function should return a CSSPropTween instance and it should ensure that it is properly inserted into the linked list. It will receive 4 paramters: 1) The target, 2) The value defined in the vars, 3) The CSSPlugin instance (whose _firstPT should be used for the linked list), and 4) A computed style object if one was calculated (this is a speed optimization that allows retrieval of starting values quicker) 3446 * - formatter: a function that formats any value received for this special property (for example, boxShadow could take "5px 5px red" and format it to "5px 5px 0px 0px red" so that both the beginning and ending values have a common order and quantity of values.) 3447 * - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O) 3448 * - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc. 3449 * - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0. 3450 * - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out. 3451 * - collapsible: if true, the formatter should treat the value like it's a top/right/bottom/left value that could be collapsed, like "5px" would apply to all, "5px, 10px" would use 5px for top/bottom and 10px for right/left, etc. 3452 * - keyword: a special keyword that can [optionally] be found inside the value (like "inset" for boxShadow). This allows us to validate beginning/ending values to make sure they match (if the keyword is found in one, it'll be added to the other for consistency by default). 3453 */ 3454 var SpecialProp = function(p, options) { 3455 options = options || {}; 3456 this.p = options.prefix ? _checkPropPrefix(p) || p : p; 3457 _specialProps[p] = _specialProps[this.p] = this; 3458 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi); 3459 if (options.parser) { 3460 this.parse = options.parser; 3461 } 3462 this.clrs = options.color; 3463 this.multi = options.multi; 3464 this.keyword = options.keyword; 3465 this.dflt = options.defaultValue; 3466 this.pr = options.priority || 0; 3467 }, 3468 3469 //shortcut for creating a new SpecialProp that can accept multiple properties as a comma-delimited list (helps minification). dflt can be an array for multiple values (we don't do a comma-delimited list because the default value may contain commas, like rect(0px,0px,0px,0px)). We attach this method to the SpecialProp class/object instead of using a private _createSpecialProp() method so that we can tap into it externally if necessary, like from another plugin. 3470 _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) { 3471 if (typeof(options) !== "object") { 3472 options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin 3473 } 3474 var a = p.split(","), 3475 d = options.defaultValue, 3476 i, temp; 3477 defaults = defaults || [d]; 3478 for (i = 0; i < a.length; i++) { 3479 options.prefix = (i === 0 && options.prefix); 3480 options.defaultValue = defaults[i] || d; 3481 temp = new SpecialProp(a[i], options); 3482 } 3483 }, 3484 3485 //creates a placeholder special prop for a plugin so that the property gets caught the first time a tween of it is attempted, and at that time it makes the plugin register itself, thus taking over for all future tweens of that property. This allows us to not mandate that things load in a particular order and it also allows us to log() an error that informs the user when they attempt to tween an external plugin-related property without loading its .js file. 3486 _registerPluginProp = function(p) { 3487 if (!_specialProps[p]) { 3488 var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin"; 3489 _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) { 3490 var pluginClass = _globals.com.greensock.plugins[pluginName]; 3491 if (!pluginClass) { 3492 _log("Error: " + pluginName + " js file not loaded."); 3493 return pt; 3494 } 3495 pluginClass._cssRegister(); 3496 return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars); 3497 }}); 3498 } 3499 }; 3500 3501 3502 p = SpecialProp.prototype; 3503 3504 /** 3505 * Alias for _parseComplex() that automatically plugs in certain values for this SpecialProp, like its property name, whether or not colors should be sensed, the default value, and priority. It also looks for any keyword that the SpecialProp defines (like "inset" for boxSh
3505adow) and ensures that the beginning and ending values have the same number of values for SpecialProps where multi is true (like boxShadow and textShadow can have a comma-delimited list) 3506 * @param {!Object} t target element 3507 * @param {(string|number|object)} b beginning value 3508 * @param {(string|number|object)} e ending (destination) value 3509 * @param {CSSPropTween=} pt next CSSPropTween in the linked list 3510 * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here. 3511 * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here. 3512 * @return {CSSPropTween=} First CSSPropTween in the linked list 3513 */ 3514 p.parseComplex = function(t, b, e, pt, plugin, setRatio) { 3515 var kwd = this.keyword, 3516 i, ba, ea, l, bi, ei; 3517 //if this SpecialProp's value can contain a comma-delimited list of values (like boxShadow or textShadow), we must parse them in a special way, and look for a keyword (like "inset" for boxShadow) and ensure that the beginning and ending BOTH have it if the end defines it as such. We also must ensure that there are an equal number of values specified (we can't tween 1 boxShadow to 3 for example) 3518 if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) { 3519 ba = b.replace(_commasOutsideParenExp, "|").split("|"); 3520 ea = e.replace(_commasOutsideParenExp, "|").split("|"); 3521 } else if (kwd) { 3522 ba = [b]; 3523 ea = [e]; 3524 } 3525 if (ea) { 3526 l = (ea.length > ba.length) ? ea.length : ba.length; 3527 for (i = 0; i < l; i++) { 3528 b = ba[i] = ba[i] || this.dflt; 3529 e = ea[i] = ea[i] || this.dflt; 3530 if (kwd) { 3531 bi = b.indexOf(kwd); 3532 ei = e.indexOf(kwd); 3533 if (bi !== ei) { 3534 if (ei === -1) { //if the keyword isn't in the end value, remove it from the beginning one. 3535 ba[i] = ba[i].split(kwd).join(""); 3536 } else if (bi === -1) { //if the keyword isn't in the beginning, add it. 3537 ba[i] += " " + kwd; 3538 } 3539 } 3540 } 3541 } 3542 b = ba.join(", "); 3543 e = ea.join(", "); 3544 } 3545 return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio); 3546 }; 3547 3548 /** 3549 * Accepts a target and end value and spits back a CSSPropTween that has been inserted into the CSSPlugin's linked list and conforms with all the conventions we use internally, like type:-1, 0, 1, or 2, setting up any extra property tweens, priority, etc. For example, if we have a boxShadow SpecialProp and call: 3550 * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this); 3551 * It should figure out the starting value of the element's boxShadow, compare it to the provided end value and create all the necessary CSSPropTweens of the appropriate types to tween the boxShadow. The CSSPropTween that gets spit back should already be inserted into the linked list (the 4th parameter is the current head, so prepend to that). 3552 * @param {!Object} t Target object whose property is being tweened 3553 * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object). 3554 * @param {!string} p Property name 3555 * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween. 3556 * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it) 3557 * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance. 3558 * @param {Object=} vars Original vars object that contains the data for parsing. 3559 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call. 3560 */ 3561 p.parse = function(t, e, p, cssp, pt, plugin, vars) { 3562 return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin); 3563 }; 3564 3565 /** 3566 * Registers a special property that should be intercepted from any "css" objects defined in tweens. This allows you to handle them however you want without CSSPlugin doing it for you. The 2nd parameter should be a function that accepts 3 parameters: 3567 * 1) Target object whose property should be tweened (typically a DOM element) 3568 * 2) The end/destination value (could be a string, number, object, or whatever you want) 3569 * 3) The tween instance (you probably don't need to worry about this, but it can be useful for looking up information like the duration) 3570 * 3571 * Then, your function should return a function which will be called each time the tween gets rendered, passing a numeric "ratio" parameter to your function that indicates the change factor (usually between 0 and 1). For example: 3572 * 3573 * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) { 3574 * var start = target.style.width;
3575 * return function(ratio) { 3576 * target.style.width = (start + value * ratio) + "px"; 3577 * console.log("set width to " + target.style.width); 3578 * } 3579 * }, 0); 3580 * 3581 * Then, when I do this tween, it will trigger my special property: 3582 * 3583 * TweenLite.to(element, 1, {css:{myCustomProp:100}}); 3584 * 3585 * In the example, of course, we're just changing the width, but you can do anything you want. 3586 * 3587 * @param {!string} name Property name (or comma-delimited list of property names) that should be intercepted and handled by your function. For example, if I define "myCustomProp", then it would handle that portion of the following tween: TweenLite.to(element, 1, {css:{myCustomProp:100}}) 3588 * @param {!function(Object, Object, Object, string):function(number)} onInitTween The function that will be called when a tween of this special property is performed. The function will receive 4 parameters: 1) Target object that should be tweened, 2) Value that was passed to the tween, 3) The tween instance itself (rarely used), and 4) The property name that's being tweened. Your function should return a function that should be called on every update of the tween. That function will receive a single parameter that is a "change factor" value (typically between 0 and 1) indicating the amount of change as a ratio. You can use this to determine how to set the values appropriately in your function. 3589 * @param {number=} priority Priority that helps the engine determine the order in which to set the properties (default: 0). Higher priority properties will be updated before lower priority ones. 3590 */ 3591 CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) { 3592 _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) { 3593 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority); 3594 rv.plugin = plugin; 3595 rv.setRatio = onInitTween(t, e, cssp._tween, p); 3596 return rv; 3597 }, priority:priority}); 3598 }; 3599 3600 3601 3602 3603 3604 3605 //transform-related methods and properties 3606 CSSPlugin.useSVGTransformAttr = _isSafari || _isFirefox; //Safari and Firefox both have some rendering bugs when applying CSS transforms to SVG elements, so default to using the "transform" attribute instead (users can override this). 3607 var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective,xPercent,yPercent").split(","), 3608 _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform. 3609 _transformPropCSS = _prefixCSS + "transform", 3610 _transformOriginProp = _checkPropPrefix("transformOrigin"), 3611 _supports3D = (_checkPropPrefix("perspective") !== null), 3612 Transform = _internals.Transform = function() { 3613 this.perspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0; 3614 this.force3D = (CSSPlugin.defaultForce3D === false || !_supports3D) ? false : CSSPlugin.defaultForce3D || "auto"; 3615 }, 3616 _SVGElement = window.SVGElement, 3617 _useSVGTransformAttr, 3618 //Some browsers (like Firefox and IE) don't honor transform-origin properly in SVG elements, so we need to manually adjust the matrix accordingly. We feature detect here rather than always doing the conversion for certain browsers because they may fix the problem at some point in the future. 3619 3620 _createSVG = function(type, container, attributes) { 3621 var element = _doc.createElementNS("http://www.w3.org/2000/svg", type), 3622 reg = /([a-z])([A-Z])/g, 3623 p; 3624 for (p in attributes) { 3625 element.setAttributeNS(null, p.replace(reg, "$1-$2").toLowerCase(), attributes[p]); 3626 } 3627 container.appendChild(element); 3628 return element; 3629 }, 3630 _docElement = _doc.documentElement, 3631 _forceSVGTransformAttr = (function() { 3632 //IE and Android stock don't support CSS transforms on SVG elements, so we must write them to the "transform" attribute. We populate this variable in the _parseTransform() method, and only if/when we come across an SVG element 3633 var force = _ieVers || (/Android/i.test(_agent) && !window.chrome), 3634 svg, rect, width; 3635 if (_doc.createElementNS && !force) { //IE8 and earlier doesn't support SVG anyway 3636 svg = _createSVG("svg", _docElement); 3637 rect = _createSVG("rect", svg, {width:100, height:50, x:100}); 3638 width = rect.getBoundingClientRect().width; 3639 rect.style[_transformOriginProp] = "50% 50%"; 3640 rect.style[_transformProp] = "scaleX(0.5)"; 3641 force = (width === rect.getBoundingClientRect().width && !(_is
3641Firefox && _supports3D)); //note: Firefox fails the test even though it does support CSS transforms in 3D. Since we can't push 3D stuff into the transform attribute, we force Firefox to pass the test here (as long as it does truly support 3D). 3642 _docElement.removeChild(svg); 3643 } 3644 return force; 3645 })(), 3646 _parseSVGOrigin = function(e, local, decoratee, absolute, smoothOrigin) { 3647 var tm = e._gsTransform, 3648 m = _getMatrix(e, true), 3649 v, x, y, xOrigin, yOrigin, a, b, c, d, tx, ty, determinant, xOriginOld, yOriginOld; 3650 if (tm) { 3651 xOriginOld = tm.xOrigin; //record the original values before we alter them. 3652 yOriginOld = tm.yOrigin; 3653 } 3654 if (!absolute || (v = absolute.split(" ")).length < 2) { 3655 b = e.getBBox(); 3656 local = _parsePosition(local).split(" "); 3657 v = [(local[0].indexOf("%") !== -1 ? parseFloat(local[0]) / 100 * b.width : parseFloat(local[0])) + b.x, 3658 (local[1].indexOf("%") !== -1 ? parseFloat(local[1]) / 100 * b.height : parseFloat(local[1])) + b.y]; 3659 } 3660 decoratee.xOrigin = xOrigin = parseFloat(v[0]); 3661 decoratee.yOrigin = yOrigin = parseFloat(v[1]); 3662 if (absolute && m !== _identity2DMatrix) { //if svgOrigin is being set, we must invert the matrix and determine where the absolute point is, factoring in the current transforms. Otherwise, the svgOrigin would be based on the element's non-transformed position on the canvas. 3663 a = m[0]; 3664 b = m[1]; 3665 c = m[2]; 3666 d = m[3]; 3667 tx = m[4]; 3668 ty = m[5]; 3669 determinant = (a * d - b * c); 3670 x = xOrigin * (d / determinant) + yOrigin * (-c / determinant) + ((c * ty - d * tx) / determinant); 3671 y = xOrigin * (-b / determinant) + yOrigin * (a / determinant) - ((a * ty - b * tx) / determinant); 3672 xOrigin = decoratee.xOrigin = v[0] = x; 3673 yOrigin = decoratee.yOrigin = v[1] = y; 3674 } 3675 if (tm) { //avoid jump when transformOrigin is changed - adjust the x/y values accordingly 3676 if (smoothOrigin || (smoothOrigin !== false && CSSPlugin.defaultSmoothOrigin !== false)) { 3677 x = xOrigin - xOriginOld; 3678 y = yOrigin - yOriginOld; 3679 //originally, we simply adjusted the x and y values, but that would cause problems if, for example, you created a rotational tween part-way through an x/y tween. Managing the offset in a separate variable gives us ultimate flexibility. 3680 //tm.x -= x - (x * m[0] + y * m[2]); 3681 //tm.y -= y - (x * m[1] + y * m[3]); 3682 tm.xOffset += (x * m[0] + y * m[2]) - x; 3683 tm.yOffset += (x * m[1] + y * m[3]) - y; 3684 } else { 3685 tm.xOffset = tm.yOffset = 0; 3686 } 3687 } 3688 e.setAttribute("data-svg-origin", v.join(" ")); 3689 }, 3690 _isSVG = function(e) { 3691 return !!(_SVGElement && typeof(e.getBBox) === "function" && e.getCTM && (!e.parentNode || (e.parentNode.getBBox && e.parentNode.getCTM))); 3692 }, 3693 _identity2DMatrix = [1,0,0,1,0,0], 3694 _getMatrix = function(e, force2D) { 3695 var tm = e._gsTransform || new Transform(), 3696 rnd = 100000, 3697 isDefault, s, m, n, dec; 3698 if (_transformProp) { 3699 s = _getStyle(e, _transformPropCSS, null, true); 3700 } else if (e.currentStyle) { 3701 //for older versions of IE, we need to interpret the filter portion that is in the format: progid:DXImageTransform.Microsoft.Matrix(M11=6.123233995736766e-17, M12=-1, M21=1, M22=6.123233995736766e-17, sizingMethod='auto expand') Notice that we need to swap b and c compared to a normal matrix. 3702 s = e.currentStyle.filter.match(_ieGetMatrixExp); 3703 s = (s && s.length === 4) ? [s[0].substr(4), Number(s[2].substr(4)), Number(s[1].substr(4)), s[3].substr(4), (tm.x || 0), (tm.y || 0)].join(",") : ""; 3704 }
3705 isDefault = (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)"); 3706 if (tm.svg || (e.getBBox && _isSVG(e))) { 3707 if (isDefault && (e.style[_transformProp] + "").indexOf("matrix") !== -1) { //some browsers (like Chrome 40) don't correctly report transforms that are applied inline on an SVG element (they don't get included in the computed style), so we double-check here and accept matrix values 3708 s = e.style[_transformProp]; 3709 isDefault = 0; 3710 } 3711 m = e.getAttribute("transform"); 3712 if (isDefault && m) { 3713 if (m.indexOf("matrix") !== -1) { //just in case there's a "transform" value specified as an attribute instead of CSS style. Accept either a matrix() or simple translate() value though. 3714 s = m; 3715 isDefault = 0; 3716 } else if (m.indexOf("translate") !== -1) { 3717 s = "matrix(1,0,0,1," + m.match(/(?:\-|\b)[\d\-\.e]+\b/gi).join(",") + ")"; 3718 isDefault = 0; 3719 } 3720 } 3721 } 3722 if (isDefault) { 3723 return _identity2DMatrix; 3724 } 3725 //split the matrix values out into an array (m for matrix) 3726 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || []; 3727 i = m.length; 3728 while (--i > -1) { 3729 n = Number(m[i]); 3730 m[i] = (dec = n - (n |= 0)) ? ((dec * rnd + (dec < 0 ? -0.5 : 0.5)) | 0) / rnd + n : n; //convert strings to Numbers and round to 5 decimal places to avoid issues with tiny numbers. Roughly 20x faster than Number.toFixed(). We also must make sure to round before dividing so that values like 0.9999999999 become 1 to avoid glitches in browser rendering and interpretation of flipped/rotated 3D matrices. And don't just multiply the number by rnd, floor it, and then divide by rnd because the bitwise operations max out at a 32-bit signed integer, thus it could get clipped at a relatively low value (like 22,000.00000 for example). 3731 } 3732 return (force2D && m.length > 6) ? [m[0], m[1], m[4], m[5], m[12], m[13]] : m; 3733 }, 3734 3735 /** 3736 * Parses the transform values for an element, returning an object with x, y, z, scaleX, scaleY, scaleZ, rotation, rotationX, rotationY, skewX, and skewY properties. Note: by default (for performance reasons), all skewing is combined into skewX and rotation but skewY still has a place in the transform object so that we can record how much of the skew is attributed to skewX vs skewY. Remember, a skewY of 10 looks the same as a rotation of 10 and skewX of -10. 3737 * @param {!Object} t target element 3738 * @param {Object=} cs computed style object (optional) 3739 * @param {boolean=} rec if true, the transform values will be recorded to the target element's _gsTransform object, like target._gsTransform = {x:0, y:0, z:0, scaleX:1...} 3740 * @param {boolean=} parse if true, we'll ignore any _gsTransform values that already exist on the element, and force a reparsing of the css (calculated style) 3741 * @return {object}
3741 object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...} 3742 */ 3743 _getTransform = _internals.getTransform = function(t, cs, rec, parse) { 3744 if (t._gsTransform && rec && !parse) { 3745 return t._gsTransform; //if the element already has a _gsTransform, use that. Note: some browsers don't accurately return the calculated style for the transform (particularly for SVG), so it's almost always safest to just use the values we've already applied rather than re-parsing things. 3746 } 3747 var tm = rec ? t._gsTransform || new Transform() : new Transform(), 3748 invX = (tm.scaleX < 0), //in order to interpret things properly, we need to know if the user applied a negative scaleX previously so that we can adjust the rotation and skewX accordingly. Otherwise, if we always interpret a flipped matrix as affecting scaleY and the user only wants to tween the scaleX on multiple sequential tweens, it would keep the negative scaleY without that being the user's intent. 3749 min = 0.00002, 3750 rnd = 100000, 3751 zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin || 0 : 0, 3752 defaultTransformPerspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0, 3753 m, i, scaleX, scaleY, rotation, skewX; 3754 3755 tm.svg = !!(t.getBBox && _isSVG(t)); 3756 if (tm.svg) { 3757 _parseSVGOrigin(t, _getStyle(t, _transformOriginProp, _cs, false, "50% 50%") + "", tm, t.getAttribute("data-svg-origin")); 3758 _useSVGTransformAttr = CSSPlugin.useSVGTransformAttr || _forceSVGTransformAttr; 3759 } 3760 m = _getMatrix(t); 3761 if (m !== _identity2DMatrix) { 3762 3763 if (m.length === 16) { 3764 //we'll only look at these position-related 6 variables first because if x/y/z all match, it's relatively safe to assume we don't need to re-parse everything which risks losing important rotational information (like rotationX:180 plus rotationY:180 would look the same as rotation:180 - there's no way to know for sure which direction was taken based solely on the matrix3d() values) 3765 var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3], 3766 a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7], 3767 a13 = m[8], a23 = m[9], a33 = m[10], 3768 a14 = m[12], a24 = m[13], a34 = m[14], 3769 a43 = m[11], 3770 angle = Math.atan2(a32, a33), 3771 t1, t2, t3, t4, cos, sin; 3772 3773 //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari 3774 if (tm.zOrigin) { 3775 a34 = -tm.zOrigin; 3776 a14 = a13*a34-m[12]; 3777 a24 = a23*a34-m[13]; 3778 a34 = a33*a34+tm.zOrigin-m[14]; 3779 } 3780 tm.rotationX = angle * _RAD2DEG; 3781 //rotationX 3782 if (angle) { 3783 cos = Math.cos(-angle); 3784 sin = Math.sin(-angle); 3785 t1 = a12*cos+a13*sin; 3786 t2 = a22*cos+a23*sin; 3787 t3 = a32*cos+a33*sin; 3788 a13 = a12*-sin+a13*cos; 3789 a23 = a22*-sin+a23*cos; 3790 a33 = a32*-sin+a33*cos; 3791 a43 = a42*-sin+a43*cos; 3792 a12 = t1; 3793 a22 = t2; 3794 a32 = t3; 3795 } 3796 //rotationY 3797 angle = Math.atan2(a13, a33); 3798 tm.rotationY = angle * _RAD2DEG; 3799 if (angle) { 3800 cos = Math.cos(-angle); 3801 sin = Math.sin(-angle); 3802 t1 = a11*cos-a13*sin; 3803 t2 = a21*cos-a23*sin; 3804 t3 = a31*cos-a33*sin; 3805 a23 = a21*sin+a23*cos; 3806 a33 = a31*sin+a33*cos; 3807 a43 = a41*sin+a43*cos; 3808 a11 = t1; 3809 a21 = t2; 3810 a31 = t3; 3811 } 3812 //rotationZ 3813 angle = Math.atan2(a21, a11); 3814 tm.rotation = angle * _RAD2DEG; 3815 if (angle) { 3816 cos = Math.cos(-angle); 3817 sin = Math.sin(-angle); 3818 a11 = a11*cos+a12*sin; 3819 t2 = a21*cos+a22*sin; 3820 a22 = a21*-sin+a22*cos; 3821 a32 = a31*-sin+a32*cos; 3822 a21 = t2; 3823 } 3824 3825 if (tm.rotationX && Math.abs(tm.rotationX) + Math.abs(tm.rotation) > 359.9) { //when rotationY is set, it will often be parsed as 180 degrees different than it should be, and rotationX and rotation both being 180 (it looks the same), so we adjust for that here. 3826 tm.rotationX = tm.rotation = 0; 3827 tm.rotationY += 180; 3828 } 3829 3830 tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd; 3831 tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd; 3832 tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd; 3833 tm.skewX = 0; 3834 tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0; 3835 tm.x = a14; 3836 tm.y = a24; 3837 tm.z = a34; 3838 if (tm.svg) { 3839 tm.x -= tm.xOrigin - (tm.xOrigin * a11 - tm.yOrigin * a12); 3840 tm.y -= tm.yOrigin - (tm.yOrigin * a21 - tm.xOrigin * a22); 3841 } 3842 3843 } else if ((!_supports3D || parse || !m.length || tm.x !== m[4] || tm.y !== m[5] || (!tm.rotationX && !tm.rotationY)) && !(tm.x !== undefined && _getStyle(t, "display", cs) === "
3843none")) { //sometimes a 6-element matrix is returned even when we performed 3D transforms, like if rotationX and rotationY are 180. In cases like this, we still need to honor the 3D transforms. If we just rely on the 2D info, it could affect how the data is interpreted, like scaleY might get set to -1 or rotation could get offset by 180 degrees. For example, do a TweenLite.to(element, 1, {css:{rotationX:180, rotationY:180}}) and then later, TweenLite.to(element, 1, {css:{rotationX:0}}) and without this conditional logic in place, it'd jump to a state of being unrotated when the 2nd tween starts. Then again, we need to honor the fact that the user COULD alter the transforms outside of CSSPlugin, like by manually applying new css, so we try to sense that by looking at x and y because if those changed, we know the changes were made outside CSSPlugin and we force a reinterpretation of the matrix values. Also, in Webkit browsers, if the element's "display" is "none", its calculated style value will always return empty, so if we've already recorded the values in the _gsTransform object, we'll just rely on those. 3844 var k = (m.length >= 6), 3845 a = k ? m[0] : 1, 3846 b = m[1] || 0, 3847 c = m[2] || 0, 3848 d = k ? m[3] : 1; 3849 tm.x = m[4] || 0; 3850 tm.y = m[5] || 0; 3851 scaleX = Math.sqrt(a * a + b * b); 3852 scaleY = Math.sqrt(d * d + c * c); 3853 rotation = (a || b) ? Math.atan2(b, a) * _RAD2DEG : tm.rotation || 0; //note: if scaleX is 0, we cannot accurately measure rotation. Same for skewX with a scaleY of 0. Therefore, we default to the previously recorded value (or zero if that doesn't exist). 3854 skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0; 3855 if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) { 3856 if (invX) { 3857 scaleX *= -1; 3858 skewX += (rotation <= 0) ? 180 : -180; 3859 rotation += (rotation <= 0) ? 180 : -180; 3860 } else { 3861 scaleY *= -1; 3862 skewX += (skewX <= 0) ? 180 : -180; 3863 } 3864 } 3865 tm.scaleX = scaleX; 3866 tm.scaleY = scaleY; 3867 tm.rotation = rotation; 3868 tm.skewX = skewX; 3869 if (_supports3D) { 3870 tm.rotationX = tm.rotationY = tm.z = 0; 3871 tm.perspective = defaultTransformPerspective; 3872 tm.scaleZ = 1; 3873 } 3874 if (tm.svg) { 3875 tm.x -= tm.xOrigin - (tm.xOrigin * a + tm.yOrigin * c); 3876 tm.y -= tm.yOrigin - (tm.xOrigin * b + tm.yOrigin * d); 3877 } 3878 } 3879 tm.zOrigin = zOrigin; 3880 //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 0 in these cases. The conditional logic here is faster than calling Math.abs(). Also, browsers tend to render a SLIGHTLY rotated object in a fuzzy way, so we need to snap to exactly 0 when appropriate. 3881 for (i in tm) { 3882 if (tm[i] < min) if (tm[i] > -min) { 3883 tm[i] = 0; 3884 } 3885 } 3886 } 3887 //DEBUG: _log("parsed rotation of " + t.getAttribute("id")+": "+(tm.rotationX)+", "+(tm.rotationY)+", "+(tm.rotation)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective+ ", origin: "+ tm.xOrigin+ ","+ tm.yOrigin); 3888 if (rec) { 3889 t._gsTransform = tm; //record to the object's _gsTransform which we use so that tweens can control individual properties independently (we need all the properties to accurately recompose the matrix in the setRatio() method) 3890 if (tm.svg) { //if we're supposed to apply transforms to the SVG element's "transform" attribute, make sure there aren't any CSS transforms applied or they'll override the attribute ones. Also clear the transform attribute if we're using CSS, just to be clean. 3891 if (_useSVGTransformAttr && t.style[_transformProp]) { 3892 TweenLite.delayedCall(0.001, function(){ //if we apply this right away (before anything has rendered), we risk there being no transforms for a brief moment and it also interferes with adjusting the transformOrigin in a tween with immediateRender:true (it'd try reading the matrix and it wouldn't have the appropriate data in place because we just removed it). 3893 _removeProp(t.style, _transformProp); 3894 }); 3895 } else if (!_useSVGTransformAttr && t.getAttribute("transform")) { 3896 TweenLite.delayedCall(0.001, function(){ 3897 t.removeAttribute("transform"); 3898 }); 3899 } 3900 } 3901 } 3902 return tm; 3903 }, 3904 3905 //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms) 3906 _setIETransformRatio = function(v) { 3907 var t = this.data, //refers to the element's _gsTransform object 3908 ang = -t.rotation * _DEG2RAD,
3909 skew = ang + t.skewX * _DEG2RAD, 3910 rnd = 100000, 3911 a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd, 3912 b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd, 3913 c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd, 3914 d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd, 3915 style = this.t.style, 3916 cs = this.t.currentStyle, 3917 filters, val; 3918 if (!cs) { 3919 return; 3920 } 3921 val = b; //just for swapping the variables an inverting them (reused "val" to avoid creating another variable in memory). IE's filter matrix uses a non-standard matrix configuration (angle goes the opposite way, and b and c are reversed and inverted) 3922 b = -c; 3923 c = -val; 3924 filters = cs.filter; 3925 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight 3926 var w = this.t.offsetWidth, 3927 h = this.t.offsetHeight, 3928 clip = (cs.position !== "absolute"), 3929 m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d, 3930 ox = t.x + (w * t.xPercent / 100), 3931 oy = t.y + (h * t.yPercent / 100), 3932 dx, dy; 3933 3934 //if transformOrigin is being used, adjust the offset x and y 3935 if (t.ox != null) { 3936 dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2; 3937 dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2; 3938 ox += dx - (dx * a + dy * b); 3939 oy += dy - (dx * c + dy * d); 3940 } 3941 3942 if (!clip) { 3943 m += ", sizingMethod='auto expand')"; 3944 } else { 3945 dx = (w / 2); 3946 dy = (h / 2); 3947 //translate to ensure that transformations occur around the correct origin (default is center). 3948 m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")"; 3949 } 3950 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) { 3951 style.filter = filters.replace(_ieSetMatrixExp, m); 3952 } else { 3953 style.filter = m + " " + filters; //we must always put the transform/matrix FIRST (before alpha(opacity=xx)) to avoid an IE bug that slices part of the object when rotation is applied with alpha. 3954 } 3955 3956 //at the end or beginning of the tween, if the matrix is normal (1, 0, 0, 1) and opacity is 100 (or doesn't exist), remove the filter to improve browser performance. 3957 if (v === 0 || v === 1) if (a === 1) if (b === 0) if (c === 0) if (d === 1) if (!clip || m.indexOf("Dx=0, Dy=0") !== -1) if (!_opacityExp.test(filters) || parseFloat(RegExp.$1) === 100) if (filters.indexOf("gradient(" && filters.indexOf("Alpha")) === -1) { 3958 style.removeAttribute("filter"); 3959 } 3960 3961 //we must set the margins AFTER applying the filter in order to avoid some bugs in IE8 that could (in rare scenarios) cause them to be ignored intermittently (vibration). 3962 if (!clip) { 3963 var mult = (_ieVers < 8) ? 1 : -1, //in Internet Explorer 7 and before, the box model is broken, causing the browser to treat the width/height of the actual rotated filtered image as the width/height of the box itself, but Microsoft corrected that in IE8. We must use a negative offset in IE8 on the right/bottom 3964 marg, prop, dif; 3965 dx = t.ieOffsetX || 0; 3966 dy = t.ieOffsetY || 0; 3967 t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox); 3968 t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy); 3969 for (i = 0; i < 4; i++) { 3970 prop = _margins[i]; 3971 marg = cs[prop]; 3972 //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes) 3973 val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0; 3974 if (val !== t[prop]) { 3975 dif = (i < 2) ? -t.ieOffsetX : -t.ieOffsetY; //if another tween is controlling a margin, we cannot only apply the difference in the ieOffsets, so we essentially zero-out the dx and dy here in that case. We record the margin(s) later so that we can keep comparing them, making this code very flexible. 3976 } else { 3977 dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY; 3978 } 3979 style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px"; 3980 } 3981 } 3982 }, 3983 3984 /* translates a super small decimal to a string WITHOUT scientific notation 3985 _safeDecimal = function(n) { 3986 var s = (n < 0 ? -n : n) + "", 3987 a = s.split("e-"); 3988 return (n < 0 ? "-0." : "0.") + new Array(parseInt(a[1], 10) || 0).join("0") + a[0].split(".").join(""); 3989 }, 3990 */ 3991 3992 _setTransformRatio = _internals.set3DTransformRatio = _internals.setTransformRatio = function(v) { 3993 var t = this.data, //refers to the element's _gsTransform object 3994 style = this.t.style, 3995 angle = t.rotation, 3996 rotationX = t.rotationX, 3997 rotationY = t.rotationY, 3998 sx = t.scaleX, 3999 sy = t.scaleY, 4000 sz = t.scaleZ, 4001 x = t.x, 4002 y = t.y, 4003 z = t.z, 4004 isSVG = t.svg, 4005 perspective = t.perspective, 4006 force3D = t.force3D, 4007 a11, a12, a13, a21, a22, a23, a31, a32, a33, a41, a42, a43, 4008 zOrigin, min, cos, sin, t1, t2, transform, comma, zero, skew, rnd; 4009 //check to see if we should render as 2D (and SVGs must use 2D when _useSVGTransformAttr is true) 4010 if (((((v === 1 || v === 0) && force3D === "auto" && (this.tween._totalTime === this.tween._totalDuration || !this.tween._totalTime)) || !force3D) && !z && !perspective && !rotationY && !rotationX) || (_useSVGTransformAttr && isSVG) || !_supports3D) { //on the final render (which could be 0 for a from tween), if there are no 3D aspects, render in 2D to free up memory and improve performance especially on mobile devices. Check the tween's totalTime/totalDuration too in order to make sure it doesn't happen between repeats if it's a repeating tween. 4011 4012 //2D 4013 if (angle || t.skewX || isSVG) { 4014 angle *= _DEG2RAD; 4015 skew = t.skewX * _DEG2RAD; 4016 rnd = 100000; 4017 a11 = Math.cos(angle) * sx; 4018 a21 = Math.sin(angle) * sx; 4019 a12 = Math.sin(angle - skew) * -sy;
4020 a22 = Math.cos(angle - skew) * sy; 4021 if (skew && t.skewType === "simple") { //by default, we compensate skewing on the other axis to make it look more natural, but you can set the skewType to "simple" to use the uncompensated skewing that CSS does 4022 t1 = Math.tan(skew); 4023 t1 = Math.sqrt(1 + t1 * t1); 4024 a12 *= t1; 4025 a22 *= t1; 4026 if (t.skewY) { 4027 a11 *= t1; 4028 a21 *= t1; 4029 } 4030 } 4031 if (isSVG) { 4032 x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12) + t.xOffset; 4033 y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22) + t.yOffset; 4034 if (_useSVGTransformAttr && (t.xPercent || t.yPercent)) { //The SVG spec doesn't support percentage-based translation in the "transform" attribute, so we merge it into the matrix to simulate it. 4035 min = this.t.getBBox(); 4036 x += t.xPercent * 0.01 * min.width; 4037 y += t.yPercent * 0.01 * min.height; 4038 } 4039 min = 0.000001; 4040 if (x < min) if (x > -min) { 4041 x = 0; 4042 } 4043 if (y < min) if (y > -min) { 4044 y = 0; 4045 } 4046 } 4047 transform = (((a11 * rnd) | 0) / rnd) + "," + (((a21 * rnd) | 0) / rnd) + "," + (((a12 * rnd) | 0) / rnd) + "," + (((a22 * rnd) | 0) / rnd) + "," + x + "," + y + ")"; 4048 if (isSVG && _useSVGTransformAttr) {
4049 this.t.setAttribute("transform", "matrix(" + transform); 4050 } else { 4051 //some browsers have a hard time with very small values like 2.4492935982947064e-16 (notice the "e-" towards the end) and would render the object slightly off. So we round to 5 decimal places. 4052 style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix(" : "matrix(") + transform; 4053 } 4054 } else { 4055 style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix(" : "matrix(") + sx + ",0,0," + sy + "," + x + "," + y + ")"; 4056 } 4057 return; 4058 4059 } 4060 if (_isFirefox) { //Firefox has a bug (at least in v25) that causes it to render the transparent part of 32-bit PNG images as black when displayed inside an iframe and the 3D scale is very small and doesn't change sufficiently enough between renders (like if you use a Power4.easeInOut to scale from 0 to 1 where the beginning values only change a tiny amount to begin the tween before accelerating). In this case, we force the scale to be 0.00002 instead which is visually the same but works around the Firefox issue. 4061 min = 0.0001; 4062 if (sx < min && sx > -min) { 4063 sx = sz = 0.00002; 4064 } 4065 if (sy < min && sy > -min) { 4066 sy = sz = 0.00002; 4067 } 4068 if (perspective && !t.z && !t.rotationX && !t.rotationY) { //Firefox has a bug that causes elements to have an odd super-thin, broken/dotted black border on elements that have a perspective set but aren't utilizing 3D space (no rotationX, rotationY, or z). 4069 perspective = 0; 4070 } 4071 } 4072 if (angle || t.skewX) { 4073 angle *= _DEG2RAD; 4074 cos = a11 = Math.cos(angle); 4075 sin = a21 = Math.sin(angle); 4076 if (t.skewX) { 4077 angle -= t.skewX * _DEG2RAD; 4078 cos = Math.cos(angle); 4079 sin = Math.sin(angle); 4080 if (t.skewType === "simple") { //by default, we compensate skewing on the other axis to make it look more natural, but you can set the skewType to "simple" to use the uncompensated skewing that CSS does 4081 t1 = Math.tan(t.skewX * _DEG2RAD); 4082 t1 = Math.sqrt(1 + t1 * t1); 4083 cos *= t1; 4084 sin *= t1; 4085 if (t.skewY) { 4086 a11 *= t1; 4087 a21 *= t1; 4088 } 4089 } 4090 } 4091 a12 = -sin; 4092 a22 = cos; 4093 4094 } else if (!rotationY && !rotationX && sz === 1 && !perspective && !isSVG) { //if we're only translating and/or 2D scaling, this is faster... 4095 style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) translate3d(" : "translate3d(") + x + "px," + y + "px," + z +"px)" + ((sx !== 1 || sy !== 1) ? " scale(" + sx + "," + sy + ")" : ""); 4096 return; 4097 } else { 4098 a11 = a22 = 1; 4099 a12 = a21 = 0; 4100 } 4101 // KEY INDEX AFFECTS 4102 // a11 0 rotation, rotationY, scaleX 4103 // a21 1 rotation, rotationY, scaleX 4104 // a31 2 rotationY, scaleX 4105 // a41 3 rotationY, scaleX 4106 // a12 4 rotation, skewX, rotationX, scaleY 4107 // a22 5 rotation, skewX, rotationX, scaleY 4108 // a32 6 rotationX, scaleY 4109 // a42 7 rotationX, scaleY 4110 // a13 8 rotationY, rotationX, scaleZ 4111 // a23 9 rotationY, rotationX, scaleZ 4112 // a33 10 rotationY, rotationX, scaleZ 4113 // a43 11 rotationY, rotationX, perspective, scaleZ 4114 // a14 12 x, zOrigin, svgOrigin 4115 // a24 13 y, zOrigin, svgOrigin 4116 // a34 14 z, zOrigin 4117 // a44 15 4118 // rotation: Math.atan2(a21, a11) 4119 // rotationY: Math.atan2(a13, a33) (or Math.atan2(a13, a11)) 4120 // rotationX: Math.atan2(a32, a33) 4121 a33 = 1; 4122 a13 = a23 = a31 = a32 = a41 = a42 = 0; 4123 a43 = (perspective) ? -1 / perspective : 0; 4124 zOrigin = t.zOrigin; 4125 min = 0.000001; //threshold below which browsers use scientific notation which won't work. 4126 comma = ","; 4127 zero = "0"; 4128 angle = rotationY * _DEG2RAD; 4129 if (angle) { 4130 cos = Math.cos(angle); 4131 sin = Math.sin(angle); 4132 a31 = -sin; 4133 a41 = a43*-sin; 4134 a13 = a11*sin; 4135 a23 = a21*sin; 4136 a33 = cos; 4137 a43 *= cos; 4138 a11 *= cos; 4139 a21 *= cos; 4140 } 4141 angle = rotationX * _DEG2RAD; 4142 if (angle) { 4143 cos = Math.cos(angle); 4144 sin = Math.sin(angle); 4145 t1 = a12*cos+a13*sin; 4146 t2 = a22*cos+a23*sin; 4147 a32 = a33*sin; 4148 a42 = a43*sin; 4149 a13 = a12*-sin+a13*cos; 4150 a23 = a22*-sin+a23*cos; 4151 a33 = a33*cos; 4152 a43 = a43*cos; 4153 a12 = t1; 4154 a22 = t2; 4155 } 4156 if (sz !== 1) { 4157 a13*=sz; 4158 a23*=sz; 4159 a33*=sz; 4160 a43*=sz; 4161 } 4162 if (sy !== 1) { 4163 a12*=sy; 4164 a22*=sy; 4165 a32*=sy; 4166 a42*=sy; 4167 } 4168 if (sx !== 1) { 4169 a11*=sx; 4170 a21*=sx; 4171 a31*=sx; 4172 a41*=sx; 4173 } 4174 4175 if (zOrigin || isSVG) { 4176 if (zOrigin) { 4177 x += a13*-zOrigin; 4178 y += a23*-zOrigin; 4179 z += a33*-zOrigin+zOrigin; 4180 } 4181 if (isSVG) { //due to bugs in some browsers, we need to manage the transform-origin of SVG manually 4182 x += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12) + t.xOffset; 4183 y += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22) + t.yOffset; 4184 } 4185 if (x < min && x > -min) { 4186 x = zero; 4187 } 4188 if (y < min && y > -min) { 4189 y = zero; 4190 } 4191 if (z < min && z > -min) { 4192 z = 0; //don't use string because we calculate perspective later and need the number. 4193 } 4194 } 4195 4196 //optimized way of concatenating all the values into a string. If we do it all in one shot, it's slower because of the way browsers have to create temp strings and the way it affects memory. If we do it piece-by-piece with +=, it's a bit slower too. We found that doing it in these sized chunks works best overall: 4197 transform = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix3d(" : "matrix3d("); 4198 transform += ((a11 < min && a11 > -min) ? zero : a11) + comma + ((a21 < min && a21 > -min) ? zero : a21) + comma + ((a31 < min && a31 > -min) ? zero : a31); 4199 transform += comma + ((a41 < min && a41 > -min) ? zero : a41) + comma + ((a12 < min && a12 > -min) ? zero : a12) + comma + ((a22 < min && a22 > -min) ? zero : a22); 4200 if (rotationX || rotationY) { //performance optimization (often there's no rotationX or rotationY, so we can skip these calculations) 4201 transform += comma + ((a32 < min && a32 > -min) ? zero : a32) + comma + ((a42 < min && a42 > -min) ? zero : a42) + comma + ((a13 < min && a13 > -min) ? zero : a13); 4202 transform += comma + ((a23 < min && a23 > -min) ? zero : a23) + comma + ((a33 < min && a33 > -min) ? zero : a33) + comma + ((a43 < min && a43 > -min) ? zero : a43) + comma; 4203 } else { 4204 transform += ",0,0,0,0,1,0,"; 4205 } 4206 transform += x + comma + y + comma + z + comma + (perspective ? (1 + (-z / perspective)) : 1) + ")"; 4207 4208 style[_transformProp] = transform; 4209 }; 4210 4211 p = Transform.prototype; 4212 p.x = p.y = p.z = p.skewX = p.skewY = p.rotation = p.rotationX = p.rotationY = p.zOrigin = p.xPercent = p.yPercent = p.xOffset = p.yOffset = 0; 4213 p.scaleX = p.scaleY = p.scaleZ = 1; 4214 4215 _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,svgOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent,smoothOrigin", {parser:function(t, e, p, cssp, pt, plugin, vars) { 4216 if (cssp._lastParsedTransform === vars) { return pt; } //only need to parse the transform once, and only if the browser supports it. 4217 cssp._lastParsedTransform = vars; 4218 var originalGSTransform = t._gsTransform, 4219 style = t.style, 4220 min = 0.000001, 4221 i = _transformProps.length, 4222 v = vars, 4223 endRotations = {}, 4224 transformOriginString = "transformOrigin", 4225 m1, m2, skewY, copy, orig, has3D, hasChange, dr, x, y; 4226 if (vars.display) { //if the user is setting display during this tween, it may not be instantiated yet but we must force it here in order to get accurate readings. If display is "none", some browsers refuse to report the transform properties correctly. 4227 copy = _getStyle(t, "display"); 4228 style.display = "block"; 4229 m1 = _getTransform(t, _cs, true, vars.parseTransform); 4230 style.display = copy; 4231 } else { 4232 m1 = _getTransform(t, _cs, true, vars.parseTransform); 4233 } 4234 cssp._transform = m1; 4235 if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)" 4236 copy = _tempDiv.style; //don't use the original target because it might be SVG in which case some browsers don't report computed style correctly. 4237 copy[_transformProp] = v.transform; 4238 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly. 4239 copy.position = "absolute"; 4240 _doc.body.appendChild(_tempDiv); 4241 m2 = _getTransform(_tempDiv, null, false); 4242 _doc.body.removeChild(_tempDiv); 4243 if (!m2.perspective) { 4244 m2.perspective = m1.perspective; //tweening to no perspective gives very unintuitive results - just keep the same perspective in that case. 4245 } 4246 if (v.xPercent != null) { 4247 m2.xPercent = _parseVal(v.xPercent, m1.xPercent); 4248 } 4249 if (v.yPercent != null) { 4250 m2.yPercent = _parseVal(v.yPercent, m1.yPercent); 4251 } 4252 } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object) 4253 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX), 4254 scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY), 4255 scaleZ:_parseVal(v.scaleZ, m1.scaleZ), 4256 x:_parseVal(v.x, m1.x), 4257 y:_parseVal(v.y, m1.y), 4258 z:_parseVal(v.z, m1.z), 4259 xPercent:_parseVal(v.xPercent, m1.xPercent), 4260 yPercent:_parseVal(v.yPercent, m1.yPercent), 4261 perspective:_parseVal(v.transformPerspective, m1.perspective)}; 4262 dr = v.directionalRotation; 4263 if (dr != null) { 4264 if (typeof(dr) === "object") { 4265 for (copy in dr) { 4266 v[copy] = dr[copy]; 4267 } 4268 } else { 4269 v.rotation = dr; 4270 } 4271 } 4272 if (typeof(v.x) === "string" && v.x.indexOf("%") !== -1) { 4273 m2.x = 0; 4274 m2.xPercent = _parseVal(v.x, m1.xPercent); 4275 } 4276 if (typeof(v.y) === "string" && v.y.indexOf("%") !== -1) { 4277 m2.y = 0; 4278 m2.yPercent = _parseVal(v.y, m1.yPercent); 4279 } 4280 4281 m2.rotation = _parseAngle(("rotation" in v) ? v.rotation : ("shortRotation" in v) ? v.shortRotation + "_short" : ("rotationZ" in v) ? v.rotationZ : m1.rotation, m1.rotation, "rotation", endRotations); 4282 if (_supports3D) { 4283 m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations); 4284 m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations); 4285 }
4286 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX); 4287 4288 //note: for performance reasons, we combine all skewing into the skewX and rotation values, ignoring skewY but we must still record it so that we can discern how much of the overall skew is attributed to skewX vs. skewY. Otherwise, if the skewY would always act relative (tween skewY to 10deg, for example, multiple times and if we always combine things into skewX, we can't remember that skewY was 10 from last time). Remember, a skewY of 10 degrees looks the same as a rotation of 10 degrees plus a skewX of -10 degrees. 4289 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY); 4290 if ((skewY = m2.skewY - m1.skewY)) { 4291 m2.skewX += skewY; 4292 m2.rotation += skewY; 4293 } 4294 } 4295 if (_supports3D && v.force3D != null) { 4296 m1.force3D = v.force3D; 4297 hasChange = true; 4298 } 4299 4300 m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType; 4301 4302 has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective); 4303 if (!has3D && v.scale != null) { 4304 m2.scaleZ = 1; //no need to tween scaleZ. 4305 } 4306 4307 while (--i > -1) { 4308 p = _transformProps[i]; 4309 orig = m2[p] - m1[p]; 4310 if (orig > min || orig < -min || v[p] != null || _forcePT[p] != null) { 4311 hasChange = true; 4312 pt = new CSSPropTween(m1, p, m1[p], orig, pt); 4313 if (p in endRotations) { 4314 pt.e = endRotations[p]; //directional rotations typically have compensated values during the tween, but we need to make sure they end at exactly what the user requested 4315 } 4316 pt.xs0 = 0; //ensures the value stays numeric in setRatio() 4317 pt.plugin = plugin; 4318 cssp._overwriteProps.push(pt.n); 4319 } 4320 } 4321 4322 orig = v.transformOrigin; 4323 if (m1.svg && (orig || v.svgOrigin)) { 4324 x = m1.xOffset; //when we change the origin, in order to prevent things from jumping we adjust the x/y so we must record those here so that we can create PropTweens for them and flip them at the same time as the origin 4325 y = m1.yOffset; 4326 _parseSVGOrigin(t, _parsePosition(orig), m2, v.svgOrigin, v.smoothOrigin); 4327 pt = _addNonTweeningNumericPT(m1, "xOrigin", (originalGSTransform ? m1 : m2).xOrigin, m2.xOrigin, pt, transformOriginString); //note: if there wasn't a transformOrigin defined yet, just start with the destination one; it's wasteful otherwise, and it causes problems with fromTo() tweens. For example, TweenLite.to("#wheel", 3, {rotation:180, transformOrigin:"50% 50%", delay:1}); TweenLite.fromTo("#wheel", 3, {scale:0.5, transformOrigin:"50% 50%"}, {scale:1, delay:2}); would cause a jump when the from values revert at the beginning of the 2nd tween. 4328 pt = _addNonTweeningNumericPT(m1, "yOrigin", (originalGSTransform ? m1 : m2).yOrigin, m2.yOrigin, pt, transformOriginString); 4329 if (x !== m1.xOffset || y !== m1.yOffset) { 4330 pt = _addNonTweeningNumericPT(m1, "xOffset", (originalGSTransform ? x : m1.xOffset), m1.xOffset, pt, transformOriginString); 4331 pt = _addNonTweeningNumericPT(m1, "yOffset", (originalGSTransform ? y : m1.yOffset), m1.yOffset, pt, transformOriginString); 4332 } 4333 orig = _useSVGTransformAttr ? null : "0px 0px"; //certain browsers (like firefox) completely botch transform-origin, so we must remove it to prevent it from contaminating transforms. We manage it ourselves with xOrigin and yOrigin 4334 } 4335 if (orig || (_supports3D && has3D && m1.zOrigin)) { //if anything 3D is happening and there's a transformOrigin with a z component that's non-zero, we must ensure that the transformOrigin's z-component is set to 0 so that we can manually do those calculations to get around Safari bugs. Even if the user didn't specifically define a "transformOrigin" in this particular tween (maybe they did it via css directly). 4336 if (_transformProp) { 4337 hasChange = true; 4338 p = _transformOriginProp; 4339 orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors 4340 pt = new CSSPropTween(style, p, 0, 0, pt, -1, transformOriginString); 4341 pt.b = style[p]; 4342 pt.plugin = plugin; 4343 if (_supports3D) { 4344 copy = m1.zOrigin; 4345 orig = orig.split(" "); 4346 m1.zOrigin = ((orig.length > 2 && !(copy !== 0 && orig[2] === "0px")) ? parseFloat(orig[2]) : copy) || 0; //Safari doesn't handle the z part of transformOrigin correctly, so we'll manually handle it in the _set3DTransformRatio() method. 4347 pt.xs0 = pt.e = orig[0] + " " + (orig[1] || "50%") + " 0px"; //we must define a z value of 0px specifically otherwise iOS 5 Safari will stick with the old one (if one was defined)! 4348 pt = new CSSPropTween(m1, "zOrigin", 0, 0, pt, -1, pt.n); //we must create a CSSPropTween for the _gsTransform.zOrigin so that it gets reset properly at the beginning if the tween runs backward (as opposed to just setting m1.zOrigin here) 4349 pt.b = copy; 4350 pt.xs0 = pt.e = m1.zOrigin; 4351 } else { 4352 pt.xs0 = pt.e = orig; 4353 } 4354 4355 //for older versions of IE (6-8), we need to manually calculate things inside the setRatio() function. We record origin x and y (ox and oy) and whether or not the values are percentages (oxp and oyp). 4356 } else { 4357 _parsePosition(orig + "", m1); 4358 } 4359 } 4360 if (hasChange) { 4361 cssp._transformType = (!(m1.svg && _useSVGTransformAttr) && (has3D || this._transformType === 3)) ? 3 : 2; //quicker than calling cssp._enableTransforms(); 4362 } 4363 return pt; 4364 }, prefix:true}); 4365 4366 _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"}); 4367 4368 _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) { 4369 e = this.format(e); 4370 var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"], 4371 style = t.style, 4372 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em; 4373 w = parseFloat(t.offsetWidth); 4374 h = parseFloat(t.offsetHeight); 4375 ea1 = e.split(" "); 4376 for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis! 4377 if (this.p.indexOf("border")) { //older browsers used a prefix 4378 props[i] = _checkPropPrefix(props[i]); 4379 }
4380 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px"); 4381 if (bs.indexOf(" ") !== -1) { 4382 bs2 = bs.split(" "); 4383 bs = bs2[0]; 4384 bs2 = bs2[1]; 4385 } 4386 es = es2 = ea1[i]; 4387 bn = parseFloat(bs); 4388 bsfx = bs.substr((bn + "").length); 4389 rel = (es.charAt(1) === "="); 4390 if (rel) { 4391 en = parseInt(es.charAt(0)+"1", 10); 4392 es = es.substr(2); 4393 en *= parseFloat(es); 4394 esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || ""; 4395 } else { 4396 en = parseFloat(es); 4397 esfx = es.substr((en + "").length); 4398 } 4399 if (esfx === "") { 4400 esfx = _suffixMap[p] || bsfx; 4401 } 4402 if (esfx !== bsfx) { 4403 hn = _convertToPixels(t, "borderLeft", bn, bsfx); //horizontal number (we use a bogus "borderLeft" property just because the _convertToPixels() method searches for the keywords "Left", "Right", "Top", and "Bottom" to determine of it's a horizontal or vertical property, and we need "border" in the name so that it knows it should measure relative to the element itself, not its parent. 4404 vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number 4405 if (esfx === "%") { 4406 bs = (hn / w * 100) + "%"; 4407 bs2 = (vn / h * 100) + "%"; 4408 } else if (esfx === "em") { 4409 em = _convertToPixels(t, "borderLeft", 1, "em"); 4410 bs = (hn / em) + "em"; 4411 bs2 = (vn / em) + "em"; 4412 } else { 4413 bs = hn + "px"; 4414 bs2 = vn + "px"; 4415 } 4416 if (rel) { 4417 es = (parseFloat(bs) + en) + esfx; 4418 es2 = (parseFloat(bs2) + en) + esfx; 4419 } 4420 } 4421 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt); 4422 } 4423 return pt; 4424 }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)}); 4425 _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) { 4426 var bp = "background-position", 4427 cs = (_cs || _getComputedStyle(t, null)), 4428 bs = this.format( ((cs) ? _ieVers ? cs.getPropertyValue(bp + "-x") + " " + cs.getPropertyValue(bp + "-y") : cs.getPropertyValue(bp) : t.currentStyle.backgroundPositionX + " " + t.currentStyle.backgroundPositionY) || "0 0"), //Internet Explorer doesn't report background-position correctly - we must query background-position-x and background-position-y and combine them (even in IE10). Before IE9, we must do the same with the currentStyle object and use camelCase 4429 es = this.format(e), 4430 ba, ea, i, pct, overlap, src; 4431 if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) { 4432 src = _getStyle(t, "backgroundImage").replace(_urlExp, ""); 4433 if (src && src !== "none") { 4434 ba = bs.split(" "); 4435 ea = es.split(" "); 4436 _tempImg.setAttribute("src", src); //set the temp IMG's src to the background-image so that we can measure its width/height 4437 i = 2; 4438 while (--i > -1) { 4439 bs = ba[i]; 4440 pct = (bs.indexOf("%") !== -1); 4441 if (pct !== (ea[i].indexOf("%") !== -1)) { 4442 overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height; 4443 ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%"; 4444 } 4445 } 4446 bs = ba.join(" "); 4447 } 4448 } 4449 return this.parseComplex(t.style, bs, es, pt, plugin); 4450 }, formatter:_parsePosition}); 4451 _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition}); 4452 _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true}); 4453 _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true}); 4454 _registerComplexSpecialProp("transformStyle", {prefix:true}); 4455 _registerComplexSpecialProp("backfaceVisibility", {prefix:true}); 4456 _registerComplexSpecialProp("userSelect", {prefix:true}); 4457 _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")}); 4458 _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")}); 4459 _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){ 4460 var b, cs, delim; 4461 if (_ieVers < 9) { //IE8 and earlier don't report a "clip" value in the currentStyle - instead, the values are split apart into clipTop, clipRight, clipBottom, and clipLeft. Also, in IE7 and earlier, the values inside rect() are space-delimited, not comma-delimited. 4462 cs = t.currentStyle; 4463 delim = _ieVers < 8 ? " " : ","; 4464 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")"; 4465 e = this.format(e).split(",").join(delim); 4466 } else { 4467 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt)); 4468 e = this.format(e); 4469 } 4470 return this.parseComplex(t.style, b, e, pt, plugin); 4471 }}); 4472 _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true}); 4473 _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them) 4474 _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) { 4475 return this.parseComplex(t.style, this.format(_getStyle(t, "borderTopWidth", _cs, false, "0px") + " " + _getStyle(t, "borderTopStyle", _cs, false, "solid") + " " + _getStyle(t, "borderTopColor", _cs, false, "#000")), this.format(e), pt, plugin); 4476 }, color:true, formatter:function(v) { 4477 var a = v.split(" "); 4478 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0]; 4479 }}); 4480 _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline). 4481 _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) { 4482 var s = t.style, 4483 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat"; 4484 return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e); 4485 }}); 4486 4487 //opacity-related 4488 var _setIEOpacityRatio = function(v) { 4489 var t = this.t, //refers to the element's style property 4490 filters = t.filter || _getStyle(this.data, "filter") || "", 4491 val = (this.s + this.c * v) | 0, 4492 skip; 4493 if (val === 100) { //for older versions of IE that need to use a filter to apply opacity, we should remove the filter if opacity hits 1 in order to improve performance, but make sure there isn't a transform (matrix) or gradient in the filters. 4494 if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) { 4495 t.removeAttribute("filter"); 4496 skip = (!_getStyle(this.data, "filter")); //if a class is applied that has an alpha filter, it will take effect (we don't want that), so re-apply our alpha filter in that case. We must first remove it and then check. 4497 } else {
4498 t.filter = filters.replace(_alphaFilterExp, ""); 4499 skip = true; 4500 } 4501 } 4502 if (!skip) { 4503 if (this.xn1) { 4504 t.filter = filters = filters || ("alpha(opacity=" + val + ")"); //works around bug in IE7/8 that prevents changes to "visibility" from being applied properly if the filter is changed to a different alpha on the same frame. 4505 } 4506 if (filters.indexOf("pacity") === -1) { //only used if browser doesn't support the standard opacity style property (IE 7 and 8). We omit the "O" to avoid case-sensitivity issues 4507 if (val !== 0 || !this.xn1) { //bugs in IE7/8 won't render the filter properly if opacity is ADDED on the same frame/render as "visibility" changes (this.xn1 is 1 if this tween is an "autoAlpha" tween) 4508 t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly. 4509 } 4510 } else { 4511 t.filter = filters.replace(_opacityExp, "opacity=" + val); 4512 } 4513 } 4514 }; 4515 _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) { 4516 var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")), 4517 style = t.style, 4518 isAutoAlpha = (p === "autoAlpha"); 4519 if (typeof(e) === "string" && e.charAt(1) === "=") { 4520 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b; 4521 } 4522 if (isAutoAlpha && b === 1 && _getStyle(t, "visibility", _cs) === "hidden" && e !== 0) { //if visibility is initially set to "hidden", we should interpret that as intent to make opacity 0 (a convenience) 4523 b = 0; 4524 } 4525 if (_supportsOpacity) { 4526 pt = new CSSPropTween(style, "opacity", b, e - b, pt); 4527 } else { 4528 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt); 4529 pt.xn1 = isAutoAlpha ? 1 : 0; //we need to record whether or not this is an autoAlpha so that in the setRatio(), we know to duplicate the setting of the alpha in order to work around a bug in IE7 and IE8 that prevents changes to "visibility" from taking effect if the filter is changed to a different alpha(opacity) at the same time. Setting it to the SAME value first, then the new value works around the IE7/8 bug. 4530 style.zoom = 1; //helps correct an IE issue. 4531 pt.type = 2; 4532 pt.b = "alpha(opacity=" + pt.s + ")"; 4533 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")"; 4534 pt.data = t; 4535 pt.plugin = plugin; 4536 pt.setRatio = _setIEOpacityRatio; 4537 } 4538 if (isAutoAlpha) { //we have to create the "visibility" PropTween after the opacity one in the linked list so that they run in the order that works properly in IE8 and earlier 4539 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit")); 4540 pt.xs0 = "inherit"; 4541 cssp._overwriteProps.push(pt.n); 4542 cssp._overwriteProps.push(p); 4543 } 4544 return pt; 4545 }}); 4546 4547 4548 var _removeProp = function(s, p) { 4549 if (p) { 4550 if (s.removeProperty) { 4551 if (p.substr(0,2) === "ms" || p.substr(0,6) === "webkit") { //Microsoft and some Webkit browsers don't conform to the standard of capitalizing the first prefix character, so we adjust so that when we prefix the caps with a dash, it's correct (otherwise it'd be "ms-transform" instead of "-ms-transform" for IE9, for example) 4552 p = "-" + p; 4553 } 4554 s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase()); 4555 } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()" 4556 s.removeAttribute(p); 4557 } 4558 } 4559 }, 4560 _setClassNameRatio = function(v) { 4561 this.t._gsClassPT = this; 4562 if (v === 1 || v === 0) { 4563 this.t.setAttribute("class", (v === 0) ? this.b : this.e); 4564 var mpt = this.data, //first MiniPropTween 4565 s = this.t.style; 4566 while (mpt) { 4567 if (!mpt.v) { 4568 _removeProp(s, mpt.p); 4569 } else { 4570 s[mpt.p] = mpt.v; 4571 } 4572 mpt = mpt._next; 4573 } 4574 if (v === 1 && this.t._gsClassPT === this) { 4575 this.t._gsClassPT = null; 4576 } 4577 } else if (this.t.getAttribute("class") !== this.e) { 4578 this.t.setAttribute("class", this.e); 4579 } 4580 }; 4581 _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) { 4582 var b = t.getAttribute("class") || "", //don't use t.className because it doesn't work consistently on SVG elements; getAttribute("class") and setAttribute("class", value") is more reliable. 4583 cssText = t.style.cssText, 4584 difData, bs, cnpt, cnptLookup, mpt; 4585 pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2); 4586 pt.setRatio = _setClassNameRatio; 4587 pt.pr = -11; 4588 _hasPriority = true; 4589 pt.b = b; 4590 bs = _getAllStyles(t, _cs); 4591 //if there's a className tween already operating on the target, force it to its end so that the necessary inline styles are removed and the class name is applied before we determine the end state (we don't want inline styles interfer
4591ing that were there just for class-specific values) 4592 cnpt = t._gsClassPT; 4593 if (cnpt) { 4594 cnptLookup = {}; 4595 mpt = cnpt.data; //first MiniPropTween which stores the inline styles - we need to force these so that the inline styles don't contaminate things. Otherwise, there's a small chance that a tween could start and the inline values match the destination values and they never get cleaned. 4596 while (mpt) { 4597 cnptLookup[mpt.p] = 1; 4598 mpt = mpt._next; 4599 } 4600 cnpt.setRatio(1); 4601 } 4602 t._gsClassPT = pt; 4603 pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : ""); 4604 t.setAttribute("class", pt.e); 4605 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup); 4606 t.setAttribute("class", b); 4607 pt.data = difData.firstMPT; 4608 t.style.cssText = cssText; //we recorded cssText before we swapped classes and ran _getAllStyles() because in cases when a className tween is overwritten, we remove all the related tweening properties from that class change (otherwise class-specific stuff can't override properties we've directly set on the target's style object due to specificity). 4609 pt = pt.xfirst = cssp.parse(t, difData.difs, pt, plugin); //we record the CSSPropTween as the xfirst so that we can handle overwriting propertly (if "className" gets overwritten, we must kill all the properties associated with the className part of the tween, so we can loop through from xfirst to the pt itself) 4610 return pt; 4611 }}); 4612 4613 4614 var _setClearPropsRatio = function(v) { 4615 if (v === 1 || v === 0) if (this.data._totalTime === this.data._totalDuration && this.data.data !== "isFromStart") { //this.data refers to the tween. Only clear at the END of the tween (remember, from() tweens make the ratio go from 1 to 0, so we can't just check that and if the tween is the zero-duration one that's created internally to render the starting values in a from() tween, ignore that because otherwise, for example, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in). 4616 var s = this.t.style, 4617 transformParse = _specialProps.transform.parse, 4618 a, p, i, clearTransform, transform; 4619 if (this.e === "all") { 4620 s.cssText = ""; 4621 clearTransform = true; 4622 } else { 4623 a = this.e.split(" ").join("").split(","); 4624 i = a.length; 4625 while (--i > -1) { 4626 p = a[i]; 4627 if (_specialProps[p]) { 4628 if (_specialProps[p].parse === transformParse) { 4629 clearTransform = true; 4630 } else { 4631 p = (p === "transformOrigin") ? _transformOriginProp : _specialProps[p].p; //ensures that special properties use the proper browser-specific property name, like "scaleX" might be "-webkit-transform" or "boxShadow" might be "-moz-box-shadow" 4632 } 4633 } 4634 _removeProp(s, p); 4635 } 4636 } 4637 if (clearTransform) { 4638 _removeProp(s, _transformProp); 4639 transform = this.t._gsTransform; 4640 if (transform) { 4641 if (transform.svg) { 4642 this.t.removeAttribute("data-svg-origin"); 4643 } 4644 delete this.t._gsTransform; 4645 } 4646 } 4647 4648 } 4649 }; 4650 _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) { 4651 pt = new CSSPropTween(t, p, 0, 0, pt, 2); 4652 pt.setRatio = _setClearPropsRatio; 4653 pt.e = e; 4654 pt.pr = -10; 4655 pt.data = cssp._tween; 4656 _hasPriority = true; 4657 return pt; 4658 }}); 4659 4660 p = "bezier,throwProps,physicsProps,physics2D".split(","); 4661 i = p.length; 4662 while (i--) { 4663 _registerPluginProp(p[i]); 4664 } 4665 4666 4667 4668 4669 4670 4671 4672 4673 p = CSSPlugin.prototype; 4674 p._firstPT = p._lastParsedTransform = p._transform = null; 4675 4676 //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc. 4677 p._onInitTween = function(target, vars, tween) { 4678 if (!target.nodeType) { //css is only for dom elements 4679 return false; 4680 } 4681 this._target = target; 4682 this._tween = tween; 4683 this._vars = vars; 4684 _autoRound = vars.autoRound; 4685 _hasPriority = false; 4686 _suffixMap = vars.suffixMap || CSSPlugin.suffixMap; 4687 _cs = _getComputedStyle(target, ""); 4688 _overwriteProps = this._overwriteProps; 4689 var style = target.style, 4690 v, pt, pt2, first, last, next, zIndex, tpt, threeD; 4691 if (_reqSafariFix) if (style.zIndex === "") {
4692 v = _getStyle(target, "zIndex", _cs); 4693 if (v === "auto" || v === "") { 4694 //corrects a bug in [non-Android] Safari that prevents it from repainting elements in their new positions if they don't have a zIndex set. We also can't just apply this inside _parseTransform() because anything that's moved in any way (like using "left" or "top" instead of transforms like "x" and "y") can be affected, so it is best to ensure that anything that's tweening has a z-index. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly. Plus zIndex is less memory-intensive. 4695 this._addLazySet(style, "zIndex", 0); 4696 } 4697 } 4698 4699 if (typeof(vars) === "string") { 4700 first = style.cssText; 4701 v = _getAllStyles(target, _cs); 4702 style.cssText = first + ";" + vars; 4703 v = _cssDif(target, v, _getAllStyles(target)).difs; 4704 if (!_supportsOpacity && _opacityValExp.test(vars)) { 4705 v.opacity = parseFloat( RegExp.$1 ); 4706 } 4707 vars = v; 4708 style.cssText = first; 4709 } 4710 4711 if (vars.className) { //className tweens will combine any differences they find in the css with the vars that are passed in, so {className:"myClass", scale:0.5, left:20} would work. 4712 this._firstPT = pt = _specialProps.className.parse(target, vars.className, "className", this, null, null, vars); 4713 } else { 4714 this._firstPT = pt = this.parse(target, vars, null); 4715 } 4716 4717 if (this._transformType) { 4718 threeD = (this._transformType === 3); 4719 if (!_transformProp) { 4720 style.zoom = 1; //helps correct an IE issue. 4721 } else if (_isSafari) { 4722 _reqSafariFix = true; 4723 //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random). 4724 if (style.zIndex === "") { 4725 zIndex = _getStyle(target, "zIndex", _cs); 4726 if (zIndex === "auto" || zIndex === "") { 4727 this._addLazySet(style, "zIndex", 0); 4728 } 4729 } 4730 //Setting WebkitBackfaceVisibility corrects 3 bugs: 4731 // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update. 4732 // 2) iOS Safari sometimes neglects to repaint elements in their new positions. Setting "WebkitPerspective" to a non-zero value worked too except that on iOS Safari things would flicker randomly. 4733 // 3) Safari sometimes displayed odd artifacts when tweening the transform (or WebkitTransform) property, like ghosts of the edges of the element remained. Definitely a browser bug. 4734 //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween. 4735 if (_isSafariLT6) { 4736 this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden")); 4737 } 4738 } 4739 pt2 = pt; 4740 while (pt2 && pt2._next) { 4741 pt2 = pt2._next; 4742 } 4743 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2); 4744 this._linkCSSP(tpt, null, pt2); 4745 tpt.setRatio = _transformProp ? _setTransformRatio : _setIETransformRatio; 4746 tpt.data = this._transform || _getTransform(target, _cs, true); 4747 tpt.tween = tween; 4748 tpt.pr = -1; //ensures that the transforms get applied after the components are updated. 4749 _overwriteProps.pop(); //we don't want to force the overwrite of all "transform" tweens of the target - we only care about individual transform properties like scaleX, rotation, etc. The CSSPropTween constructor automatically adds the property to _overwriteProps which is why we need to pop() here. 4750 } 4751 4752 if (_hasPriority) { 4753 //reorders the linked list in order of pr (priority) 4754 while (pt) { 4755 next = pt._next; 4756 pt2 = first; 4757 while (pt2 && pt2.pr > pt.pr) { 4758 pt2 = pt2._next; 4759 } 4760 if ((pt._prev = pt2 ? pt2._prev : last)) { 4761 pt._prev._next = pt; 4762 } else { 4763 first = pt; 4764 } 4765 if ((pt._next = pt2)) { 4766 pt2._prev = pt; 4767 } else { 4768 last = pt; 4769 } 4770 pt = next; 4771 } 4772 this._firstPT = first; 4773 } 4774 return true; 4775 }; 4776 4777 4778 p.parse = function(target, vars, pt, plugin) { 4779 var style = target.style, 4780 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel; 4781 for (p in vars) { 4782 es = vars[p]; //ending value string 4783 sp = _specialProps[p]; //SpecialProp lookup. 4784 if (sp) { 4785 pt = sp.parse(target, es, p, this, pt, plugin, vars); 4786 4787 } else { 4788 bs = _getStyle(target, p, _cs) + ""; 4789 isStr = (typeof(es) === "string"); 4790 if (p === "color" || p === "fill" || p === "stroke" || p.indexOf("Color") !== -1 || (isStr && _rgbhslExp.test(es))) { //Opera uses background: to define color sometimes in addition to backgroundColor: 4791 if (!isStr) { 4792 es = _parseColor(es); 4793 es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")"; 4794 } 4795 pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin); 4796 4797 } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) { 4798 pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin); 4799 4800 } else { 4801 bn = parseFloat(bs); 4802 bsfx = (bn || bn === 0) ? bs.substr((bn + "").length) : ""; //remember, bs could be non-numeric like "normal" for fontWeight, so we should default to a blank suffix in that case. 4803 4804 if (bs === "" || bs === "auto") { 4805 if (p === "width" || p === "height") { 4806 bn = _getDimension(target, p, _cs); 4807 bsfx = "px"; 4808 } else if (p === "left" || p === "top") {
4809 bn = _calculateOffset(target, p, _cs); 4810 bsfx = "px"; 4811 } else { 4812 bn = (p !== "opacity") ? 0 : 1; 4813 bsfx = ""; 4814 } 4815 } 4816 4817 rel = (isStr && es.charAt(1) === "="); 4818 if (rel) { 4819 en = parseInt(es.charAt(0) + "1", 10); 4820 es = es.substr(2); 4821 en *= parseFloat(es); 4822 esfx = es.replace(_suffixExp, ""); 4823 } else { 4824 en = parseFloat(es); 4825 esfx = isStr ? es.replace(_suffixExp, "") : ""; 4826 } 4827 4828 if (esfx === "") { 4829 esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix. 4830 } 4831 4832 es = (en || en === 0) ? (rel ? en + bn : en) + esfx : vars[p]; //ensures that any += or -= prefixes are taken care of. Record the end value before normalizing the suffix because we always want to end the tween on exactly what they intended even if it doesn't match the beginning value's suffix. 4833 4834 //if the beginning/ending suffixes don't match, normalize them... 4835 if (bsfx !== esfx) if (esfx !== "") if (en || en === 0) if (bn) { //note: if the beginning value (bn) is 0, we don't need to convert units! 4836 bn = _convertToPixels(target, p, bn, bsfx); 4837 if (esfx === "%") { 4838 bn /= _convertToPixels(target, p, 100, "%") / 100; 4839 if (vars.strictUnits !== true) { //some browsers report only "px" values instead of allowing "%" with getComputedStyle(), so we assume that if we're tweening to a %, we should start there too unless strictUnits:true is defined. This approach is particularly useful for responsive designs that use from() tweens. 4840 bs = bn + "%"; 4841 } 4842 4843 } else if (esfx === "em" || esfx === "rem") { 4844 bn /= _convertToPixels(target, p, 1, esfx); 4845 4846 //otherwise convert to pixels. 4847 } else if (esfx !== "px") { 4848 en = _convertToPixels(target, p, en, esfx); 4849 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too. 4850 } 4851 if (rel) if (en || en === 0) { 4852 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here. 4853 } 4854 } 4855 4856 if (rel) { 4857 en += bn; 4858 } 4859 4860 if ((bn || bn === 0) && (en || en === 0)) { //faster than isNaN(). Also, previously we required en !== bn but that doesn't really gain much performance and it prevents _parseToProxy() from working properly if beginning and ending values match but need to get tweened by an external plugin anyway. For example, a bezier tween where the target starts at left:0 and has these points: [{left:50},{left:0}] wouldn't work properly because when parsing the last point, it'd match the first (current) one and a non-tweening CSSPropTween would be recorded when we actually need a normal tween (type:0) so that things get updated during the tween properly. 4861 pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es); 4862 pt.xs0 = esfx; 4863 //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0); 4864 } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) { 4865 _log("invalid " + p + " tween value: " + vars[p]); 4866 } else { 4867 pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es); 4868 pt.xs0 = (es === "none" && (p === "display" || p.indexOf("Style") !== -1)) ? bs : es; //intermediate value should typically be set immediately (end value) except for "display" or things like borderTopStyle, borderBottomStyle, etc. which should use the beginning value during the tween. 4869 //DEBUG: _log("non-tweening value "+p+": "+pt.xs0); 4870 } 4871 } 4872 } 4873 if (plugin) if (pt && !pt.plugin) { 4874 pt.plugin = plugin; 4875 } 4876 } 4877 return pt; 4878 }; 4879 4880 4881 //gets called every time the tween updates, passing the new ratio (typically a value between 0 and 1, but not always (for example, if an Elastic.easeOut is used, the value can jump above 1 mid-tween). It will always start and 0 and end at 1. 4882 p.setRatio = function(v) { 4883 var pt = this._firstPT, 4884 min = 0.000001, 4885 val, str, i; 4886 //at the end of the tween, we set the values to exactly what we received in order to make sure non-tweening values (like "position" or "float" or whatever) are set and so that if the beginning/ending suffixes (units) didn't match and we normalized to px, the value that the user passed in is used here. We check to see if the tween is at its beginning in case it's a from() tween in which case the ratio will actually go from 1 to 0 over the course of the tween (backwards). 4887 if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) { 4888 while (pt) { 4889 if (pt.type !== 2) { 4890 if (pt.r && pt.type !== -1) { 4891 val = Math.round(pt.s + pt.c); 4892 if (!pt.type) { 4893 pt.t[pt.p] = val + pt.xs0; 4894 } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)" 4895 i = pt.l; 4896 str = pt.xs0 + val + pt.xs1; 4897 for (i = 1; i < pt.l; i++) {
4898 str += pt["xn"+i] + pt["xs"+(i+1)]; 4899 } 4900 pt.t[pt.p] = str; 4901 } 4902 } else { 4903 pt.t[pt.p] = pt.e; 4904 } 4905 } else { 4906 pt.setRatio(v); 4907 } 4908 pt = pt._next; 4909 } 4910 4911 } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) { 4912 while (pt) { 4913 val = pt.c * v + pt.s; 4914 if (pt.r) { 4915 val = Math.round(val); 4916 } else if (val < min) if (val > -min) { 4917 val = 0; 4918 } 4919 if (!pt.type) { 4920 pt.t[pt.p] = val + pt.xs0; 4921 } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)" 4922 i = pt.l; 4923 if (i === 2) { 4924 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2; 4925 } else if (i === 3) { 4926 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3; 4927 } else if (i === 4) { 4928 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4; 4929 } else if (i === 5) { 4930 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4 + pt.xn4 + pt.xs5; 4931 } else { 4932 str = pt.xs0 + val + pt.xs1; 4933 for (i = 1; i < pt.l; i++) { 4934 str += pt["xn"+i] + pt["xs"+(i+1)]; 4935 } 4936 pt.t[pt.p] = str; 4937 } 4938 4939 } else if (pt.type === -1) { //non-tweening value 4940 pt.t[pt.p] = pt.xs0; 4941 4942 } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc. 4943 pt.setRatio(v); 4944 } 4945 pt = pt._next; 4946 } 4947 4948 //if the tween is reversed all the way back to the beginning, we need to restore the original values which may have different units (like % instead of px or em or whatever). 4949 } else { 4950 while (pt) { 4951 if (pt.type !== 2) { 4952 pt.t[pt.p] = pt.b; 4953 } else { 4954 pt.setRatio(v); 4955 } 4956 pt = pt._next; 4957 } 4958 } 4959 }; 4960 4961 /** 4962 * @private 4963 * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called. 4964 * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked 4965 * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call 4966 * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin 4967 * doesn't have any transform-related properties of its own. You can call this method as many times as you 4968 * want and it won't create duplicate CSSPropTweens. 4969 * 4970 * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster) 4971 */ 4972 p._enableTransforms = function(threeD) { 4973 this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values. 4974 this._transformType = (!(this._transform.svg && _useSVGTransformAttr) && (threeD || this._transformType === 3)) ? 3 : 2; 4975 }; 4976 4977 var lazySet = function(v) { 4978 this.t[this.p] = this.e; 4979 this.data._linkCSSP(this, this._next, null, true); //we purposefully keep this._next even though it'd make sense to null it, but this is a performance optimization, as this happens during the while (pt) {} loop in setRatio() at the bottom of which it sets pt = pt._next, so if we null it, the linked list will be broken in that loop. 4980 }; 4981 /** @private Gives us a way to set a value on the first render (and only the first render). **/ 4982 p._addLazySet = function(t, p, v) { 4983 var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2); 4984 pt.e = v; 4985 pt.setRatio = lazySet; 4986 pt.data = this; 4987 }; 4988 4989 /** @private **/ 4990 p._linkCSSP = function(pt, next, prev, remove) { 4991 if (pt) { 4992 if (next) { 4993 next._prev = pt; 4994 } 4995 if (pt._next) { 4996 pt._next._prev = pt._prev; 4997 } 4998 if (pt._prev) { 4999 pt._prev._next = pt._next; 5000 } else if (this._firstPT === pt) { 5001 this._firstPT = pt._next; 5002 remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed) 5003 } 5004 if (prev) { 5005 prev._next = pt; 5006 } else if (!remove && this._firstPT === null) { 5007 this._firstPT = pt; 5008 } 5009 pt._next = next; 5010 pt._prev = prev; 5011 } 5012 return pt; 5013 }; 5014 5015 //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property. 5016 p._kill = function(lookup) { 5017 var copy = lookup, 5018 pt, p, xfirst; 5019 if (lookup.autoAlpha || lookup.alpha) { 5020 copy = {}; 5021 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere. 5022 copy[p] = lookup[p]; 5023 } 5024 copy.opacity = 1; 5025 if (copy.autoAlpha) { 5026 copy.visibility = 1; 5027 } 5028 } 5029 if (lookup.className && (pt = this._classNamePT)) { //for className tweens, we need to kill any associated CSSPropTweens too; a linked list starts at the className's "xfirst". 5030 xfirst = pt.xfirst; 5031 if (xfirst && xfirst._prev) { 5032 this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev 5033 } else if (xfirst === this._firstPT) { 5034 this._firstPT = pt._next; 5035 } 5036 if (pt._next) { 5037 this._linkCSSP(pt._next, pt._next._next, xfirst._prev); 5038 } 5039 this._classNamePT = null; 5040 } 5041 return TweenPlugin.prototype._kill.call(this, copy); 5042 }; 5043 5044 5045 5046 //used by cascadeTo() for gathering all the style properties of each child element into an array for c
5046omparison. 5047 var _getChildStyles = function(e, props, targets) { 5048 var children, i, child, type; 5049 if (e.slice) { 5050 i = e.length; 5051 while (--i > -1) { 5052 _getChildStyles(e[i], props, targets); 5053 } 5054 return; 5055 } 5056 children = e.childNodes; 5057 i = children.length; 5058 while (--i > -1) { 5059 child = children[i]; 5060 type = child.type; 5061 if (child.style) { 5062 props.push(_getAllStyles(child)); 5063 if (targets) { 5064 targets.push(child); 5065 } 5066 } 5067 if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) { 5068 _getChildStyles(child, props, targets); 5069 } 5070 } 5071 }; 5072 5073 /** 5074 * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite 5075 * and then compares the style properties of all the target's child elements at the tween's start and end, and 5076 * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting 5077 * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is 5078 * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens 5079 * is because it creates entirely new tweens that may have completely different targets than the original tween, 5080 * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API 5081 * and it would create other problems. For example: 5082 * - If I create a tween of elementA, that tween instance may suddenly change its target to include 50 other elements (unintuitive if I specifically defined the target I wanted) 5083 * - We can't just create new independent tweens because otherwise, what happens if the original/parent tween is reversed or pause or dropped into a TimelineLite for tight control? You'd expect that tween's behavior to affect all the others. 5084 * - Analyzing every style property of every child before and after the tween is an expensive operation when there are many children, so this behavior shouldn't be imposed on all className tweens by default, especially since it's probably rare that this extra functionality is needed. 5085 * 5086 * @param {Object} target object to be tweened 5087 * @param {number} Duration in seconds (or frames for frames-based tweens) 5088 * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone} 5089 * @return {Array} An array of TweenLite instances 5090 */ 5091 CSSPlugin.cascadeTo = function(target, duration, vars) { 5092 var tween = TweenLite.to(target, duration, vars), 5093 results = [tween], 5094 b = [], 5095 e = [], 5096 targets = [], 5097 _reservedProps = TweenLite._internals.reservedProps, 5098 i, difs, p, from; 5099 target = tween._targets || tween.target; 5100 _getChildStyles(target, b, targets); 5101 tween.render(duration, true, true); 5102 _getChildStyles(target, e); 5103 tween.render(0, true, true); 5104 tween._enabled(true); 5105 i = targets.length; 5106 while (--i > -1) { 5107 difs = _cssDif(targets[i], b[i], e[i]); 5108 if (difs.firstMPT) { 5109 difs = difs.difs; 5110 for (p in vars) { 5111 if (_reservedProps[p]) { 5112 difs[p] = vars[p]; 5113 } 5114 } 5115 from = {}; 5116 for (p in difs) { 5117 from[p] = b[i][p]; 5118 } 5119 results.push(TweenLite.fromTo(targets[i], duration, from, difs)); 5120 } 5121 } 5122 return results; 5123 }; 5124 5125 TweenPlugin.activate([CSSPlugin]); 5126 return CSSPlugin; 5127 5128 }, true); 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 5139 5140/* 5141 * ---------------------------------------------------------------- 5142 * RoundPropsPlugin 5143 * ---------------------------------------------------------------- 5144 */ 5145 (function() { 5146 5147 var RoundPropsPlugin = _gsScope._gsDefine.plugin({ 5148 propName: "roundProps", 5149 version: "1.5", 5150 priority: -1, 5151 API: 2, 5152 5153 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 5154 init: function(target, value, tween) { 5155 this._tween = tween; 5156 return true; 5157 } 5158 5159 }), 5160 _roundLinkedList = function(node) { 5161 while (node) { 5162 if (!node.f && !node.blob) { 5163 node.r = 1; 5164 } 5165 node = node._next; 5166 } 5167 }, 5168 p = RoundPropsPlugin.prototype; 5169 5170 p._onInitAllProps = function() { 5171 var tween = this._tween,
5172 rp = (tween.vars.roundProps.join) ? tween.vars.roundProps : tween.vars.roundProps.split(","), 5173 i = rp.length, 5174 lookup = {}, 5175 rpt = tween._propLookup.roundProps, 5176 prop, pt, next; 5177 while (--i > -1) { 5178 lookup[rp[i]] = 1; 5179 } 5180 i = rp.length; 5181 while (--i > -1) { 5182 prop = rp[i]; 5183 pt = tween._firstPT; 5184 while (pt) { 5185 next = pt._next; //record here, because it may get removed 5186 if (pt.pg) { 5187 pt.t._roundProps(lookup, true); 5188 } else if (pt.n === prop) { 5189 if (pt.f === 2 && pt.t) { //a blob (text containing multiple numeric values) 5190 _roundLinkedList(pt.t._firstPT); 5191 } else { 5192 this._add(pt.t, prop, pt.s, pt.c); 5193 //remove from linked list 5194 if (next) { 5195 next._prev = pt._prev; 5196 } 5197 if (pt._prev) { 5198 pt._prev._next = next; 5199 } else if (tween._firstPT === pt) { 5200 tween._firstPT = next; 5201 } 5202 pt._next = pt._prev = null; 5203 tween._propLookup[prop] = rpt; 5204 } 5205 } 5206 pt = next; 5207 } 5208 } 5209 return false; 5210 }; 5211 5212 p._add = function(target, p, s, c) { 5213 this._addTween(target, p, s, s + c, p, true); 5214 this._overwriteProps.push(p); 5215 }; 5216 5217 }()); 5218 5219 5220 5221 5222 5223 5224 5225 5226 5227 5228/* 5229 * ---------------------------------------------------------------- 5230 * AttrPlugin 5231 * ---------------------------------------------------------------- 5232 */ 5233 5234 (function() { 5235 5236 _gsScope._gsDefine.plugin({ 5237 propName: "attr", 5238 API: 2, 5239 version: "0.5.0", 5240 5241 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 5242 init: function(target, value, tween) { 5243 var p; 5244 if (typeof(target.setAttribute) !== "function") { 5245 return false; 5246 } 5247 for (p in value) { 5248 this._addTween(target, "setAttribute", target.getAttribute(p) + "", value[p] + "", p, false, p); 5249 this._overwriteProps.push(p); 5250 } 5251 return true; 5252 } 5253 5254 }); 5255 5256 }()); 5257 5258 5259 5260 5261 5262 5263 5264 5265 5266 5267/* 5268 * ---------------------------------------------------------------- 5269 * DirectionalRotationPlugin 5270 * ---------------------------------------------------------------- 5271 */ 5272 _gsScope._gsDefine.plugin({ 5273 propName: "directionalRotation", 5274 version: "0.2.1", 5275 API: 2, 5276 5277 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 5278 init: function(target, value, tween) { 5279 if (typeof(value) !== "object") { 5280 value = {rotation:value}; 5281 } 5282 this.finals = {}; 5283 var cap = (value.useRadians === true) ? Math.PI * 2 : 360, 5284 min = 0.000001, 5285 p, v, start, end, dif, split; 5286 for (p in value) { 5287 if (p !== "useRadians") { 5288 split = (value[p] + "").split("_"); 5289 v = split[0]; 5290 start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() ); 5291 end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0; 5292 dif = end - start; 5293 if (split.length) { 5294 v = split.join("_"); 5295 if (v.indexOf("short") !== -1) { 5296 dif = dif % cap; 5297 if (dif !== dif % (cap / 2)) { 5298 dif = (dif < 0) ? dif + cap : dif - cap; 5299 } 5300 } 5301 if (v.indexOf("_cw") !== -1 && dif < 0) { 5302 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 5303 } else if (v.indexOf("ccw") !== -1 && dif > 0) { 5304 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 5305 } 5306 } 5307 if (dif > min || dif < -min) { 5308 this._addTween(target, p, start, start + dif, p); 5309 this._overwriteProps.push(p); 5310 } 5311 } 5312 } 5313 return true; 5314 }, 5315 5316 //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.) 5317 set: function(ratio) { 5318 var pt; 5319 if (ratio !== 1) { 5320 this._super.setRatio.call(this, ratio); 5321 } else { 5322 pt = this._firstPT; 5323 while (pt) { 5324 if (pt.f) { 5325 pt.t[pt.p](this.finals[pt.p]); 5326 } else { 5327 pt.t[pt.p] = this.finals[pt.p]; 5328 } 5329 pt = pt._next; 5330 } 5331 } 5332 } 5333 5334 })._autoCSS = true; 5335 5336 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346/* 5347 * ---------------------------------------------------------------- 5348 * EasePack 5349 * ---------------------------------------------------------------- 5350 */ 5351 _gsScope._gsDefine("easing.Back", ["easing.Ease"], function(Ease) { 5352 5353 var w = (_gsScope.GreenSockGlobals || _gsScope), 5354 gs = w.com.greensock, 5355 _2PI = Math.PI * 2, 5356 _HALF_PI = Math.PI / 2, 5357 _class = gs._class, 5358 _create = function(n, f) { 5359 var C = _class("easing." + n, function(){}, true), 5360 p = C.prototype = new Ease(); 5361 p.constructor = C; 5362 p.getRatio = f; 5363 return C; 5364 }, 5365 _easeReg = Ease.register || function(){}, //put an empty function in place just as a safety measure in case someone loads an OLD version of TweenLite.js where Ease.register doesn't exist. 5366 _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) { 5367 var C = _class("easing."+name, { 5368 easeOut:new EaseOut(), 5369 easeIn:new EaseIn(), 5370 easeInOut:new EaseInOut() 5371 }, true); 5372 _easeReg(C, name); 5373 return C; 5374 }, 5375 EasePoint = function(time, value, next) { 5376 this.t = time; 5377 this.v = value; 5378 if (next) { 5379 this.next = next; 5380 next.prev = this; 5381 this.c = next.v - value; 5382 this.gap = next.t - time; 5383 } 5384 }, 5385 5386 //Back 5387 _createBack = function(n, f) { 5388 var C = _class("easing." + n, function(overshoot) { 5389 this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158; 5390 this._p2 = this._p1 * 1.525; 5391 }, true), 5392 p = C.prototype = new Ease(); 5393 p.constructor = C; 5394 p.getRatio = f; 5395 p.config = function(overshoot) { 5396 return new C(overshoot); 5397 }; 5398 return C; 5399 }, 5400 5401 Back = _wrap("Back", 5402 _createBack("BackOut", function(p) { 5403 return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1); 5404 }), 5405 _createBack("BackIn", function(p) { 5406 return p * p * ((this._p1 + 1) * p - this._p1); 5407 }), 5408 _createBack("BackInOut", function(p) { 5409 return ((p *= 2) < 1) ? 0.5 * p * p * ((this._p2 + 1) * p - this._p2) : 0.5 * ((p -= 2) * p * ((this._p2 + 1) * p + this._p2) + 2); 5410 }) 5411 ), 5412 5413 5414 //SlowMo
5415 SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) { 5416 power = (power || power === 0) ? power : 0.7; 5417 if (linearRatio == null) { 5418 linearRatio = 0.7; 5419 } else if (linearRatio > 1) { 5420 linearRatio = 1; 5421 } 5422 this._p = (linearRatio !== 1) ? power : 0; 5423 this._p1 = (1 - linearRatio) / 2; 5424 this._p2 = linearRatio; 5425 this._p3 = this._p1 + this._p2; 5426 this._calcEnd = (yoyoMode === true); 5427 }, true), 5428 p = SlowMo.prototype = new Ease(), 5429 SteppedEase, RoughEase, _createElastic; 5430 5431 p.constructor = SlowMo; 5432 p.getRatio = function(p) { 5433 var r = p + (0.5 - p) * this._p; 5434 if (p < this._p1) { 5435 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r); 5436 } else if (p > this._p3) { 5437 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p); 5438 } 5439 return this._calcEnd ? 1 : r; 5440 }; 5441 SlowMo.ease = new SlowMo(0.7, 0.7); 5442 5443 p.config = SlowMo.config = function(linearRatio, power, yoyoMode) { 5444 return new SlowMo(linearRatio, power, yoyoMode); 5445 }; 5446 5447 5448 //SteppedEase 5449 SteppedEase = _class("easing.SteppedEase", function(steps) { 5450 steps = steps || 1; 5451 this._p1 = 1 / steps; 5452 this._p2 = steps + 1; 5453 }, true); 5454 p = SteppedEase.prototype = new Ease(); 5455 p.constructor = SteppedEase; 5456 p.getRatio = function(p) { 5457 if (p < 0) { 5458 p = 0; 5459 } else if (p >= 1) { 5460 p = 0.999999999; 5461 } 5462 return ((this._p2 * p) >> 0) * this._p1; 5463 }; 5464 p.config = SteppedEase.config = function(steps) { 5465 return new SteppedEase(steps); 5466 }; 5467 5468 5469 //RoughEase 5470 RoughEase = _class("easing.RoughEase", function(vars) { 5471 vars = vars || {}; 5472 var taper = vars.taper || "none", 5473 a = [], 5474 cnt = 0, 5475 points = (vars.points || 20) | 0, 5476 i = points, 5477 randomize = (vars.randomize !== false), 5478 clamp = (vars.clamp === true), 5479 template = (vars.template instanceof Ease) ? vars.template : null, 5480 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4, 5481 x, y, bump, invX, obj, pnt; 5482 while (--i > -1) { 5483 x = randomize ? Math.random() : (1 / points) * i; 5484 y = template ? template.getRatio(x) : x; 5485 if (taper === "none") { 5486 bump = strength; 5487 } else if (taper === "out") { 5488 invX = 1 - x; 5489 bump = invX * invX * strength; 5490 } else if (taper === "in") { 5491 bump = x * x * strength; 5492 } else if (x < 0.5) { //"both" (start) 5493 invX = x * 2; 5494 bump = invX * invX * 0.5 * strength; 5495 } else { //"both" (end) 5496 invX = (1 - x) * 2; 5497 bump = invX * invX * 0.5 * strength; 5498 } 5499 if (randomize) { 5500 y += (Math.random() * bump) - (bump * 0.5); 5501 } else if (i % 2) { 5502 y += bump * 0.5; 5503 } else { 5504 y -= bump * 0.5; 5505 } 5506 if (clamp) { 5507 if (y > 1) { 5508 y = 1; 5509 } else if (y < 0) { 5510 y = 0; 5511 } 5512 } 5513 a[cnt++] = {x:x, y:y}; 5514 } 5515 a.sort(function(a, b) { 5516 return a.x - b.x; 5517 }); 5518 5519 pnt = new EasePoint(1, 1, null); 5520 i = points; 5521 while (--i > -1) { 5522 obj = a[i]; 5523 pnt = new EasePoint(obj.x, obj.y, pnt); 5524 } 5525 5526 this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next); 5527 }, true); 5528 p = RoughEase.prototype = new Ease(); 5529 p.constructor = RoughEase; 5530 p.getRatio = function(p) { 5531 var pnt = this._prev; 5532 if (p > pnt.t) { 5533 while (pnt.next && p >= pnt.t) { 5534 pnt = pnt.next; 5535 } 5536 pnt = pnt.prev; 5537 } else { 5538 while (pnt.prev && p <= pnt.t) { 5539 pnt = pnt.prev; 5540 } 5541 } 5542 this._prev = pnt; 5543 return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c); 5544 }; 5545 p.config = function(vars) { 5546 return new RoughEase(vars); 5547 }; 5548 RoughEase.ease = new RoughEase(); 5549 5550 5551 //Bounce 5552 _wrap("Bounce", 5553 _create("BounceOut", function(p) { 5554 if (p < 1 / 2.75) { 5555 return 7.5625 * p * p; 5556 } else if (p < 2 / 2.75) { 5557 return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75; 5558 } else if (p < 2.5 / 2.75) { 5559 return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375; 5560 } 5561 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375; 5562 }), 5563 _create("BounceIn", function(p) { 5564 if ((p = 1 - p) < 1 / 2.75) { 5565 return 1 - (7.5625 * p * p); 5566 } else if (p < 2 / 2.75) { 5567 return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75); 5568 } else if (p < 2.5 / 2.75) { 5569 return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375); 5570 } 5571 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375); 5572 }), 5573 _create("BounceInOut", function(p) { 5574 var invert = (p < 0.5); 5575 if (invert) { 5576 p = 1 - (p * 2); 5577 } else { 5578 p = (p * 2) - 1; 5579 } 5580 if (p < 1 / 2.75) { 5581 p = 7.5625 * p * p; 5582 } else if (p < 2 / 2.75) { 5583 p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75; 5584 } else if (p < 2.5 / 2.75) { 5585 p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375; 5586 } else { 5587 p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375; 5588 } 5589 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5; 5590 }) 5591 ); 5592 5593 5594 //CIRC 5595 _wrap("Circ", 5596 _create("CircOut", function(p) { 5597 return Math.sqrt(1 - (p = p - 1) * p); 5598 }), 5599 _create("CircIn", function(p) { 5600 return -(Math.sqrt(1 - (p * p)) - 1); 5601 }), 5602 _create("CircInOut", function(p) { 5603 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1); 5604 }) 5605 ); 5606 5607 5608 //Elastic 5609 _createElastic = function(n, f, def) { 5610 var C = _class("easing." + n, function(amplitude, period) { 5611 this._p1 = (amplitude >= 1) ? amplitude : 1;
5611 //note: if amplitude is < 1, we simply adjust the period for a more natural feel. Otherwise the math doesn't work right and the curve starts at 1. 5612 this._p2 = (period || def) / (amplitude < 1 ? amplitude : 1); 5613 this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0); 5614 this._p2 = _2PI / this._p2; //precalculate to optimize 5615 }, true), 5616 p = C.prototype = new Ease(); 5617 p.constructor = C; 5618 p.getRatio = f; 5619 p.config = function(amplitude, period) { 5620 return new C(amplitude, period); 5621 }; 5622 return C; 5623 }; 5624 _wrap("Elastic", 5625 _createElastic("ElasticOut", function(p) { 5626 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * this._p2 ) + 1; 5627 }, 0.3), 5628 _createElastic("ElasticIn", function(p) { 5629 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * this._p2 )); 5630 }, 0.3), 5631 _createElastic("ElasticInOut", function(p) { 5632 return ((p *= 2) < 1) ? -0.5 * (this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * this._p2)) : this._p1 * Math.pow(2, -10 *(p -= 1)) * Math.sin( (p - this._p3) * this._p2 ) * 0.5 + 1; 5633 }, 0.45) 5634 ); 5635 5636 5637 //Expo 5638 _wrap("Expo", 5639 _create("ExpoOut", function(p) { 5640 return 1 - Math.pow(2, -10 * p); 5641 }), 5642 _create("ExpoIn", function(p) { 5643 return Math.pow(2, 10 * (p - 1)) - 0.001; 5644 }), 5645 _create("ExpoInOut", function(p) { 5646 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1))); 5647 }) 5648 ); 5649 5650 5651 //Sine 5652 _wrap("Sine", 5653 _create("SineOut", function(p) { 5654 return Math.sin(p * _HALF_PI); 5655 }), 5656 _create("SineIn", function(p) { 5657 return -Math.cos(p * _HALF_PI) + 1; 5658 }), 5659 _create("SineInOut", function(p) { 5660 return -0.5 * (Math.cos(Math.PI * p) - 1); 5661 }) 5662 ); 5663 5664 _class("easing.EaseLookup", { 5665 find:function(s) { 5666 return Ease.map[s]; 5667 } 5668 }, true); 5669 5670 //register the non-standard eases 5671 _easeReg(w.SlowMo, "SlowMo", "ease,"); 5672 _easeReg(RoughEase, "RoughEase", "ease,"); 5673 _easeReg(SteppedEase, "SteppedEase", "ease,"); 5674 5675 return Back; 5676 5677 }, true); 5678 5679 5680}); 5681 5682if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case TweenLite was already loaded separately. 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694/* 5695 * ---------------------------------------------------------------- 5696 * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc. 5697 * ---------------------------------------------------------------- 5698 */ 5699(function(window, moduleName) { 5700 5701 "use strict"; 5702 var _globals = window.GreenSockGlobals = window.GreenSockGlobals || window; 5703 if (_globals.TweenLite) { 5704 return; //in case the core set of classes is already loaded, don't instantiate twice. 5705 } 5706 var _namespace = function(ns) { 5707 var a = ns.split("."), 5708 p = _globals, i; 5709 for (i = 0; i < a.length; i++) { 5710 p[a[i]] = p = p[a[i]] || {}; 5711 } 5712 return p; 5713 }, 5714 gs = _namespace("com.greensock"), 5715 _tinyNum = 0.0000000001, 5716 _slice = function(a) { //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll() 5717 var b = [], 5718 l = a.length, 5719 i; 5720 for (i = 0; i !== l; b.push(a[i++])) {} 5721 return b; 5722 }, 5723 _emptyFunc = function() {}, 5724 _isArray = (function() { //works around issues in iframe environments where the Array global isn't shared, thus if the object originates in a different window/iframe, "(obj instanceof Array)" will evaluate false. We added some speed optimizations to avoid Object.prototype.toString.call() unless it's absolutely necessary because it's VERY slow (like 20x slower) 5725 var toString = Object.prototype.toString, 5726 array = toString.call([]); 5727 return function(obj) { 5728 return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array)); 5729 }; 5730 }()), 5731 a, i, p, _ticker, _tickerActive, 5732 _defLookup = {}, 5733 5734 /** 5735 * @constructor 5736 * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition. 5737 * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is 5738 * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin 5739 * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally. 5740 *
5741 * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found, 5742 * it will go there as of v1.7). For example, TweenLite will be found at window.com.greensock.TweenLite and since it's a global class that should be available anywhere, 5743 * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so 5744 * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything 5745 * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock 5746 * files and put them into distinct objects (imagine a banner ad uses a newer version but the main site uses an older one). In that case, you could 5747 * sandbox the banner one like: 5748 * 5749 * <script> 5750 * var gs = window.GreenSockGlobals = {}; //the newer version we're about to load could now be referenced in a "gs" object, like gs.TweenLite.to(...). Use whatever alias you want as long as it's unique, "gs" or "banner" or whatever. 5751 * </script> 5752 * <script src="js/greensock/v1.7/TweenMax.js"></script> 5753 * <script> 5754 * window.GreenSockGlobals = window._gsQueue = window._gsDefine = null; //reset it back to null (along with the special _gsQueue variable) so that the next load of TweenMax affects the window and we can reference things directly like TweenLite.to(...) 5755 * </script> 5756 * <script src="js/greensock/v1.6/TweenMax.js"></script> 5757 * <script> 5758 * gs.TweenLite.to(...); //would use v1.7 5759 * TweenLite.to(...); //would use v1.6 5760 * </script> 5761 * 5762 * @param {!string} ns The namespace of the class definition, leaving off "com.greensock." as that's assumed. For example, "TweenLite" or "plugins.CSSPlugin" or "easing.Back". 5763 * @param {!Array.<string>} dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"] 5764 * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition. 5765 * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object) 5766 */ 5767 Definition = function(ns, dependencies, func, global) { 5768 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses 5769 _defLookup[ns] = this; 5770 this.gsClass = null; 5771 this.func = func; 5772 var _classes = []; 5773 this.check = function(init) { 5774 var i = dependencies.length, 5775 missing = i, 5776 cur, a, n, cl, hasModule; 5777 while (--i > -1) { 5778 if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) { 5779 _classes[i] = cur.gsClass; 5780 missing--; 5781 } else if (init) { 5782 cur.sc.push(this); 5783 } 5784 } 5785 if (missing === 0 && func) { 5786 a = ("com.greensock." + ns).split("."); 5787 n = a.pop(); 5788 cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes); 5789 5790 //exports to multiple environments 5791 if (global) { 5792 _globals[n] = cl; //provides a way to avoid global namespace pollution. By default, the main classes like TweenLite, Power1, Strong, etc. are added to window unless a GreenSockGlobals is defined. So if you want to have things added to a custom object instead, just do something like window.GreenSockGlobals = {} before loading any GreenSock files. You can even set up an alias like window.GreenSockGlobals = windows.gs = {} so that you can access everything like gs.TweenLite. Also remember that ALL classes are added to the window.com.greensock object (in their respective packages, like com.greensock.easing.Power1, com.greensock.TweenLite, etc.) 5793 hasModule = (typeof(module) !== "undefined" && module.exports); 5794 if (!hasModule && typeof(define) === "function" && define.amd){ //AMD 5795 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").pop(), [], function() { return cl; }); 5796 } else if (ns === moduleName && hasModule){ //node 5797 module.exports = cl; 5798 } 5799 } 5800 for (i = 0; i < this.sc.length; i++) { 5801 this.sc[i].check(); 5802 } 5803 } 5804 }; 5805 this.check(true); 5806 }, 5807 5808 //used to create Definition instances (which basically registers a class that has dependencies). 5809 _gsDefine = window._gsDefine = function(ns, dependencies, func, global) { 5810 return new Definition(ns, dependencies, func, global); 5811 }, 5812 5813 //a quick way to create a class that doesn't have any dependencies. Returns the class, but first registers it in the GreenSock namespace so that other classes can grab it (other classes might be dependent on the class). 5814 _class = gs._class = function(ns, func, global) { 5815 func = func || function() {}; 5816 _gsDefine(ns, [], function(){ return func; }, global); 5817 return func; 5818 }; 5819 5820 _gsDefine.globals = _globals; 5821 5822 5823 5824/* 5825 * ---------------------------------------------------------------- 5826 * Ease 5827 * ---------------------------------------------------------------- 5828 */ 5829 var _baseParams = [0, 0, 1, 1], 5830 _blankArray = [], 5831 Ease = _class("easing.Ease", function(func, extraParams, type, power) { 5832 this._func = func; 5833 this._type = type || 0; 5834 this._power = power || 0; 5835 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams; 5836 }, true), 5837 _easeMap = Ease.map = {}, 5838 _easeReg = Ease.register = function(ease, names, types, create) { 5839 var na = names.split(","), 5840 i = na.length, 5841 ta = (types || "easeIn,easeOut,easeInOut").split(","), 5842 e, name, j, type; 5843 while (--i > -1) { 5844 name = na[i]; 5845 e = create ? _class("easing."+name, null, true) : gs.easing[name] || {}; 5846 j = ta.length; 5847 while (--j > -1) { 5848 type = ta[j]; 5849 _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease(); 5850 } 5851 } 5852 }; 5853 5854 p = Ease.prototype; 5855 p._calcEnd = false;
5856 p.getRatio = function(p) { 5857 if (this._func) { 5858 this._params[0] = p; 5859 return this._func.apply(null, this._params); 5860 } 5861 var t = this._type, 5862 pw = this._power, 5863 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2; 5864 if (pw === 1) { 5865 r *= r; 5866 } else if (pw === 2) { 5867 r *= r * r; 5868 } else if (pw === 3) { 5869 r *= r * r * r; 5870 } else if (pw === 4) { 5871 r *= r * r * r * r; 5872 } 5873 return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2); 5874 }; 5875 5876 //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut) 5877 a = ["Linear","Quad","Cubic","Quart","Quint,Strong"]; 5878 i = a.length; 5879 while (--i > -1) { 5880 p = a[i]+",Power"+i; 5881 _easeReg(new Ease(null,null,1,i), p, "easeOut", true); 5882 _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : "")); 5883 _easeReg(new Ease(null,null,3,i), p, "easeInOut"); 5884 } 5885 _easeMap.linear = gs.easing.Linear.easeIn; 5886 _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks 5887 5888 5889/* 5890 * ---------------------------------------------------------------- 5891 * EventDispatcher 5892 * ---------------------------------------------------------------- 5893 */ 5894 var EventDispatcher = _class("events.EventDispatcher", function(target) { 5895 this._listeners = {}; 5896 this._eventTarget = target || this; 5897 }); 5898 p = EventDispatcher.prototype; 5899 5900 p.addEventListener = function(type, callback, scope, useParam, priority) { 5901 priority = priority || 0; 5902 var list = this._listeners[type], 5903 index = 0, 5904 listener, i; 5905 if (list == null) { 5906 this._listeners[type] = list = []; 5907 } 5908 i = list.length; 5909 while (--i > -1) { 5910 listener = list[i]; 5911 if (listener.c === callback && listener.s === scope) { 5912 list.splice(i, 1); 5913 } else if (index === 0 && listener.pr < priority) { 5914 index = i + 1; 5915 } 5916 } 5917 list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority}); 5918 if (this === _ticker && !_tickerActive) { 5919 _ticker.wake(); 5920 } 5921 }; 5922 5923 p.removeEventListener = function(type, callback) { 5924 var list = this._listeners[type], i; 5925 if (list) { 5926 i = list.length; 5927 while (--i > -1) { 5928 if (list[i].c === callback) { 5929 list.splice(i, 1); 5930 return; 5931 } 5932 } 5933 } 5934 }; 5935 5936 p.dispatchEvent = function(type) { 5937 var list = this._listeners[type], 5938 i, t, listener; 5939 if (list) { 5940 i = list.length; 5941 t = this._eventTarget; 5942 while (--i > -1) { 5943 listener = list[i]; 5944 if (listener) { 5945 if (listener.up) { 5946 listener.c.call(listener.s || t, {type:type, target:t}); 5947 } else { 5948 listener.c.call(listener.s || t); 5949 } 5950 } 5951 } 5952 } 5953 }; 5954 5955 5956/* 5957 * ---------------------------------------------------------------- 5958 * Ticker 5959 * ---------------------------------------------------------------- 5960 */ 5961 var _reqAnimFrame = window.requestAnimationFrame, 5962 _cancelAnimFrame = window.cancelAnimationFrame, 5963 _getTime = Date.now || function() {return new Date().getTime();}, 5964 _lastUpdate = _getTime(); 5965 5966 //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill. 5967 a = ["ms","moz","webkit","o"]; 5968 i = a.length; 5969 while (--i > -1 && !_reqAnimFrame) { 5970 _reqAnimFrame = window[a[i] + "RequestAnimationFrame"]; 5971 _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"]; 5972 } 5973 5974 _class("Ticker", function(fps, useRAF) { 5975 var _self = this, 5976 _startTime = _getTime(), 5977 _useRAF = (useRAF !== false && _reqAnimFrame), 5978 _lagThreshold = 500, 5979 _adjustedLag = 33, 5980 _tickWord = "tick", //helps reduce gc burden 5981 _fps, _req, _id, _gap, _nextTime, 5982 _tick = function(manual) { 5983 var elapsed = _getTime() - _lastUpdate, 5984 overlap, dispatch; 5985 if (elapsed > _lagThreshold) { 5986 _startTime += elapsed - _adjustedLag; 5987 } 5988 _lastUpdate += elapsed; 5989 _self.time = (_lastUpdate - _startTime) / 1000; 5990 overlap = _self.time - _nextTime; 5991 if (!_fps || overlap > 0 || manual === true) { 5992 _self.frame++; 5993 _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap); 5994 dispatch = true; 5995 } 5996 if (manual !== true) { //make sure the request is made before we dispatch the "tick" event so that timing is maintained. Otherwise, if processing the "tick" requires a bunch of time (like 15ms) and we're using a setTimeout() that's based on 16.7ms, it'd technically take 31.7ms between frames otherwise. 5997 _id = _req(_tick); 5998 }
5999 if (dispatch) { 6000 _self.dispatchEvent(_tickWord); 6001 } 6002 }; 6003 6004 EventDispatcher.call(_self); 6005 _self.time = _self.frame = 0; 6006 _self.tick = function() { 6007 _tick(true); 6008 }; 6009 6010 _self.lagSmoothing = function(threshold, adjustedLag) { 6011 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited 6012 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0); 6013 }; 6014 6015 _self.sleep = function() { 6016 if (_id == null) { 6017 return; 6018 } 6019 if (!_useRAF || !_cancelAnimFrame) { 6020 clearTimeout(_id); 6021 } else { 6022 _cancelAnimFrame(_id); 6023 } 6024 _req = _emptyFunc; 6025 _id = null; 6026 if (_self === _ticker) { 6027 _tickerActive = false; 6028 } 6029 }; 6030 6031 _self.wake = function() { 6032 if (_id !== null) { 6033 _self.sleep(); 6034 } else if (_self.frame > 10) { //don't trigger lagSmoothing if we're just waking up, and make sure that at least 10 frames have elapsed because of the iOS bug that we work around below with the 1.5-second setTimout(). 6035 _lastUpdate = _getTime() - _lagThreshold + 5; 6036 } 6037 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame; 6038 if (_self === _ticker) { 6039 _tickerActive = true; 6040 } 6041 _tick(2); 6042 }; 6043 6044 _self.fps = function(value) { 6045 if (!arguments.length) { 6046 return _fps; 6047 } 6048 _fps = value; 6049 _gap = 1 / (_fps || 60); 6050 _nextTime = this.time + _gap; 6051 _self.wake(); 6052 }; 6053 6054 _self.useRAF = function(value) { 6055 if (!arguments.length) { 6056 return _useRAF; 6057 } 6058 _self.sleep(); 6059 _useRAF = value; 6060 _self.fps(_fps); 6061 }; 6062 _self.fps(fps); 6063 6064 //a bug in iOS 6 Safari occasionally prevents the requestAnimationFrame from working initially, so we use a 1.5-second timeout that automatically falls back to setTimeout() if it senses this condition. 6065 setTimeout(function() { 6066 if (_useRAF && _self.frame < 5) { 6067 _self.useRAF(false); 6068 } 6069 }, 1500); 6070 }); 6071 6072 p = gs.Ticker.prototype = new gs.events.EventDispatcher(); 6073 p.constructor = gs.Ticker; 6074 6075 6076/* 6077 * ---------------------------------------------------------------- 6078 * Animation 6079 * ---------------------------------------------------------------- 6080 */ 6081 var Animation = _class("core.Animation", function(duration, vars) { 6082 this.vars = vars = vars || {}; 6083 this._duration = this._totalDuration = duration || 0; 6084 this._delay = Number(vars.delay) || 0; 6085 this._timeScale = 1; 6086 this._active = (vars.immediateRender === true); 6087 this.data = vars.data; 6088 this._reversed = (vars.reversed === true); 6089 6090 if (!_rootTimeline) { 6091 return; 6092 } 6093 if (!_tickerActive) { //some browsers (like iOS 6 Safari) shut down JavaScript execution when the tab is disabled and they [occasionally] neglect to start up requestAnimationFrame again when returning - this code ensures that the engine starts up again properly. 6094 _ticker.wake(); 6095 } 6096 6097 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline; 6098 tl.add(this, tl._time); 6099 6100 if (this.vars.paused) { 6101 this.paused(true); 6102 } 6103 }); 6104 6105 _ticker = Animation.ticker = new gs.Ticker(); 6106 p = Animation.prototype; 6107 p._dirty = p._gc = p._initted = p._paused = false; 6108 p._totalTime = p._time = 0; 6109 p._rawPrevTime = -1; 6110 p._next = p._last = p._onUpdate = p._timeline = p.timeline = null; 6111 p._paused = false; 6112 6113 6114 //some browsers (like iOS) occasionally drop the requestAnimationFrame event when the user switches to a different tab and then comes back again, so we use a 2-second setTimeout() to sense if/when that condition occurs and then wake() the ticker. 6115 var _checkTimeout = function() { 6116 if (_tickerActive && _getTime() - _lastUpdate > 2000) { 6117 _ticker.wake(); 6118 } 6119 setTimeout(_checkTimeout, 2000); 6120 }; 6121 _checkTimeout(); 6122 6123 6124 p.play = function(from, suppressEvents) { 6125 if (from != null) { 6126 this.seek(from, suppressEvents); 6127 } 6128 return this.reversed(false).paused(false); 6129 }; 6130 6131 p.pause = function(atTime, suppressEvents) { 6132 if (atTime != null) { 6133 this.seek(atTime, suppressEvents); 6134 } 6135 return this.paused(true); 6136 }; 6137 6138 p.resume = function(from, suppressEvents) { 6139 if (from != null) { 6140 this.seek(from, suppressEvents); 6141 } 6142 return this.paused(false); 6143 }; 6144 6145 p.seek = function(time, suppressEvents) { 6146 return this.totalTime(Number(time), suppressEvents !== false); 6147 }; 6148 6149 p.restart = function(includeDelay, suppressEvents) { 6150 return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true); 6151 }; 6152 6153 p.reverse = function(from, suppressEvents) { 6154 if (from != null) { 6155 this.seek((from || this.totalDuration()), suppressEvents); 6156 } 6157 return this.reversed(true).paused(false); 6158 }; 6159 6160 p.render = function(time, suppressEvents, force) { 6161 //stub - we override this method in subclasses. 6162 }; 6163 6164 p.invalidate = function() { 6165 this._time = this._totalTime = 0; 6166 this._initted = this._gc = false;
6167 this._rawPrevTime = -1; 6168 if (this._gc || !this.timeline) { 6169 this._enabled(true); 6170 } 6171 return this; 6172 }; 6173 6174 p.isActive = function() { 6175 var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active. 6176 startTime = this._startTime, 6177 rawTime; 6178 return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale)); 6179 }; 6180 6181 p._enabled = function (enabled, ignoreTimeline) { 6182 if (!_tickerActive) { 6183 _ticker.wake(); 6184 } 6185 this._gc = !enabled; 6186 this._active = this.isActive(); 6187 if (ignoreTimeline !== true) { 6188 if (enabled && !this.timeline) { 6189 this._timeline.add(this, this._startTime - this._delay); 6190 } else if (!enabled && this.timeline) { 6191 this._timeline._remove(this, true); 6192 } 6193 } 6194 return false; 6195 }; 6196 6197 6198 p._kill = function(vars, target) { 6199 return this._enabled(false, false); 6200 }; 6201 6202 p.kill = function(vars, target) { 6203 this._kill(vars, target); 6204 return this; 6205 }; 6206 6207 p._uncache = function(includeSelf) { 6208 var tween = includeSelf ? this : this.timeline; 6209 while (tween) { 6210 tween._dirty = true; 6211 tween = tween.timeline; 6212 } 6213 return this; 6214 }; 6215 6216 p._swapSelfInParams = function(params) { 6217 var i = params.length, 6218 copy = params.concat(); 6219 while (--i > -1) { 6220 if (params[i] === "{self}") { 6221 copy[i] = this; 6222 } 6223 } 6224 return copy; 6225 }; 6226 6227 p._callback = function(type) { 6228 var v = this.vars; 6229 v[type].apply(v[type + "Scope"] || v.callbackScope || this, v[type + "Params"] || _blankArray); 6230 }; 6231 6232//----Animation getters/setters -------------------------------------------------------- 6233 6234 p.eventCallback = function(type, callback, params, scope) { 6235 if ((type || "").substr(0,2) === "on") { 6236 var v = this.vars; 6237 if (arguments.length === 1) { 6238 return v[type]; 6239 } 6240 if (callback == null) { 6241 delete v[type]; 6242 } else { 6243 v[type] = callback; 6244 v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params; 6245 v[type + "Scope"] = scope; 6246 } 6247 if (type === "onUpdate") { 6248 this._onUpdate = callback; 6249 } 6250 } 6251 return this; 6252 }; 6253 6254 p.delay = function(value) { 6255 if (!arguments.length) { 6256 return this._delay; 6257 } 6258 if (this._timeline.smoothChildTiming) { 6259 this.startTime( this._startTime + value - this._delay ); 6260 } 6261 this._delay = value; 6262 return this; 6263 }; 6264 6265 p.duration = function(value) { 6266 if (!arguments.length) { 6267 this._dirty = false; 6268 return this._duration; 6269 } 6270 this._duration = this._totalDuration = value; 6271 this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration. 6272 if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) { 6273 this.totalTime(this._totalTime * (value / this._duration), true); 6274 } 6275 return this; 6276 }; 6277 6278 p.totalDuration = function(value) { 6279 this._dirty = false; 6280 return (!arguments.length) ? this._totalDuration : this.duration(value); 6281 }; 6282 6283 p.time = function(value, suppressEvents) { 6284 if (!arguments.length) { 6285 return this._time; 6286 } 6287 if (this._dirty) { 6288 this.totalDuration(); 6289 } 6290 return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents); 6291 }; 6292 6293 p.totalTime = function(time, suppressEvents, uncapped) { 6294 if (!_tickerActive) { 6295 _ticker.wake(); 6296 } 6297 if (!arguments.length) { 6298 return this._totalTime; 6299 } 6300 if (this._timeline) { 6301 if (time < 0 && !uncapped) { 6302 time += this.totalDuration(); 6303 } 6304 if (this._timeline.smoothChildTiming) { 6305 if (this._dirty) { 6306 this.totalDuration(); 6307 } 6308 var totalDuration = this._totalDuration, 6309 tl = this._timeline; 6310 if (time > totalDuration && !uncapped) { 6311 time = totalDuration; 6312 } 6313 this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale); 6314 if (!tl._dirty) { //for performance improvement. If the parent's cache is already dirty, it already took care of marking the ancestors as dirty too, so skip the function call here. 6315 this._uncache(false); 6316 } 6317 //in case any of the ancestor timelines had completed but should now be enabled, we should reset the
6317ir totalTime() which will also ensure that they're lined up properly and enabled. Skip for animations that are on the root (wasteful). Example: a TimelineLite.exportRoot() is performed when there's a paused tween on the root, the export will not complete until that tween is unpaused, but imagine a child gets restarted later, after all [unpaused] tweens have completed. The startTime of that child would get pushed out, but one of the ancestors may have completed. 6318 if (tl._timeline) { 6319 while (tl._timeline) { 6320 if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) { 6321 tl.totalTime(tl._totalTime, true); 6322 } 6323 tl = tl._timeline; 6324 } 6325 } 6326 } 6327 if (this._gc) { 6328 this._enabled(true, false); 6329 } 6330 if (this._totalTime !== time || this._duration === 0) { 6331 if (_lazyTweens.length) { 6332 _lazyRender(); 6333 } 6334 this.render(time, suppressEvents, false); 6335 if (_lazyTweens.length) { //in case rendering caused any tweens to lazy-init, we should render them because typically when someone calls seek() or time() or progress(), they expect an immediate render. 6336 _lazyRender(); 6337 } 6338 } 6339 } 6340 return this; 6341 }; 6342 6343 p.progress = p.totalProgress = function(value, suppressEvents) { 6344 var duration = this.duration(); 6345 return (!arguments.length) ? (duration ? this._time / duration : this.ratio) : this.totalTime(duration * value, suppressEvents); 6346 }; 6347 6348 p.startTime = function(value) { 6349 if (!arguments.length) { 6350 return this._startTime; 6351 } 6352 if (value !== this._startTime) { 6353 this._startTime = value; 6354 if (this.timeline) if (this.timeline._sortChildren) { 6355 this.timeline.add(this, value - this._delay); //ensures that any necessary re-sequencing of Animations in the timeline occurs to make sure the rendering order is correct. 6356 } 6357 } 6358 return this; 6359 }; 6360 6361 p.endTime = function(includeRepeats) { 6362 return this._startTime + ((includeRepeats != false) ? this.totalDuration() : this.duration()) / this._timeScale; 6363 }; 6364 6365 p.timeScale = function(value) { 6366 if (!arguments.length) { 6367 return this._timeScale; 6368 } 6369 value = value || _tinyNum; //can't allow zero because it'll throw the math off 6370 if (this._timeline && this._timeline.smoothChildTiming) { 6371 var pauseTime = this._pauseTime, 6372 t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime(); 6373 this._startTime = t - ((t - this._startTime) * this._timeScale / value); 6374 } 6375 this._timeScale = value; 6376 return this._uncache(false); 6377 }; 6378 6379 p.reversed = function(value) { 6380 if (!arguments.length) { 6381 return this._reversed; 6382 } 6383 if (value != this._reversed) { 6384 this._reversed = value; 6385 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true); 6386 } 6387 return this; 6388 }; 6389 6390 p.paused = function(value) { 6391 if (!arguments.length) { 6392 return this._paused; 6393 } 6394 var tl = this._timeline, 6395 raw, elapsed; 6396 if (value != this._paused) if (tl) { 6397 if (!_tickerActive && !value) { 6398 _ticker.wake(); 6399 } 6400 raw = tl.rawTime(); 6401 elapsed = raw - this._pauseTime; 6402 if (!value && tl.smoothChildTiming) { 6403 this._startTime += elapsed; 6404 this._uncache(false); 6405 } 6406 this._pauseTime = value ? raw : null; 6407 this._paused = value; 6408 this._active = this.isActive(); 6409 if (!value && elapsed !== 0 && this._initted && this.duration()) { 6410 raw = tl.smoothChildTiming ? this._totalTime : (raw - this._startTime) / this._timeScale; 6411 this.render(raw, (raw === this._totalTime), true); //in case the target's properties changed via some other tween or manual update by the user, we should force a render. 6412 } 6413 } 6414 if (this._gc && !value) { 6415 this._enabled(true, false); 6416 } 6417 return this; 6418 }; 6419 6420 6421/* 6422 * ---------------------------------------------------------------- 6423 * SimpleTimeline 6424 * ---------------------------------------------------------------- 6425 */ 6426 var SimpleTimeline = _class("core.SimpleTimeline", function(vars) { 6427 Animation.call(this, 0, vars); 6428 this.autoRemoveChildren = this.smoothChildTiming = true; 6429 }); 6430 6431 p = SimpleTimeline.prototype = new Animation(); 6432 p.constructor = SimpleTimeline; 6433 p.kill()._gc = false;
6434 p._first = p._last = p._recent = null; 6435 p._sortChildren = false; 6436 6437 p.add = p.insert = function(child, position, align, stagger) { 6438 var prevTween, st; 6439 child._startTime = Number(position || 0) + child._delay; 6440 if (child._paused) if (this !== child._timeline) { //we only adjust the _pauseTime if it wasn't in this timeline already. Remember, sometimes a tween will be inserted again into the same timeline when its startTime is changed so that the tweens in the TimelineLite/Max are re-ordered properly in the linked list (so everything renders in the proper order). 6441 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale); 6442 } 6443 if (child.timeline) { 6444 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one. 6445 } 6446 child.timeline = child._timeline = this; 6447 if (child._gc) { 6448 child._enabled(true, true); 6449 } 6450 prevTween = this._last; 6451 if (this._sortChildren) { 6452 st = child._startTime; 6453 while (prevTween && prevTween._startTime > st) { 6454 prevTween = prevTween._prev; 6455 } 6456 } 6457 if (prevTween) { 6458 child._next = prevTween._next; 6459 prevTween._next = child; 6460 } else { 6461 child._next = this._first; 6462 this._first = child; 6463 } 6464 if (child._next) { 6465 child._next._prev = child; 6466 } else { 6467 this._last = child; 6468 } 6469 child._prev = prevTween; 6470 this._recent = child; 6471 if (this._timeline) { 6472 this._uncache(true); 6473 } 6474 return this; 6475 }; 6476 6477 p._remove = function(tween, skipDisable) { 6478 if (tween.timeline === this) { 6479 if (!skipDisable) { 6480 tween._enabled(false, true); 6481 } 6482 6483 if (tween._prev) { 6484 tween._prev._next = tween._next; 6485 } else if (this._first === tween) { 6486 this._first = tween._next; 6487 } 6488 if (tween._next) { 6489 tween._next._prev = tween._prev; 6490 } else if (this._last === tween) { 6491 this._last = tween._prev; 6492 } 6493 tween._next = tween._prev = tween.timeline = null; 6494 if (tween === this._recent) { 6495 this._recent = this._last; 6496 } 6497 6498 if (this._timeline) { 6499 this._uncache(true); 6500 } 6501 } 6502 return this; 6503 }; 6504 6505 p.render = function(time, suppressEvents, force) { 6506 var tween = this._first, 6507 next; 6508 this._totalTime = this._time = this._rawPrevTime = time; 6509 while (tween) { 6510 next = tween._next; //record it here because the value could change after rendering... 6511 if (tween._active || (time >= tween._startTime && !tween._paused)) { 6512 if (!tween._reversed) { 6513 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 6514 } else { 6515 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 6516 } 6517 } 6518 tween = next; 6519 } 6520 }; 6521 6522 p.rawTime = function() { 6523 if (!_tickerActive) { 6524 _ticker.wake(); 6525 } 6526 return this._totalTime; 6527 }; 6528 6529/* 6530 * ---------------------------------------------------------------- 6531 * TweenLite 6532 * ---------------------------------------------------------------- 6533 */ 6534 var TweenLite = _class("TweenLite", function(target, duration, vars) { 6535 Animation.call(this, duration, vars); 6536 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method) 6537 6538 if (target == null) { 6539 throw "Cannot tween a null target."; 6540 } 6541 6542 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target; 6543 6544 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))), 6545 overwrite = this.vars.overwrite, 6546 i, targ, targets; 6547 6548 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite]; 6549 6550 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") { 6551 this._targets = targets = _slice(target); //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll() 6552 this._propLookup = []; 6553 this._siblings = []; 6554 for (i = 0; i < targets.length; i++) { 6555 targ = targets[i]; 6556 if (!targ) { 6557 targets.splice(i--, 1); 6558 continue; 6559 } else if (typeof(targ) === "string") { 6560 targ = targets[i--] = TweenLite.selector(targ);
6560 //in case it's an array of strings 6561 if (typeof(targ) === "string") { 6562 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case) 6563 } 6564 continue; 6565 } else if (targ.length && targ !== window && targ[0] && (targ[0] === window || (targ[0].nodeType && targ[0].style && !targ.nodeType))) { //in case the user is passing in an array of selector objects (like jQuery objects), we need to check one more level and pull things out if necessary. Also note that <select> elements pass all the criteria regarding length and the first child having style, so we must also check to ensure the target isn't an HTML node itself. 6566 targets.splice(i--, 1); 6567 this._targets = targets = targets.concat(_slice(targ)); 6568 continue; 6569 } 6570 this._siblings[i] = _register(targ, this, false); 6571 if (overwrite === 1) if (this._siblings[i].length > 1) { 6572 _applyOverwrite(targ, this, null, 1, this._siblings[i]); 6573 } 6574 } 6575 6576 } else { 6577 this._propLookup = {}; 6578 this._siblings = _register(target, this, false); 6579 if (overwrite === 1) if (this._siblings.length > 1) { 6580 _applyOverwrite(target, this, null, 1, this._siblings); 6581 } 6582 } 6583 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) { 6584 this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render) 6585 this.render(-this._delay); 6586 } 6587 }, true), 6588 _isSelector = function(v) { 6589 return (v && v.length && v !== window && v[0] && (v[0] === window || (v[0].nodeType && v[0].style && !v.nodeType))); //we cannot check "nodeType" if the target is window from within an iframe, otherwise it will trigger a security error in some browsers like Firefox. 6590 }, 6591 _autoCSS = function(vars, target) { 6592 var css = {}, 6593 p; 6594 for (p in vars) { 6595 if (!_reservedProps[p] && (!(p in target) || p === "transform" || p === "x" || p === "y" || p === "width" || p === "height" || p === "className" || p === "border") && (!_plugins[p] || (_plugins[p] && _plugins[p]._autoCSS))) { //note: <img> elements contain read-only "x" and "y" properties. We should also prioritize editing css width/height rather than the element's properties. 6596 css[p] = vars[p]; 6597 delete vars[p]; 6598 } 6599 } 6600 vars.css = css; 6601 }; 6602 6603 p = TweenLite.prototype = new Animation(); 6604 p.constructor = TweenLite; 6605 p.kill()._gc = false; 6606 6607//----TweenLite defaults, overwrite management, and root updates ---------------------------------------------------- 6608 6609 p.ratio = 0; 6610 p._firstPT = p._targets = p._overwrittenProps = p._startAt = null; 6611 p._notifyPluginsOfEnabled = p._lazy = false; 6612 6613 TweenLite.version = "1.18.0"; 6614 TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1); 6615 TweenLite.defaultOverwrite = "auto"; 6616 TweenLite.ticker = _ticker; 6617 TweenLite.autoSleep = 120; 6618 TweenLite.lagSmoothing = function(threshold, adjustedLag) { 6619 _ticker.lagSmoothing(threshold, adjustedLag); 6620 }; 6621 6622 TweenLite.selector = window.$ || window.jQuery || function(e) { 6623 var selector = window.$ || window.jQuery; 6624 if (selector) { 6625 TweenLite.selector = selector; 6626 return selector(e); 6627 } 6628 return (typeof(document) === "undefined") ? e : (document.querySelectorAll ? document.querySelectorAll(e) : document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e)); 6629 }; 6630 6631 var _lazyTweens = [], 6632 _lazyLookup = {}, 6633 _numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig, 6634 //_nonNumbersExp = /(?:([\-+](?!(\d|=)))|[^\d\-+=e]|(e(?![\-+][\d])))+/ig, 6635 _setRatio = function(v) { 6636 var pt = this._firstPT, 6637 min = 0.000001, 6638 val; 6639 while (pt) { 6640 val = !pt.blob ? pt.c * v + pt.s : v ? this.join("") : this.start; 6641 if (pt.r) { 6642 val = Math.round(val); 6643 } else if (val < min) if (val > -min) { //prevents issues with converting very small numbers to strings in the browser 6644 val = 0; 6645 } 6646 if (!pt.f) { 6647 pt.t[pt.p] = val; 6648 } else if (pt.fp) { 6649 pt.t[pt.p](pt.fp, val); 6650 } else { 6651 pt.t[pt.p](val); 6652 } 6653 pt = pt._next; 6654 } 6655 }, 6656 //compares two strings (start/end), finds the numbers that are different and spits back an array representing the whole value but with the changing values isolated as elements. For example, "rgb(0,0,0)" and "rgb(100,50,0)" would become ["rgb(", 0, ",", 50, ",0)"]. Notice it merges the parts that are identical (performance optimization). The array also has a linked list of PropTweens attached starting with _firstPT that contain the tweening data (t, p, s, c, f, etc.). It also stores the starting value as a "start" property so that we can revert to it if/when necessary, like when a tween rewinds fully. If the quantity of numbers differs between the start and end, it will always prioritize the end value(s). The pt parameter is optional - it's for a PropTween that will be appended to the end of the linked list and is typically for actually setting the value after all of the elements have been updated (with array.join("")). 6657 _blobDif = function(start, end, filter, pt) { 6658 var a = [start, end], 6659 charIndex = 0, 6660 s = "", 6661 color = 0, 6662 startNums, endNums, num, i, l, nonNumbers, currentNum; 6663 a.start = start; 6664 if (filter) { 6665 filter(a); //pass an array with the starting and ending values and let the filter do whatever it needs to the values. 6666 start = a[0]; 6667 end = a[1]; 6668 } 6669 a.length = 0; 6670 startNums = start.match(_numbersExp) || []; 6671 endNums = end.match(_numbersExp) || []; 6672 if (pt) { 6673 pt._next = null; 6674 pt.blob = 1; 6675 a._firstPT = pt; //apply last in the linked list (which means inserting it first) 6676 } 6677 l = endNums.length; 6678 for (i = 0; i < l; i++) { 6679 currentNum = endNums[i]; 6680 nonNumbers = end.substr(charIndex, end.indexOf(currentNum, charIndex)-charIndex); 6681 s += (nonNumbers || !i) ? nonNumbers : ",";
6681 //note: SVG spec allows omission of comma/space when a negative sign is wedged between two numbers, like 2.5-5.3 instead of 2.5,-5.3 but when tweening, the negative value may switch to positive, so we insert the comma just in case. 6682 charIndex += nonNumbers.length; 6683 if (color) { //sense rgba() values and round them. 6684 color = (color + 1) % 5; 6685 } else if (nonNumbers.substr(-5) === "rgba(") { 6686 color = 1; 6687 } 6688 if (currentNum === startNums[i] || startNums.length <= i) { 6689 s += currentNum; 6690 } else { 6691 if (s) { 6692 a.push(s); 6693 s = ""; 6694 } 6695 num = parseFloat(startNums[i]); 6696 a.push(num); 6697 a._firstPT = {_next: a._firstPT, t:a, p: a.length-1, s:num, c:((currentNum.charAt(1) === "=") ? parseInt(currentNum.charAt(0) + "1", 10) * parseFloat(currentNum.substr(2)) : (parseFloat(currentNum) - num)) || 0, f:0, r:(color && color < 4)}; 6698 //note: we don't set _prev because we'll never need to remove individual PropTweens from this list. 6699 } 6700 charIndex += currentNum.length; 6701 } 6702 s += end.substr(charIndex); 6703 if (s) { 6704 a.push(s); 6705 } 6706 a.setRatio = _setRatio; 6707 return a; 6708 }, 6709 //note: "funcParam" is only necessary for function-based getters/setters that require an extra parameter like getAttribute("width") and setAttribute("width", value). In this example, funcParam would be "width". Used by AttrPlugin for example. 6710 _addPropTween = function(target, prop, start, end, overwriteProp, round, funcParam, stringFilter) { 6711 var s = (start === "get") ? target[prop] : start, 6712 type = typeof(target[prop]), 6713 isRelative = (typeof(end) === "string" && end.charAt(1) === "="), 6714 pt = {t:target, p:prop, s:s, f:(type === "function"), pg:0, n:overwriteProp || prop, r:round, pr:0, c:isRelative ? parseInt(end.charAt(0) + "1", 10) * parseFloat(end.substr(2)) : (parseFloat(end) - s) || 0}, 6715 blob, getterName; 6716 if (type !== "number") { 6717 if (type === "function" && start === "get") { 6718 getterName = ((prop.indexOf("set") || typeof(target["get" + prop.substr(3)]) !== "function") ? prop : "get" + prop.substr(3)); 6719 pt.s = s = funcParam ? target[getterName](funcParam) : target[getterName](); 6720 } 6721 if (typeof(s) === "string" && (funcParam || isNaN(s))) { 6722 //a blob (string that has multiple numbers in it) 6723 pt.fp = funcParam; 6724 blob = _blobDif(s, end, stringFilter || TweenLite.defaultStringFilter, pt); 6725 pt = {t:blob, p:"setRatio", s:0, c:1, f:2, pg:0, n:overwriteProp || prop, pr:0}; //"2" indicates it's a Blob property tween. Needed for RoundPropsPlugin for example. 6726 } else if (!isRelative) { 6727 pt.c = (parseFloat(end) - parseFloat(s)) || 0; 6728 } 6729 } 6730 if (pt.c) { //only add it to the linked list if there's a change. 6731 if ((pt._next = this._firstPT)) { 6732 pt._next._prev = pt; 6733 } 6734 this._firstPT = pt; 6735 return pt; 6736 } 6737 }, 6738 _internals = TweenLite._internals = {isArray:_isArray, isSelector:_isSelector, lazyTweens:_lazyTweens, blobDif:_blobDif}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object. 6739 _plugins = TweenLite._plugins = {}, 6740 _tweenLookup = _internals.tweenLookup = {}, 6741 _tweenLookupNum = 0, 6742 _reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUpdate:1, onUpdateParams:1, onUpdateScope:1, onStart:1, onStartParams:1, onStartScope:1, onReverseComplete:1, onReverseCompleteParams:1, onReverseCompleteScope:1, onRepeat:1, onRepeatParams:1, onRepeatScope:1, easeParams:1, yoyo:1, immediateRender:1, repeat:1, repeatDelay:1, data:1, paused:1, reversed:1, autoCSS:1, lazy:1, onOverwrite:1, callbackScope:1, stringFilter:1}, 6743 _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0}, 6744 _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(), 6745 _rootTimeline = Animation._rootTimeline = new SimpleTimeline(), 6746 _nextGCFrame = 30, 6747 _lazyRender = _internals.lazyRender = function() { 6748 var i = _lazyTweens.length, 6749 tween; 6750 _lazyLookup = {}; 6751 while (--i > -1) { 6752 tween = _lazyTweens[i]; 6753 if (tween && tween._lazy !== false) { 6754 tween.render(tween._lazy[0], tween._lazy[1], true); 6755 tween._lazy = false;
6756 } 6757 } 6758 _lazyTweens.length = 0; 6759 }; 6760 6761 _rootTimeline._startTime = _ticker.time; 6762 _rootFramesTimeline._startTime = _ticker.frame; 6763 _rootTimeline._active = _rootFramesTimeline._active = true; 6764 setTimeout(_lazyRender, 1); //on some mobile devices, there isn't a "tick" before code runs which means any lazy renders wouldn't run before the next official "tick". 6765 6766 Animation._updateRoot = TweenLite.render = function() { 6767 var i, a, p; 6768 if (_lazyTweens.length) { //if code is run outside of the requestAnimationFrame loop, there may be tweens queued AFTER the engine refreshed, so we need to ensure any pending renders occur before we refresh again. 6769 _lazyRender(); 6770 } 6771 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false); 6772 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false); 6773 if (_lazyTweens.length) { 6774 _lazyRender(); 6775 } 6776 if (_ticker.frame >= _nextGCFrame) { //dump garbage every 120 frames or whatever the user sets TweenLite.autoSleep to 6777 _nextGCFrame = _ticker.frame + (parseInt(TweenLite.autoSleep, 10) || 120); 6778 for (p in _tweenLookup) { 6779 a = _tweenLookup[p].tweens; 6780 i = a.length; 6781 while (--i > -1) { 6782 if (a[i]._gc) { 6783 a.splice(i, 1); 6784 } 6785 } 6786 if (a.length === 0) { 6787 delete _tweenLookup[p]; 6788 } 6789 } 6790 //if there are no more tweens in the root timelines, or if they're all paused, make the _timer sleep to reduce load on the CPU slightly 6791 p = _rootTimeline._first; 6792 if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) { 6793 while (p && p._paused) { 6794 p = p._next; 6795 } 6796 if (!p) { 6797 _ticker.sleep(); 6798 } 6799 } 6800 } 6801 }; 6802 6803 _ticker.addEventListener("tick", Animation._updateRoot); 6804 6805 var _register = function(target, tween, scrub) { 6806 var id = target._gsTweenID, a, i; 6807 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) { 6808 _tweenLookup[id] = {target:target, tweens:[]}; 6809 } 6810 if (tween) { 6811 a = _tweenLookup[id].tweens; 6812 a[(i = a.length)] = tween; 6813 if (scrub) { 6814 while (--i > -1) { 6815 if (a[i] === tween) { 6816 a.splice(i, 1); 6817 } 6818 } 6819 } 6820 } 6821 return _tweenLookup[id].tweens; 6822 }, 6823 _onOverwrite = function(overwrittenTween, overwritingTween, target, killedProps) { 6824 var func = overwrittenTween.vars.onOverwrite, r1, r2; 6825 if (func) { 6826 r1 = func(overwrittenTween, overwritingTween, target, killedProps); 6827 } 6828 func = TweenLite.onOverwrite; 6829 if (func) { 6830 r2 = func(overwrittenTween, overwritingTween, target, killedProps); 6831 } 6832 return (r1 !== false && r2 !== false); 6833 }, 6834 _applyOverwrite = function(target, tween, props, mode, siblings) { 6835 var i, changed, curTween, l; 6836 if (mode === 1 || mode >= 4) { 6837 l = siblings.length; 6838 for (i = 0; i < l; i++) { 6839 if ((curTween = siblings[i]) !== tween) { 6840 if (!curTween._gc) { 6841 if (curTween._kill(null, target, tween)) { 6842 changed = true; 6843 } 6844 } 6845 } else if (mode === 5) { 6846 break; 6847 } 6848 } 6849 return changed; 6850 } 6851 //NOTE: Add 0.0000000001 to overcome floating point errors that can cause the startTime to be VERY slightly off (when a tween's time() is set for example) 6852 var startTime = tween._startTime + _tinyNum, 6853 overlaps = [], 6854 oCount = 0, 6855 zeroDur = (tween._duration === 0), 6856 globalStart; 6857 i = siblings.length; 6858 while (--i > -1) { 6859 if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) { 6860 //ignore 6861 } else if (curTween._timeline !== tween._timeline) { 6862 globalStart = globalStart || _checkOverlap(tween, 0, zeroDur); 6863 if (_checkOverlap(curTween, globalStart, zeroDur) === 0) { 6864 overlaps[oCount++] = curTween; 6865 } 6866 } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) { 6867 overlaps[oCount++] = curTween; 6868 } 6869 } 6870 6871 i = oCount; 6872 while (--i > -1) { 6873 curTween = overlaps[i]; 6874 if (mode === 2) if (curTween._kill(props, target, tween)) { 6875 changed = true; 6876 } 6877 if (mode !== 2 || (!curTween._firstPT && curTween._initted)) { 6878 if (mode !== 2 && !_onOverwrite(curTween, tween)) { 6879 continue; 6880 } 6881 if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween. 6882 changed = true; 6883 } 6884 } 6885 } 6886 return changed; 6887 }, 6888 _checkOverlap = function(tween, reference, zeroDur) { 6889 var tl = tween._timeline, 6890 ts = tl._timeScale, 6891 t = tween._startTime; 6892 while (tl._timeline) { 6893 t += tl._startTime; 6894 ts *= tl._timeScale; 6895 if (tl._paused) { 6896 return -100; 6897 } 6898 tl = tl._timeline; 6899 } 6900 t /= ts; 6901 return (t > reference) ? t - reference : ((zeroDur && t === reference) || (!tween._initted && t - reference < 2 * _tinyNum)) ? _tinyNum : ((t += tween.totalDuration() / tween._timeScale / ts) > reference + _tinyNum) ? 0 : t - reference - _tinyNum; 6902 }; 6903 6904 6905//---- TweenLite instance methods ----------------------------------------------------------------------------- 6906 6907 p._init = function() { 6908 var v = this.vars, 6909 op = this._overwrittenProps, 6910 dur = this._duration, 6911 immediate = !!v.immediateRender, 6912 ease = v.ease, 6913 i, initPlugins, pt, p, startVars; 6914 if (v.startAt) { 6915 if (this._startAt) { 6916 this._startAt.render(-1, true); //if we've run a startAt previously (when the tween instantiated), we should revert it so that the values re-instantiate correctly particularly for relative tweens. Without this, a TweenLite.fromTo(obj, 1, {x:"+=100"}, {x:"-=100"}), for example, would actually jump to +=200 because the startAt would run twice, doubling the relative change. 6917 this._startAt.kill(); 6918 } 6919 startVars = {}; 6920 for (p in v.startAt) { //copy the properties/values into a new object to avoid collisions, like var to = {x:0}, from = {x:500}; timeline.fromTo(e, 1, from, to).fromTo(e, 1, to, from); 6921 startVars[p] = v.startAt[p]; 6922 } 6923 startVars.overwrite = false;
6924 startVars.immediateRender = true; 6925 startVars.lazy = (immediate && v.lazy !== false); 6926 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop). 6927 this._startAt = TweenLite.to(this.target, 0, startVars); 6928 if (immediate) { 6929 if (this._time > 0) { 6930 this._startAt = null; //tweens that render immediately (like most from() and fromTo() tweens) shouldn't revert when their parent timeline's playhead goes backward past the startTime because the initial render could have happened anytime and it shouldn't be directly correlated to this tween's startTime. Imagine setting up a complex animation where the beginning states of various objects are rendered immediately but the tween doesn't happen for quite some time - if we revert to the starting values as soon as the playhead goes backward past the tween's startTime, it will throw things off visually. Reversion should only happen in TimelineLite/Max instances where immediateRender was false (which is the default in the convenience methods like from()). 6931 } else if (dur !== 0) { 6932 return; //we skip initialization here so that overwriting doesn't occur until the tween actually begins. Otherwise, if you create several immediateRender:true tweens of the same target/properties to drop into a TimelineLite or TimelineMax, the last one created would overwrite the first ones because they didn't get placed into the timeline yet before the first render occurs and kicks in overwriting. 6933 } 6934 } 6935 } else if (v.runBackwards && dur !== 0) { 6936 //from() tweens must be handled uniquely: their beginning values must be rendered but we don't want overwriting to occur yet (when time is still 0). Wait until the tween actually begins before doing all the routines like overwriting. At that time, we should render at the END of the tween to ensure that things initialize correctly (remember, from() tweens go backwards) 6937 if (this._startAt) { 6938 this._startAt.render(-1, true); 6939 this._startAt.kill(); 6940 this._startAt = null; 6941 } else { 6942 if (this._time !== 0) { //in rare cases (like if a from() tween runs and then is invalidate()-ed), immediateRender could be true but the initial forced-render gets skipped, so there's no need to force the render in this context when the _time is greater than 0 6943 immediate = false; 6944 } 6945 pt = {}; 6946 for (p in v) { //copy props into a new object and skip any reserved props, otherwise onComplete or onUpdate or onStart could fire. We should, however, permit autoCSS to go through. 6947 if (!_reservedProps[p] || p === "autoCSS") { 6948 pt[p] = v[p]; 6949 } 6950 } 6951 pt.overwrite = 0; 6952 pt.data = "isFromStart"; //we tag the tween with as "isFromStart" so that if [inside a plugin] we need to only do something at the very END of a tween, we have a way of identifying this tween as merely the one that's setting the beginning values for a "from()" tween. For example, clearProps in CSSPlugin should only get applied at the very END of a tween and without this tag, from(...{height:100, clearProps:"height", delay:1}) would wipe the height at the beginning of the tween and after 1 second, it'd kick back in. 6953 pt.lazy = (immediate && v.lazy !== false); 6954 pt.immediateRender = immediate; //zero-duration tweens render immediately by default, but if we're not specifically instructed to render this tween immediately, we should skip this and merely _init() to record the starting values (rendering them immediately would push them to completion which is wasteful in that case - we'd have to render(-1) immediately after) 6955 this._startAt = TweenLite.to(this.target, 0, pt); 6956 if (!immediate) { 6957 this._startAt._init(); //ensures that the initial values are recorded 6958 this._startAt._enabled(false); //no need to have the tween render on the next cycle. Disable it because we'll always manually control the renders of the _startAt tween. 6959 if (this.vars.immediateRender) { 6960 this._startAt = null; 6961 } 6962 } else if (this._time === 0) { 6963 return; 6964 } 6965 } 6966 } 6967 this._ease = ease = (!ease) ? TweenLite.defaultEase : (ease instanceof Ease) ? ease : (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase; 6968 if (v.easeParams instanceof Array && ease.config) { 6969 this._ease = ease.config.apply(ease, v.easeParams); 6970 } 6971 this._easeType = this._ease._type; 6972 this._easePower = this._ease._power; 6973 this._firstPT = null; 6974 6975 if (this._targets) { 6976 i = this._targets.length; 6977 while (--i > -1) { 6978 if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) { 6979 initPlugins = true; 6980 } 6981 } 6982 } else { 6983 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op); 6984 } 6985 6986 if (initPlugins) { 6987 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite 6988 } 6989 if (op) if (!this._firstPT) if (typeof(this.target) !== "function") { //if all tweening properties have been overwritten, kill the tween. If the target is a function, it's probably a delayedCall so let it live. 6990 this._enabled(false, false); 6991 } 6992 if (v.runBackwards) { 6993 pt = this._firstPT; 6994 while (pt) { 6995 pt.s += pt.c; 6996 pt.c = -pt.c; 6997 pt = pt._next; 6998 } 6999 } 7000 this._onUpdate = v.onUpdate; 7001 this._initted = true; 7002 }; 7003 7004 p._initProps = function(target, propLookup, siblings, overwrittenProps) { 7005 var p, i, initPlugins, plugin, pt, v; 7006 if (target == null) { 7007 return false;
7008 } 7009 7010 if (_lazyLookup[target._gsTweenID]) { 7011 _lazyRender(); //if other tweens of the same target have recently initted but haven't rendered yet, we've got to force the render so that the starting values are correct (imagine populating a timeline with a bunch of sequential tweens and then jumping to the end) 7012 } 7013 7014 if (!this.vars.css) if (target.style) if (target !== window && target.nodeType) if (_plugins.css) if (this.vars.autoCSS !== false) { //it's so common to use TweenLite/Max to animate the css of DOM elements, we assume that if the target is a DOM element, that's what is intended (a convenience so that users don't have to wrap things in css:{}, although we still recommend it for a slight performance boost and better specificity). Note: we cannot check "nodeType" on the window inside an iframe. 7015 _autoCSS(this.vars, target); 7016 } 7017 for (p in this.vars) { 7018 v = this.vars[p]; 7019 if (_reservedProps[p]) { 7020 if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) { 7021 this.vars[p] = v = this._swapSelfInParams(v, this); 7022 } 7023 7024 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) { 7025 7026 //t - target [object] 7027 //p - property [string] 7028 //s - start [number] 7029 //c - change [number] 7030 //f - isFunction [boolean] 7031 //n - name [string] 7032 //pg - isPlugin [boolean] 7033 //pr - priority [number] 7034 this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:1, n:p, pg:1, pr:plugin._priority}; 7035 i = plugin._overwriteProps.length; 7036 while (--i > -1) { 7037 propLookup[plugin._overwriteProps[i]] = this._firstPT; 7038 } 7039 if (plugin._priority || plugin._onInitAllProps) { 7040 initPlugins = true; 7041 } 7042 if (plugin._onDisable || plugin._onEnable) { 7043 this._notifyPluginsOfEnabled = true; 7044 } 7045 if (pt._next) { 7046 pt._next._prev = pt; 7047 } 7048 7049 } else { 7050 propLookup[p] = _addPropTween.call(this, target, p, "get", v, p, 0, null, this.vars.stringFilter); 7051 } 7052 } 7053 7054 if (overwrittenProps) if (this._kill(overwrittenProps, target)) { //another tween may have tried to overwrite properties of this tween before init() was called (like if two tweens start at the same time, the one created second will run first) 7055 return this._initProps(target, propLookup, siblings, overwrittenProps); 7056 } 7057 if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) { 7058 this._kill(propLookup, target); 7059 return this._initProps(target, propLookup, siblings, overwrittenProps); 7060 } 7061 if (this._firstPT) if ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration)) { //zero duration tweens don't lazy render by default; everything else does. 7062 _lazyLookup[target._gsTweenID] = true; 7063 } 7064 return initPlugins; 7065 }; 7066 7067 p.render = function(time, suppressEvents, force) { 7068 var prevTime = this._time, 7069 duration = this._duration, 7070 prevRawPrevTime = this._rawPrevTime, 7071 isComplete, callback, pt, rawPrevTime; 7072 if (time >= duration) { 7073 this._totalTime = this._time = duration; 7074 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1; 7075 if (!this._reversed ) { 7076 isComplete = true; 7077 callback = "onComplete"; 7078 force = (force || this._timeline.autoRemoveChildren); //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline. 7079 } 7080 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered. 7081 if (this._startTime === this._timeline._duration) { //if a zero-duration tween is at the VERY end of a timeline and that timeline renders at its end, it will typically add a tiny bit of cushion to the render time to prevent roun
7081ding errors from getting in the way of tweens rendering their VERY end. If we then reverse() that timeline, the zero-duration tween will trigger its onReverseComplete even though technically the playhead didn't pass over it again. It's a very specific edge case we must accommodate. 7082 time = 0; 7083 } 7084 if (time === 0 || prevRawPrevTime < 0 || (prevRawPrevTime === _tinyNum && this.data !== "isPause")) if (prevRawPrevTime !== time) { //note: when this.data is "isPause", it's a callback added by addPause() on a timeline that we should not be triggered when LEAVING its exact start time. In other words, tl.addPause(1).play(1) shouldn't pause. 7085 force = true; 7086 if (prevRawPrevTime > _tinyNum) { 7087 callback = "onReverseComplete"; 7088 } 7089 } 7090 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 7091 } 7092 7093 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 7094 this._totalTime = this._time = 0; 7095 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0; 7096 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0)) { 7097 callback = "onReverseComplete"; 7098 isComplete = this._reversed; 7099 } 7100 if (time < 0) { 7101 this._active = false; 7102 if (duration === 0) if (this._initted || !this.vars.lazy || force) { //zero-duration tweens are tricky because we must discern the momentum/direction of time in order to determine whether the starting values should be rendered or the ending values. If the "playhead" of its timeline goes past the zero-duration tween in the forward direction or lands directly on it, the end values should be rendered, but if the timeline's "playhead" moves past it in the backward direction (from a postitive time to a negative time), the starting values must be rendered. 7103 if (prevRawPrevTime >= 0 && !(prevRawPrevTime === _tinyNum && this.data === "isPause")) { 7104 force = true; 7105 } 7106 this._rawPrevTime = rawPrevTime = (!suppressEvents || time || prevRawPrevTime === time) ? time : _tinyNum; //when the playhead arrives at EXACTLY time 0 (right on top) of a zero-duration tween, we need to discern if events are suppressed so that when the playhead moves again (next time), it'll trigger the callback. If events are NOT suppressed, obviously the callback would be triggered in this render. Basically, the callback should fire either when the playhead ARRIVES or LEAVES this exact spot, not both. Imagine doing a timeline.seek(0) and there's a callback that sits at 0. Since events are suppressed on that seek() by default, nothing will fire, but when the playhead moves off of that position, the callback should fire. This behavior is what people intuitively expect. We set the _rawPrevTime to be a precise tiny number to indicate this scenario rather than using another property/variable which would increase memory usage. This technique is less readable, but more efficient. 7107 } 7108 } 7109 if (!this._initted) { //if we render the very beginning (time == 0) of a fromTo(), we must force the render (normal tweens wouldn't need to render at a time of 0 when the prevTime was also 0). This is also mandatory to make sure overwriting kicks in immediately. 7110 force = true; 7111 } 7112 } else { 7113 this._totalTime = this._time = time; 7114 7115 if (this._easeType) { 7116 var r = time / duration, type = this._easeType, pow = this._easePower; 7117 if (type === 1 || (type === 3 && r >= 0.5)) { 7118 r = 1 - r; 7119 } 7120 if (type === 3) { 7121 r *= 2; 7122 } 7123 if (pow === 1) { 7124 r *= r; 7125 } else if (pow === 2) { 7126 r *= r * r; 7127 } else if (pow === 3) { 7128 r *= r * r * r; 7129 } else if (pow === 4) { 7130 r *= r * r * r * r; 7131 } 7132 7133 if (type === 1) { 7134 this.ratio = 1 - r; 7135 } else if (type === 2) { 7136 this.ratio = r; 7137 } else if (time / duration < 0.5) { 7138 this.ratio = r / 2; 7139 } else { 7140 this.ratio = 1 - (r / 2); 7141 } 7142 7143 } else { 7144 this.ratio = this._ease.getRatio(time / duration); 7145 } 7146 } 7147 7148 if (this._time === prevTime && !force) { 7149 return; 7150 } else if (!this._initted) { 7151 this._init(); 7152 if (!this._initted || this._gc) { //immediateRender tweens typically won't initialize until the playhead advances (_time is greater than 0) in order to ensure that over
7152writing occurs properly. Also, if all of the tweening properties have been overwritten (which would cause _gc to be true, as set in _init()), we shouldn't continue otherwise an onStart callback could be called for example. 7153 return; 7154 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) { 7155 this._time = this._totalTime = prevTime; 7156 this._rawPrevTime = prevRawPrevTime; 7157 _lazyTweens.push(this); 7158 this._lazy = [time, suppressEvents]; 7159 return; 7160 } 7161 //_ease is initially set to defaultEase, so now that init() has run, _ease is set properly and we need to recalculate the ratio. Overall this is faster than using conditional logic earlier in the method to avoid having to set ratio twice because we only init() once but renderTime() gets called VERY frequently. 7162 if (this._time && !isComplete) { 7163 this.ratio = this._ease.getRatio(this._time / duration); 7164 } else if (isComplete && this._ease._calcEnd) { 7165 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1); 7166 } 7167 } 7168 if (this._lazy !== false) { //in case a lazy render is pending, we should flush it because the new render is occurring now (imagine a lazy tween instantiating and then immediately the user calls tween.seek(tween.duration()), skipping to the end - the end render would be forced, and then if we didn't flush the lazy render, it'd fire AFTER the seek(), rendering it at the wrong time. 7169 this._lazy = false; 7170 } 7171 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) { 7172 this._active = true; //so that if the user renders a tween (as opposed to the timeline rendering it), the timeline is forced to re-render and align it with the proper time/frame on the next rendering cycle. Maybe the tween already finished but the user manually re-renders it as halfway done. 7173 } 7174 if (prevTime === 0) { 7175 if (this._startAt) { 7176 if (time >= 0) { 7177 this._startAt.render(time, suppressEvents, force); 7178 } else if (!callback) { 7179 callback = "_dummyGS"; //if no callback is defined, use a dummy value just so that the condition at the end evaluates as true because _startAt should render AFTER the normal render loop when the time is negative. We could handle this in a more intuitive way, of course, but the render loop is the MOST important thing to optimize, so this technique allows us to avoid adding extra conditional logic in a high-frequency area. 7180 } 7181 } 7182 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) { 7183 this._callback("onStart"); 7184 } 7185 } 7186 pt = this._firstPT; 7187 while (pt) { 7188 if (pt.f) { 7189 pt.t[pt.p](pt.c * this.ratio + pt.s); 7190 } else { 7191 pt.t[pt.p] = pt.c * this.ratio + pt.s; 7192 } 7193 pt = pt._next; 7194 } 7195 7196 if (this._onUpdate) { 7197 if (time < 0) if (this._startAt && time !== -0.0001) { //if the tween is positioned at the VERY beginning (_startTime 0) of its parent timeline, it's illegal for the playhead to go back further, so we should not render the recorded startAt values. 7198 this._startAt.render(time, suppressEvents, force); //note: for performance reasons, we tuck this conditional logic inside less traveled areas (most tweens don't have an onUpdate). We'd just have it at the end before the onComplete, but the values should be updated before any onUpdate is called, so we ALSO put it here and then if it's not called, we do so later near the onComplete. 7199 } 7200 if (!suppressEvents) if (this._time !== prevTime || isComplete) { 7201 this._callback("onUpdate"); 7202 } 7203 } 7204 if (callback) if (!this._gc || force) { //check _gc because there's a chance that kill() could be called in an onUpdate 7205 if (time < 0 && this._startAt && !this._onUpdate && time !== -0.0001) { //-0.0001 is a special value that we use when looping back to the beginning of a repeated TimelineMax, in which case we shouldn't render the _startAt values. 7206 this._startAt.render(time, suppressEvents, force); 7207 } 7208 if (isComplete) { 7209 if (this._timeline.autoRemoveChildren) { 7210 this._enabled(false, false); 7211 } 7212 this._active = false;
7213 } 7214 if (!suppressEvents && this.vars[callback]) { 7215 this._callback(callback); 7216 } 7217 if (duration === 0 && this._rawPrevTime === _tinyNum && rawPrevTime !== _tinyNum) { //the onComplete or onReverseComplete could trigger movement of the playhead and for zero-duration tweens (which must discern direction) that land directly back on their start time, we don't want to fire again on the next render. Think of several addPause()'s in a timeline that forces the playhead to a certain spot, but what if it's already paused and another tween is tweening the "time" of the timeline? Each time it moves [forward] past that spot, it would move back, and since suppressEvents is true, it'd reset _rawPrevTime to _tinyNum so that when it begins again, the callback would fire (so ultimately it could bounce back and forth during that tween). Again, this is a very uncommon scenario, but possible nonetheless. 7218 this._rawPrevTime = 0; 7219 } 7220 } 7221 }; 7222 7223 p._kill = function(vars, target, overwritingTween) { 7224 if (vars === "all") { 7225 vars = null; 7226 } 7227 if (vars == null) if (target == null || target === this.target) { 7228 this._lazy = false; 7229 return this._enabled(false, false); 7230 } 7231 target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target; 7232 var simultaneousOverwrite = (overwritingTween && this._time && overwritingTween._startTime === this._startTime && this._timeline === overwritingTween._timeline), 7233 i, overwrittenProps, p, pt, propLookup, changed, killProps, record, killed; 7234 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") { 7235 i = target.length; 7236 while (--i > -1) { 7237 if (this._kill(vars, target[i], overwritingTween)) { 7238 changed = true; 7239 } 7240 } 7241 } else { 7242 if (this._targets) { 7243 i = this._targets.length; 7244 while (--i > -1) { 7245 if (target === this._targets[i]) { 7246 propLookup = this._propLookup[i] || {}; 7247 this._overwrittenProps = this._overwrittenProps || []; 7248 overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all"; 7249 break; 7250 } 7251 } 7252 } else if (target !== this.target) { 7253 return false; 7254 } else { 7255 propLookup = this._propLookup; 7256 overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all"; 7257 } 7258 7259 if (propLookup) { 7260 killProps = vars || propLookup; 7261 record = (vars !== overwrittenProps && overwrittenProps !== "all" && vars !== propLookup && (typeof(vars) !== "object" || !vars._tempKill)); //_tempKill is a super-secret way to delete a particular tweening property but NOT have it remembered as an official overwritten property (like in BezierPlugin) 7262 if (overwritingTween && (TweenLite.onOverwrite || this.vars.onOverwrite)) { 7263 for (p in killProps) { 7264 if (propLookup[p]) { 7265 if (!killed) { 7266 killed = []; 7267 } 7268 killed.push(p); 7269 } 7270 } 7271 if ((killed || !vars) && !_onOverwrite(this, overwritingTween, target, killed)) { //if the onOverwrite returned false, that means the user wants to override the overwriting (cancel it). 7272 return false; 7273 } 7274 } 7275 7276 for (p in killProps) { 7277 if ((pt = propLookup[p])) { 7278 if (simultaneousOverwrite) { //if another tween overwrites this one and they both start at exactly the same time, yet this tween has already rendered once (for example, at 0.001) because it's first in the queue, we should revert the values to where they were at 0 so that the starting values aren't contaminated on the overwriting tween. 7279 if (pt.f) { 7280 pt.t[pt.p](pt.s); 7281 } else { 7282 pt.t[pt.p] = pt.s; 7283 } 7284 changed = true; 7285 } 7286 if (pt.pg && pt.t._kill(killProps)) { 7287 changed = true; //some plugins need to be notified so they can perform cleanup tasks first 7288 } 7289 if (!pt.pg || pt.t._overwriteProps.length === 0) { 7290 if (pt._prev) { 7291 pt._prev._next = pt._next; 7292 } else if (pt === this._firstPT) { 7293 this._firstPT = pt._next; 7294 } 7295 if (pt._next) { 7296 pt._next._prev = pt._prev; 7297 } 7298 pt._next = pt._prev = null; 7299 } 7300 delete propLookup[p]; 7301 } 7302 if (record) { 7303 overwrittenProps[p] = 1; 7304 } 7305 } 7306 if (!this._firstPT && this._initted) { //if all tweening properties are killed, kill the tween. Without this line, if there's a tween with multiple targets and then you killTweensOf() each target individually, the tween would technically still remain active and fire its onComplete even though there aren't any more properties tweening. 7307 this._enabled(false, false); 7308 } 7309 } 7310 } 7311 return changed; 7312 }; 7313 7314 p.invalidate = function() { 7315 if (this._notifyPluginsOfEnabled) { 7316 TweenLite._onPluginEvent("_onDisable", this); 7317 } 7318 this._firstPT = this._overwrittenProps = this._startAt = this._onUpdate = null; 7319 this._notifyPluginsOfEnabled = this._active = this._lazy = false;
7320 this._propLookup = (this._targets) ? {} : []; 7321 Animation.prototype.invalidate.call(this); 7322 if (this.vars.immediateRender) { 7323 this._time = -_tinyNum; //forces a render without having to set the render() "force" parameter to true because we want to allow lazying by default (using the "force" parameter always forces an immediate full render) 7324 this.render(-this._delay); 7325 } 7326 return this; 7327 }; 7328 7329 p._enabled = function(enabled, ignoreTimeline) { 7330 if (!_tickerActive) { 7331 _ticker.wake(); 7332 } 7333 if (enabled && this._gc) { 7334 var targets = this._targets, 7335 i; 7336 if (targets) { 7337 i = targets.length; 7338 while (--i > -1) { 7339 this._siblings[i] = _register(targets[i], this, true); 7340 } 7341 } else { 7342 this._siblings = _register(this.target, this, true); 7343 } 7344 } 7345 Animation.prototype._enabled.call(this, enabled, ignoreTimeline); 7346 if (this._notifyPluginsOfEnabled) if (this._firstPT) { 7347 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this); 7348 } 7349 return false; 7350 }; 7351 7352 7353//----TweenLite static methods ----------------------------------------------------- 7354 7355 TweenLite.to = function(target, duration, vars) { 7356 return new TweenLite(target, duration, vars); 7357 }; 7358 7359 TweenLite.from = function(target, duration, vars) { 7360 vars.runBackwards = true; 7361 vars.immediateRender = (vars.immediateRender != false); 7362 return new TweenLite(target, duration, vars); 7363 }; 7364 7365 TweenLite.fromTo = function(target, duration, fromVars, toVars) { 7366 toVars.startAt = fromVars; 7367 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 7368 return new TweenLite(target, duration, toVars); 7369 }; 7370 7371 TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) { 7372 return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, callbackScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, immediateRender:false, lazy:false, useFrames:useFrames, overwrite:0}); 7373 }; 7374 7375 TweenLite.set = function(target, vars) { 7376 return new TweenLite(target, 0, vars); 7377 }; 7378 7379 TweenLite.getTweensOf = function(target, onlyActive) { 7380 if (target == null) { return []; } 7381 target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target; 7382 var i, a, j, t; 7383 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") { 7384 i = target.length; 7385 a = []; 7386 while (--i > -1) { 7387 a = a.concat(TweenLite.getTweensOf(target[i], onlyActive)); 7388 } 7389 i = a.length; 7390 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates) 7391 while (--i > -1) { 7392 t = a[i]; 7393 j = i; 7394 while (--j > -1) { 7395 if (t === a[j]) { 7396 a.splice(i, 1); 7397 } 7398 } 7399 } 7400 } else { 7401 a = _register(target).concat(); 7402 i = a.length; 7403 while (--i > -1) { 7404 if (a[i]._gc || (onlyActive && !a[i].isActive())) { 7405 a.splice(i, 1); 7406 } 7407 } 7408 } 7409 return a; 7410 }; 7411 7412 TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) { 7413 if (typeof(onlyActive) === "object") { 7414 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted) 7415 onlyActive = false; 7416 } 7417 var a = TweenLite.getTweensOf(target, onlyActive), 7418 i = a.length; 7419 while (--i > -1) { 7420 a[i]._kill(vars, target); 7421 } 7422 }; 7423 7424 7425 7426/* 7427 * ---------------------------------------------------------------- 7428 * TweenPlugin (could easily be split out as a separate file/class, but included for ease of use (so that people don't need to include another script call before loading plugins which is easy to forget) 7429 * ---------------------------------------------------------------- 7430 */ 7431 var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) { 7432 this._overwriteProps = (props || "").split(","); 7433 this._propName = this._overwriteProps[0]; 7434 this._priority = priority || 0; 7435 this._super = TweenPlugin.prototype; 7436 }, true); 7437 7438 p = TweenPlugin.prototype; 7439 TweenPlugin.version = "1.18.0"; 7440 TweenPlugin.API = 2; 7441 p._firstPT = null; 7442 p._addTween = _addPropTween; 7443 p.setRatio = _setRatio; 7444 7445 p._kill = function(lookup) { 7446 var a = this._overwriteProps, 7447 pt = this._firstPT, 7448 i; 7449 if (lookup[this._propName] != null) { 7450 this._overwriteProps = []; 7451 } else { 7452 i = a.length; 7453 while (--i > -1) { 7454 if (lookup[a[i]] != null) { 7455 a.splice(i, 1); 7456 } 7457 } 7458 } 7459 while (pt) { 7460 if (lookup[pt.n] != null) { 7461 if (pt._next) { 7462 pt._next._prev = pt._prev; 7463 } 7464 if (pt._prev) { 7465 pt._prev._next = pt._next; 7466 pt._prev = null; 7467 } else if (this._firstPT === pt) { 7468 this._firstPT = pt._next; 7469 } 7470 } 7471 pt = pt._next; 7472 } 7473 return false;
7474 }; 7475 7476 p._roundProps = function(lookup, value) { 7477 var pt = this._firstPT; 7478 while (pt) { 7479 if (lookup[this._propName] || (pt.n != null && lookup[ pt.n.split(this._propName + "_").join("") ])) { //some properties that are very plugin-specific add a prefix named after the _propName plus an underscore, so we need to ignore that extra stuff here. 7480 pt.r = value; 7481 } 7482 pt = pt._next; 7483 } 7484 }; 7485 7486 TweenLite._onPluginEvent = function(type, tween) { 7487 var pt = tween._firstPT, 7488 changed, pt2, first, last, next; 7489 if (type === "_onInitAllProps") { 7490 //sorts the PropTween linked list in order of priority because some plugins need to render earlier/later than others, like MotionBlurPlugin applies its effects after all x/y/alpha tweens have rendered on each frame. 7491 while (pt) { 7492 next = pt._next; 7493 pt2 = first; 7494 while (pt2 && pt2.pr > pt.pr) { 7495 pt2 = pt2._next; 7496 } 7497 if ((pt._prev = pt2 ? pt2._prev : last)) { 7498 pt._prev._next = pt; 7499 } else { 7500 first = pt; 7501 } 7502 if ((pt._next = pt2)) { 7503 pt2._prev = pt; 7504 } else { 7505 last = pt; 7506 } 7507 pt = next; 7508 } 7509 pt = tween._firstPT = first; 7510 } 7511 while (pt) { 7512 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) { 7513 changed = true; 7514 } 7515 pt = pt._next; 7516 } 7517 return changed; 7518 }; 7519 7520 TweenPlugin.activate = function(plugins) { 7521 var i = plugins.length; 7522 while (--i > -1) { 7523 if (plugins[i].API === TweenPlugin.API) { 7524 _plugins[(new plugins[i]())._propName] = plugins[i]; 7525 } 7526 } 7527 return true; 7528 }; 7529 7530 //provides a more concise way to define plugins that have no dependencies besides TweenPlugin and TweenLite, wrapping common boilerplate stuff into one function (added in 1.9.0). You don't NEED to use this to define a plugin - the old way still works and can be useful in certain (rare) situations. 7531 _gsDefine.plugin = function(config) { 7532 if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; } 7533 var propName = config.propName, 7534 priority = config.priority || 0, 7535 overwriteProps = config.overwriteProps, 7536 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"}, 7537 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin", 7538 function() { 7539 TweenPlugin.call(this, propName, priority); 7540 this._overwriteProps = overwriteProps || []; 7541 }, (config.global === true)), 7542 p = Plugin.prototype = new TweenPlugin(propName), 7543 prop; 7544 p.constructor = Plugin; 7545 Plugin.API = config.API; 7546 for (prop in map) { 7547 if (typeof(config[prop]) === "function") { 7548 p[map[prop]] = config[prop]; 7549 } 7550 } 7551 Plugin.version = config.version; 7552 TweenPlugin.activate([Plugin]); 7553 return Plugin; 7554 }; 7555 7556 7557 //now run through all the dependencies discovered and if any are missing, log that to the console as a warning. This is why it's best to have TweenLite load last - it can check all the dependencies for you. 7558 a = window._gsQueue; 7559 if (a) { 7560 for (i = 0; i < a.length; i++) { 7561 a[i](); 7562 } 7563 for (p in _defLookup) { 7564 if (!_defLookup[p].func) { 7565 window.console.log("GSAP encountered missing dependency: com.greensock." + p); 7566 } 7567 } 7568 } 7569 7570 _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated 7571 7572})((typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window, "TweenMax");
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.