1/*! 2 * VERSION: 1.14.2 3 * DATE: 2014-10-29 4 * UPDATES AND DOCS AT: http://www.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-2014, GreenSock. All rights reserved. 9 * This work is subject to the terms at http://www.greensock.com/terms_of_use.html 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 TweenMax = function(target, duration, vars) { 29 TweenLite.call(this, target, duration, vars); 30 this._cycle = 0; 31 this._yoyo = (this.vars.yoyo === true); 32 this._repeat = this.vars.repeat || 0; 33 this._repeatDelay = this.vars.repeatDelay || 0; 34 this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it. 35 this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method) 36 }, 37 _tinyNum = 0.0000000001, 38 TweenLiteInternals = TweenLite._internals, 39 _isSelector = TweenLiteInternals.isSelector, 40 _isArray = TweenLiteInternals.isArray, 41 p = TweenMax.prototype = TweenLite.to({}, 0.1, {}), 42 _blankArray = []; 43 44 TweenMax.version = "1.14.2"; 45 p.constructor = TweenMax; 46 p.kill()._gc = false; 47 TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf; 48 TweenMax.getTweensOf = TweenLite.getTweensOf; 49 TweenMax.lagSmoothing = TweenLite.lagSmoothing; 50 TweenMax.ticker = TweenLite.ticker; 51 TweenMax.render = TweenLite.render; 52 53 p.invalidate = function() { 54 this._yoyo = (this.vars.yoyo === true); 55 this._repeat = this.vars.repeat || 0; 56 this._repeatDelay = this.vars.repeatDelay || 0; 57 this._uncache(true); 58 return TweenLite.prototype.invalidate.call(this); 59 }; 60 61 p.updateTo = function(vars, resetDuration) { 62 var curRatio = this.ratio, 63 immediate = this.vars.immediateRender || vars.immediateRender, 64 p; 65 if (resetDuration && this._startTime < this._timeline._time) { 66 this._startTime = this._timeline._time; 67 this._uncache(false); 68 if (this._gc) { 69 this._enabled(true, false); 70 } else { 71 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. 72 } 73 } 74 for (p in vars) { 75 this.vars[p] = vars[p]; 76 } 77 if (this._initted || immediate) { 78 if (resetDuration) { 79 this._initted = false; 80 } else { 81 if (this._gc) { 82 this._enabled(true, false); 83 } 84 if (this._notifyPluginsOfEnabled && this._firstPT) { 85 TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks 86 } 87 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. 88 var prevTime = this._time; 89 this.render(0, true, false); 90 this._initted = false;
91 this.render(prevTime, true, false); 92 } else if (this._time > 0 || immediate) { 93 this._initted = false; 94 this._init(); 95 var inv = 1 / (1 - curRatio), 96 pt = this._firstPT, endValue; 97 while (pt) { 98 endValue = pt.s + pt.c; 99 pt.c *= inv; 100 pt.s = endValue - pt.c; 101 pt = pt._next; 102 } 103 } 104 } 105 } 106 return this; 107 }; 108 109 p.render = function(time, suppressEvents, force) { 110 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. 111 this.invalidate(); 112 } 113 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(), 114 prevTime = this._time, 115 prevTotalTime = this._totalTime, 116 prevCycle = this._cycle, 117 duration = this._duration, 118 prevRawPrevTime = this._rawPrevTime, 119 isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime, i; 120 if (time >= totalDur) { 121 this._totalTime = totalDur; 122 this._cycle = this._repeat; 123 if (this._yoyo && (this._cycle & 1) !== 0) { 124 this._time = 0; 125 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0; 126 } else { 127 this._time = duration; 128 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1; 129 } 130 if (!this._reversed) { 131 isComplete = true; 132 callback = "onComplete"; 133 } 134 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. 135 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. 136 time = 0; 137 } 138 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) { 139 force = true; 140 if (prevRawPrevTime > _tinyNum) { 141 callback = "onReverseComplete"; 142 } 143 } 144 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. 145 } 146 147 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 148 this._totalTime = this._time = this._cycle = 0; 149 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0; 150 if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) { 151 callback = "onReverseComplete"; 152 isComplete = this._reversed; 153 } 154 if (time < 0) { 155 this._active = false;
156 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. 157 if (prevRawPrevTime >= 0) { 158 force = true; 159 } 160 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. 161 } 162 } 163 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. 164 force = true; 165 } 166 } else { 167 this._totalTime = this._time = time; 168 169 if (this._repeat !== 0) { 170 cycleDuration = duration + this._repeatDelay; 171 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!) 172 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) { 173 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning) 174 } 175 this._time = this._totalTime - (this._cycle * cycleDuration); 176 if (this._yoyo) if ((this._cycle & 1) !== 0) { 177 this._time = duration - this._time; 178 } 179 if (this._time > duration) { 180 this._time = duration; 181 } else if (this._time < 0) { 182 this._time = 0; 183 } 184 } 185 186 if (this._easeType) { 187 r = this._time / duration; 188 type = this._easeType; 189 pow = this._easePower; 190 if (type === 1 || (type === 3 && r >= 0.5)) { 191 r = 1 - r; 192 } 193 if (type === 3) { 194 r *= 2; 195 } 196 if (pow === 1) { 197 r *= r; 198 } else if (pow === 2) { 199 r *= r * r; 200 } else if (pow === 3) { 201 r *= r * r * r; 202 } else if (pow === 4) { 203 r *= r * r * r * r; 204 } 205 206 if (type === 1) { 207 this.ratio = 1 - r; 208 } else if (type === 2) { 209 this.ratio = r; 210 } else if (this._time / duration < 0.5) { 211 this.ratio = r / 2; 212 } else { 213 this.ratio = 1 - (r / 2); 214 } 215 216 } else { 217 this.ratio = this._ease.getRatio(this._time / duration); 218 } 219 220 } 221 222 if (prevTime === this._time && !force && prevCycle === this._cycle) { 223 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. 224 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray); 225 } 226 return; 227 } else if (!this._initted) { 228 this._init(); 229 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
229writing 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. 230 return; 231 } 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. 232 this._time = prevTime; 233 this._totalTime = prevTotalTime; 234 this._rawPrevTime = prevRawPrevTime; 235 this._cycle = prevCycle; 236 TweenLiteInternals.lazyTweens.push(this); 237 this._lazy = [time, suppressEvents]; 238 return; 239 } 240 //_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. 241 if (this._time && !isComplete) { 242 this.ratio = this._ease.getRatio(this._time / duration); 243 } else if (isComplete && this._ease._calcEnd) { 244 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1); 245 } 246 } 247 if (this._lazy !== false) { 248 this._lazy = false; 249 } 250 251 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) { 252 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. 253 } 254 if (prevTotalTime === 0) { 255 if (this._initted === 2 && time > 0) { 256 //this.invalidate(); 257 this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true 258 } 259 if (this._startAt) { 260 if (time >= 0) { 261 this._startAt.render(time, suppressEvents, force); 262 } else if (!callback) { 263 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. 264 } 265 } 266 if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) { 267 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray); 268 } 269 } 270 271 pt = this._firstPT; 272 while (pt) { 273 if (pt.f) { 274 pt.t[pt.p](pt.c * this.ratio + pt.s); 275 } else { 276 pt.t[pt.p] = pt.c * this.ratio + pt.s; 277 } 278 pt = pt._next; 279 } 280 281 if (this._onUpdate) { 282 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. 283 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. 284 } 285 if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
286 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray); 287 } 288 } 289 if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) { 290 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray); 291 } 292 if (callback) if (!this._gc || force) { //check gc because there's a chance that kill() could be called in an onUpdate 293 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. 294 this._startAt.render(time, suppressEvents, force); 295 } 296 if (isComplete) { 297 if (this._timeline.autoRemoveChildren) { 298 this._enabled(false, false); 299 } 300 this._active = false; 301 } 302 if (!suppressEvents && this.vars[callback]) { 303 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray); 304 } 305 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
305nario, but possible nonetheless. 306 this._rawPrevTime = 0; 307 } 308 } 309 }; 310 311//---- STATIC FUNCTIONS ----------------------------------------------------------------------------------------------------------- 312 313 TweenMax.to = function(target, duration, vars) { 314 return new TweenMax(target, duration, vars); 315 }; 316 317 TweenMax.from = function(target, duration, vars) { 318 vars.runBackwards = true; 319 vars.immediateRender = (vars.immediateRender != false); 320 return new TweenMax(target, duration, vars); 321 }; 322 323 TweenMax.fromTo = function(target, duration, fromVars, toVars) { 324 toVars.startAt = fromVars; 325 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 326 return new TweenMax(target, duration, toVars); 327 }; 328 329 TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 330 stagger = stagger || 0; 331 var delay = vars.delay || 0, 332 a = [], 333 finalComplete = function() { 334 if (vars.onComplete) { 335 vars.onComplete.apply(vars.onCompleteScope || this, arguments); 336 } 337 onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray); 338 }, 339 l, copy, i, p; 340 if (!_isArray(targets)) { 341 if (typeof(targets) === "string") { 342 targets = TweenLite.selector(targets) || targets; 343 } 344 if (_isSelector(targets)) { 345 targets = _slice(targets); 346 } 347 } 348 targets = targets || []; 349 if (stagger < 0) { 350 targets = _slice(targets); 351 targets.reverse(); 352 stagger *= -1; 353 } 354 l = targets.length - 1; 355 for (i = 0; i <= l; i++) { 356 copy = {}; 357 for (p in vars) { 358 copy[p] = vars[p]; 359 } 360 copy.delay = delay; 361 if (i === l && onCompleteAll) { 362 copy.onComplete = finalComplete; 363 } 364 a[i] = new TweenMax(targets[i], duration, copy); 365 delay += stagger; 366 } 367 return a; 368 }; 369 370 TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 371 vars.runBackwards = true; 372 vars.immediateRender = (vars.immediateRender != false); 373 return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 374 }; 375 376 TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 377 toVars.startAt = fromVars; 378 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 379 return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 380 }; 381 382 TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) { 383 return new TweenMax(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0}); 384 }; 385 386 TweenMax.set = function(target, vars) { 387 return new TweenMax(target, 0, vars); 388 }; 389 390 TweenMax.isTweening = function(target) { 391 return (TweenLite.getTweensOf(target, true).length > 0); 392 }; 393 394 var _getChildrenOf = function(timeline, includeTimelines) { 395 var a = [], 396 cnt = 0, 397 tween = timeline._first; 398 while (tween) { 399 if (tween instanceof TweenLite) { 400 a[cnt++] = tween; 401 } else { 402 if (includeTimelines) { 403 a[cnt++] = tween; 404 } 405 a = a.concat(_getChildrenOf(tween, includeTimelines)); 406 cnt = a.length; 407 } 408 tween = tween._next; 409 } 410 return a; 411 }, 412 getAllTweens = TweenMax.getAllTweens = function(includeTimelines) { 413 return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) ); 414 }; 415 416 TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) { 417 if (tweens == null) { 418 tweens = true; 419 } 420 if (delayedCalls == null) { 421 delayedCalls = true; 422 } 423 var a = getAllTweens((timelines != false)), 424 l = a.length, 425 allTrue = (tweens && delayedCalls && timelines), 426 isDC, tween, i; 427 for (i = 0; i < l; i++) { 428 tween = a[i]; 429 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) { 430 if (complete) { 431 tween.totalTime(tween._reversed ? 0 : tween.totalDuration()); 432 } else { 433 tween._enabled(false, false); 434 } 435 } 436 } 437 }; 438 439 TweenMax.killChildTweensOf = function(parent, complete) { 440 if (parent == null) { 441 return; 442 } 443 var tl = TweenLiteInternals.tweenLookup, 444 a, curParent, p, i, l; 445 if (typeof(parent) === "string") { 446 parent = TweenLite.selector(parent) || parent; 447 } 448 if (_isSelector(parent)) { 449 parent = _slice(parent); 450 } 451 if (_isArray(parent)) { 452 i = parent.length; 453 while (--i > -1) { 454 TweenMax.killChildTweensOf(parent[i], complete); 455 } 456 return; 457 } 458 a = []; 459 for (p in tl) { 460 curParent = tl[p].target.parentNode; 461 while (curParent) { 462 if (curParent === parent) { 463 a = a.concat(tl[p].tweens); 464 } 465 curParent = curParent.parentNode; 466 } 467 } 468 l = a.length; 469 for (i = 0; i < l; i++) { 470 if (complete) { 471 a[i].totalTime(a[i].totalDuration()); 472 } 473 a[i]._enabled(false, false); 474 } 475 }; 476 477 var _changePause = function(pause, tweens, delayedCalls, timelines) { 478 tweens = (tweens !== false); 479 delayedCalls = (delayedCalls !== false); 480 timelines = (timelines !== false); 481 var a = getAllTweens(timelines), 482 allTrue = (tweens && delayedCalls && timelines), 483 i = a.length, 484 isDC, tween; 485 while (--i > -1) { 486 tween = a[i]; 487 if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) { 488 tween.paused(pause); 489 } 490 } 491 }; 492 493 TweenMax.pauseAll = function(tweens, delayedCalls, timelines) { 494 _changePause(true, tweens, delayedCalls, timelines); 495 }; 496
497 TweenMax.resumeAll = function(tweens, delayedCalls, timelines) { 498 _changePause(false, tweens, delayedCalls, timelines); 499 }; 500 501 TweenMax.globalTimeScale = function(value) { 502 var tl = Animation._rootTimeline, 503 t = TweenLite.ticker.time; 504 if (!arguments.length) { 505 return tl._timeScale; 506 } 507 value = value || _tinyNum; //can't allow zero because it'll throw the math off 508 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value); 509 tl = Animation._rootFramesTimeline; 510 t = TweenLite.ticker.frame; 511 tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value); 512 tl._timeScale = Animation._rootTimeline._timeScale = value; 513 return value; 514 }; 515 516 517//---- GETTERS / SETTERS ---------------------------------------------------------------------------------------------------------- 518 519 p.progress = function(value) { 520 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); 521 }; 522 523 p.totalProgress = function(value) { 524 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false); 525 }; 526 527 p.time = function(value, suppressEvents) { 528 if (!arguments.length) { 529 return this._time; 530 } 531 if (this._dirty) { 532 this.totalDuration(); 533 } 534 if (value > this._duration) { 535 value = this._duration; 536 } 537 if (this._yoyo && (this._cycle & 1) !== 0) { 538 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay)); 539 } else if (this._repeat !== 0) { 540 value += this._cycle * (this._duration + this._repeatDelay); 541 } 542 return this.totalTime(value, suppressEvents); 543 }; 544 545 p.duration = function(value) { 546 if (!arguments.length) { 547 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. 548 } 549 return Animation.prototype.duration.call(this, value); 550 }; 551 552 p.totalDuration = function(value) { 553 if (!arguments.length) { 554 if (this._dirty) { 555 //instead of Infinity, we use 999999999999 so that we can accommodate reverses 556 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat); 557 this._dirty = false; 558 } 559 return this._totalDuration; 560 } 561 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) ); 562 }; 563 564 p.repeat = function(value) { 565 if (!arguments.length) { 566 return this._repeat; 567 } 568 this._repeat = value; 569 return this._uncache(true); 570 }; 571 572 p.repeatDelay = function(value) { 573 if (!arguments.length) { 574 return this._repeatDelay; 575 } 576 this._repeatDelay = value; 577 return this._uncache(true); 578 }; 579 580 p.yoyo = function(value) { 581 if (!arguments.length) { 582 return this._yoyo; 583 } 584 this._yoyo = value; 585 return this; 586 }; 587 588 589 return TweenMax; 590 591 }, true); 592 593 594 595 596 597 598 599 600/* 601 * ---------------------------------------------------------------- 602 * TimelineLite 603 * ---------------------------------------------------------------- 604 */ 605 _gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) { 606 607 var TimelineLite = function(vars) { 608 SimpleTimeline.call(this, vars); 609 this._labels = {}; 610 this.autoRemoveChildren = (this.vars.autoRemoveChildren === true); 611 this.smoothChildTiming = (this.vars.smoothChildTiming === true); 612 this._sortChildren = true; 613 this._onUpdate = this.vars.onUpdate; 614 var v = this.vars, 615 val, p; 616 for (p in v) { 617 val = v[p]; 618 if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) { 619 v[p] = this._swapSelfInParams(val); 620 } 621 } 622 if (_isArray(v.tweens)) { 623 this.add(v.tweens, 0, v.align, v.stagger); 624 } 625 }, 626 _tinyNum = 0.0000000001, 627 TweenLiteInternals = TweenLite._internals, 628 _isSelector = TweenLiteInternals.isSelector, 629 _isArray = TweenLiteInternals.isArray, 630 _lazyTweens = TweenLiteInternals.lazyTweens, 631 _lazyRender = TweenLiteInternals.lazyRender, 632 _blankArray = [], 633 _globals = _gsScope._gsDefine.globals, 634 _copy = function(vars) { 635 var copy = {}, p; 636 for (p in vars) { 637 copy[p] = vars[p]; 638 } 639 return copy; 640 }, 641 _pauseCallback = function(tween, callback, params, scope) { 642 var time = tween._timeline._totalTime; 643 if (callback || !this._forcingPlayhead) { //if the user calls a method that moves the playhead (like progress() or time()), it should honor that and skip any pauses (although if there's a callback positioned at that pause, it must jump there and make the call to ensure the time is EXACTLY what it is supposed to be, and then proceed to where the playhead is being forced). Otherwise, imagine placing a pause in the middle of a timeline and then doing timeline.progress(0.9) - it would get stuck where the pause is. 644 tween._timeline.pause(tween._startTime); 645 if (callback) { 646 callback.apply(scope || tween._timeline, params || _blankArray); 647 } 648 if (this._forcingPlayhead) { 649 tween._timeline.seek(time); 650 } 651 } 652 }, 653 _slice = function(a) { //don't use [].slice because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll() 654 var b = [], 655 l = a.length, 656 i; 657 for (i = 0; i !== l; b.push(a[i++])); 658 return b; 659 }, 660 p = TimelineLite.prototype = new SimpleTimeline(); 661
662 TimelineLite.version = "1.14.2"; 663 p.constructor = TimelineLite; 664 p.kill()._gc = p._forcingPlayhead = false; 665 666 /* might use later... 667 //translates a local time inside an animation to the corresponding time on the root/global timeline, factoring in all nesting and timeScales. 668 function localToGlobal(time, animation) { 669 while (animation) { 670 time = (time / animation._timeScale) + animation._startTime; 671 animation = animation.timeline; 672 } 673 return time; 674 } 675 676 //translates the supplied time on the root/global timeline into the corresponding local time inside a particular animation, factoring in all nesting and timeScales 677 function globalToLocal(time, animation) { 678 var scale = 1; 679 time -= localToGlobal(0, animation); 680 while (animation) { 681 scale *= animation._timeScale; 682 animation = animation.timeline; 683 } 684 return time * scale; 685 } 686 */ 687 688 p.to = function(target, duration, vars, position) { 689 var Engine = (vars.repeat && _globals.TweenMax) || TweenLite; 690 return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position); 691 }; 692 693 p.from = function(target, duration, vars, position) { 694 return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position); 695 }; 696 697 p.fromTo = function(target, duration, fromVars, toVars, position) { 698 var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite; 699 return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position); 700 }; 701 702 p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 703 var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}), 704 i; 705 if (typeof(targets) === "string") { 706 targets = TweenLite.selector(targets) || targets; 707 } 708 targets = targets || []; 709 if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array. 710 targets = _slice(targets); 711 } 712 stagger = stagger || 0; 713 if (stagger < 0) { 714 targets = _slice(targets); 715 targets.reverse(); 716 stagger *= -1; 717 } 718 for (i = 0; i < targets.length; i++) { 719 if (vars.startAt) { 720 vars.startAt = _copy(vars.startAt); 721 } 722 tl.to(targets[i], duration, _copy(vars), i * stagger); 723 } 724 return this.add(tl, position); 725 }; 726 727 p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 728 vars.immediateRender = (vars.immediateRender != false); 729 vars.runBackwards = true; 730 return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 731 }; 732 733 p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) { 734 toVars.startAt = fromVars; 735 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 736 return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope); 737 }; 738 739 p.call = function(callback, params, scope, position) { 740 return this.add( TweenLite.delayedCall(0, callback, params, scope), position); 741 }; 742 743 p.set = function(target, vars, position) { 744 position = this._parseTimeOrLabel(position, 0, true); 745 if (vars.immediateRender == null) { 746 vars.immediateRender = (position === this._time && !this._paused); 747 } 748 return this.add( new TweenLite(target, 0, vars), position); 749 }; 750 751 TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) { 752 vars = vars || {}; 753 if (vars.smoothChildTiming == null) { 754 vars.smoothChildTiming = true; 755 } 756 var tl = new TimelineLite(vars), 757 root = tl._timeline, 758 tween, next; 759 if (ignoreDelayedCalls == null) { 760 ignoreDelayedCalls = true; 761 } 762 root._remove(tl, true); 763 tl._startTime = 0; 764 tl._rawPrevTime = tl._time = tl._totalTime = root._time; 765 tween = root._first; 766 while (tween) { 767 next = tween._next; 768 if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) { 769 tl.add(tween, tween._startTime - tween._delay); 770 } 771 tween = next; 772 } 773 root.add(tl, 0); 774 return tl; 775 }; 776 777 p.add = function(value, position, align, stagger) { 778 var curTime, l, i, child, tl, beforeRawTime; 779 if (typeof(position) !== "number") { 780 position = this._parseTimeOrLabel(position, 0, true, value); 781 } 782 if (!(value instanceof Animation)) { 783 if ((value instanceof Array) || (value && value.push && _isArray(value))) {
784 align = align || "normal"; 785 stagger = stagger || 0; 786 curTime = position; 787 l = value.length; 788 for (i = 0; i < l; i++) { 789 if (_isArray(child = value[i])) { 790 child = new TimelineLite({tweens:child}); 791 } 792 this.add(child, curTime); 793 if (typeof(child) !== "string" && typeof(child) !== "function") { 794 if (align === "sequence") { 795 curTime = child._startTime + (child.totalDuration() / child._timeScale); 796 } else if (align === "start") { 797 child._startTime -= child.delay(); 798 } 799 } 800 curTime += stagger; 801 } 802 return this._uncache(true); 803 } else if (typeof(value) === "string") { 804 return this.addLabel(value, position); 805 } else if (typeof(value) === "function") { 806 value = TweenLite.delayedCall(0, value); 807 } else { 808 throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string."); 809 } 810 } 811 812 SimpleTimeline.prototype.add.call(this, value, position); 813 814 //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. 815 if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) { 816 //in case any of the ancestors had completed but should now be enabled... 817 tl = this; 818 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. 819 while (tl._timeline) { 820 if (beforeRawTime && tl._timeline.smoothChildTiming) { 821 tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it. 822 } else if (tl._gc) { 823 tl._enabled(true, false); 824 } 825 tl = tl._timeline; 826 } 827 } 828 829 return this; 830 }; 831 832 p.remove = function(value) { 833 if (value instanceof Animation) { 834 return this._remove(value, false); 835 } else if (value instanceof Array || (value && value.push && _isArray(value))) { 836 var i = value.length; 837 while (--i > -1) { 838 this.remove(value[i]); 839 } 840 return this; 841 } else if (typeof(value) === "string") { 842 return this.removeLabel(value); 843 } 844 return this.kill(null, value); 845 }; 846 847 p._remove = function(tween, skipDisable) { 848 SimpleTimeline.prototype._remove.call(this, tween, skipDisable); 849 var last = this._last; 850 if (!last) { 851 this._time = this._totalTime = this._duration = this._totalDuration = 0; 852 } else if (this._time > last._startTime + last._totalDuration / last._timeScale) { 853 this._time = this.duration(); 854 this._totalTime = this._totalDuration; 855 } 856 return this; 857 }; 858 859 p.append = function(value, offsetOrLabel) { 860 return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value)); 861 }; 862 863 p.insert = p.insertMultiple = function(value, position, align, stagger) { 864 return this.add(value, position || 0, align, stagger); 865 }; 866 867 p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) { 868 return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger); 869 }; 870 871 p.addLabel = function(label, position) { 872 this._labels[label] = this._parseTimeOrLabel(position); 873 return this; 874 }; 875 876 p.addPause = function(position, callback, params, scope) { 877 return this.call(_pauseCallback, ["{self}", callback, params, scope], this, position); 878 }; 879 880 p.removeLabel = function(label) { 881 delete this._labels[label]; 882 return this; 883 }; 884 885 p.getLabelTime = function(label) { 886 return (this._labels[label] != null) ? this._labels[label] : -1; 887 }; 888 889 p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) { 890 var i; 891 //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(). 892 if (ignore instanceof Animation && ignore.timeline === this) { 893 this.remove(ignore); 894 } else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) { 895 i = ignore.length; 896 while (--i > -1) { 897 if (ignore[i] instanceof Animation && ignore[i].timeline === this) { 898 this.remove(ignore[i]); 899 } 900 } 901 } 902 if (typeof(offsetOrLabel) === "string") { 903 return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent); 904 } 905 offsetOrLabel = offsetOrLabel || 0; 906 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). 907 i = timeOrLabel.indexOf("="); 908 if (i === -1) { 909 if (this._labels[timeOrLabel] == null) { 910 return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel; 911 } 912 return this._labels[timeOrLabel] + offsetOrLabel; 913 } 914 offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1)); 915 timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration(); 916 } else if (timeOrLabel == null) { 917 timeOrLabel = this.duration(); 918 } 919 return Number(timeOrLabel) + offsetOrLabel; 920 }; 921 922 p.seek = function(position, suppressEvents) {
923 return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false)); 924 }; 925 926 p.stop = function() { 927 return this.paused(true); 928 }; 929 930 p.gotoAndPlay = function(position, suppressEvents) { 931 return this.play(position, suppressEvents); 932 }; 933 934 p.gotoAndStop = function(position, suppressEvents) { 935 return this.pause(position, suppressEvents); 936 }; 937 938 p.render = function(time, suppressEvents, force) { 939 if (this._gc) { 940 this._enabled(true, false); 941 } 942 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(), 943 prevTime = this._time, 944 prevStart = this._startTime, 945 prevTimeScale = this._timeScale, 946 prevPaused = this._paused, 947 tween, isComplete, next, callback, internalForce; 948 if (time >= totalDur) { 949 this._totalTime = this._time = totalDur; 950 if (!this._reversed) if (!this._hasPausedChild()) { 951 isComplete = true; 952 callback = "onComplete"; 953 if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) { 954 internalForce = true; 955 if (this._rawPrevTime > _tinyNum) { 956 callback = "onReverseComplete"; 957 } 958 } 959 } 960 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. 961 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. 962 963 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 964 this._totalTime = this._time = 0; 965 if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) { 966 callback = "onReverseComplete"; 967 isComplete = this._reversed; 968 } 969 if (time < 0) { 970 this._active = false; 971 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. 972 internalForce = true; 973 } 974 this._rawPrevTime = time; 975 } else { 976 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. 977 978 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline) 979 if (!this._initted) { 980 internalForce = true; 981 } 982 } 983 984 } else { 985 this._totalTime = this._time = this._rawPrevTime = time; 986 } 987 if ((this._time === prevTime || !this._first) && !force && !internalForce) { 988 return; 989 } else if (!this._initted) { 990 this._initted = true; 991 } 992 993 if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) { 994 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. 995 } 996 997 if (prevTime === 0) if (this.vars.onStart) if (this._time !== 0) if (!suppressEvents) { 998 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray); 999 } 1000 1001 if (this._time >= prevTime) { 1002 tween = this._first; 1003 while (tween) { 1004 next = tween._next; //record it here because the value could change after rendering... 1005 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1006 break; 1007 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) { 1008 if (!tween._reversed) { 1009 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1010 } else { 1011 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1012 } 1013 } 1014 tween = next; 1015 } 1016 } else { 1017 tween = this._last; 1018 while (tween) { 1019 next = tween._prev; //record it here because the value could change after rendering... 1020 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1021 break; 1022 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) { 1023 if (!tween._reversed) { 1024 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1025 } else { 1026 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1027 } 1028 } 1029 tween = next; 1030 } 1031 } 1032 1033 if (this._onUpdate) if (!suppressEvents) { 1034 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. 1035 _lazyRender(); 1036 }
1037 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray); 1038 } 1039 1040 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 1041 if (isComplete) { 1042 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. 1043 _lazyRender(); 1044 } 1045 if (this._timeline.autoRemoveChildren) { 1046 this._enabled(false, false); 1047 } 1048 this._active = false; 1049 } 1050 if (!suppressEvents && this.vars[callback]) { 1051 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray); 1052 } 1053 } 1054 }; 1055 1056 p._hasPausedChild = function() { 1057 var tween = this._first; 1058 while (tween) { 1059 if (tween._paused || ((tween instanceof TimelineLite) && tween._hasPausedChild())) { 1060 return true; 1061 } 1062 tween = tween._next; 1063 } 1064 return false; 1065 }; 1066 1067 p.getChildren = function(nested, tweens, timelines, ignoreBeforeTime) { 1068 ignoreBeforeTime = ignoreBeforeTime || -9999999999; 1069 var a = [], 1070 tween = this._first, 1071 cnt = 0; 1072 while (tween) { 1073 if (tween._startTime < ignoreBeforeTime) { 1074 //do nothing 1075 } else if (tween instanceof TweenLite) { 1076 if (tweens !== false) { 1077 a[cnt++] = tween; 1078 } 1079 } else { 1080 if (timelines !== false) { 1081 a[cnt++] = tween; 1082 } 1083 if (nested !== false) { 1084 a = a.concat(tween.getChildren(true, tweens, timelines)); 1085 cnt = a.length; 1086 } 1087 } 1088 tween = tween._next; 1089 } 1090 return a; 1091 }; 1092 1093 p.getTweensOf = function(target, nested) { 1094 var disabled = this._gc, 1095 a = [], 1096 cnt = 0, 1097 tweens, i; 1098 if (disabled) { 1099 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. 1100 } 1101 tweens = TweenLite.getTweensOf(target); 1102 i = tweens.length; 1103 while (--i > -1) { 1104 if (tweens[i].timeline === this || (nested && this._contains(tweens[i]))) { 1105 a[cnt++] = tweens[i]; 1106 } 1107 } 1108 if (disabled) { 1109 this._enabled(false, true); 1110 } 1111 return a; 1112 }; 1113 1114 p.recent = function() { 1115 return this._recent; 1116 }; 1117 1118 p._contains = function(tween) { 1119 var tl = tween.timeline; 1120 while (tl) { 1121 if (tl === this) { 1122 return true; 1123 } 1124 tl = tl.timeline; 1125 } 1126 return false; 1127 }; 1128 1129 p.shiftChildren = function(amount, adjustLabels, ignoreBeforeTime) { 1130 ignoreBeforeTime = ignoreBeforeTime || 0; 1131 var tween = this._first, 1132 labels = this._labels, 1133 p; 1134 while (tween) { 1135 if (tween._startTime >= ignoreBeforeTime) { 1136 tween._startTime += amount; 1137 } 1138 tween = tween._next; 1139 }
1140 if (adjustLabels) { 1141 for (p in labels) { 1142 if (labels[p] >= ignoreBeforeTime) { 1143 labels[p] += amount; 1144 } 1145 } 1146 } 1147 return this._uncache(true); 1148 }; 1149 1150 p._kill = function(vars, target) { 1151 if (!vars && !target) { 1152 return this._enabled(false, false); 1153 } 1154 var tweens = (!target) ? this.getChildren(true, true, false) : this.getTweensOf(target), 1155 i = tweens.length, 1156 changed = false; 1157 while (--i > -1) { 1158 if (tweens[i]._kill(vars, target)) { 1159 changed = true; 1160 } 1161 } 1162 return changed; 1163 }; 1164 1165 p.clear = function(labels) { 1166 var tweens = this.getChildren(false, true, true), 1167 i = tweens.length; 1168 this._time = this._totalTime = 0; 1169 while (--i > -1) { 1170 tweens[i]._enabled(false, false); 1171 } 1172 if (labels !== false) { 1173 this._labels = {}; 1174 } 1175 return this._uncache(true); 1176 }; 1177 1178 p.invalidate = function() { 1179 var tween = this._first; 1180 while (tween) { 1181 tween.invalidate(); 1182 tween = tween._next; 1183 } 1184 return Animation.prototype.invalidate.call(this);; 1185 }; 1186 1187 p._enabled = function(enabled, ignoreTimeline) { 1188 if (enabled === this._gc) { 1189 var tween = this._first; 1190 while (tween) { 1191 tween._enabled(enabled, true); 1192 tween = tween._next; 1193 } 1194 } 1195 return SimpleTimeline.prototype._enabled.call(this, enabled, ignoreTimeline); 1196 }; 1197 1198 p.totalTime = function(time, suppressEvents, uncapped) { 1199 this._forcingPlayhead = true; 1200 var val = Animation.prototype.totalTime.apply(this, arguments); 1201 this._forcingPlayhead = false; 1202 return val; 1203 }; 1204 1205 p.duration = function(value) { 1206 if (!arguments.length) { 1207 if (this._dirty) { 1208 this.totalDuration(); //just triggers recalculation 1209 } 1210 return this._duration; 1211 } 1212 if (this.duration() !== 0 && value !== 0) { 1213 this.timeScale(this._duration / value); 1214 } 1215 return this; 1216 }; 1217 1218 p.totalDuration = function(value) { 1219 if (!arguments.length) { 1220 if (this._dirty) { 1221 var max = 0, 1222 tween = this._last, 1223 prevStart = 999999999999, 1224 prev, end; 1225 while (tween) { 1226 prev = tween._prev; //record it here in case the tween changes position in the sequence... 1227 if (tween._dirty) { 1228 tween.totalDuration(); //could change the tween._startTime, so make sure the tween's cache is clean before analyzing it. 1229 } 1230 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 1231 this.add(tween, tween._startTime - tween._delay); 1232 } else { 1233 prevStart = tween._startTime; 1234 } 1235 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. 1236 max -= tween._startTime; 1237 if (this._timeline.smoothChildTiming) { 1238 this._startTime += tween._startTime / this._timeScale; 1239 } 1240 this.shiftChildren(-tween._startTime, false, -9999999999); 1241 prevStart = 0; 1242 } 1243 end = tween._startTime + (tween._totalDuration / tween._timeScale); 1244 if (end > max) { 1245 max = end; 1246 } 1247 tween = prev; 1248 } 1249 this._duration = this._totalDuration = max; 1250 this._dirty = false; 1251 } 1252 return this._totalDuration; 1253 } 1254 if (this.totalDuration() !== 0) if (value !== 0) { 1255 this.timeScale(this._totalDuration / value); 1256 } 1257 return this; 1258 }; 1259 1260 p.usesFrames = function() { 1261 var tl = this._timeline; 1262 while (tl._timeline) { 1263 tl = tl._timeline; 1264 } 1265 return (tl === Animation._rootFramesTimeline); 1266 }; 1267 1268 p.rawTime = function() { 1269 return this._paused ? this._totalTime : (this._timeline.rawTime() - this._startTime) * this._timeScale; 1270 }; 1271 1272 return TimelineLite; 1273 1274 }, true); 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288/* 1289 * ---------------------------------------------------------------- 1290 * TimelineMax 1291 * ---------------------------------------------------------------- 1292 */ 1293 _gsScope._gsDefine("TimelineMax", ["TimelineLite","TweenLite","easing.Ease"], function(TimelineLite, TweenLite, Ease) { 1294 1295 var TimelineMax = function(vars) { 1296 TimelineLite.call(this, vars); 1297 this._repeat = this.vars.repeat || 0; 1298 this._repeatDelay = this.vars.repeatDelay || 0; 1299 this._cycle = 0; 1300 this._yoyo = (this.vars.yoyo === true); 1301 this._dirty = true; 1302 }, 1303 _tinyNum = 0.0000000001, 1304 _blankArray = [], 1305 TweenLiteInternals = TweenLite._internals, 1306 _lazyTweens = TweenLiteInternals.lazyTweens, 1307 _lazyRender = TweenLiteInternals.lazyRender,
1308 _easeNone = new Ease(null, null, 1, 0), 1309 p = TimelineMax.prototype = new TimelineLite(); 1310 1311 p.constructor = TimelineMax; 1312 p.kill()._gc = false; 1313 TimelineMax.version = "1.14.2"; 1314 1315 p.invalidate = function() { 1316 this._yoyo = (this.vars.yoyo === true); 1317 this._repeat = this.vars.repeat || 0; 1318 this._repeatDelay = this.vars.repeatDelay || 0; 1319 this._uncache(true); 1320 return TimelineLite.prototype.invalidate.call(this); 1321 }; 1322 1323 p.addCallback = function(callback, position, params, scope) { 1324 return this.add( TweenLite.delayedCall(0, callback, params, scope), position); 1325 }; 1326 1327 p.removeCallback = function(callback, position) { 1328 if (callback) { 1329 if (position == null) { 1330 this._kill(null, callback); 1331 } else { 1332 var a = this.getTweensOf(callback, false), 1333 i = a.length, 1334 time = this._parseTimeOrLabel(position); 1335 while (--i > -1) { 1336 if (a[i]._startTime === time) { 1337 a[i]._enabled(false, false); 1338 } 1339 } 1340 } 1341 } 1342 return this; 1343 }; 1344 1345 p.tweenTo = function(position, vars) { 1346 vars = vars || {}; 1347 var copy = {ease:_easeNone, overwrite:(vars.delay ? 2 : 1), useFrames:this.usesFrames(), immediateRender:false},//note: set overwrite to 1 (true/all) by default unless there's a delay so that we avoid a racing situation that could happen if, for example, an onmousemove creates the same tweenTo() over and over again. 1348 duration, p, t; 1349 for (p in vars) { 1350 copy[p] = vars[p]; 1351 } 1352 copy.time = this._parseTimeOrLabel(position); 1353 duration = (Math.abs(Number(copy.time) - this._time) / this._timeScale) || 0.001; 1354 t = new TweenLite(this, duration, copy); 1355 copy.onStart = function() { 1356 t.target.paused(true); 1357 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. 1358 t.duration( Math.abs( t.vars.time - t.target.time()) / t.target._timeScale ); 1359 } 1360 if (vars.onStart) { //in case the user had an onStart in the vars - we don't want to overwrite it. 1361 vars.onStart.apply(vars.onStartScope || t, vars.onStartParams || _blankArray); 1362 } 1363 }; 1364 return t; 1365 }; 1366 1367 p.tweenFromTo = function(fromPosition, toPosition, vars) { 1368 vars = vars || {}; 1369 fromPosition = this._parseTimeOrLabel(fromPosition); 1370 vars.startAt = {onComplete:this.seek, onCompleteParams:[fromPosition], onCompleteScope:this}; 1371 vars.immediateRender = (vars.immediateRender !== false); 1372 var t = this.tweenTo(toPosition, vars); 1373 return t.duration((Math.abs( t.vars.time - fromPosition) / this._timeScale) || 0.001); 1374 }; 1375 1376 p.render = function(time, suppressEvents, force) { 1377 if (this._gc) { 1378 this._enabled(true, false); 1379 } 1380 var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(), 1381 dur = this._duration, 1382 prevTime = this._time, 1383 prevTotalTime = this._totalTime, 1384 prevStart = this._startTime, 1385 prevTimeScale = this._timeScale, 1386 prevRawPrevTime = this._rawPrevTime, 1387 prevPaused = this._paused, 1388 prevCycle = this._cycle, 1389 tween, isComplete, next, callback, internalForce, cycleDuration; 1390 if (time >= totalDur) { 1391 if (!this._locked) { 1392 this._totalTime = totalDur; 1393 this._cycle = this._repeat; 1394 } 1395 if (!this._reversed) if (!this._hasPausedChild()) { 1396 isComplete = true; 1397 callback = "onComplete"; 1398 if (this._duration === 0) if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time && this._first) { 1399 internalForce = true; 1400 if (prevRawPrevTime > _tinyNum) { 1401 callback = "onReverseComplete"; 1402 } 1403 } 1404 } 1405 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. 1406 if (this._yoyo && (this._cycle & 1) !== 0) { 1407 this._time = time = 0; 1408 } else { 1409 this._time = dur; 1410 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
1410which case adding 0.00000001, for example, causes it to act like nothing was added. 1411 } 1412 1413 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 1414 if (!this._locked) { 1415 this._totalTime = this._cycle = 0; 1416 } 1417 this._time = 0; 1418 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) 1419 callback = "onReverseComplete"; 1420 isComplete = this._reversed; 1421 } 1422 if (time < 0) { 1423 this._active = false; 1424 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. 1425 internalForce = true; 1426 } 1427 this._rawPrevTime = time; 1428 } else { 1429 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. 1430 time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline) 1431 if (!this._initted) { 1432 internalForce = true; 1433 } 1434 } 1435 1436 } else { 1437 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. 1438 internalForce = true; 1439 } 1440 this._time = this._rawPrevTime = time; 1441 if (!this._locked) { 1442 this._totalTime = time; 1443 if (this._repeat !== 0) { 1444 cycleDuration = dur + this._repeatDelay; 1445 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!) 1446 if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) { 1447 this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning) 1448 } 1449 this._time = this._totalTime - (this._cycle * cycleDuration); 1450 if (this._yoyo) if ((this._cycle & 1) !== 0) { 1451 this._time = dur - this._time; 1452 } 1453 if (this._time > dur) { 1454 this._time = dur; 1455 time = dur + 0.0001; //to avoid occasional floating point rounding error 1456 } else if (this._time < 0) { 1457 this._time = time = 0; 1458 } else { 1459 time = this._time; 1460 } 1461 } 1462 } 1463 } 1464 1465 if (this._cycle !== prevCycle) if (!this._locked) { 1466 /* 1467 make sure children at the end/beginning of the timeline are rendered properly. If, for example, 1468 a 3-second long timeline rendered at 2.9 seconds previously, and now renders at 3.2 seconds (which 1469 would get transated to 2.8 seconds if the timeline yoyos or 0.2 seconds if it just repeats), there 1470 could be a callback or a short tween that's at 2.95 or 3 seconds
1470in which wouldn't render. So 1471 we need to push the timeline to the end (and/or beginning depending on its yoyo value). Also we must 1472 ensure that zero-duration tweens at the very beginning or end of the TimelineMax work. 1473 */ 1474 var backwards = (this._yoyo && (prevCycle & 1) !== 0), 1475 wrap = (backwards === (this._yoyo && (this._cycle & 1) !== 0)), 1476 recTotalTime = this._totalTime, 1477 recCycle = this._cycle, 1478 recRawPrevTime = this._rawPrevTime, 1479 recTime = this._time; 1480 1481 this._totalTime = prevCycle * dur; 1482 if (this._cycle < prevCycle) { 1483 backwards = !backwards; 1484 } else { 1485 this._totalTime += dur; 1486 } 1487 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. 1488 1489 this._rawPrevTime = (dur === 0) ? prevRawPrevTime - 0.0001 : prevRawPrevTime; 1490 this._cycle = prevCycle; 1491 this._locked = true; //prevents changes to totalTime and skips repeat/yoyo behavior when we recursively call render() 1492 prevTime = (backwards) ? 0 : dur; 1493 this.render(prevTime, suppressEvents, (dur === 0)); 1494 if (!suppressEvents) if (!this._gc) { 1495 if (this.vars.onRepeat) { 1496 this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray); 1497 } 1498 } 1499 if (wrap) { 1500 prevTime = (backwards) ? dur + 0.0001 : -0.0001; 1501 this.render(prevTime, true, false); 1502 } 1503 this._locked = false; 1504 if (this._paused && !prevPaused) { //if the render() triggered callback that paused this timeline, we should abort (very rare, but possible) 1505 return; 1506 } 1507 this._time = recTime; 1508 this._totalTime = recTotalTime; 1509 this._cycle = recCycle; 1510 this._rawPrevTime = recRawPrevTime; 1511 } 1512 1513 if ((this._time === prevTime || !this._first) && !force && !internalForce) { 1514 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. 1515 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray); 1516 } 1517 return; 1518 } else if (!this._initted) { 1519 this._initted = true; 1520 } 1521 1522 if (!this._active) if (!this._paused && this._totalTime !== prevTotalTime && time > 0) { 1523 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. 1524 } 1525 1526 if (prevTotalTime === 0) if (this.vars.onStart) if (this._totalTime !== 0) if (!suppressEvents) { 1527 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray); 1528 } 1529 1530 if (this._time >= prevTime) { 1531 tween = this._first; 1532 while (tween) { 1533 next = tween._next; //record it here because the value could change after rendering... 1534 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1535 break; 1536 } else if (tween._active || (tween._startTime <= this._time && !tween._paused && !tween._gc)) { 1537 if (!tween._reversed) { 1538 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1539 } else { 1540 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1541 } 1542 1543 } 1544 tween = next; 1545 } 1546 } else { 1547 tween = this._last; 1548 while (tween) { 1549 next = tween._prev; //record it here because the value could change after rendering... 1550 if (this._paused && !prevPaused) { //in case a tween pauses the timeline when rendering 1551 break; 1552 } else if (tween._active || (tween._startTime <= prevTime && !tween._paused && !tween._gc)) { 1553 if (!tween._reversed) { 1554 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 1555 } else { 1556 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 1557 } 1558 } 1559 tween = next; 1560 } 1561 } 1562 1563 if (this._onUpdate) if (!suppressEvents) { 1564 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. 1565 _lazyRender(); 1566 }
1567 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray); 1568 } 1569 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 1570 if (isComplete) { 1571 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. 1572 _lazyRender(); 1573 } 1574 if (this._timeline.autoRemoveChildren) { 1575 this._enabled(false, false); 1576 } 1577 this._active = false; 1578 } 1579 if (!suppressEvents && this.vars[callback]) { 1580 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray); 1581 } 1582 } 1583 }; 1584 1585 p.getActive = function(nested, tweens, timelines) { 1586 if (nested == null) { 1587 nested = true; 1588 } 1589 if (tweens == null) { 1590 tweens = true; 1591 } 1592 if (timelines == null) { 1593 timelines = false; 1594 } 1595 var a = [], 1596 all = this.getChildren(nested, tweens, timelines), 1597 cnt = 0, 1598 l = all.length, 1599 i, tween; 1600 for (i = 0; i < l; i++) { 1601 tween = all[i]; 1602 if (tween.isActive()) { 1603 a[cnt++] = tween; 1604 } 1605 } 1606 return a; 1607 }; 1608 1609 1610 p.getLabelAfter = function(time) { 1611 if (!time) if (time !== 0) { //faster than isNan() 1612 time = this._time; 1613 } 1614 var labels = this.getLabelsArray(), 1615 l = labels.length, 1616 i; 1617 for (i = 0; i < l; i++) { 1618 if (labels[i].time > time) { 1619 return labels[i].name; 1620 } 1621 } 1622 return null; 1623 }; 1624 1625 p.getLabelBefore = function(time) { 1626 if (time == null) { 1627 time = this._time; 1628 } 1629 var labels = this.getLabelsArray(), 1630 i = labels.length; 1631 while (--i > -1) { 1632 if (labels[i].time < time) { 1633 return labels[i].name; 1634 } 1635 } 1636 return null; 1637 }; 1638 1639 p.getLabelsArray = function() { 1640 var a = [], 1641 cnt = 0, 1642 p; 1643 for (p in this._labels) { 1644 a[cnt++] = {time:this._labels[p], name:p}; 1645 } 1646 a.sort(function(a,b) { 1647 return a.time - b.time; 1648 }); 1649 return a; 1650 }; 1651 1652 1653//---- GETTERS / SETTERS ------------------------------------------------------------------------------------------------------- 1654 1655 p.progress = function(value, suppressEvents) { 1656 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); 1657 }; 1658 1659 p.totalProgress = function(value, suppressEvents) { 1660 return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, suppressEvents); 1661 }; 1662 1663 p.totalDuration = function(value) { 1664 if (!arguments.length) { 1665 if (this._dirty) { 1666 TimelineLite.prototype.totalDuration.call(this); //just forces refresh 1667 //Instead of Infinity, we use 999999999999 so that we can accommodate reverses. 1668 this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat); 1669 } 1670 return this._totalDuration; 1671 } 1672 return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) ); 1673 }; 1674 1675 p.time = function(value, suppressEvents) { 1676 if (!arguments.length) { 1677 return this._time; 1678 } 1679 if (this._dirty) { 1680 this.totalDuration(); 1681 } 1682 if (value > this._duration) { 1683 value = this._duration; 1684 } 1685 if (this._yoyo && (this._cycle & 1) !== 0) { 1686 value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay)); 1687 } else if (this._repeat !== 0) { 1688 value += this._cycle * (this._duration + this._repeatDelay); 1689 } 1690 return this.totalTime(value, suppressEvents); 1691 }; 1692 1693 p.repeat = function(value) { 1694 if (!arguments.length) { 1695 return this._repeat; 1696 } 1697 this._repeat = value; 1698 return this._uncache(true); 1699 }; 1700 1701 p.repeatDelay = function(value) { 1702 if (!arguments.length) { 1703 return this._repeatDelay; 1704 } 1705 this._repeatDelay = value; 1706 return this._uncache(true); 1707 }; 1708 1709 p.yoyo = function(value) { 1710 if (!arguments.length) { 1711 return this._yoyo; 1712 } 1713 this._yoyo = value; 1714 return this; 1715 }; 1716 1717 p.currentLabel = function(value) { 1718 if (!arguments.length) { 1719 return this.getLabelBefore(this._time + 0.00000001); 1720 } 1721 return this.seek(value, true); 1722 }; 1723 1724 return TimelineMax; 1725 1726 }, true); 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739/* 1740 * ---------------------------------------------------------------- 1741 * BezierPlugin 1742 * ---------------------------------------------------------------- 1743 */ 1744 (function() { 1745 1746 var _RAD2DEG = 180 / Math.PI, 1747 _r1 = [], 1748 _r2 = [], 1749 _r3 = [], 1750 _corProps = {}, 1751 Segment = function(a, b, c, d) { 1752 this.a = a; 1753 this.b = b; 1754 this.c = c; 1755 this.d = d; 1756 this.da = d - a; 1757 this.ca = c - a; 1758 this.ba = b - a; 1759 }, 1760 _correlate = ",x,y,z,left,top,right,bottom,marginTop,marginLeft,marginRight,marginBottom,paddingLeft,paddingTop,paddingRight,paddingBottom,backgroundPosition,backgroundPosition_y,", 1761 cubicToQuadratic = function(a, b, c, d) { 1762 var q1 = {a:a}, 1763 q2 = {}, 1764 q3 = {}, 1765 q4 = {c:d}, 1766 mab = (a + b) / 2, 1767 mbc = (b + c) / 2, 1768 mcd = (c + d) / 2, 1769 mabc = (mab + mbc) / 2, 1770 mbcd = (mbc + mcd) / 2, 1771 m8 = (mbcd - mabc) / 8; 1772 q1.b = mab + (a - mab) / 4; 1773 q2.b = mabc + m8; 1774 q1.c = q2.a = (q1.b + q2.b) / 2; 1775 q2.c = q3.a = (mabc + mbcd) / 2; 1776 q3.b = mbcd - m8; 1777 q4.b = mcd + (d - mcd) / 4; 1778 q3.c = q4.a = (q3.b + q4.b) / 2; 1779 return [q1, q2, q3, q4]; 1780 }, 1781 _calculateControlPoints = function(a, curviness, quad, basic, correlate) { 1782 var l = a.length - 1, 1783 ii = 0, 1784 cp1 = a[0].a, 1785 i, p1, p2, p3, seg, m1, m2, mm, cp2, qb, r1, r2, tl; 1786 for (i = 0; i < l; i++) { 1787 seg = a[ii]; 1788 p1 = seg.a; 1789 p2 = seg.d; 1790 p3 = a[ii+1].d; 1791 1792 if (correlate) { 1793 r1 = _r1[i]; 1794 r2 = _r2[i]; 1795 tl = ((r2 + r1) * curviness * 0.25) / (basic ? 0.5 : _r3[i] || 0.5); 1796 m1 = p2 - (p2 - p1) * (basic ? curviness * 0.5 : (r1 !== 0 ? tl / r1 : 0)); 1797 m2 = p2 + (p3 - p2) * (basic ? curviness * 0.5 : (r2 !== 0 ? tl / r2 : 0)); 1798 mm = p2 - (m1 + (((m2 - m1) * ((r1 * 3 / (r1 + r2)) + 0.5) / 4) || 0)); 1799 } else { 1800 m1 = p2 - (p2 - p1) * curviness * 0.5; 1801 m2 = p2 + (p3 - p2) * curviness * 0.5; 1802 mm = p2 - (m1 + m2) / 2; 1803 } 1804 m1 += mm; 1805 m2 += mm; 1806 1807 seg.c = cp2 = m1; 1808 if (i !== 0) { 1809 seg.b = cp1; 1810 } else { 1811 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. 1812 } 1813 1814 seg.da = p2 - p1; 1815 seg.ca = cp2 - p1; 1816 seg.ba = cp1 - p1; 1817 1818 if (quad) { 1819 qb = cubicToQuadratic(p1, cp1, cp2, p2); 1820 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]); 1821 ii += 4; 1822 } else { 1823 ii++; 1824 } 1825 1826 cp1 = m2; 1827 } 1828 seg = a[ii]; 1829 seg.b = cp1; 1830 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. 1831 seg.da = seg.d - seg.a; 1832 seg.ca = seg.c - seg.a; 1833 seg.ba = cp1 - seg.a; 1834 if (quad) { 1835 qb = cubicToQuadratic(seg.a, cp1, seg.c, seg.d); 1836 a.splice(ii, 1, qb[0], qb[1], qb[2], qb[3]); 1837 } 1838 }, 1839 _parseAnchors = function(values, p, correlate, prepend) { 1840 var a = [], 1841 l, i, p1, p2, p3, tmp; 1842 if (prepend) {
1843 values = [prepend].concat(values); 1844 i = values.length; 1845 while (--i > -1) { 1846 if (typeof( (tmp = values[i][p]) ) === "string") if (tmp.charAt(1) === "=") { 1847 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 1848 } 1849 } 1850 } 1851 l = values.length - 2; 1852 if (l < 0) { 1853 a[0] = new Segment(values[0][p], 0, 0, values[(l < -1) ? 0 : 1][p]); 1854 return a; 1855 } 1856 for (i = 0; i < l; i++) { 1857 p1 = values[i][p]; 1858 p2 = values[i+1][p]; 1859 a[i] = new Segment(p1, 0, 0, p2); 1860 if (correlate) { 1861 p3 = values[i+2][p]; 1862 _r1[i] = (_r1[i] || 0) + (p2 - p1) * (p2 - p1); 1863 _r2[i] = (_r2[i] || 0) + (p3 - p2) * (p3 - p2); 1864 } 1865 } 1866 a[i] = new Segment(values[i][p], 0, 0, values[i+1][p]); 1867 return a; 1868 }, 1869 bezierThrough = function(values, curviness, quadratic, basic, correlate, prepend) { 1870 var obj = {}, 1871 props = [], 1872 first = prepend || values[0], 1873 i, p, a, j, r, l, seamless, last; 1874 correlate = (typeof(correlate) === "string") ? ","+correlate+"," : _correlate; 1875 if (curviness == null) { 1876 curviness = 1; 1877 } 1878 for (p in values[0]) { 1879 props.push(p); 1880 } 1881 //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) 1882 if (values.length > 1) { 1883 last = values[values.length - 1]; 1884 seamless = true; 1885 i = props.length; 1886 while (--i > -1) { 1887 p = props[i]; 1888 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 1889 seamless = false; 1890 break; 1891 } 1892 } 1893 if (seamless) { 1894 values = values.concat(); //duplicate the array to avoid contaminating the original which the user may be reusing for other tweens 1895 if (prepend) { 1896 values.unshift(prepend); 1897 } 1898 values.push(values[1]); 1899 prepend = values[values.length - 3]; 1900 } 1901 } 1902 _r1.length = _r2.length = _r3.length = 0; 1903 i = props.length; 1904 while (--i > -1) { 1905 p = props[i]; 1906 _corProps[p] = (correlate.indexOf(","+p+",") !== -1); 1907 obj[p] = _parseAnchors(values, p, _corProps[p], prepend); 1908 } 1909 i = _r1.length; 1910 while (--i > -1) { 1911 _r1[i] = Math.sqrt(_r1[i]); 1912 _r2[i] = Math.sqrt(_r2[i]); 1913 } 1914 if (!basic) { 1915 i = props.length; 1916 while (--i > -1) { 1917 if (_corProps[p]) { 1918 a = obj[props[i]]; 1919 l = a.length - 1; 1920 for (j = 0; j < l; j++) { 1921 r = a[j+1].da / _r2[j] + a[j].da / _r1[j]; 1922 _r3[j] = (_r3[j] || 0) + r * r; 1923 } 1924 } 1925 } 1926 i = _r3.length; 1927 while (--i > -1) { 1928 _r3[i] = Math.sqrt(_r3[i]); 1929 } 1930 } 1931 i = props.length; 1932 j = quadratic ? 4 : 1; 1933 while (--i > -1) { 1934 p = props[i]; 1935 a = obj[p]; 1936 _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 1937 if (seamless) { 1938 a.splice(0, j); 1939 a.splice(a.length - j, j); 1940 } 1941 } 1942 return obj; 1943 }, 1944 _parseBezierData = function(values, type, prepend) { 1945 type = type || "soft"; 1946 var obj = {}, 1947 inc = (type === "cubic") ? 3 : 2, 1948 soft = (type === "soft"), 1949 props = [], 1950 a, b, c, d, cur, i, j, l, p, cnt, tmp; 1951 if (soft && prepend) { 1952 values = [prepend].concat(values); 1953 } 1954 if (values == null || values.length < inc + 1) { throw "invalid Bezier data"; } 1955 for (p in values[0]) { 1956 props.push(p); 1957 } 1958 i = props.length; 1959 while (--i > -1) { 1960 p = props[i]; 1961 obj[p] = cur = []; 1962 cnt = 0; 1963 l = values.length; 1964 for (j = 0; j < l; j++) { 1965 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); 1966 if (soft) if (j > 1) if (j < l - 1) { 1967 cur[cnt++] = (a + cur[cnt-2]) / 2; 1968 } 1969 cur[cnt++] = a; 1970 } 1971 l = cnt - inc + 1; 1972 cnt = 0; 1973 for (j = 0; j < l; j += inc) { 1974 a = cur[j]; 1975 b = cur[j+1]; 1976 c = cur[j+2]; 1977 d = (inc === 2) ? 0 : cur[j+3]; 1978 cur[cnt++] = tmp = (inc === 3) ? new Segment(a, b, c, d) : new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c); 1979 } 1980 cur.length = cnt; 1981 } 1982 return obj; 1983 }, 1984 _addCubicLengths = function(a, steps, resolution) { 1985 var inc = 1 / resolution, 1986 j = a.length, 1987 d, d1, s, da, ca, ba, p, i, inv, bez, index; 1988 while (--j > -1) { 1989 bez = a[j]; 1990 s = bez.a; 1991 da = bez.d - s; 1992 ca = bez.c - s; 1993 ba = bez.b - s; 1994 d = d1 = 0; 1995 for (i = 1; i <= resolution; i++) { 1996 p = inc * i; 1997 inv = 1 - p; 1998 d = d1 - (d1 = (p * p * da + 3 * inv * (p * ca + inv * ba)) * p); 1999 index = j * resolution + i - 1; 2000 steps[index] = (steps[index] || 0) + d * d; 2001 } 2002 } 2003 }, 2004 _parseLengthData = function(obj, resolution) { 2005 resolution = resolution >> 0 || 6; 2006 var a = [], 2007 lengths = [], 2008 d = 0, 2009 total = 0, 2010 threshold = resolution - 1, 2011 segments = [], 2012 curLS = [], //current length segments array 2013 p, i, l, index; 2014 for (p in obj) { 2015 _addCubicLengths(obj[p], a, resolution); 2016 } 2017 l = a.length; 2018 for (i = 0; i < l; i++) { 2019 d += Math.sqrt(a[i]); 2020 index = i % resolution; 2021 curLS[index] = d; 2022 if (index === threshold) { 2023 total += d; 2024 index = (i / resolution) >> 0; 2025 segments[index] = curLS; 2026 lengths[index] = total; 2027 d = 0; 2028 curLS = []; 2029 } 2030 } 2031 return {length:total, lengths:lengths, segments:segments}; 2032 }, 2033 2034 2035 2036 BezierPlugin = _gsScope._gsDefine.plugin({ 2037 propName: "bezier", 2038 priority: -1, 2039 version: "1.3.3", 2040 API: 2, 2041 global:true, 2042 2043 //gets called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 2044 init: function(target, vars, tween) { 2045 this._target = target; 2046 if (vars instanceof Array) { 2047 vars = {values:vars}; 2048 } 2049 this._func = {}; 2050 this._round = {}; 2051 this._props = []; 2052 this._timeRes = (vars.timeResolution == null) ? 6 : parseInt(vars.timeResolution, 10); 2053 var values = vars.values || [], 2054 first = {}, 2055 second = values[0], 2056 autoRotate = vars.autoRotate || tween.vars.orientToBezier, 2057 p, isFunc, i, j, prepend; 2058 2059 this._autoRotate = autoRotate ? (autoRotate instanceof Array) ? autoRotate : [["x","y","rotation",((autoRotate === true) ? 0 : Number(autoRotate) || 0)]] : null; 2060 for (p in second) { 2061 this._props.push(p); 2062 } 2063 2064 i = this._props.length; 2065 while (--i > -1) { 2066 p = this._props[i]; 2067 2068 this._overwriteProps.push(p); 2069 isFunc = this._func[p] = (typeof(target[p]) === "function"); 2070 first[p] = (!isFunc) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ](); 2071 if (!prepend) if (first[p] !== values[0][p]) { 2072 prepend = first; 2073 } 2074 } 2075 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); 2076 this._segCount = this._beziers[p].length; 2077 2078 if (this._timeRes) { 2079 var ld = _parseLengthData(this._beziers, this._timeRes); 2080 this._length = ld.length; 2081 this._lengths = ld.lengths; 2082 this._segments = ld.segments; 2083 this._l1 = this._li = this._s1 = this._si = 0; 2084 this._l2 = this._lengths[0]; 2085 this._curSeg = this._segments[0]; 2086 this._s2 = this._curSeg[0]; 2087 this._prec = 1 / this._curSeg.length; 2088 } 2089 2090 if ((autoRotate = this._autoRotate)) { 2091 this._initialRotations = []; 2092 if (!(autoRotate[0] instanceof Array)) { 2093 this._autoRotate = autoRotate = [autoRotate]; 2094 } 2095 i = autoRotate.length; 2096 while (--i > -1) { 2097 for (j = 0; j < 3; j++) { 2098 p = autoRotate[i][j]; 2099 this._func[p] = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ] : false;
2100 } 2101 p = autoRotate[i][2]; 2102 this._initialRotations[i] = this._func[p] ? this._func[p].call(this._target) : this._target[p]; 2103 } 2104 } 2105 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. 2106 return true; 2107 }, 2108 2109 //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.) 2110 set: function(v) { 2111 var segments = this._segCount, 2112 func = this._func, 2113 target = this._target, 2114 notStart = (v !== this._startRatio), 2115 curIndex, inv, i, p, b, t, val, l, lengths, curSeg; 2116 if (!this._timeRes) { 2117 curIndex = (v < 0) ? 0 : (v >= 1) ? segments - 1 : (segments * v) >> 0; 2118 t = (v - (curIndex * (1 / segments))) * segments; 2119 } else { 2120 lengths = this._lengths; 2121 curSeg = this._curSeg; 2122 v *= this._length; 2123 i = this._li; 2124 //find the appropriate segment (if the currently cached one isn't correct) 2125 if (v > this._l2 && i < segments - 1) { 2126 l = segments - 1; 2127 while (i < l && (this._l2 = lengths[++i]) <= v) { } 2128 this._l1 = lengths[i-1]; 2129 this._li = i; 2130 this._curSeg = curSeg = this._segments[i]; 2131 this._s2 = curSeg[(this._s1 = this._si = 0)]; 2132 } else if (v < this._l1 && i > 0) { 2133 while (i > 0 && (this._l1 = lengths[--i]) >= v) { } 2134 if (i === 0 && v < this._l1) { 2135 this._l1 = 0; 2136 } else { 2137 i++; 2138 } 2139 this._l2 = lengths[i]; 2140 this._li = i; 2141 this._curSeg = curSeg = this._segments[i]; 2142 this._s1 = curSeg[(this._si = curSeg.length - 1) - 1] || 0; 2143 this._s2 = curSeg[this._si]; 2144 } 2145 curIndex = i; 2146 //now find the appropriate sub-segment (we split it into the number of pieces that was defined by "precision" and measured each one) 2147 v -= this._l1; 2148 i = this._si; 2149 if (v > this._s2 && i < curSeg.length - 1) { 2150 l = curSeg.length - 1; 2151 while (i < l && (this._s2 = curSeg[++i]) <= v) { } 2152 this._s1 = curSeg[i-1]; 2153 this._si = i; 2154 } else if (v < this._s1 && i > 0) { 2155 while (i > 0 && (this._s1 = curSeg[--i]) >= v) { } 2156 if (i === 0 && v < this._s1) { 2157 this._s1 = 0; 2158 } else { 2159 i++; 2160 } 2161 this._s2 = curSeg[i]; 2162 this._si = i; 2163 } 2164 t = (i + (v - this._s1) / (this._s2 - this._s1)) * this._prec; 2165 } 2166 inv = 1 - t; 2167 2168 i = this._props.length; 2169 while (--i > -1) { 2170 p = this._props[i]; 2171 b = this._beziers[p][curIndex]; 2172 val = (t * t * b.da + 3 * inv * (t * b.ca + inv * b.ba)) * t + b.a; 2173 if (this._round[p]) { 2174 val = Math.round(val); 2175 } 2176 if (func[p]) { 2177 target[p](val); 2178 } else { 2179 target[p] = val; 2180 } 2181 } 2182 2183 if (this._autoRotate) { 2184 var ar = this._autoRotate, 2185 b2, x1, y1, x2, y2, add, conv; 2186 i = ar.length; 2187 while (--i > -1) { 2188 p = ar[i][2]; 2189 add = ar[i][3] || 0; 2190 conv = (ar[i][4] === true) ? 1 : _RAD2DEG; 2191 b = this._beziers[ar[i][0]]; 2192 b2 = this._beziers[ar[i][1]]; 2193 2194 if (b && b2) { //in case one of the properties got overwritten. 2195 b = b[curIndex]; 2196 b2 = b2[curIndex]; 2197 2198 x1 = b.a + (b.b - b.a) * t; 2199 x2 = b.b + (b.c - b.b) * t; 2200 x1 += (x2 - x1) * t; 2201 x2 += ((b.c + (b.d - b.c) * t) - x2) * t; 2202 2203 y1 = b2.a + (b2.b - b2.a) * t; 2204 y2 = b2.b + (b2.c - b2.b) * t; 2205 y1 += (y2 - y1) * t; 2206 y2 += ((b2.c + (b2.d - b2.c) * t) - y2) * t; 2207 2208 val = notStart ? Math.atan2(y2 - y1, x2 - x1) * conv + add : this._initialRotations[i]; 2209 2210 if (func[p]) { 2211 target[p](val); 2212 } else { 2213 target[p] = val; 2214 } 2215 } 2216 } 2217 } 2218 } 2219 }), 2220 p = BezierPlugin.prototype; 2221 2222 2223 BezierPlugin.bezierThrough = bezierThrough; 2224 BezierPlugin.cubicToQuadratic = cubicToQuadratic; 2225 BezierPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite 2226 BezierPlugin.quadraticToCubic = function(a, b, c) { 2227 return new Segment(a, (2 * b + a) / 3, (2 * b + c) / 3, c); 2228 }; 2229 2230 BezierPlugin._cssRegister = function() { 2231 var CSSPlugin = _gsScope._gsDefine.globals.CSSPlugin; 2232 if (!CSSPlugin) { 2233 return; 2234 } 2235 var _internals = CSSPlugin._internals, 2236 _parseToProxy = _internals._parseToProxy, 2237 _setPluginRatio = _internals._setPluginRatio, 2238 CSSPropTween = _internals.CSSPropTween; 2239 _internals._registerComplexSpecialProp("bezier", {parser:function(t, e, prop, cssp, pt, plugin) { 2240 if (e instanceof Array) { 2241 e = {values:e}; 2242 } 2243 plugin = new BezierPlugin(); 2244 var values = e.values, 2245 l = values.length - 1, 2246 pluginValues = [], 2247 v = {}, 2248 i, p, data; 2249 if (l < 0) { 2250 return pt; 2251 } 2252 for (i = 0; i <= l; i++) { 2253 data = _parseToProxy(t, values[i], cssp, pt, plugin, (l !== i)); 2254 pluginValues[i] = data.end; 2255 } 2256 for (p in e) { 2257 v[p] = e[p]; //duplicate the vars object because we need to alter some things which w
2257ould cause problems if the user plans to reuse the same vars object for another tween. 2258 } 2259 v.values = pluginValues; 2260 pt = new CSSPropTween(t, "bezier", 0, 0, data.pt, 2); 2261 pt.data = data; 2262 pt.plugin = plugin; 2263 pt.setRatio = _setPluginRatio; 2264 if (v.autoRotate === 0) { 2265 v.autoRotate = true; 2266 } 2267 if (v.autoRotate && !(v.autoRotate instanceof Array)) { 2268 i = (v.autoRotate === true) ? 0 : Number(v.autoRotate); 2269 v.autoRotate = (data.end.left != null) ? [["left","top","rotation",i,false]] : (data.end.x != null) ? [["x","y","rotation",i,false]] : false; 2270 } 2271 if (v.autoRotate) { 2272 if (!cssp._transform) { 2273 cssp._enableTransforms(false); 2274 } 2275 data.autoRotate = cssp._target._gsTransform; 2276 } 2277 plugin._onInitTween(data.proxy, v, cssp._tween); 2278 return pt; 2279 }}); 2280 }; 2281 2282 p._roundProps = function(lookup, value) { 2283 var op = this._overwriteProps, 2284 i = op.length; 2285 while (--i > -1) { 2286 if (lookup[op[i]] || lookup.bezier || lookup.bezierThrough) { 2287 this._round[op[i]] = value; 2288 } 2289 } 2290 }; 2291 2292 p._kill = function(lookup) { 2293 var a = this._props, 2294 p, i; 2295 for (p in this._beziers) { 2296 if (p in lookup) { 2297 delete this._beziers[p]; 2298 delete this._func[p]; 2299 i = a.length; 2300 while (--i > -1) { 2301 if (a[i] === p) { 2302 a.splice(i, 1); 2303 } 2304 } 2305 } 2306 } 2307 return this._super._kill.call(this, lookup); 2308 }; 2309 2310 }()); 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325/* 2326 * ---------------------------------------------------------------- 2327 * CSSPlugin 2328 * ---------------------------------------------------------------- 2329 */ 2330 _gsScope._gsDefine("plugins.CSSPlugin", ["plugins.TweenPlugin","TweenLite"], function(TweenPlugin, TweenLite) { 2331 2332 /** @constructor **/ 2333 var CSSPlugin = function() { 2334 TweenPlugin.call(this, "css"); 2335 this._overwriteProps.length = 0; 2336 this.setRatio = CSSPlugin.prototype.setRatio; //speed optimization (avoid prototype lookup on this "hot" method) 2337 }, 2338 _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. 2339 _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 2340 _cs, //computed style (we store this in a shared variable to conserve memory and make minification tighter 2341 _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. 2342 _specialProps = {}, 2343 p = CSSPlugin.prototype = new TweenPlugin("css"); 2344 2345 p.constructor = CSSPlugin; 2346 CSSPlugin.version = "1.14.2"; 2347 CSSPlugin.API = 2; 2348 CSSPlugin.defaultTransformPerspective = 0; 2349 CSSPlugin.defaultSkewType = "compensated"; 2350 p = "px"; //we'll reuse the "p" variable to keep file size down 2351 CSSPlugin.suffixMap = {top:p, right:p, bottom:p, left:p, width:p, height:p, fontSize:p, padding:p, margin:p, perspective:p, lineHeight:""}; 2352 2353 2354 var _numExp = /(?:\d|\-\d|\.\d|\-\.\d)+/g, 2355 _relNumExp = /(?:\d|\-\d|\.\d|\-\.\d|\+=\d|\-=\d|\+=.\d|\-=\.\d)+/g, 2356 _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)" 2357 _NaNExp = /(?![+-]?\d*\.?\d+|e[+-]\d+)[^0-9]/g, //also allows scientific notation 2358 _suffixExp = /(?:\d|\-|\+|=|#|\.)*/g, 2359 _opacityExp = /opacity *= *([^)]*)/i, 2360 _opacityValExp = /opacity:([^;]*)/i, 2361 _alphaFilterExp = /alpha\(opacity *=.+?\)/i, 2362 _rgbhslExp = /^(rgb|hsl)/, 2363 _capsExp = /([A-Z])/g, 2364 _camelExp = /-([a-z])/gi, 2365 _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) 2366 _camelFunc = function(s, g) { return g.toUpperCase(); }, 2367 _horizExp = /(?:Left|Right|Width)/i, 2368 _ieGetMatrixExp = /(M11|M12|M21|M22)=[\d\-\.e]+/gi,
2369 _ieSetMatrixExp = /progid\:DXImageTransform\.Microsoft\.Matrix\(.+?\)/i, 2370 _commasOutsideParenExp = /,(?=[^\)]*(?:\(|$))/gi, //finds any commas that are not within parenthesis 2371 _DEG2RAD = Math.PI / 180, 2372 _RAD2DEG = 180 / Math.PI, 2373 _forcePT = {}, 2374 _doc = document, 2375 _tempDiv = _doc.createElement("div"), 2376 _tempImg = _doc.createElement("img"), 2377 _internals = CSSPlugin._internals = {_specialProps:_specialProps}, //provides a hook to a few internal methods that we need to access from inside other plugins 2378 _agent = navigator.userAgent, 2379 _autoRound, 2380 _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). 2381 2382 _isSafari, 2383 _isFirefox, //Firefox has a bug that causes 3D transformed elements to randomly disappear unless a repaint is forced after each update on each element. 2384 _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!) 2385 _ieVers, 2386 _supportsOpacity = (function() { //we set _isSafari, _ieVers, _isFirefox, and _supportsOpacity all in one function here to reduce file size slightly, especially in the minified version. 2387 var i = _agent.indexOf("Android"), 2388 d = _doc.createElement("div"), a; 2389 2390 _isSafari = (_agent.indexOf("Safari") !== -1 && _agent.indexOf("Chrome") === -1 && (i === -1 || Number(_agent.substr(i+8, 1)) > 3)); 2391 _isSafariLT6 = (_isSafari && (Number(_agent.substr(_agent.indexOf("Version/")+8, 1)) < 6)); 2392 _isFirefox = (_agent.indexOf("Firefox") !== -1); 2393 if ((/MSIE ([0-9]{1,}[\.0-9]{0,})/).exec(_agent) || (/Trident\/.*rv:([0-9]{1,}[\.0-9]{0,})/).exec(_agent)) { 2394 _ieVers = parseFloat( RegExp.$1 ); 2395 } 2396 d.innerHTML = "<a style='top:1px;opacity:.55;'>a</a>"; 2397 a = d.getElementsByTagName("a")[0]; 2398 return a ? /^0.55/.test(a.style.opacity) : false; 2399 }()), 2400 _getIEOpacity = function(v) { 2401 return (_opacityExp.test( ((typeof(v) === "string") ? v : (v.currentStyle ? v.currentStyle.filter : v.style.filter) || "") ) ? ( parseFloat( RegExp.$1 ) / 100 ) : 1); 2402 }, 2403 _log = function(s) {//for logging messages, but in a way that won't throw errors in old versions of IE. 2404 if (window.console) { 2405 console.log(s); 2406 } 2407 }, 2408 2409 _prefixCSS = "", //the non-camelCase vendor prefix like "-o-", "-moz-", "-ms-", or "-webkit-" 2410 _prefix = "", //camelCase vendor prefix like "O", "ms", "Webkit", or "Moz". 2411 2412 // @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) 2413 _checkPropPrefix = function(p, e) { 2414 e = e || _tempDiv; 2415 var s = e.style, 2416 a, i; 2417 if (s[p] !== undefined) { 2418 return p; 2419 } 2420 p = p.charAt(0).toUpperCase() + p.substr(1); 2421 a = ["O","Moz","ms","Ms","Webkit"]; 2422 i = 5; 2423 while (--i > -1 && s[a[i]+p] === undefined) { } 2424 if (i >= 0) { 2425 _prefix = (i === 3) ? "ms" : a[i]; 2426 _prefixCSS = "-" + _prefix.toLowerCase() + "-"; 2427 return _prefix + p; 2428 } 2429 return null; 2430 }, 2431 2432 _getComputedStyle = _doc.defaultView ? _doc.defaultView.getComputedStyle : function() {}, 2433 2434 /** 2435 * @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: 2436 * var currentLeft = CSSPlugin.getStyle( document.getElementById("myElement"), "left"); 2437 * 2438 * @param {!Object} t Target element whose style property you want to query 2439 * @param {!string} p Property name (like "left" or "top" or "marginTop", etc.) 2440 * @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. 2441 * @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. 2442 * @param {string=} dflt Default value that should be returned in the place of null, "none", "auto" or "auto auto". 2443 * @return {?string} The current property value 2444 */ 2445 _getStyle = CSSPlugin.getStyle = function(t, p, cs, calc, dflt) { 2446 var rv; 2447 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. 2448 return _getIEOpacity(t); 2449 } 2450 if (!calc && t.style[p]) { 2451 rv = t.style[p]; 2452 } else if ((cs = cs || _getComputedStyle(t))) { 2453 rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase()); 2454 } else if (t.currentStyle) { 2455 rv = t.currentStyle[p]; 2456 } 2457 return (dflt != null && (!rv || rv === "none" || rv === "auto" || rv === "auto auto")) ? dflt : rv; 2458 }, 2459 2460 /** 2461 * @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. 2462 * @param {!Object} t Target element 2463 * @param {!string} p Property name (like "left", "top", "marginLeft", etc.) 2464 * @param {!number} v Value 2465 * @param {string=} sfx Suffix (like "px" or "%" or "em") 2466 * @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. 2467 * @return {number} value in pixels 2468 */ 2469 _convertToPixels = _internals.convertToPixels = function(t, p, v, sfx, recurse) { 2470 if (sfx === "px" || !sfx) { return v; } 2471 if (sfx === "auto" || !v) { return 0; } 2472 var horiz = _horizExp.test(p), 2473 node = t, 2474 style = _tempDiv.style, 2475 neg = (v < 0), 2476 pix, cache, time; 2477 if (neg) { 2478 v = -v; 2479 } 2480 if (sfx === "%" && p.indexOf("border") !== -1) { 2481 pix = (v / 100) * (horiz ? t.clientWidth : t.clientHeight); 2482 } else { 2483 style.cssText = "border:0 solid red;position:" + _getStyle(t, "position") + ";line-height:0;"; 2484 if (sfx === "%" || !node.appendChild) { 2485 node = t.parentNode || _doc.body; 2486 cache = node._gsCache; 2487 time = TweenLite.ticker.frame; 2488 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) 2489 return cache.width * v / 100; 2490 } 2491 style[(horiz ? "width" : "height")] = v + sfx; 2492 } else { 2493 style[(horiz ? "borderLeftWidth" : "borderTopWidth")] = v + sfx; 2494 } 2495 node.appendChild(_tempDiv); 2496 pix = parseFloat(_tempDiv[(horiz ? "offsetWidth" : "offsetHeight")]); 2497 node.removeChild(_tempDiv); 2498 if (horiz && sfx === "%" && CSSPlugin.cacheWidths !== false) { 2499 cache = node._gsCache = node._gsCache || {}; 2500 cache.time = time; 2501 cache.width = pix / v * 100; 2502 } 2503 if (pix === 0 && !recurse) { 2504 pix = _convertToPixels(t, p, v, sfx, true); 2505 } 2506 } 2507 return neg ? -pix : pix; 2508 }, 2509 _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 2510 if (_getStyle(t, "position", cs) !== "absolute") { return 0; } 2511 var dim = ((p === "left") ? "Left" : "Top"),
2512 v = _getStyle(t, "margin" + dim, cs); 2513 return t["offset" + dim] - (_convertToPixels(t, p, parseFloat(v), v.replace(_suffixExp, "")) || 0); 2514 }, 2515 2516 // @private returns at object containing ALL of the style properties in camelCase and their associated values. 2517 _getAllStyles = function(t, cs) { 2518 var s = {}, 2519 i, tr; 2520 if ((cs = cs || _getComputedStyle(t, null))) { 2521 if ((i = cs.length)) { 2522 while (--i > -1) { 2523 s[cs[i].replace(_camelExp, _camelFunc)] = cs.getPropertyValue(cs[i]); 2524 } 2525 } else { //Opera behaves differently - cs.length is always 0, so we must do a for...in loop. 2526 for (i in cs) { 2527 s[i] = cs[i]; 2528 } 2529 } 2530 } else if ((cs = t.currentStyle || t.style)) { 2531 for (i in cs) { 2532 if (typeof(i) === "string" && s[i] === undefined) { 2533 s[i.replace(_camelExp, _camelFunc)] = cs[i]; 2534 } 2535 } 2536 } 2537 if (!_supportsOpacity) { 2538 s.opacity = _getIEOpacity(t); 2539 } 2540 tr = _getTransform(t, cs, false); 2541 s.rotation = tr.rotation; 2542 s.skewX = tr.skewX; 2543 s.scaleX = tr.scaleX; 2544 s.scaleY = tr.scaleY; 2545 s.x = tr.x; 2546 s.y = tr.y; 2547 if (_supports3D) { 2548 s.z = tr.z; 2549 s.rotationX = tr.rotationX; 2550 s.rotationY = tr.rotationY; 2551 s.scaleZ = tr.scaleZ; 2552 } 2553 if (s.filters) { 2554 delete s.filters; 2555 } 2556 return s; 2557 }, 2558 2559 // @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
2559ontaining 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. 2560 _cssDif = function(t, s1, s2, vars, forceLookup) { 2561 var difs = {}, 2562 style = t.style, 2563 val, p, mpt; 2564 for (p in s2) { 2565 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") { 2566 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. 2567 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. 2568 mpt = new MiniPropTween(style, p, style[p], mpt); 2569 } 2570 } 2571 } 2572 if (vars) { 2573 for (p in vars) { //copy properties (except className) 2574 if (p !== "className") { 2575 difs[p] = vars[p]; 2576 } 2577 } 2578 } 2579 return {difs:difs, firstMPT:mpt}; 2580 }, 2581 _dimensions = {width:["Left","Right"], height:["Top","Bottom"]}, 2582 _margins = ["marginLeft","marginRight","marginTop","marginBottom"], 2583 2584 /** 2585 * @private Gets the width or height of an element 2586 * @param {!Object} t Target element 2587 * @param {!string} p Property name ("width" or "height") 2588 * @param {Object=} cs Computed style object (if one exists). Just a speed optimization. 2589 * @return {number} Dimension (in pixels) 2590 */ 2591 _getDimension = function(t, p, cs) { 2592 var v = parseFloat((p === "width") ? t.offsetWidth : t.offsetHeight), 2593 a = _dimensions[p], 2594 i = a.length; 2595 cs = cs || _getComputedStyle(t, null); 2596 while (--i > -1) { 2597 v -= parseFloat( _getStyle(t, "padding" + a[i], cs, true) ) || 0; 2598 v -= parseFloat( _getStyle(t, "border" + a[i] + "Width", cs, true) ) || 0; 2599 } 2600 return v; 2601 }, 2602 2603 // @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) 2604 _parsePosition = function(v, recObj) { 2605 if (v == null || v === "" || v === "auto" || v === "auto auto") { //note: Firefox uses "auto auto" as default whereas Chrome uses "auto". 2606 v = "0 0"; 2607 } 2608 var a = v.split(" "), 2609 x = (v.indexOf("left") !== -1) ? "0%" : (v.indexOf("right") !== -1) ? "100%" : a[0], 2610 y = (v.indexOf("top") !== -1) ? "0%" : (v.indexOf("bottom") !== -1) ? "100%" : a[1]; 2611 if (y == null) { 2612 y = "0"; 2613 } else if (y === "center") { 2614 y = "50%"; 2615 } 2616 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
2616ould be used to describe horizontal or vertical, hence the isNaN(). If there's an "=" sign in the value, it's relative. 2617 x = "50%"; 2618 } 2619 if (recObj) { 2620 recObj.oxp = (x.indexOf("%") !== -1); 2621 recObj.oyp = (y.indexOf("%") !== -1); 2622 recObj.oxr = (x.charAt(1) === "="); 2623 recObj.oyr = (y.charAt(1) === "="); 2624 recObj.ox = parseFloat(x.replace(_NaNExp, "")); 2625 recObj.oy = parseFloat(y.replace(_NaNExp, "")); 2626 } 2627 return x + " " + y + ((a.length > 2) ? " " + a[2] : ""); 2628 }, 2629 2630 /** 2631 * @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!) 2632 * @param {(number|string)} e End value which is typically a string, but could be a number 2633 * @param {(number|string)} b Beginning value which is typically a string but could be a number 2634 * @return {number} Amount of change between the beginning and ending values (relative values that have a "+=" or "-=" are recognized) 2635 */ 2636 _parseChange = function(e, b) { 2637 return (typeof(e) === "string" && e.charAt(1) === "=") ? parseInt(e.charAt(0) + "1", 10) * parseFloat(e.substr(2)) : parseFloat(e) - parseFloat(b); 2638 }, 2639 2640 /** 2641 * @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. 2642 * @param {Object} v Value to be parsed 2643 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter) 2644 * @return {number} Parsed value 2645 */ 2646 _parseVal = function(v, d) { 2647 return (v == null) ? d : (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * parseFloat(v.substr(2)) + d : parseFloat(v); 2648 }, 2649 2650 /** 2651 * @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. 2652 * @param {Object} v Value to be parsed 2653 * @param {!number} d Default value (which is also used for relative calculations if "+=" or "-=" is found in the first parameter) 2654 * @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" 2655 * @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. 2656 * @return {number} parsed angle in radians 2657 */ 2658 _parseAngle = function(v, d, p, directionalEnd) { 2659 var min = 0.000001, 2660 cap, split, dif, result; 2661 if (v == null) { 2662 result = d; 2663 } else if (typeof(v) === "number") { 2664 result = v; 2665 } else { 2666 cap = 360; 2667 split = v.split("_"); 2668 dif = Number(split[0].replace(_NaNExp, "")) * ((v.indexOf("rad") === -1) ? 1 : _RAD2DEG) - ((v.charAt(1) === "=") ? 0 : d); 2669 if (split.length) { 2670 if (directionalEnd) { 2671 directionalEnd[p] = d + dif; 2672 } 2673 if (v.indexOf("short") !== -1) { 2674 dif = dif % cap; 2675 if (dif !== dif % (cap / 2)) { 2676 dif = (dif < 0) ? dif + cap : dif - cap; 2677 } 2678 } 2679 if (v.indexOf("_cw") !== -1 && dif < 0) { 2680 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 2681 } else if (v.indexOf("ccw") !== -1 && dif > 0) { 2682 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 2683 } 2684 } 2685 result = d + dif; 2686 } 2687 if (result < min && result > -min) { 2688 result = 0; 2689 } 2690 return result; 2691 }, 2692 2693 _colorLookup = {aqua:[0,255,255], 2694 lime:[0,255,0], 2695 silver:[192,192,192], 2696 black:[0,0,0], 2697 maroon:[128,0,0], 2698 teal:[0,128,128], 2699 blue:[0,0,255], 2700 navy:[0,0,128], 2701 white:[255,255,255], 2702 fuchsia:[255,0,255], 2703 olive:[128,128,0], 2704 yellow:[255,255,0], 2705 orange:[255,165,0], 2706 gray:[128,128,128], 2707 purple:[128,0,128], 2708 green:[0,128,0], 2709 red:[255,0,0], 2710 pink:[255,192,203], 2711 cyan:[0,255,255], 2712 transparent:[255,255,255,0]}, 2713 2714 _hue = function(h, m1, m2) { 2715 h = (h < 0) ? h + 1 : (h > 1) ? h - 1 : h; 2716 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; 2717 }, 2718 2719 /** 2720 * @private Parses a color (like #9F0, #FF9900, or rgb(255,51,153)) into an array with 3 elements for red, green, and blue. Also handles rgba() values (splits into array of 4 elements of course) 2721 * @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. 2722 * @return {Array.<number>} An array containing red, green, and blue (and optionally alpha) in that order. 2723 */ 2724 _parseColor = CSSPlugin.parseColor = function(v) { 2725 var c1, c2, c3, h, s, l; 2726 if (!v || v === "") { 2727 return _colorLookup.black; 2728 } 2729 if (typeof(v) === "number") { 2730 return [v >> 16, (v >> 8) & 255, v & 255]; 2731 } 2732 if (v.charAt(v.length - 1) === ",") { //sometimes a trailing commma 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. 2733 v = v.substr(0, v.length - 1); 2734 } 2735 if (_colorLookup[v]) { 2736 return _colorLookup[v]; 2737 } 2738 if (v.charAt(0) === "#") { 2739 if (v.length === 4) { //for shorthand like #9F0 2740 c1 = v.charAt(1), 2741 c2 = v.charAt(2), 2742 c3 = v.charAt(3); 2743 v = "#" + c1 + c1 + c2 + c2 + c3 + c3; 2744 } 2745 v = parseInt(v.substr(1), 16); 2746 return [v >> 16, (v >> 8) & 255, v & 255]; 2747 } 2748 if (v.substr(0, 3) === "hsl") { 2749 v = v.match(_numExp); 2750 h = (Number(v[0]) % 360) / 360;
2751 s = Number(v[1]) / 100; 2752 l = Number(v[2]) / 100; 2753 c2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s; 2754 c1 = l * 2 - c2; 2755 if (v.length > 3) { 2756 v[3] = Number(v[3]); 2757 } 2758 v[0] = _hue(h + 1 / 3, c1, c2); 2759 v[1] = _hue(h, c1, c2); 2760 v[2] = _hue(h - 1 / 3, c1, c2); 2761 return v; 2762 } 2763 v = v.match(_numExp) || _colorLookup.transparent; 2764 v[0] = Number(v[0]); 2765 v[1] = Number(v[1]); 2766 v[2] = Number(v[2]); 2767 if (v.length > 3) { 2768 v[3] = Number(v[3]); 2769 } 2770 return v; 2771 }, 2772 _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. 2773 2774 for (p in _colorLookup) { 2775 _colorExp += "|" + p + "\\b"; 2776 } 2777 _colorExp = new RegExp(_colorExp+")", "gi"); 2778 2779 /** 2780 * @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. 2781 * @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. 2782 * @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. 2783 * @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. 2784 * @return {Function} formatter function 2785 */ 2786 var _getFormatter = function(dflt, clr, collapsible, multi) { 2787 if (dflt == null) { 2788 return function(v) {return v;}; 2789 } 2790 var dColor = clr ? (dflt.match(_colorExp) || [""])[0] : "", 2791 dVals = dflt.split(dColor).join("").match(_valuesExp) || [], 2792 pfx = dflt.substr(0, dflt.indexOf(dVals[0])), 2793 sfx = (dflt.charAt(dflt.length - 1) === ")") ? ")" : "", 2794 delim = (dflt.indexOf(" ") !== -1) ? " " : ",", 2795 numVals = dVals.length, 2796 dSfx = (numVals > 0) ? dVals[0].replace(_numExp, "") : "", 2797 formatter; 2798 if (!numVals) { 2799 return function(v) {return v;}; 2800 } 2801 if (clr) { 2802 formatter = function(v) { 2803 var color, vals, i, a; 2804 if (typeof(v) === "number") { 2805 v += dSfx; 2806 } else if (multi && _commasOutsideParenExp.test(v)) { 2807 a = v.replace(_commasOutsideParenExp, "|").split("|"); 2808 for (i = 0; i < a.length; i++) { 2809 a[i] = formatter(a[i]); 2810 } 2811 return a.join(","); 2812 } 2813 color = (v.match(_colorExp) || [dColor])[0]; 2814 vals = v.split(color).join("").match(_valuesExp) || []; 2815 i = vals.length; 2816 if (numVals > i--) { 2817 while (++i < numVals) { 2818 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i]; 2819 } 2820 } 2821 return pfx + vals.join(delim) + delim + color + sfx + (v.indexOf("inset") !== -1 ? " inset" : ""); 2822 }; 2823 return formatter; 2824 2825 } 2826 formatter = function(v) { 2827 var vals, a, i; 2828 if (typeof(v) === "number") { 2829 v += dSfx; 2830 } else if (multi && _commasOutsideParenExp.test(v)) { 2831 a = v.replace(_commasOutsideParenExp, "|").split("|"); 2832 for (i = 0; i < a.length; i++) { 2833 a[i] = formatter(a[i]); 2834 } 2835 return a.join(","); 2836 } 2837 vals = v.match(_valuesExp) || []; 2838 i = vals.length; 2839 if (numVals > i--) { 2840 while (++i < numVals) { 2841 vals[i] = collapsible ? vals[(((i - 1) / 2) | 0)] : dVals[i]; 2842 } 2843 } 2844 return pfx + vals.join(delim) + sfx; 2845 }; 2846 return formatter; 2847 }, 2848 2849 /** 2850 * @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. 2851 * @param {!string} props a comma-delimited list of property names in order from top to left, like "marginTop,marginRight,marginBottom,marginLeft" 2852 * @return {Function} a formatter function 2853 */ 2854 _getEdgeParser = function(props) { 2855 props = props.split(","); 2856 return function(t, e, p, cssp, pt, plugin, vars) { 2857 var a = (e + "").split(" "), 2858 i; 2859 vars = {}; 2860 for (i = 0; i < 4; i++) { 2861 vars[props[i]] = a[i] = a[i] || a[(((i - 1) / 2) >> 0)]; 2862 } 2863 return cssp.parse(t, vars, pt, plugin); 2864 }; 2865 }, 2866 2867 // @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. 2868 _setPluginRatio = _internals._setPluginRatio = function(v) { 2869 this.plugin.setRatio(v); 2870 var d = this.data, 2871 proxy = d.proxy, 2872 mpt = d.firstMPT, 2873 min = 0.000001, 2874 val, pt, i, str; 2875 while (mpt) { 2876 val = proxy[mpt.v]; 2877 if (mpt.r) { 2878 val = Math.round(val); 2879 } else if (val < min && val > -min) { 2880 val = 0; 2881 } 2882 mpt.t[mpt.p] = val; 2883 mpt = mpt._next; 2884 } 2885 if (d.autoRotate) { 2886 d.autoRotate.rotation = proxy.rotation; 2887 } 2888 //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. 2889 if (v === 1) { 2890 mpt = d.firstMPT; 2891 while (mpt) { 2892 pt = mpt.t; 2893 if (!pt.type) { 2894 pt.e = pt.s + pt.xs0; 2895 } else if (pt.type === 1) { 2896 str = pt.xs0 + pt.s + pt.xs1; 2897 for (i = 1; i < pt.l; i++) {
2898 str += pt["xn"+i] + pt["xs"+(i+1)]; 2899 } 2900 pt.e = str; 2901 } 2902 mpt = mpt._next; 2903 } 2904 } 2905 }, 2906 2907 /** 2908 * @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. 2909 * @param {!Object} t target object whose property we're tweening (often a CSSPropTween) 2910 * @param {!string} p property name 2911 * @param {(number|string|object)} v value 2912 * @param {MiniPropTween=} next next MiniPropTween in the linked list 2913 * @param {boolean=} r if true, the tweened value should be rounded to the nearest integer 2914 */ 2915 MiniPropTween = function(t, p, v, next, r) { 2916 this.t = t; 2917 this.p = p; 2918 this.v = v; 2919 this.r = r; 2920 if (next) { 2921 next._prev = this; 2922 this._next = next; 2923 } 2924 }, 2925 2926 /** 2927 * @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. 2928 * This method returns an object that has the following properties:
2929 * - 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 2930 * - 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 2931 * - firstMPT: the first MiniPropTween in the linked list 2932 * - 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. 2933 * @param {!Object} t target object to be tweened 2934 * @param {!(Object|string)} vars the object containing the information about the tweening values (typically the end/destination values) that should be parsed 2935 * @param {!CSSPlugin} cssp The CSSPlugin instance 2936 * @param {CSSPropTween=} pt the next CSSPropTween in the linked list 2937 * @param {TweenPlugin=} plugin the external TweenPlugin instance that will be handling tweening the numeric values 2938 * @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. 2939 * @return An object containing the following properties: proxy, end, firstMPT, and pt (see above for descriptions) 2940 */ 2941 _parseToProxy = _internals._parseToProxy = function(t, vars, cssp, pt, plugin, shallow) { 2942 var bpt = pt, 2943 start = {}, 2944 end = {}, 2945 transform = cssp._transform, 2946 oldForce = _forcePT, 2947 i, p, xp, mpt, firstPT; 2948 cssp._transform = null; 2949 _forcePT = vars; 2950 pt = firstPT = cssp.parse(t, vars, pt, plugin); 2951 _forcePT = oldForce; 2952 //break off from the linked list so the new ones are isolated. 2953 if (shallow) { 2954 cssp._transform = transform; 2955 if (bpt) { 2956 bpt._prev = null; 2957 if (bpt._prev) { 2958 bpt._prev._next = null; 2959 } 2960 } 2961 } 2962 while (pt && pt !== bpt) { 2963 if (pt.type <= 1) { 2964 p = pt.p; 2965 end[p] = pt.s + pt.c; 2966 start[p] = pt.s; 2967 if (!shallow) { 2968 mpt = new MiniPropTween(pt, "s", p, mpt, pt.r); 2969 pt.c = 0; 2970 } 2971 if (pt.type === 1) { 2972 i = pt.l; 2973 while (--i > 0) { 2974 xp = "xn" + i; 2975 p = pt.p + "_" + xp; 2976 end[p] = pt.data[xp]; 2977 start[p] = pt[xp]; 2978 if (!shallow) { 2979 mpt = new MiniPropTween(pt, xp, p, mpt, pt.rxp[xp]); 2980 } 2981 } 2982 } 2983 } 2984 pt = pt._next; 2985 } 2986 return {proxy:start, end:end, firstMPT:mpt, pt:firstPT}; 2987 }, 2988 2989 2990 2991 /** 2992 * @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. 2993 * CSSPropTweens have the following optional properties as well (not defined through the constructor): 2994 * - 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. 2995 * - 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) 2996 * - plugin: The TweenPlugin instance that will handle the tweening of any complex values. For example, sometimes we don't want to use normal subt
2996weens (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. 2997 * - 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. 2998 * - 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. 2999 * @param {!Object} t Target object whose property will be tweened. Often a DOM element, but not always. It could be anything. 3000 * @param {string} p Property to tween (name). For example, to tween element.width, p would be "width". 3001 * @param {number} s Starting numeric value 3002 * @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. 3003 * @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. 3004 * @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. 3005 * @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" 3006 * @param {boolean=} r If true, the value(s) should be rounded 3007 * @param {number=} pr Priority in the linked list order. Higher priority CSSPropTweens will be updated before lower priority ones. The default priority is 0. 3008 * @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. 3009 * @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. 3010 */ 3011 CSSPropTween = _internals.CSSPropTween = function(t, p, s, c, next, type, n, r, pr, b, e) { 3012 this.t = t; //target 3013 this.p = p; //property 3014 this.s = s; //starting value 3015 this.c = c; //change value 3016 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) 3017 if (!(t instanceof CSSPropTween)) { 3018 _overwriteProps.push(this.n); 3019 } 3020 this.r = r; //round (boolean) 3021 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 3022 if (pr) { 3023 this.pr = pr; 3024 _hasPriority = true; 3025 } 3026 this.b = (b === undefined) ? s : b; 3027 this.e = (e === undefined) ? s + c : e; 3028 if (next) { 3029 this._next = next; 3030 next._prev = this; 3031 } 3032 }, 3033 3034 /** 3035 * 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: 3036 * 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); 3037 * 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}
3037 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(). 3038 * 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. 3039 * 3040 * @param {!Object} t Target whose property will be tweened 3041 * @param {!string} p Property that will be tweened (its name, like "left" or "backgroundColor" or "boxShadow") 3042 * @param {string} b Beginning value 3043 * @param {string} e Ending value 3044 * @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) 3045 * @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 3046 * @param {?CSSPropTween} pt CSSPropTween instance that is the current head of the linked list (we'll prepend to this). 3047 * @param {number=} pr Priority in the linked list order. Higher priority properties will be updated before lower priority ones. The default priority is 0. 3048 * @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} 3049 * @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. 3050 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parseComplex() call. 3051 */ 3052 _parseComplex = CSSPlugin.parseComplex = function(t, p, b, e, clrs, dflt, pt, pr, plugin, setRatio) { 3053 //DEBUG: _log("parseComplex: "+p+", b: "+b+", e: "+e); 3054 b = b || dflt || ""; 3055 pt = new CSSPropTween(t, p, 0, 0, pt, (setRatio ? 2 : 1), null, false, pr, b, e); 3056 e += ""; //ensures it's a string 3057 var ba = b.split(", ").join(",").split(" "), //beginning array 3058 ea = e.split(", ").join(",").split(" "), //ending array 3059 l = ba.length, 3060 autoRound = (_autoRound !== false), 3061 i, xi, ni, bv, ev, bnums, enums, bn, rgba, temp, cv, str; 3062 if (e.indexOf(",") !== -1 || b.indexOf(",") !== -1) { 3063 ba = ba.join(" ").replace(_commasOutsideParenExp, ", ").split(" "); 3064 ea = ea.join(" ").replace(_commasOutsideParenExp, ", ").split(" "); 3065 l = ba.length; 3066 } 3067 if (l !== ea.length) { 3068 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")"); 3069 ba = (dflt || "").split(" "); 3070 l = ba.length; 3071 } 3072 pt.plugin = plugin; 3073 pt.setRatio = setRatio; 3074 for (i = 0; i < l; i++) { 3075 bv = ba[i]; 3076 ev = ea[i]; 3077 bn = parseFloat(bv); 3078 3079 //if the value begins with a number (most common). It's fine if it has a suffix like px 3080 if (bn || bn === 0) { 3081 pt.appendXtra("", bn, _parseChange(ev, bn), ev.replace(_relNumExp, ""), (autoRound && ev.indexOf("px") !== -1), true); 3082 3083 //if the value is a color 3084 } else if (clrs && (bv.charAt(0) === "#" || _colorLookup[bv] || _rgbhslExp.test(bv))) { 3085 str = ev.charAt(ev.length - 1) === "," ? ")," : ")"; //if there's a comma at the end, retain it. 3086 bv = _parseColor(bv); 3087 ev = _parseColor(ev); 3088 rgba = (bv.length + ev.length > 6); 3089 if (rgba && !_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 3090 pt["xs" + pt.l] += pt.l ? " transparent" : "transparent"; 3091 pt.e = pt.e.split(ea[i]).join("transparent"); 3092 } else { 3093 if (!_supportsOpacity) { //old versions of IE don't support rgba(). 3094 rgba = false;
3095 } 3096 pt.appendXtra((rgba ? "rgba(" : "rgb("), bv[0], ev[0] - bv[0], ",", true, true) 3097 .appendXtra("", bv[1], ev[1] - bv[1], ",", true) 3098 .appendXtra("", bv[2], ev[2] - bv[2], (rgba ? "," : str), true); 3099 if (rgba) { 3100 bv = (bv.length < 4) ? 1 : bv[3]; 3101 pt.appendXtra("", bv, ((ev.length < 4) ? 1 : ev[3]) - bv, str, false); 3102 } 3103 } 3104 3105 } else { 3106 bnums = bv.match(_numExp); //gets each group of numbers in the beginning value string and drops them into an array 3107 3108 //if no number is found, treat it as a non-tweening value and just append the string to the current xs. 3109 if (!bnums) { 3110 pt["xs" + pt.l] += pt.l ? " " + bv : bv; 3111 3112 //loop through all the numbers that are found and construct the extra values on the pt. 3113 } else { 3114 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 3115 if (!enums || enums.length !== bnums.length) { 3116 //DEBUG: _log("mismatched formatting detected on " + p + " (" + b + " vs " + e + ")"); 3117 return pt; 3118 } 3119 ni = 0; 3120 for (xi = 0; xi < bnums.length; xi++) { 3121 cv = bnums[xi]; 3122 temp = bv.indexOf(cv, ni); 3123 pt.appendXtra(bv.substr(ni, temp - ni), Number(cv), _parseChange(enums[xi], cv), "", (autoRound && bv.substr(temp + cv.length, 2) === "px"), (xi === 0)); 3124 ni = temp + cv.length; 3125 } 3126 pt["xs" + pt.l] += bv.substr(ni); 3127 } 3128 } 3129 } 3130 //if there are relative values ("+=" or "-=" prefix), we need to adjust the ending value to eliminate the prefixes and combine the values properly. 3131 if (e.indexOf("=") !== -1) if (pt.data) { 3132 str = pt.xs0 + pt.data.s; 3133 for (i = 1; i < pt.l; i++) { 3134 str += pt["xs" + i] + pt.data["xn" + i]; 3135 } 3136 pt.e = str + pt["xs" + i]; 3137 } 3138 if (!pt.l) { 3139 pt.type = -1; 3140 pt.xs0 = pt.e; 3141 } 3142 return pt.xfirst || pt; 3143 }, 3144 i = 9; 3145 3146 3147 p = CSSPropTween.prototype; 3148 p.l = p.pr = 0; //length (number of extra properties like xn1, xn2, xn3, etc. 3149 while (--i > 0) { 3150 p["xn" + i] = 0; 3151 p["xs" + i] = ""; 3152 } 3153 p.xs0 = ""; 3154 p._next = p._prev = p.xfirst = p.data = p.plugin = p.setRatio = p.rxp = null; 3155 3156 3157 /** 3158 * 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: 3159 * xs0:"rect(", s:10, xs1:"px, ", xn1:5, xs2:"px, ", xn2:0, xs3:"px, ", xn3:20, xn4:"px)" 3160 * And they'd all get joined together when the CSSPlugin renders (in the setRatio() method). 3161 * @param {string=} pfx Prefix (if any) 3162 * @param {!number} s Starting value 3163 * @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. 3164 * @param {string=} sfx Suffix (if any) 3165 * @param {boolean=} r Round (if true). 3166 * @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. 3167 * @return {CSSPropTween} returns itself so that multiple methods can be chained together. 3168 */ 3169 p.appendXtra = function(pfx, s, c, sfx, r, pad) { 3170 var pt = this, 3171 l = pt.l; 3172 pt["xs" + l] += (pad && l) ? " " + pfx : pfx || ""; 3173 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! 3174 pt["xs" + l] += s + (sfx || ""); 3175 return pt; 3176 } 3177 pt.l++; 3178 pt.type = pt.setRatio ? 2 : 1; 3179 pt["xs" + pt.l] = sfx || ""; 3180 if (l > 0) { 3181 pt.data["xn" + l] = s + c; 3182 pt.rxp["xn" + l] = r; //round extra property (we need to tap into this in the _parseToProxy() method) 3183 pt["xn" + l] = s; 3184 if (!pt.plugin) { 3185 pt.xfirst = new CSSPropTween(pt, "xn" + l, s, c, pt.xfirst || pt, 0, pt.n, r, pt.pr); 3186 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. 3187 } 3188 return pt; 3189 } 3190 pt.data = {s:s + c}; 3191 pt.rxp = {}; 3192 pt.s = s; 3193 pt.c = c; 3194 pt.r = r; 3195 return pt; 3196 }; 3197 3198 /** 3199 * @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. 3200 * @param {!string} p Property name (like "boxShadow" or "throwProps") 3201 * @param {Object=}
3201 options An object containing any of the following configuration options: 3202 * - defaultValue: the default value 3203 * - 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) 3204 * - 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.) 3205 * - prefix: if true, we'll determine whether or not this property requires a vendor prefix (like Webkit or Moz or ms or O) 3206 * - color: set this to true if the value for this SpecialProp may contain color-related values like rgb(), rgba(), etc. 3207 * - priority: priority in the linked list order. Higher priority SpecialProps will be updated before lower priority ones. The default priority is 0. 3208 * - multi: if true, the formatter should accommodate a comma-delimited list of values, like boxShadow could have multiple boxShadows listed out. 3209 * - 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. 3210 * - 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). 3211 */ 3212 var SpecialProp = function(p, options) { 3213 options = options || {}; 3214 this.p = options.prefix ? _checkPropPrefix(p) || p : p; 3215 _specialProps[p] = _specialProps[this.p] = this; 3216 this.format = options.formatter || _getFormatter(options.defaultValue, options.color, options.collapsible, options.multi); 3217 if (options.parser) { 3218 this.parse = options.parser; 3219 } 3220 this.clrs = options.color; 3221 this.multi = options.multi; 3222 this.keyword = options.keyword; 3223 this.dflt = options.defaultValue; 3224 this.pr = options.priority || 0; 3225 }, 3226 3227 //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. 3228 _registerComplexSpecialProp = _internals._registerComplexSpecialProp = function(p, options, defaults) { 3229 if (typeof(options) !== "object") { 3230 options = {parser:defaults}; //to make backwards compatible with older versions of BezierPlugin and ThrowPropsPlugin 3231 } 3232 var a = p.split(","), 3233 d = options.defaultValue, 3234 i, temp; 3235 defaults = defaults || [d]; 3236 for (i = 0; i < a.length; i++) { 3237 options.prefix = (i === 0 && options.prefix); 3238 options.defaultValue = defaults[i] || d; 3239 temp = new SpecialProp(a[i], options); 3240 } 3241 }, 3242 3243 //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. 3244 _registerPluginProp = function(p) { 3245 if (!_specialProps[p]) { 3246 var pluginName = p.charAt(0).toUpperCase() + p.substr(1) + "Plugin"; 3247 _registerComplexSpecialProp(p, {parser:function(t, e, p, cssp, pt, plugin, vars) { 3248 var pluginClass = (_gsScope.GreenSockGlobals || _gsScope).com.greensock.plugins[pluginName]; 3249 if (!pluginClass) { 3250 _log("Error: " + pluginName + " js file not loaded."); 3251 return pt; 3252 } 3253 pluginClass._cssRegister(); 3254 return _specialProps[p].parse(t, e, p, cssp, pt, plugin, vars); 3255 }}); 3256 } 3257 }; 3258 3259 3260 p = SpecialProp.prototype; 3261 3262 /** 3263 * 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
3263adow) 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) 3264 * @param {!Object} t target element 3265 * @param {(string|number|object)} b beginning value 3266 * @param {(string|number|object)} e ending (destination) value 3267 * @param {CSSPropTween=} pt next CSSPropTween in the linked list 3268 * @param {TweenPlugin=} plugin If another plugin will be tweening the complex value, that TweenPlugin instance goes here. 3269 * @param {function=} setRatio If a custom setRatio() method should be used to handle this complex value, that goes here. 3270 * @return {CSSPropTween=} First CSSPropTween in the linked list 3271 */ 3272 p.parseComplex = function(t, b, e, pt, plugin, setRatio) { 3273 var kwd = this.keyword, 3274 i, ba, ea, l, bi, ei; 3275 //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) 3276 if (this.multi) if (_commasOutsideParenExp.test(e) || _commasOutsideParenExp.test(b)) { 3277 ba = b.replace(_commasOutsideParenExp, "|").split("|"); 3278 ea = e.replace(_commasOutsideParenExp, "|").split("|"); 3279 } else if (kwd) { 3280 ba = [b]; 3281 ea = [e]; 3282 } 3283 if (ea) { 3284 l = (ea.length > ba.length) ? ea.length : ba.length; 3285 for (i = 0; i < l; i++) { 3286 b = ba[i] = ba[i] || this.dflt; 3287 e = ea[i] = ea[i] || this.dflt; 3288 if (kwd) { 3289 bi = b.indexOf(kwd); 3290 ei = e.indexOf(kwd); 3291 if (bi !== ei) { 3292 e = (ei === -1) ? ea : ba; 3293 e[i] += " " + kwd; 3294 } 3295 } 3296 } 3297 b = ba.join(", "); 3298 e = ea.join(", "); 3299 } 3300 return _parseComplex(t, this.p, b, e, this.clrs, this.dflt, pt, this.pr, plugin, setRatio); 3301 }; 3302 3303 /** 3304 * 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: 3305 * this._firstPT = sp.parse(element, "5px 10px 20px rgb(2550,102,51)", "boxShadow", this); 3306 * 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). 3307 * @param {!Object} t Target object whose property is being tweened 3308 * @param {Object} e End value as provided in the vars object (typically a string, but not always - like a throwProps would be an object). 3309 * @param {!string} p Property name 3310 * @param {!CSSPlugin} cssp The CSSPlugin instance that should be associated with this tween. 3311 * @param {?CSSPropTween} pt The CSSPropTween that is the current head of the linked list (we'll prepend to it) 3312 * @param {TweenPlugin=} plugin If a plugin will be used to tween the parsed value, this is the plugin instance. 3313 * @param {Object=} vars Original vars object that contains the data for parsing. 3314 * @return {CSSPropTween} The first CSSPropTween in the linked list which includes the new one(s) added by the parse() call. 3315 */ 3316 p.parse = function(t, e, p, cssp, pt, plugin, vars) { 3317 return this.parseComplex(t.style, this.format(_getStyle(t, this.p, _cs, false, this.dflt)), this.format(e), pt, plugin); 3318 }; 3319 3320 /** 3321 * 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: 3322 * 1) Target object whose property should be tweened (typically a DOM element) 3323 * 2) The end/destination value (could be a string, number, object, or whatever you want) 3324 * 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) 3325 * 3326 * 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: 3327 * 3328 * CSSPlugin.registerSpecialProp("myCustomProp", function(target, value, tween) { 3329 * var start = target.style.width;
3330 * return function(ratio) { 3331 * target.style.width = (start + value * ratio) + "px"; 3332 * console.log("set width to " + target.style.width); 3333 * } 3334 * }, 0); 3335 * 3336 * Then, when I do this tween, it will trigger my special property: 3337 * 3338 * TweenLite.to(element, 1, {css:{myCustomProp:100}}); 3339 * 3340 * In the example, of course, we're just changing the width, but you can do anything you want. 3341 * 3342 * @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}}) 3343 * @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. 3344 * @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. 3345 */ 3346 CSSPlugin.registerSpecialProp = function(name, onInitTween, priority) { 3347 _registerComplexSpecialProp(name, {parser:function(t, e, p, cssp, pt, plugin, vars) { 3348 var rv = new CSSPropTween(t, p, 0, 0, pt, 2, p, false, priority); 3349 rv.plugin = plugin; 3350 rv.setRatio = onInitTween(t, e, cssp._tween, p); 3351 return rv; 3352 }, priority:priority}); 3353 }; 3354 3355 3356 3357 3358 3359 3360 3361 //transform-related methods and properties 3362 var _transformProps = ("scaleX,scaleY,scaleZ,x,y,z,skewX,skewY,rotation,rotationX,rotationY,perspective,xPercent,yPercent").split(","), 3363 _transformProp = _checkPropPrefix("transform"), //the Javascript (camelCase) transform property, like msTransform, WebkitTransform, MozTransform, or OTransform. 3364 _transformPropCSS = _prefixCSS + "transform", 3365 _transformOriginProp = _checkPropPrefix("transformOrigin"), 3366 _supports3D = (_checkPropPrefix("perspective") !== null), 3367 Transform = _internals.Transform = function() { 3368 this.skewY = 0; 3369 }, 3370 _SVGElement = window.SVGElement, 3371 _useSVGTransformAttr, 3372 //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. 3373 3374 _createSVG = function(type, container, attributes) { 3375 var element = _doc.createElementNS("http://www.w3.org/2000/svg", type), 3376 reg = /([a-z])([A-Z])/g, 3377 p; 3378 for (p in attributes) { 3379 element.setAttributeNS(null, p.replace(reg, "$1-$2").toLowerCase(), attributes[p]); 3380 } 3381 container.appendChild(element); 3382 return element; 3383 }, 3384 _docElement = document.documentElement, 3385 _forceSVGTransformAttr = (function() { 3386 //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 3387 var force = _ieVers || (/Android/i.test(_agent) && !window.chrome), 3388 svg, rect, left; 3389 if (_doc.createElementNS && !force) { //IE8 and earlier doesn't support SVG anyway 3390 svg = _createSVG("svg", _docElement); 3391 rect = _createSVG("rect", svg, {width:100, height:50, x:100}); 3392 left = rect.getBoundingClientRect().left; 3393 rect.style[_transformOriginProp] = "50% 50%"; 3394 rect.style[_transformProp] = "scale(0.5,0.5)";
3395 force = (left === rect.getBoundingClientRect().left); 3396 _docElement.removeChild(svg); 3397 } 3398 return force; 3399 })(), 3400 _parseSVGOrigin = function(e, origin, decoratee) { 3401 var bbox = e.getBBox(); 3402 origin = _parsePosition(origin).split(" "); 3403 decoratee.xOrigin = (origin[0].indexOf("%") !== -1 ? parseFloat(origin[0]) / 100 * bbox.width : parseFloat(origin[0])) + bbox.x; 3404 decoratee.yOrigin = (origin[1].indexOf("%") !== -1 ? parseFloat(origin[1]) / 100 * bbox.height : parseFloat(origin[1])) + bbox.y; 3405 }, 3406 3407 /** 3408 * 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. 3409 * @param {!Object} t target element 3410 * @param {Object=} cs computed style object (optional) 3411 * @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...} 3412 * @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) 3413 * @return {object}
3413 object containing all of the transform properties/values like {x:0, y:0, z:0, scaleX:1...} 3414 */ 3415 _getTransform = _internals.getTransform = function(t, cs, rec, parse) { 3416 if (t._gsTransform && rec && !parse) { 3417 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. 3418 } 3419 var tm = rec ? t._gsTransform || new Transform() : new Transform(), 3420 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. 3421 min = 0.00002, 3422 rnd = 100000, 3423 minAngle = 179.99, 3424 minPI = minAngle * _DEG2RAD, 3425 zOrigin = _supports3D ? parseFloat(_getStyle(t, _transformOriginProp, cs, false, "0 0 0").split(" ")[2]) || tm.zOrigin || 0 : 0, 3426 defaultTransformPerspective = parseFloat(CSSPlugin.defaultTransformPerspective) || 0, 3427 s, m, i, n, dec, scaleX, scaleY, rotation, skewX, difX, difY, difR, difS; 3428 if (_transformProp) { 3429 s = _getStyle(t, _transformPropCSS, cs, true); 3430 } else if (t.currentStyle) { 3431 //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. 3432 s = t.currentStyle.filter.match(_ieGetMatrixExp); 3433 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(",") : ""; 3434 }
3435 if (!s || s === "none" || s === "matrix(1, 0, 0, 1, 0, 0)") { //if no transforms are applied, just use the defaults to optimize performance (no need to parse). 3436 tm = {x:0, y:0, z:0, scaleX:1, scaleY:1, scaleZ:1, skewX:0, skewY:0, perspective:defaultTransformPerspective, rotation:0, rotationX:0, rotationY:0, zOrigin:0}; 3437 } else { 3438 //split the matrix values out into an array (m for matrix) 3439 m = (s || "").match(/(?:\-|\b)[\d\-\.e]+\b/gi) || []; 3440 i = m.length; 3441 while (--i > -1) { 3442 n = Number(m[i]); 3443 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). 3444 } 3445 if (m.length === 16) { 3446 3447 //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) 3448 var a13 = m[8], a23 = m[9], a33 = m[10], 3449 a14 = m[12], a24 = m[13], a34 = m[14]; 3450 3451 //we manually compensate for non-zero z component of transformOrigin to work around bugs in Safari 3452 if (tm.zOrigin) { 3453 a34 = -tm.zOrigin; 3454 a14 = a13*a34-m[12]; 3455 a24 = a23*a34-m[13]; 3456 a34 = a33*a34+tm.zOrigin-m[14]; 3457 } 3458 3459 //only parse from the matrix if we MUST because not only is it usually unnecessary due to the fact that we store the values in the _gsTransform object, but also because it's impossible to accurately interpret rotationX, rotationY, rotationZ, scaleX, and scaleY if all are applied, so it's much better to rely on what we store. However, we must parse the first time that an object is tweened. We also assume that if the position has changed, the user must have done some styling changes outside of CSSPlugin, thus we force a parse in that scenario. 3460 if (!rec || parse || tm.rotationX == null) { 3461 var a11 = m[0], a21 = m[1], a31 = m[2], a41 = m[3], 3462 a12 = m[4], a22 = m[5], a32 = m[6], a42 = m[7], 3463 a43 = m[11], 3464 angle = Math.atan2(a32, a33), 3465 xFlip = (angle < -minPI || angle > minPI), 3466 t1, t2, t3, cos, sin, yFlip, zFlip; 3467 tm.rotationX = angle * _RAD2DEG; 3468 //rotationX 3469 if (angle) { 3470 cos = Math.cos(-angle); 3471 sin = Math.sin(-angle); 3472 t1 = a12*cos+a13*sin; 3473 t2 = a22*cos+a23*sin; 3474 t3 = a32*cos+a33*sin; 3475 a13 = a12*-sin+a13*cos; 3476 a23 = a22*-sin+a23*cos; 3477 a33 = a32*-sin+a33*cos; 3478 a43 = a42*-sin+a43*cos; 3479 a12 = t1; 3480 a22 = t2; 3481 a32 = t3; 3482 } 3483 //rotationY 3484 angle = Math.atan2(a13, a11); 3485 tm.rotationY = angle * _RAD2DEG; 3486 if (angle) { 3487 yFlip = (angle < -minPI || angle > minPI); 3488 cos = Math.cos(-angle); 3489 sin = Math.sin(-angle); 3490 t1 = a11*cos-a13*sin; 3491 t2 = a21*cos-a23*sin; 3492 t3 = a31*cos-a33*sin; 3493 a23 = a21*sin+a23*cos; 3494 a33 = a31*sin+a33*cos; 3495 a43 = a41*sin+a43*cos; 3496 a11 = t1; 3497 a21 = t2; 3498 a31 = t3; 3499 } 3500 //rotationZ 3501 angle = Math.atan2(a21, a22); 3502 tm.rotation = angle * _RAD2DEG; 3503 if (angle) { 3504 zFlip = (angle < -minPI || angle > minPI); 3505 cos = Math.cos(-angle); 3506 sin = Math.sin(-angle); 3507 a11 = a11*cos+a12*sin; 3508 t2 = a21*cos+a22*sin; 3509 a22 = a21*-sin+a22*cos; 3510 a32 = a31*-sin+a32*cos; 3511 a21 = t2; 3512 } 3513 3514 if (zFlip && xFlip) { 3515 tm.rotation = tm.rotationX = 0; 3516 } else if (zFlip && yFlip) { 3517 tm.rotation = tm.rotationY = 0; 3518 } else if (yFlip && xFlip) { 3519 tm.rotationY = tm.rotationX = 0; 3520 } 3521 3522 tm.scaleX = ((Math.sqrt(a11 * a11 + a21 * a21) * rnd + 0.5) | 0) / rnd; 3523 tm.scaleY = ((Math.sqrt(a22 * a22 + a23 * a23) * rnd + 0.5) | 0) / rnd; 3524 tm.scaleZ = ((Math.sqrt(a32 * a32 + a33 * a33) * rnd + 0.5) | 0) / rnd; 3525 tm.skewX = 0; 3526 tm.perspective = a43 ? 1 / ((a43 < 0) ? -a43 : a43) : 0; 3527 tm.x = a14; 3528 tm.y = a24; 3529 tm.z = a34; 3530 } 3531 3532 } 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) === "
3532none")) { //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. 3533 var k = (m.length >= 6), 3534 a = k ? m[0] : 1, 3535 b = m[1] || 0, 3536 c = m[2] || 0, 3537 d = k ? m[3] : 1; 3538 tm.x = m[4] || 0; 3539 tm.y = m[5] || 0; 3540 scaleX = Math.sqrt(a * a + b * b); 3541 scaleY = Math.sqrt(d * d + c * c); 3542 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). 3543 skewX = (c || d) ? Math.atan2(c, d) * _RAD2DEG + rotation : tm.skewX || 0; 3544 difX = scaleX - Math.abs(tm.scaleX || 0); 3545 difY = scaleY - Math.abs(tm.scaleY || 0); 3546 if (Math.abs(skewX) > 90 && Math.abs(skewX) < 270) { 3547 if (invX) { 3548 scaleX *= -1; 3549 skewX += (rotation <= 0) ? 180 : -180; 3550 rotation += (rotation <= 0) ? 180 : -180; 3551 } else { 3552 scaleY *= -1; 3553 skewX += (skewX <= 0) ? 180 : -180; 3554 } 3555 } 3556 difR = (rotation - tm.rotation) % 180; //note: matching ranges would be very small (+/-0.0001) or very close to 180. 3557 difS = (skewX - tm.skewX) % 180; 3558 //if there's already a recorded _gsTransform in place for the target, we should leave those values in place unless we know things changed for sure (beyond a super small amount). This gets around ambiguous interpretations, like if scaleX and scaleY are both -1, the matrix would be the same as if the rotation was 180 with normal scaleX/scaleY. If the user tweened to particular values, those must be prioritized to ensure animation is consistent. 3559 if (tm.skewX === undefined || difX > min || difX < -min || difY > min || difY < -min || (difR > -minAngle && difR < minAngle && (difR * rnd) | 0 !== 0) || (difS > -minAngle && difS < minAngle && (difS * rnd) | 0 !== 0)) { 3560 tm.scaleX = scaleX; 3561 tm.scaleY = scaleY; 3562 tm.rotation = rotation; 3563 tm.skewX = skewX; 3564 } 3565 if (_supports3D) { 3566 tm.rotationX = tm.rotationY = tm.z = 0; 3567 tm.perspective = defaultTransformPerspective; 3568 tm.scaleZ = 1; 3569 } 3570 } 3571 tm.zOrigin = zOrigin; 3572 3573 //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. 3574 for (i in tm) { 3575 if (tm[i] < min) if (tm[i] > -min) { 3576 tm[i] = 0; 3577 } 3578 } 3579 } 3580 //DEBUG: _log("parsed rotation: "+(tm.rotationX)+", "+(tm.rotationY)+", "+(tm.rotation)+", scale: "+tm.scaleX+", "+tm.scaleY+", "+tm.scaleZ+", position: "+tm.x+", "+tm.y+", "+tm.z+", perspective: "+tm.perspective); 3581 if (rec) { 3582 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) 3583 } 3584 tm.svg = (_SVGElement && (t instanceof _SVGElement) && (t.parentNode instanceof _SVGElement)); 3585 if (tm.svg) { 3586 _parseSVGOrigin(t, _getStyle(t, _transformOriginProp, _cs, false, "50% 50%") + "", tm); 3587 _useSVGTransformAttr = CSSPlugin.useSVGTransformAttr || _forceSVGTransformAttr; 3588 } 3589 tm.xPercent = tm.yPercent = 0; 3590 return tm; 3591 }, 3592 3593 //for setting 2D transforms in IE6, IE7, and IE8 (must use a "filter" to emulate the behavior of modern day browser transforms) 3594 _setIETransformRatio = function(v) { 3595 var t = this.data, //refers to the element's _gsTransform object 3596 ang = -t.rotation * _DEG2RAD,
3597 skew = ang + t.skewX * _DEG2RAD, 3598 rnd = 100000, 3599 a = ((Math.cos(ang) * t.scaleX * rnd) | 0) / rnd, 3600 b = ((Math.sin(ang) * t.scaleX * rnd) | 0) / rnd, 3601 c = ((Math.sin(skew) * -t.scaleY * rnd) | 0) / rnd, 3602 d = ((Math.cos(skew) * t.scaleY * rnd) | 0) / rnd, 3603 style = this.t.style, 3604 cs = this.t.currentStyle, 3605 filters, val; 3606 if (!cs) { 3607 return; 3608 } 3609 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) 3610 b = -c; 3611 c = -val; 3612 filters = cs.filter; 3613 style.filter = ""; //remove filters so that we can accurately measure offsetWidth/offsetHeight 3614 var w = this.t.offsetWidth, 3615 h = this.t.offsetHeight, 3616 clip = (cs.position !== "absolute"), 3617 m = "progid:DXImageTransform.Microsoft.Matrix(M11=" + a + ", M12=" + b + ", M21=" + c + ", M22=" + d, 3618 ox = t.x + (w * t.xPercent / 100), 3619 oy = t.y + (h * t.yPercent / 100), 3620 dx, dy; 3621 3622 //if transformOrigin is being used, adjust the offset x and y 3623 if (t.ox != null) { 3624 dx = ((t.oxp) ? w * t.ox * 0.01 : t.ox) - w / 2; 3625 dy = ((t.oyp) ? h * t.oy * 0.01 : t.oy) - h / 2; 3626 ox += dx - (dx * a + dy * b); 3627 oy += dy - (dx * c + dy * d); 3628 } 3629 3630 if (!clip) { 3631 m += ", sizingMethod='auto expand')"; 3632 } else { 3633 dx = (w / 2); 3634 dy = (h / 2); 3635 //translate to ensure that transformations occur around the correct origin (default is center). 3636 m += ", Dx=" + (dx - (dx * a + dy * b) + ox) + ", Dy=" + (dy - (dx * c + dy * d) + oy) + ")"; 3637 } 3638 if (filters.indexOf("DXImageTransform.Microsoft.Matrix(") !== -1) { 3639 style.filter = filters.replace(_ieSetMatrixExp, m); 3640 } else { 3641 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. 3642 } 3643 3644 //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. 3645 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) { 3646 style.removeAttribute("filter"); 3647 } 3648 3649 //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). 3650 if (!clip) { 3651 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 3652 marg, prop, dif; 3653 dx = t.ieOffsetX || 0; 3654 dy = t.ieOffsetY || 0; 3655 t.ieOffsetX = Math.round((w - ((a < 0 ? -a : a) * w + (b < 0 ? -b : b) * h)) / 2 + ox); 3656 t.ieOffsetY = Math.round((h - ((d < 0 ? -d : d) * h + (c < 0 ? -c : c) * w)) / 2 + oy); 3657 for (i = 0; i < 4; i++) { 3658 prop = _margins[i]; 3659 marg = cs[prop]; 3660 //we need to get the current margin in case it is being tweened separately (we want to respect that tween's changes) 3661 val = (marg.indexOf("px") !== -1) ? parseFloat(marg) : _convertToPixels(this.t, prop, parseFloat(marg), marg.replace(_suffixExp, "")) || 0; 3662 if (val !== t[prop]) { 3663 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. 3664 } else { 3665 dif = (i < 2) ? dx - t.ieOffsetX : dy - t.ieOffsetY; 3666 } 3667 style[prop] = (t[prop] = Math.round( val - dif * ((i === 0 || i === 2) ? 1 : mult) )) + "px"; 3668 } 3669 } 3670 }, 3671 3672 _set3DTransformRatio = _internals.set3DTransformRatio = function(v) { 3673 var t = this.data, //refers to the element's _gsTransform object 3674 style = this.t.style, 3675 angle = t.rotation * _DEG2RAD, 3676 sx = t.scaleX, 3677 sy = t.scaleY, 3678 sz = t.scaleZ, 3679 x = t.x, 3680 y = t.y, 3681 z = t.z, 3682 perspective = t.perspective, 3683 a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, 3684 zOrigin, rnd, cos, sin, t1, t2, t3, t4;
3685 if (v === 1 || v === 0) if (t.force3D === "auto") if (!t.rotationY && !t.rotationX && sz === 1 && !perspective && !z) { //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 3686 _set2DTransformRatio.call(this, v); 3687 return; 3688 } 3689 if (_isFirefox) { 3690 var n = 0.0001; 3691 if (sx < n && sx > -n) { //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. 3692 sx = sz = 0.00002; 3693 } 3694 if (sy < n && sy > -n) { 3695 sy = sz = 0.00002; 3696 } 3697 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). 3698 perspective = 0; 3699 } 3700 } 3701 if (angle || t.skewX) { 3702 cos = Math.cos(angle); 3703 sin = Math.sin(angle); 3704 a11 = cos; 3705 a21 = sin; 3706 if (t.skewX) { 3707 angle -= t.skewX * _DEG2RAD; 3708 cos = Math.cos(angle); 3709 sin = Math.sin(angle); 3710 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 3711 t1 = Math.tan(t.skewX * _DEG2RAD); 3712 t1 = Math.sqrt(1 + t1 * t1); 3713 cos *= t1; 3714 sin *= t1; 3715 } 3716 } 3717 a12 = -sin; 3718 a22 = cos; 3719 3720 } else if (!t.rotationY && !t.rotationX && sz === 1 && !perspective && !t.svg) { //if we're only translating and/or 2D scaling, this is faster... 3721 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 + ")" : ""); 3722 return; 3723 } else { 3724 a11 = a22 = 1; 3725 a12 = a21 = 0; 3726 } 3727 a33 = 1; 3728 a13 = a14 = a23 = a24 = a31 = a32 = a34 = a41 = a42 = 0; 3729 a43 = (perspective) ? -1 / perspective : 0; 3730 zOrigin = t.zOrigin; 3731 rnd = 100000; 3732 angle = t.rotationY * _DEG2RAD; 3733 if (angle) { 3734 cos = Math.cos(angle); 3735 sin = Math.sin(angle); 3736 a31 = a33*-sin; 3737 a41 = a43*-sin; 3738 a13 = a11*sin; 3739 a23 = a21*sin; 3740 a33 *= cos; 3741 a43 *= cos; 3742 a11 *= cos; 3743 a21 *= cos; 3744 } 3745 angle = t.rotationX * _DEG2RAD; 3746 if (angle) { 3747 cos = Math.cos(angle); 3748 sin = Math.sin(angle); 3749 t1 = a12*cos+a13*sin; 3750 t2 = a22*cos+a23*sin; 3751 t3 = a32*cos+a33*sin; 3752 t4 = a42*cos+a43*sin; 3753 a13 = a12*-sin+a13*cos; 3754 a23 = a22*-sin+a23*cos; 3755 a33 = a32*-sin+a33*cos; 3756 a43 = a42*-sin+a43*cos; 3757 a12 = t1; 3758 a22 = t2; 3759 a32 = t3; 3760 a42 = t4; 3761 } 3762 if (sz !== 1) { 3763 a13*=sz; 3764 a23*=sz; 3765 a33*=sz; 3766 a43*=sz; 3767 } 3768 if (sy !== 1) { 3769 a12*=sy; 3770 a22*=sy; 3771 a32*=sy; 3772 a42*=sy; 3773 } 3774 if (sx !== 1) { 3775 a11*=sx; 3776 a21*=sx; 3777 a31*=sx; 3778 a41*=sx; 3779 } 3780 if (zOrigin) { 3781 a34 -= zOrigin; 3782 a14 = a13*a34; 3783 a24 = a23*a34; 3784 a34 = a33*a34+zOrigin; 3785 } 3786 if (t.svg) { //due to bugs in some browsers, we need to manage the transform-origin of SVG manually 3787 a14 += t.xOrigin - (t.xOrigin * a11 + t.yOrigin * a12); 3788 a24 += t.yOrigin - (t.xOrigin * a21 + t.yOrigin * a22); 3789 } 3790 //we round the x, y, and z slightly differently to allow even larger values. 3791 a14 = (t1 = (a14 += x) - (a14 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a14 : a14; 3792 a24 = (t1 = (a24 += y) - (a24 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a24 : a24; 3793 a34 = (t1 = (a34 += z) - (a34 |= 0)) ? ((t1 * rnd + (t1 < 0 ? -0.5 : 0.5)) | 0) / rnd + a34 : a34; 3794 style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix3d(" : "matrix3d(") + [ (((a11 * rnd) | 0) / rnd), (((a21 * rnd) | 0) / rnd), (((a31 * rnd) | 0) / rnd), (((a41 * rnd) | 0) / rnd), (((a12 * rnd) | 0) / rnd), (((a22 * rnd) | 0) / rnd), (((a32 * rnd) | 0) / rnd), (((a42 * rnd) | 0) / rnd), (((a13 * rnd) | 0) / rnd), (((a23 * rnd) | 0) / rnd), (((a33 * rnd) | 0) / rnd), (((a43 * rnd) | 0) / rnd), a14, a24, a34, (perspective ? (1 + (-a34 / perspective)) : 1) ].join(",") + ")"; 3795 }, 3796 3797 _set2DTransformRatio = _internals.set2DTransformRatio = function(v) { 3798 var t = this.data, //refers to the element's _gsTransform object 3799 targ = this.t, 3800 style = targ.style, 3801 x = t.x, 3802 y = t.y, 3803 ang, skew, rnd, sx, sy, a, b, c, d, matrix, min; 3804 if ((t.rotationX || t.rotationY || t.z || t.force3D === true || (t.force3D === "auto" && v !== 1 && v !== 0)) && !(t.svg && _useSVGTransformAttr) && _supports3D) { //if a 3D tween begins while a 2D one is running, we need to kick the rendering over to the 3D method. For example, imagine a yoyo-ing, infinitely repeating scale tween running, and then the object gets rotated in 3D space with a different tween. 3805 this.setRatio = _set3DTransformRatio; 3806 _set3DTransformRatio.call(this, v); 3807 return; 3808 } 3809 sx = t.scaleX; 3810 sy = t.scaleY; 3811 if (t.rotation || t.skewX || t.svg) { 3812 ang = t.rotation * _DEG2RAD; 3813 skew = ang - t.skewX * _DEG2RAD; 3814 rnd = 100000; 3815 a = Math.cos(ang) * sx; 3816 b = Math.sin(ang) * sx; 3817 c = Math.sin(skew) * -sy; 3818 d = Math.cos(skew) * sy; 3819 if (t.svg) { 3820 x += t.xOrigin - (t.xOrigin * a + t.yOrigin * c); 3821 y += t.yOrigin - (t.xOrigin * b + t.yOrigin * d); 3822 min = 0.000001; 3823 if (x < min) if (x > -min) { 3824 x = 0; 3825 } 3826 if (y < min) if (y > -min) { 3827 y = 0; 3828 } 3829 } 3830 matrix = (((a * rnd) | 0) / rnd) + "," + (((b * rnd) | 0) / rnd) + "," + (((c * rnd) | 0) / rnd) + "," + (((d * rnd) | 0) / rnd) + "," + x + "," + y + ")"; 3831 if (t.svg && _useSVGTransformAttr) {
3832 targ.setAttribute("transform", "matrix(" + matrix); 3833 } else { 3834 //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. 3835 style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix(" : "matrix(") + matrix; 3836 } 3837 } else { 3838 style[_transformProp] = ((t.xPercent || t.yPercent) ? "translate(" + t.xPercent + "%," + t.yPercent + "%) matrix(" : "matrix(") + sx + ",0,0," + sy + "," + x + "," + y + ")"; 3839 } 3840 }; 3841 3842 _registerComplexSpecialProp("transform,scale,scaleX,scaleY,scaleZ,x,y,z,rotation,rotationX,rotationY,rotationZ,skewX,skewY,shortRotation,shortRotationX,shortRotationY,shortRotationZ,transformOrigin,transformPerspective,directionalRotation,parseTransform,force3D,skewType,xPercent,yPercent", {parser:function(t, e, p, cssp, pt, plugin, vars) { 3843 if (cssp._transform) { return pt; } //only need to parse the transform once, and only if the browser supports it. 3844 var m1 = cssp._transform = _getTransform(t, _cs, true, vars.parseTransform), 3845 style = t.style, 3846 min = 0.000001, 3847 i = _transformProps.length, 3848 v = vars, 3849 endRotations = {}, 3850 m2, skewY, copy, orig, has3D, hasChange, dr; 3851 if (typeof(v.transform) === "string" && _transformProp) { //for values like transform:"rotate(60deg) scale(0.5, 0.8)" 3852 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. 3853 copy[_transformProp] = v.transform; 3854 copy.display = "block"; //if display is "none", the browser often refuses to report the transform properties correctly. 3855 copy.position = "absolute"; 3856 _doc.body.appendChild(_tempDiv); 3857 m2 = _getTransform(_tempDiv, null, false); 3858 _doc.body.removeChild(_tempDiv); 3859 } else if (typeof(v) === "object") { //for values like scaleX, scaleY, rotation, x, y, skewX, and skewY or transform:{...} (object) 3860 m2 = {scaleX:_parseVal((v.scaleX != null) ? v.scaleX : v.scale, m1.scaleX), 3861 scaleY:_parseVal((v.scaleY != null) ? v.scaleY : v.scale, m1.scaleY), 3862 scaleZ:_parseVal(v.scaleZ, m1.scaleZ), 3863 x:_parseVal(v.x, m1.x), 3864 y:_parseVal(v.y, m1.y), 3865 z:_parseVal(v.z, m1.z), 3866 xPercent:_parseVal(v.xPercent, m1.xPercent), 3867 yPercent:_parseVal(v.yPercent, m1.yPercent), 3868 perspective:_parseVal(v.transformPerspective, m1.perspective)}; 3869 dr = v.directionalRotation; 3870 if (dr != null) { 3871 if (typeof(dr) === "object") { 3872 for (copy in dr) { 3873 v[copy] = dr[copy]; 3874 } 3875 } else { 3876 v.rotation = dr; 3877 } 3878 } 3879 if (typeof(v.x) === "string" && v.x.indexOf("%") !== -1) { 3880 m2.x = 0; 3881 m2.xPercent = _parseVal(v.x, m1.xPercent); 3882 } 3883 if (typeof(v.y) === "string" && v.y.indexOf("%") !== -1) { 3884 m2.y = 0; 3885 m2.yPercent = _parseVal(v.y, m1.yPercent); 3886 } 3887 3888 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); 3889 if (_supports3D) { 3890 m2.rotationX = _parseAngle(("rotationX" in v) ? v.rotationX : ("shortRotationX" in v) ? v.shortRotationX + "_short" : m1.rotationX || 0, m1.rotationX, "rotationX", endRotations); 3891 m2.rotationY = _parseAngle(("rotationY" in v) ? v.rotationY : ("shortRotationY" in v) ? v.shortRotationY + "_short" : m1.rotationY || 0, m1.rotationY, "rotationY", endRotations); 3892 }
3893 m2.skewX = (v.skewX == null) ? m1.skewX : _parseAngle(v.skewX, m1.skewX); 3894 3895 //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. 3896 m2.skewY = (v.skewY == null) ? m1.skewY : _parseAngle(v.skewY, m1.skewY); 3897 if ((skewY = m2.skewY - m1.skewY)) { 3898 m2.skewX += skewY; 3899 m2.rotation += skewY; 3900 } 3901 } 3902 if (_supports3D && v.force3D != null) { 3903 m1.force3D = v.force3D; 3904 hasChange = true; 3905 } 3906 3907 m1.skewType = v.skewType || m1.skewType || CSSPlugin.defaultSkewType; 3908 3909 has3D = (m1.force3D || m1.z || m1.rotationX || m1.rotationY || m2.z || m2.rotationX || m2.rotationY || m2.perspective); 3910 if (!has3D && v.scale != null) { 3911 m2.scaleZ = 1; //no need to tween scaleZ. 3912 } 3913 3914 while (--i > -1) { 3915 p = _transformProps[i]; 3916 orig = m2[p] - m1[p]; 3917 if (orig > min || orig < -min || v[p] != null || _forcePT[p] != null) { 3918 hasChange = true; 3919 pt = new CSSPropTween(m1, p, m1[p], orig, pt); 3920 if (p in endRotations) { 3921 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 3922 } 3923 pt.xs0 = 0; //ensures the value stays numeric in setRatio() 3924 pt.plugin = plugin; 3925 cssp._overwriteProps.push(pt.n); 3926 } 3927 } 3928 3929 orig = v.transformOrigin; 3930 if (orig && m1.svg) { 3931 _parseSVGOrigin(t, orig, m2); 3932 pt = new CSSPropTween(m1, "xOrigin", m1.xOrigin, m2.xOrigin - m1.xOrigin, pt, -1, "transformOrigin"); 3933 pt.b = m1.xOrigin; 3934 pt.e = pt.xs0 = m2.xOrigin; 3935 pt = new CSSPropTween(m1, "yOrigin", m1.yOrigin, m2.yOrigin - m1.yOrigin, pt, -1, "transformOrigin"); 3936 pt.b = m1.yOrigin; 3937 pt.e = pt.xs0 = m2.yOrigin; 3938 orig = "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 3939 } 3940 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). 3941 if (_transformProp) { 3942 hasChange = true; 3943 p = _transformOriginProp; 3944 orig = (orig || _getStyle(t, p, _cs, false, "50% 50%")) + ""; //cast as string to avoid errors 3945 pt = new CSSPropTween(style, p, 0, 0, pt, -1, "transformOrigin"); 3946 pt.b = style[p]; 3947 pt.plugin = plugin; 3948 if (_supports3D) { 3949 copy = m1.zOrigin; 3950 orig = orig.split(" "); 3951 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. 3952 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)! 3953 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) 3954 pt.b = copy; 3955 pt.xs0 = pt.e = m1.zOrigin; 3956 } else { 3957 pt.xs0 = pt.e = orig; 3958 } 3959 3960 //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). 3961 } else { 3962 _parsePosition(orig + "", m1); 3963 } 3964 } 3965 if (hasChange) { 3966 cssp._transformType = (!(m1.svg && _useSVGTransformAttr) && (has3D || this._transformType === 3)) ? 3 : 2; //quicker than calling cssp._enableTransforms(); 3967 } 3968 return pt; 3969 }, prefix:true}); 3970 3971 _registerComplexSpecialProp("boxShadow", {defaultValue:"0px 0px 0px 0px #999", prefix:true, color:true, multi:true, keyword:"inset"}); 3972 3973 _registerComplexSpecialProp("borderRadius", {defaultValue:"0px", parser:function(t, e, p, cssp, pt, plugin) { 3974 e = this.format(e); 3975 var props = ["borderTopLeftRadius","borderTopRightRadius","borderBottomRightRadius","borderBottomLeftRadius"], 3976 style = t.style, 3977 ea1, i, es2, bs2, bs, es, bn, en, w, h, esfx, bsfx, rel, hn, vn, em; 3978 w = parseFloat(t.offsetWidth); 3979 h = parseFloat(t.offsetHeight); 3980 ea1 = e.split(" "); 3981 for (i = 0; i < props.length; i++) { //if we're dealing with percentages, we must convert things separately for the horizontal and vertical axis! 3982 if (this.p.indexOf("border")) { //older browsers used a prefix 3983 props[i] = _checkPropPrefix(props[i]); 3984 }
3985 bs = bs2 = _getStyle(t, props[i], _cs, false, "0px"); 3986 if (bs.indexOf(" ") !== -1) { 3987 bs2 = bs.split(" "); 3988 bs = bs2[0]; 3989 bs2 = bs2[1]; 3990 } 3991 es = es2 = ea1[i]; 3992 bn = parseFloat(bs); 3993 bsfx = bs.substr((bn + "").length); 3994 rel = (es.charAt(1) === "="); 3995 if (rel) { 3996 en = parseInt(es.charAt(0)+"1", 10); 3997 es = es.substr(2); 3998 en *= parseFloat(es); 3999 esfx = es.substr((en + "").length - (en < 0 ? 1 : 0)) || ""; 4000 } else { 4001 en = parseFloat(es); 4002 esfx = es.substr((en + "").length); 4003 } 4004 if (esfx === "") { 4005 esfx = _suffixMap[p] || bsfx; 4006 } 4007 if (esfx !== bsfx) { 4008 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. 4009 vn = _convertToPixels(t, "borderTop", bn, bsfx); //vertical number 4010 if (esfx === "%") { 4011 bs = (hn / w * 100) + "%"; 4012 bs2 = (vn / h * 100) + "%"; 4013 } else if (esfx === "em") { 4014 em = _convertToPixels(t, "borderLeft", 1, "em"); 4015 bs = (hn / em) + "em"; 4016 bs2 = (vn / em) + "em"; 4017 } else { 4018 bs = hn + "px"; 4019 bs2 = vn + "px"; 4020 } 4021 if (rel) { 4022 es = (parseFloat(bs) + en) + esfx; 4023 es2 = (parseFloat(bs2) + en) + esfx; 4024 } 4025 } 4026 pt = _parseComplex(style, props[i], bs + " " + bs2, es + " " + es2, false, "0px", pt); 4027 } 4028 return pt; 4029 }, prefix:true, formatter:_getFormatter("0px 0px 0px 0px", false, true)}); 4030 _registerComplexSpecialProp("backgroundPosition", {defaultValue:"0 0", parser:function(t, e, p, cssp, pt, plugin) { 4031 var bp = "background-position", 4032 cs = (_cs || _getComputedStyle(t, null)), 4033 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 4034 es = this.format(e), 4035 ba, ea, i, pct, overlap, src; 4036 if ((bs.indexOf("%") !== -1) !== (es.indexOf("%") !== -1)) { 4037 src = _getStyle(t, "backgroundImage").replace(_urlExp, ""); 4038 if (src && src !== "none") { 4039 ba = bs.split(" "); 4040 ea = es.split(" "); 4041 _tempImg.setAttribute("src", src); //set the temp IMG's src to the background-image so that we can measure its width/height 4042 i = 2; 4043 while (--i > -1) { 4044 bs = ba[i]; 4045 pct = (bs.indexOf("%") !== -1); 4046 if (pct !== (ea[i].indexOf("%") !== -1)) { 4047 overlap = (i === 0) ? t.offsetWidth - _tempImg.width : t.offsetHeight - _tempImg.height; 4048 ba[i] = pct ? (parseFloat(bs) / 100 * overlap) + "px" : (parseFloat(bs) / overlap * 100) + "%"; 4049 } 4050 } 4051 bs = ba.join(" "); 4052 } 4053 } 4054 return this.parseComplex(t.style, bs, es, pt, plugin); 4055 }, formatter:_parsePosition}); 4056 _registerComplexSpecialProp("backgroundSize", {defaultValue:"0 0", formatter:_parsePosition}); 4057 _registerComplexSpecialProp("perspective", {defaultValue:"0px", prefix:true}); 4058 _registerComplexSpecialProp("perspectiveOrigin", {defaultValue:"50% 50%", prefix:true}); 4059 _registerComplexSpecialProp("transformStyle", {prefix:true}); 4060 _registerComplexSpecialProp("backfaceVisibility", {prefix:true}); 4061 _registerComplexSpecialProp("userSelect", {prefix:true}); 4062 _registerComplexSpecialProp("margin", {parser:_getEdgeParser("marginTop,marginRight,marginBottom,marginLeft")}); 4063 _registerComplexSpecialProp("padding", {parser:_getEdgeParser("paddingTop,paddingRight,paddingBottom,paddingLeft")}); 4064 _registerComplexSpecialProp("clip", {defaultValue:"rect(0px,0px,0px,0px)", parser:function(t, e, p, cssp, pt, plugin){ 4065 var b, cs, delim; 4066 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. 4067 cs = t.currentStyle; 4068 delim = _ieVers < 8 ? " " : ","; 4069 b = "rect(" + cs.clipTop + delim + cs.clipRight + delim + cs.clipBottom + delim + cs.clipLeft + ")"; 4070 e = this.format(e).split(",").join(delim); 4071 } else { 4072 b = this.format(_getStyle(t, this.p, _cs, false, this.dflt)); 4073 e = this.format(e); 4074 } 4075 return this.parseComplex(t.style, b, e, pt, plugin); 4076 }}); 4077 _registerComplexSpecialProp("textShadow", {defaultValue:"0px 0px 0px #999", color:true, multi:true}); 4078 _registerComplexSpecialProp("autoRound,strictUnits", {parser:function(t, e, p, cssp, pt) {return pt;}}); //just so that we can ignore these properties (not tween them) 4079 _registerComplexSpecialProp("border", {defaultValue:"0px solid #000", parser:function(t, e, p, cssp, pt, plugin) { 4080 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); 4081 }, color:true, formatter:function(v) { 4082 var a = v.split(" "); 4083 return a[0] + " " + (a[1] || "solid") + " " + (v.match(_colorExp) || ["#000"])[0]; 4084 }}); 4085 _registerComplexSpecialProp("borderWidth", {parser:_getEdgeParser("borderTopWidth,borderRightWidth,borderBottomWidth,borderLeftWidth")}); //Firefox doesn't pick up on borderWidth set in style sheets (only inline). 4086 _registerComplexSpecialProp("float,cssFloat,styleFloat", {parser:function(t, e, p, cssp, pt, plugin) { 4087 var s = t.style, 4088 prop = ("cssFloat" in s) ? "cssFloat" : "styleFloat"; 4089 return new CSSPropTween(s, prop, 0, 0, pt, -1, p, false, 0, s[prop], e); 4090 }}); 4091 4092 //opacity-related 4093 var _setIEOpacityRatio = function(v) { 4094 var t = this.t, //refers to the element's style property 4095 filters = t.filter || _getStyle(this.data, "filter") || "", 4096 val = (this.s + this.c * v) | 0, 4097 skip; 4098 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. 4099 if (filters.indexOf("atrix(") === -1 && filters.indexOf("radient(") === -1 && filters.indexOf("oader(") === -1) { 4100 t.removeAttribute("filter"); 4101 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. 4102 } else {
4103 t.filter = filters.replace(_alphaFilterExp, ""); 4104 skip = true; 4105 } 4106 } 4107 if (!skip) { 4108 if (this.xn1) { 4109 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. 4110 } 4111 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 4112 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) 4113 t.filter = filters + " alpha(opacity=" + val + ")"; //we round the value because otherwise, bugs in IE7/8 can prevent "visibility" changes from being applied properly. 4114 } 4115 } else { 4116 t.filter = filters.replace(_opacityExp, "opacity=" + val); 4117 } 4118 } 4119 }; 4120 _registerComplexSpecialProp("opacity,alpha,autoAlpha", {defaultValue:"1", parser:function(t, e, p, cssp, pt, plugin) { 4121 var b = parseFloat(_getStyle(t, "opacity", _cs, false, "1")), 4122 style = t.style, 4123 isAutoAlpha = (p === "autoAlpha"); 4124 if (typeof(e) === "string" && e.charAt(1) === "=") { 4125 e = ((e.charAt(0) === "-") ? -1 : 1) * parseFloat(e.substr(2)) + b; 4126 } 4127 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) 4128 b = 0; 4129 } 4130 if (_supportsOpacity) { 4131 pt = new CSSPropTween(style, "opacity", b, e - b, pt); 4132 } else { 4133 pt = new CSSPropTween(style, "opacity", b * 100, (e - b) * 100, pt); 4134 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. 4135 style.zoom = 1; //helps correct an IE issue. 4136 pt.type = 2; 4137 pt.b = "alpha(opacity=" + pt.s + ")"; 4138 pt.e = "alpha(opacity=" + (pt.s + pt.c) + ")"; 4139 pt.data = t; 4140 pt.plugin = plugin; 4141 pt.setRatio = _setIEOpacityRatio; 4142 } 4143 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 4144 pt = new CSSPropTween(style, "visibility", 0, 0, pt, -1, null, false, 0, ((b !== 0) ? "inherit" : "hidden"), ((e === 0) ? "hidden" : "inherit")); 4145 pt.xs0 = "inherit"; 4146 cssp._overwriteProps.push(pt.n); 4147 cssp._overwriteProps.push(p); 4148 } 4149 return pt; 4150 }}); 4151 4152 4153 var _removeProp = function(s, p) { 4154 if (p) { 4155 if (s.removeProperty) { 4156 if (p.substr(0,2) === "ms") { //Microsoft browsers don't conform to the standard of capping 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) 4157 p = "M" + p.substr(1); 4158 } 4159 s.removeProperty(p.replace(_capsExp, "-$1").toLowerCase()); 4160 } else { //note: old versions of IE use "removeAttribute()" instead of "removeProperty()" 4161 s.removeAttribute(p); 4162 } 4163 } 4164 }, 4165 _setClassNameRatio = function(v) { 4166 this.t._gsClassPT = this; 4167 if (v === 1 || v === 0) { 4168 this.t.setAttribute("class", (v === 0) ? this.b : this.e); 4169 var mpt = this.data, //first MiniPropTween 4170 s = this.t.style; 4171 while (mpt) { 4172 if (!mpt.v) { 4173 _removeProp(s, mpt.p); 4174 } else { 4175 s[mpt.p] = mpt.v; 4176 } 4177 mpt = mpt._next; 4178 } 4179 if (v === 1 && this.t._gsClassPT === this) { 4180 this.t._gsClassPT = null; 4181 } 4182 } else if (this.t.getAttribute("class") !== this.e) { 4183 this.t.setAttribute("class", this.e); 4184 } 4185 }; 4186 _registerComplexSpecialProp("className", {parser:function(t, e, p, cssp, pt, plugin, vars) { 4187 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. 4188 cssText = t.style.cssText, 4189 difData, bs, cnpt, cnptLookup, mpt; 4190 pt = cssp._classNamePT = new CSSPropTween(t, p, 0, 0, pt, 2); 4191 pt.setRatio = _setClassNameRatio; 4192 pt.pr = -11; 4193 _hasPriority = true; 4194 pt.b = b; 4195 bs = _getAllStyles(t, _cs); 4196 //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
4196ing that were there just for class-specific values) 4197 cnpt = t._gsClassPT; 4198 if (cnpt) { 4199 cnptLookup = {}; 4200 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. 4201 while (mpt) { 4202 cnptLookup[mpt.p] = 1; 4203 mpt = mpt._next; 4204 } 4205 cnpt.setRatio(1); 4206 } 4207 t._gsClassPT = pt; 4208 pt.e = (e.charAt(1) !== "=") ? e : b.replace(new RegExp("\\s*\\b" + e.substr(2) + "\\b"), "") + ((e.charAt(0) === "+") ? " " + e.substr(2) : ""); 4209 if (cssp._tween._duration) { //if it's a zero-duration tween, there's no need to tween anything or parse the data. In fact, if we switch classes temporarily (which we must do for proper parsing) and the class has a transition applied, it could cause a quick flash to the end state and back again initially in some browsers. 4210 t.setAttribute("class", pt.e); 4211 difData = _cssDif(t, bs, _getAllStyles(t), vars, cnptLookup); 4212 t.setAttribute("class", b); 4213 pt.data = difData.firstMPT; 4214 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). 4215 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) 4216 } 4217 return pt; 4218 }}); 4219 4220 4221 var _setClearPropsRatio = function(v) { 4222 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). 4223 var s = this.t.style, 4224 transformParse = _specialProps.transform.parse, 4225 a, p, i, clearTransform; 4226 if (this.e === "all") { 4227 s.cssText = ""; 4228 clearTransform = true; 4229 } else { 4230 a = this.e.split(" ").join("").split(","); 4231 i = a.length; 4232 while (--i > -1) { 4233 p = a[i]; 4234 if (_specialProps[p]) { 4235 if (_specialProps[p].parse === transformParse) { 4236 clearTransform = true; 4237 } else { 4238 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" 4239 } 4240 } 4241 _removeProp(s, p); 4242 } 4243 } 4244 if (clearTransform) { 4245 _removeProp(s, _transformProp); 4246 if (this.t._gsTransform) { 4247 delete this.t._gsTransform; 4248 } 4249 } 4250 4251 } 4252 }; 4253 _registerComplexSpecialProp("clearProps", {parser:function(t, e, p, cssp, pt) { 4254 pt = new CSSPropTween(t, p, 0, 0, pt, 2); 4255 pt.setRatio = _setClearPropsRatio; 4256 pt.e = e; 4257 pt.pr = -10; 4258 pt.data = cssp._tween; 4259 _hasPriority = true; 4260 return pt; 4261 }}); 4262 4263 p = "bezier,throwProps,physicsProps,physics2D".split(","); 4264 i = p.length; 4265 while (i--) { 4266 _registerPluginProp(p[i]); 4267 } 4268 4269 4270 4271 4272 4273 4274 4275 4276 p = CSSPlugin.prototype; 4277 p._firstPT = null; 4278 4279 //gets called when the tween renders for the first time. This kicks everything off, recording start/end values, etc. 4280 p._onInitTween = function(target, vars, tween) { 4281 if (!target.nodeType) { //css is only for dom elements 4282 return false; 4283 } 4284 this._target = target; 4285 this._tween = tween; 4286 this._vars = vars; 4287 _autoRound = vars.autoRound; 4288 _hasPriority = false;
4289 _suffixMap = vars.suffixMap || CSSPlugin.suffixMap; 4290 _cs = _getComputedStyle(target, ""); 4291 _overwriteProps = this._overwriteProps; 4292 var style = target.style, 4293 v, pt, pt2, first, last, next, zIndex, tpt, threeD; 4294 if (_reqSafariFix) if (style.zIndex === "") { 4295 v = _getStyle(target, "zIndex", _cs); 4296 if (v === "auto" || v === "") { 4297 //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. 4298 this._addLazySet(style, "zIndex", 0); 4299 } 4300 } 4301 4302 if (typeof(vars) === "string") { 4303 first = style.cssText; 4304 v = _getAllStyles(target, _cs); 4305 style.cssText = first + ";" + vars; 4306 v = _cssDif(target, v, _getAllStyles(target)).difs; 4307 if (!_supportsOpacity && _opacityValExp.test(vars)) { 4308 v.opacity = parseFloat( RegExp.$1 ); 4309 } 4310 vars = v; 4311 style.cssText = first; 4312 } 4313 this._firstPT = pt = this.parse(target, vars, null); 4314 4315 if (this._transformType) { 4316 threeD = (this._transformType === 3); 4317 if (!_transformProp) { 4318 style.zoom = 1; //helps correct an IE issue. 4319 } else if (_isSafari) { 4320 _reqSafariFix = true; 4321 //if zIndex isn't set, iOS Safari doesn't repaint things correctly sometimes (seemingly at random). 4322 if (style.zIndex === "") { 4323 zIndex = _getStyle(target, "zIndex", _cs); 4324 if (zIndex === "auto" || zIndex === "") { 4325 this._addLazySet(style, "zIndex", 0); 4326 } 4327 } 4328 //Setting WebkitBackfaceVisibility corrects 3 bugs: 4329 // 1) [non-Android] Safari skips rendering changes to "top" and "left" that are made on the same frame/render as a transform update. 4330 // 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. 4331 // 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. 4332 //Note: we allow the user to override the auto-setting by defining WebkitBackfaceVisibility in the vars of the tween. 4333 if (_isSafariLT6) { 4334 this._addLazySet(style, "WebkitBackfaceVisibility", this._vars.WebkitBackfaceVisibility || (threeD ? "visible" : "hidden")); 4335 } 4336 } 4337 pt2 = pt; 4338 while (pt2 && pt2._next) { 4339 pt2 = pt2._next; 4340 } 4341 tpt = new CSSPropTween(target, "transform", 0, 0, null, 2); 4342 this._linkCSSP(tpt, null, pt2); 4343 tpt.setRatio = (threeD && _supports3D) ? _set3DTransformRatio : _transformProp ? _set2DTransformRatio : _setIETransformRatio; 4344 tpt.data = this._transform || _getTransform(target, _cs, true); 4345 _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. 4346 } 4347 4348 if (_hasPriority) { 4349 //reorders the linked list in order of pr (priority) 4350 while (pt) { 4351 next = pt._next; 4352 pt2 = first; 4353 while (pt2 && pt2.pr > pt.pr) { 4354 pt2 = pt2._next; 4355 } 4356 if ((pt._prev = pt2 ? pt2._prev : last)) { 4357 pt._prev._next = pt; 4358 } else { 4359 first = pt; 4360 } 4361 if ((pt._next = pt2)) { 4362 pt2._prev = pt; 4363 } else { 4364 last = pt; 4365 } 4366 pt = next; 4367 } 4368 this._firstPT = first; 4369 } 4370 return true; 4371 }; 4372 4373 4374 p.parse = function(target, vars, pt, plugin) { 4375 var style = target.style, 4376 p, sp, bn, en, bs, es, bsfx, esfx, isStr, rel; 4377 for (p in vars) { 4378 es = vars[p]; //ending value string 4379 sp = _specialProps[p]; //SpecialProp lookup. 4380 if (sp) { 4381 pt = sp.parse(target, es, p, this, pt, plugin, vars); 4382 4383 } else { 4384 bs = _getStyle(target, p, _cs) + ""; 4385 isStr = (typeof(es) === "string"); 4386 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: 4387 if (!isStr) { 4388 es = _parseColor(es); 4389 es = ((es.length > 3) ? "rgba(" : "rgb(") + es.join(",") + ")"; 4390 } 4391 pt = _parseComplex(style, p, bs, es, true, "transparent", pt, 0, plugin); 4392 4393 } else if (isStr && (es.indexOf(" ") !== -1 || es.indexOf(",") !== -1)) { 4394 pt = _parseComplex(style, p, bs, es, true, null, pt, 0, plugin); 4395 4396 } else { 4397 bn = parseFloat(bs); 4398 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. 4399 4400 if (bs === "" || bs === "auto") { 4401 if (p === "width" || p === "height") { 4402 bn = _getDimension(target, p, _cs); 4403 bsfx = "px"; 4404 } else if (p === "left" || p === "top") {
4405 bn = _calculateOffset(target, p, _cs); 4406 bsfx = "px"; 4407 } else { 4408 bn = (p !== "opacity") ? 0 : 1; 4409 bsfx = ""; 4410 } 4411 } 4412 4413 rel = (isStr && es.charAt(1) === "="); 4414 if (rel) { 4415 en = parseInt(es.charAt(0) + "1", 10); 4416 es = es.substr(2); 4417 en *= parseFloat(es); 4418 esfx = es.replace(_suffixExp, ""); 4419 } else { 4420 en = parseFloat(es); 4421 esfx = isStr ? es.substr((en + "").length) || "" : ""; 4422 } 4423 4424 if (esfx === "") { 4425 esfx = (p in _suffixMap) ? _suffixMap[p] : bsfx; //populate the end suffix, prioritizing the map, then if none is found, use the beginning suffix. 4426 } 4427 4428 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. 4429 4430 //if the beginning/ending suffixes don't match, normalize them... 4431 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! 4432 bn = _convertToPixels(target, p, bn, bsfx); 4433 if (esfx === "%") { 4434 bn /= _convertToPixels(target, p, 100, "%") / 100; 4435 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. 4436 bs = bn + "%"; 4437 } 4438 4439 } else if (esfx === "em") { 4440 bn /= _convertToPixels(target, p, 1, "em"); 4441 4442 //otherwise convert to pixels. 4443 } else if (esfx !== "px") { 4444 en = _convertToPixels(target, p, en, esfx); 4445 esfx = "px"; //we don't use bsfx after this, so we don't need to set it to px too. 4446 } 4447 if (rel) if (en || en === 0) { 4448 es = (en + bn) + esfx; //the changes we made affect relative calculations, so adjust the end value here. 4449 } 4450 } 4451 4452 if (rel) { 4453 en += bn; 4454 } 4455 4456 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. 4457 pt = new CSSPropTween(style, p, bn, en - bn, pt, 0, p, (_autoRound !== false && (esfx === "px" || p === "zIndex")), 0, bs, es); 4458 pt.xs0 = esfx; 4459 //DEBUG: _log("tween "+p+" from "+pt.b+" ("+bn+esfx+") to "+pt.e+" with suffix: "+pt.xs0); 4460 } else if (style[p] === undefined || !es && (es + "" === "NaN" || es == null)) { 4461 _log("invalid " + p + " tween value: " + vars[p]); 4462 } else { 4463 pt = new CSSPropTween(style, p, en || bn || 0, 0, pt, -1, p, false, 0, bs, es); 4464 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. 4465 //DEBUG: _log("non-tweening value "+p+": "+pt.xs0); 4466 } 4467 } 4468 } 4469 if (plugin) if (pt && !pt.plugin) { 4470 pt.plugin = plugin; 4471 } 4472 } 4473 return pt; 4474 }; 4475 4476 4477 //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. 4478 p.setRatio = function(v) { 4479 var pt = this._firstPT, 4480 min = 0.000001, 4481 val, str, i; 4482 //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). 4483 if (v === 1 && (this._tween._time === this._tween._duration || this._tween._time === 0)) { 4484 while (pt) { 4485 if (pt.type !== 2) { 4486 pt.t[pt.p] = pt.e; 4487 } else { 4488 pt.setRatio(v); 4489 } 4490 pt = pt._next; 4491 } 4492 4493 } else if (v || !(this._tween._time === this._tween._duration || this._tween._time === 0) || this._tween._rawPrevTime === -0.000001) { 4494 while (pt) { 4495 val = pt.c * v + pt.s; 4496 if (pt.r) { 4497 val = Math.round(val); 4498 } else if (val < min) if (val > -min) { 4499 val = 0; 4500 } 4501 if (!pt.type) { 4502 pt.t[pt.p] = val + pt.xs0; 4503 } else if (pt.type === 1) { //complex value (one that typically has multiple numbers inside a string, like "rect(5px,10px,20px,25px)" 4504 i = pt.l; 4505 if (i === 2) { 4506 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2; 4507 } else if (i === 3) { 4508 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3; 4509 } else if (i === 4) { 4510 pt.t[pt.p] = pt.xs0 + val + pt.xs1 + pt.xn1 + pt.xs2 + pt.xn2 + pt.xs3 + pt.xn3 + pt.xs4; 4511 } else if (i === 5) { 4512 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; 4513 } else { 4514 str = pt.xs0 + val + pt.xs1; 4515 for (i = 1; i < pt.l; i++) {
4516 str += pt["xn"+i] + pt["xs"+(i+1)]; 4517 } 4518 pt.t[pt.p] = str; 4519 } 4520 4521 } else if (pt.type === -1) { //non-tweening value 4522 pt.t[pt.p] = pt.xs0; 4523 4524 } else if (pt.setRatio) { //custom setRatio() for things like SpecialProps, external plugins, etc. 4525 pt.setRatio(v); 4526 } 4527 pt = pt._next; 4528 } 4529 4530 //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). 4531 } else { 4532 while (pt) { 4533 if (pt.type !== 2) { 4534 pt.t[pt.p] = pt.b; 4535 } else { 4536 pt.setRatio(v); 4537 } 4538 pt = pt._next; 4539 } 4540 } 4541 }; 4542 4543 /** 4544 * @private 4545 * Forces rendering of the target's transforms (rotation, scale, etc.) whenever the CSSPlugin's setRatio() is called. 4546 * Basically, this tells the CSSPlugin to create a CSSPropTween (type 2) after instantiation that runs last in the linked 4547 * list and calls the appropriate (3D or 2D) rendering function. We separate this into its own method so that we can call 4548 * it from other plugins like BezierPlugin if, for example, it needs to apply an autoRotation and this CSSPlugin 4549 * doesn't have any transform-related properties of its own. You can call this method as many times as you 4550 * want and it won't create duplicate CSSPropTweens. 4551 * 4552 * @param {boolean} threeD if true, it should apply 3D tweens (otherwise, just 2D ones are fine and typically faster) 4553 */ 4554 p._enableTransforms = function(threeD) { 4555 this._transform = this._transform || _getTransform(this._target, _cs, true); //ensures that the element has a _gsTransform property with the appropriate values. 4556 this._transformType = (!(this._transform.svg && _useSVGTransformAttr) && (threeD || this._transformType === 3)) ? 3 : 2; 4557 }; 4558 4559 var lazySet = function(v) { 4560 this.t[this.p] = this.e; 4561 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. 4562 }; 4563 /** @private Gives us a way to set a value on the first render (and only the first render). **/ 4564 p._addLazySet = function(t, p, v) { 4565 var pt = this._firstPT = new CSSPropTween(t, p, 0, 0, this._firstPT, 2); 4566 pt.e = v; 4567 pt.setRatio = lazySet; 4568 pt.data = this; 4569 }; 4570 4571 /** @private **/ 4572 p._linkCSSP = function(pt, next, prev, remove) { 4573 if (pt) { 4574 if (next) { 4575 next._prev = pt; 4576 } 4577 if (pt._next) { 4578 pt._next._prev = pt._prev; 4579 } 4580 if (pt._prev) { 4581 pt._prev._next = pt._next; 4582 } else if (this._firstPT === pt) { 4583 this._firstPT = pt._next; 4584 remove = true; //just to prevent resetting this._firstPT 5 lines down in case pt._next is null. (optimized for speed) 4585 } 4586 if (prev) { 4587 prev._next = pt; 4588 } else if (!remove && this._firstPT === null) { 4589 this._firstPT = pt; 4590 } 4591 pt._next = next; 4592 pt._prev = prev; 4593 } 4594 return pt; 4595 }; 4596 4597 //we need to make sure that if alpha or autoAlpha is killed, opacity is too. And autoAlpha affects the "visibility" property. 4598 p._kill = function(lookup) { 4599 var copy = lookup, 4600 pt, p, xfirst; 4601 if (lookup.autoAlpha || lookup.alpha) { 4602 copy = {}; 4603 for (p in lookup) { //copy the lookup so that we're not changing the original which may be passed elsewhere. 4604 copy[p] = lookup[p]; 4605 } 4606 copy.opacity = 1; 4607 if (copy.autoAlpha) { 4608 copy.visibility = 1; 4609 } 4610 } 4611 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". 4612 xfirst = pt.xfirst; 4613 if (xfirst && xfirst._prev) { 4614 this._linkCSSP(xfirst._prev, pt._next, xfirst._prev._prev); //break off the prev 4615 } else if (xfirst === this._firstPT) { 4616 this._firstPT = pt._next; 4617 } 4618 if (pt._next) { 4619 this._linkCSSP(pt._next, pt._next._next, xfirst._prev); 4620 } 4621 this._classNamePT = null; 4622 } 4623 return TweenPlugin.prototype._kill.call(this, copy); 4624 }; 4625 4626 4627 4628 //used by cascadeTo() for gathering all the style properties of each child element into an array for c
4628omparison. 4629 var _getChildStyles = function(e, props, targets) { 4630 var children, i, child, type; 4631 if (e.slice) { 4632 i = e.length; 4633 while (--i > -1) { 4634 _getChildStyles(e[i], props, targets); 4635 } 4636 return; 4637 } 4638 children = e.childNodes; 4639 i = children.length; 4640 while (--i > -1) { 4641 child = children[i]; 4642 type = child.type; 4643 if (child.style) { 4644 props.push(_getAllStyles(child)); 4645 if (targets) { 4646 targets.push(child); 4647 } 4648 } 4649 if ((type === 1 || type === 9 || type === 11) && child.childNodes.length) { 4650 _getChildStyles(child, props, targets); 4651 } 4652 } 4653 }; 4654 4655 /** 4656 * Typically only useful for className tweens that may affect child elements, this method creates a TweenLite 4657 * and then compares the style properties of all the target's child elements at the tween's start and end, and 4658 * if any are different, it also creates tweens for those and returns an array containing ALL of the resulting 4659 * tweens (so that you can easily add() them to a TimelineLite, for example). The reason this functionality is 4660 * wrapped into a separate static method of CSSPlugin instead of being integrated into all regular className tweens 4661 * is because it creates entirely new tweens that may have completely different targets than the original tween, 4662 * so if they were all lumped into the original tween instance, it would be inconsistent with the rest of the API 4663 * and it would create other problems. For example: 4664 * - 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) 4665 * - 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. 4666 * - 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. 4667 * 4668 * @param {Object} target object to be tweened 4669 * @param {number} Duration in seconds (or frames for frames-based tweens) 4670 * @param {Object} Object containing the end values, like {className:"newClass", ease:Linear.easeNone} 4671 * @return {Array} An array of TweenLite instances 4672 */ 4673 CSSPlugin.cascadeTo = function(target, duration, vars) { 4674 var tween = TweenLite.to(target, duration, vars), 4675 results = [tween], 4676 b = [], 4677 e = [], 4678 targets = [], 4679 _reservedProps = TweenLite._internals.reservedProps, 4680 i, difs, p; 4681 target = tween._targets || tween.target; 4682 _getChildStyles(target, b, targets); 4683 tween.render(duration, true); 4684 _getChildStyles(target, e); 4685 tween.render(0, true); 4686 tween._enabled(true); 4687 i = targets.length; 4688 while (--i > -1) { 4689 difs = _cssDif(targets[i], b[i], e[i]); 4690 if (difs.firstMPT) { 4691 difs = difs.difs; 4692 for (p in vars) { 4693 if (_reservedProps[p]) { 4694 difs[p] = vars[p]; 4695 } 4696 } 4697 results.push( TweenLite.to(targets[i], duration, difs) ); 4698 } 4699 } 4700 return results; 4701 }; 4702 4703 TweenPlugin.activate([CSSPlugin]); 4704 return CSSPlugin; 4705 4706 }, true); 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718/* 4719 * ---------------------------------------------------------------- 4720 * RoundPropsPlugin 4721 * ---------------------------------------------------------------- 4722 */ 4723 (function() { 4724 4725 var RoundPropsPlugin = _gsScope._gsDefine.plugin({ 4726 propName: "roundProps", 4727 priority: -1, 4728 API: 2, 4729 4730 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 4731 init: function(target, value, tween) { 4732 this._tween = tween; 4733 return true; 4734 } 4735 4736 }), 4737 p = RoundPropsPlugin.prototype; 4738 4739 p._onInitAllProps = function() { 4740 var tween = this._tween, 4741 rp = (tween.vars.roundProps instanceof Array) ? tween.vars.roundProps : tween.vars.roundProps.split(","), 4742 i = rp.length, 4743 lookup = {}, 4744 rpt = tween._propLookup.roundProps, 4745 prop, pt, next; 4746 while (--i > -1) { 4747 lookup[rp[i]] = 1; 4748 } 4749 i = rp.length; 4750 while (--i > -1) { 4751 prop = rp[i]; 4752 pt = tween._firstPT; 4753 while (pt) { 4754 next = pt._next; //record here, because it may get removed 4755 if (pt.pg) { 4756 pt.t._roundProps(lookup, true); 4757 } else if (pt.n === prop) { 4758 this._add(pt.t, prop, pt.s, pt.c); 4759 //remove from linked list 4760 if (next) { 4761 next._prev = pt._prev; 4762 } 4763 if (pt._prev) { 4764 pt._prev._next = next; 4765 } else if (tween._firstPT === pt) { 4766 tween._firstPT = next; 4767 } 4768 pt._next = pt._prev = null; 4769 tween._propLookup[prop] = rpt; 4770 } 4771 pt = next; 4772 } 4773 } 4774 return false;
4775 }; 4776 4777 p._add = function(target, p, s, c) { 4778 this._addTween(target, p, s, s + c, p, true); 4779 this._overwriteProps.push(p); 4780 }; 4781 4782 }()); 4783 4784 4785 4786 4787 4788 4789 4790 4791 4792 4793/* 4794 * ---------------------------------------------------------------- 4795 * AttrPlugin 4796 * ---------------------------------------------------------------- 4797 */ 4798 _gsScope._gsDefine.plugin({ 4799 propName: "attr", 4800 API: 2, 4801 version: "0.3.3", 4802 4803 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 4804 init: function(target, value, tween) { 4805 var p, start, end; 4806 if (typeof(target.setAttribute) !== "function") { 4807 return false; 4808 } 4809 this._target = target; 4810 this._proxy = {}; 4811 this._start = {}; // we record start and end values exactly as they are in case they're strings (not numbers) - we need to be able to revert to them cleanly. 4812 this._end = {}; 4813 for (p in value) { 4814 this._start[p] = this._proxy[p] = start = target.getAttribute(p); 4815 end = this._addTween(this._proxy, p, parseFloat(start), value[p], p); 4816 this._end[p] = end ? end.s + end.c : value[p]; 4817 this._overwriteProps.push(p); 4818 } 4819 return true; 4820 }, 4821 4822 //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.) 4823 set: function(ratio) { 4824 this._super.setRatio.call(this, ratio); 4825 var props = this._overwriteProps, 4826 i = props.length, 4827 lookup = (ratio === 1) ? this._end : ratio ? this._proxy : this._start, 4828 p; 4829 while (--i > -1) { 4830 p = props[i]; 4831 this._target.setAttribute(p, lookup[p] + ""); 4832 } 4833 } 4834 4835 }); 4836 4837 4838 4839 4840 4841 4842 4843 4844 4845 4846/* 4847 * ---------------------------------------------------------------- 4848 * DirectionalRotationPlugin 4849 * ---------------------------------------------------------------- 4850 */ 4851 _gsScope._gsDefine.plugin({ 4852 propName: "directionalRotation", 4853 version: "0.2.1", 4854 API: 2, 4855 4856 //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run. 4857 init: function(target, value, tween) { 4858 if (typeof(value) !== "object") { 4859 value = {rotation:value}; 4860 } 4861 this.finals = {}; 4862 var cap = (value.useRadians === true) ? Math.PI * 2 : 360, 4863 min = 0.000001, 4864 p, v, start, end, dif, split; 4865 for (p in value) { 4866 if (p !== "useRadians") { 4867 split = (value[p] + "").split("_"); 4868 v = split[0]; 4869 start = parseFloat( (typeof(target[p]) !== "function") ? target[p] : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() ); 4870 end = this.finals[p] = (typeof(v) === "string" && v.charAt(1) === "=") ? start + parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : Number(v) || 0; 4871 dif = end - start; 4872 if (split.length) { 4873 v = split.join("_"); 4874 if (v.indexOf("short") !== -1) { 4875 dif = dif % cap; 4876 if (dif !== dif % (cap / 2)) { 4877 dif = (dif < 0) ? dif + cap : dif - cap; 4878 } 4879 } 4880 if (v.indexOf("_cw") !== -1 && dif < 0) { 4881 dif = ((dif + cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 4882 } else if (v.indexOf("ccw") !== -1 && dif > 0) { 4883 dif = ((dif - cap * 9999999999) % cap) - ((dif / cap) | 0) * cap; 4884 } 4885 } 4886 if (dif > min || dif < -min) { 4887 this._addTween(target, p, start, start + dif, p); 4888 this._overwriteProps.push(p); 4889 } 4890 } 4891 } 4892 return true; 4893 }, 4894 4895 //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.) 4896 set: function(ratio) { 4897 var pt; 4898 if (ratio !== 1) { 4899 this._super.setRatio.call(this, ratio); 4900 } else { 4901 pt = this._firstPT; 4902 while (pt) { 4903 if (pt.f) { 4904 pt.t[pt.p](this.finals[pt.p]); 4905 } else { 4906 pt.t[pt.p] = this.finals[pt.p]; 4907 } 4908 pt = pt._next; 4909 } 4910 } 4911 } 4912 4913 })._autoCSS = true; 4914 4915 4916 4917 4918 4919 4920 4921 4922 4923 4924 4925/* 4926 * ---------------------------------------------------------------- 4927 * EasePack 4928 * ---------------------------------------------------------------- 4929 */ 4930 _gsScope._gsDefine("easing.Back", ["easing.Ease"], function(Ease) { 4931 4932 var w = (_gsScope.GreenSockGlobals || _gsScope), 4933 gs = w.com.greensock, 4934 _2PI = Math.PI * 2, 4935 _HALF_PI = Math.PI / 2, 4936 _class = gs._class, 4937 _create = function(n, f) { 4938 var C = _class("easing." + n, function(){}, true), 4939 p = C.prototype = new Ease(); 4940 p.constructor = C; 4941 p.getRatio = f; 4942 return C; 4943 }, 4944 _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. 4945 _wrap = function(name, EaseOut, EaseIn, EaseInOut, aliases) { 4946 var C = _class("easing."+name, { 4947 easeOut:new EaseOut(), 4948 easeIn:new EaseIn(), 4949 easeInOut:new EaseInOut() 4950 }, true); 4951 _easeReg(C, name); 4952 return C; 4953 }, 4954 EasePoint = function(time, value, next) { 4955 this.t = time; 4956 this.v = value; 4957 if (next) { 4958 this.next = next; 4959 next.prev = this; 4960 this.c = next.v - value; 4961 this.gap = next.t - time; 4962 } 4963 }, 4964 4965 //Back 4966 _createBack = function(n, f) { 4967 var C = _class("easing." + n, function(overshoot) { 4968 this._p1 = (overshoot || overshoot === 0) ? overshoot : 1.70158; 4969 this._p2 = this._p1 * 1.525; 4970 }, true), 4971 p = C.prototype = new Ease(); 4972 p.constructor = C; 4973 p.getRatio = f; 4974 p.config = function(overshoot) { 4975 return new C(overshoot); 4976 }; 4977 return C; 4978 }, 4979 4980 Back = _wrap("Back", 4981 _createBack("BackOut", function(p) { 4982 return ((p = p - 1) * p * ((this._p1 + 1) * p + this._p1) + 1); 4983 }), 4984 _createBack("BackIn", function(p) { 4985 return p * p * ((this._p1 + 1) * p - this._p1); 4986 }), 4987 _createBack("BackInOut", function(p) { 4988 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); 4989 }) 4990 ), 4991 4992 4993 //SlowMo
4994 SlowMo = _class("easing.SlowMo", function(linearRatio, power, yoyoMode) { 4995 power = (power || power === 0) ? power : 0.7; 4996 if (linearRatio == null) { 4997 linearRatio = 0.7; 4998 } else if (linearRatio > 1) { 4999 linearRatio = 1; 5000 } 5001 this._p = (linearRatio !== 1) ? power : 0; 5002 this._p1 = (1 - linearRatio) / 2; 5003 this._p2 = linearRatio; 5004 this._p3 = this._p1 + this._p2; 5005 this._calcEnd = (yoyoMode === true); 5006 }, true), 5007 p = SlowMo.prototype = new Ease(), 5008 SteppedEase, RoughEase, _createElastic; 5009 5010 p.constructor = SlowMo; 5011 p.getRatio = function(p) { 5012 var r = p + (0.5 - p) * this._p; 5013 if (p < this._p1) { 5014 return this._calcEnd ? 1 - ((p = 1 - (p / this._p1)) * p) : r - ((p = 1 - (p / this._p1)) * p * p * p * r); 5015 } else if (p > this._p3) { 5016 return this._calcEnd ? 1 - (p = (p - this._p3) / this._p1) * p : r + ((p - r) * (p = (p - this._p3) / this._p1) * p * p * p); 5017 } 5018 return this._calcEnd ? 1 : r; 5019 }; 5020 SlowMo.ease = new SlowMo(0.7, 0.7); 5021 5022 p.config = SlowMo.config = function(linearRatio, power, yoyoMode) { 5023 return new SlowMo(linearRatio, power, yoyoMode); 5024 }; 5025 5026 5027 //SteppedEase 5028 SteppedEase = _class("easing.SteppedEase", function(steps) { 5029 steps = steps || 1; 5030 this._p1 = 1 / steps; 5031 this._p2 = steps + 1; 5032 }, true); 5033 p = SteppedEase.prototype = new Ease(); 5034 p.constructor = SteppedEase; 5035 p.getRatio = function(p) { 5036 if (p < 0) { 5037 p = 0; 5038 } else if (p >= 1) { 5039 p = 0.999999999; 5040 } 5041 return ((this._p2 * p) >> 0) * this._p1; 5042 }; 5043 p.config = SteppedEase.config = function(steps) { 5044 return new SteppedEase(steps); 5045 }; 5046 5047 5048 //RoughEase 5049 RoughEase = _class("easing.RoughEase", function(vars) { 5050 vars = vars || {}; 5051 var taper = vars.taper || "none", 5052 a = [], 5053 cnt = 0, 5054 points = (vars.points || 20) | 0, 5055 i = points, 5056 randomize = (vars.randomize !== false), 5057 clamp = (vars.clamp === true), 5058 template = (vars.template instanceof Ease) ? vars.template : null, 5059 strength = (typeof(vars.strength) === "number") ? vars.strength * 0.4 : 0.4, 5060 x, y, bump, invX, obj, pnt; 5061 while (--i > -1) { 5062 x = randomize ? Math.random() : (1 / points) * i; 5063 y = template ? template.getRatio(x) : x; 5064 if (taper === "none") { 5065 bump = strength; 5066 } else if (taper === "out") { 5067 invX = 1 - x; 5068 bump = invX * invX * strength; 5069 } else if (taper === "in") { 5070 bump = x * x * strength; 5071 } else if (x < 0.5) { //"both" (start) 5072 invX = x * 2; 5073 bump = invX * invX * 0.5 * strength; 5074 } else { //"both" (end) 5075 invX = (1 - x) * 2; 5076 bump = invX * invX * 0.5 * strength; 5077 } 5078 if (randomize) { 5079 y += (Math.random() * bump) - (bump * 0.5); 5080 } else if (i % 2) { 5081 y += bump * 0.5; 5082 } else { 5083 y -= bump * 0.5; 5084 } 5085 if (clamp) { 5086 if (y > 1) { 5087 y = 1; 5088 } else if (y < 0) { 5089 y = 0; 5090 } 5091 } 5092 a[cnt++] = {x:x, y:y}; 5093 } 5094 a.sort(function(a, b) { 5095 return a.x - b.x; 5096 }); 5097 5098 pnt = new EasePoint(1, 1, null); 5099 i = points; 5100 while (--i > -1) { 5101 obj = a[i]; 5102 pnt = new EasePoint(obj.x, obj.y, pnt); 5103 } 5104 5105 this._prev = new EasePoint(0, 0, (pnt.t !== 0) ? pnt : pnt.next); 5106 }, true); 5107 p = RoughEase.prototype = new Ease(); 5108 p.constructor = RoughEase; 5109 p.getRatio = function(p) { 5110 var pnt = this._prev; 5111 if (p > pnt.t) { 5112 while (pnt.next && p >= pnt.t) { 5113 pnt = pnt.next; 5114 } 5115 pnt = pnt.prev; 5116 } else { 5117 while (pnt.prev && p <= pnt.t) { 5118 pnt = pnt.prev; 5119 } 5120 } 5121 this._prev = pnt; 5122 return (pnt.v + ((p - pnt.t) / pnt.gap) * pnt.c); 5123 }; 5124 p.config = function(vars) { 5125 return new RoughEase(vars); 5126 }; 5127 RoughEase.ease = new RoughEase(); 5128 5129 5130 //Bounce 5131 _wrap("Bounce", 5132 _create("BounceOut", function(p) { 5133 if (p < 1 / 2.75) { 5134 return 7.5625 * p * p; 5135 } else if (p < 2 / 2.75) { 5136 return 7.5625 * (p -= 1.5 / 2.75) * p + 0.75; 5137 } else if (p < 2.5 / 2.75) { 5138 return 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375; 5139 } 5140 return 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375; 5141 }), 5142 _create("BounceIn", function(p) { 5143 if ((p = 1 - p) < 1 / 2.75) { 5144 return 1 - (7.5625 * p * p); 5145 } else if (p < 2 / 2.75) { 5146 return 1 - (7.5625 * (p -= 1.5 / 2.75) * p + 0.75); 5147 } else if (p < 2.5 / 2.75) { 5148 return 1 - (7.5625 * (p -= 2.25 / 2.75) * p + 0.9375); 5149 } 5150 return 1 - (7.5625 * (p -= 2.625 / 2.75) * p + 0.984375); 5151 }), 5152 _create("BounceInOut", function(p) { 5153 var invert = (p < 0.5); 5154 if (invert) { 5155 p = 1 - (p * 2); 5156 } else { 5157 p = (p * 2) - 1; 5158 } 5159 if (p < 1 / 2.75) { 5160 p = 7.5625 * p * p; 5161 } else if (p < 2 / 2.75) { 5162 p = 7.5625 * (p -= 1.5 / 2.75) * p + 0.75; 5163 } else if (p < 2.5 / 2.75) { 5164 p = 7.5625 * (p -= 2.25 / 2.75) * p + 0.9375; 5165 } else { 5166 p = 7.5625 * (p -= 2.625 / 2.75) * p + 0.984375; 5167 } 5168 return invert ? (1 - p) * 0.5 : p * 0.5 + 0.5; 5169 }) 5170 ); 5171 5172 5173 //CIRC 5174 _wrap("Circ", 5175 _create("CircOut", function(p) { 5176 return Math.sqrt(1 - (p = p - 1) * p); 5177 }), 5178 _create("CircIn", function(p) { 5179 return -(Math.sqrt(1 - (p * p)) - 1); 5180 }), 5181 _create("CircInOut", function(p) { 5182 return ((p*=2) < 1) ? -0.5 * (Math.sqrt(1 - p * p) - 1) : 0.5 * (Math.sqrt(1 - (p -= 2) * p) + 1); 5183 }) 5184 ); 5185 5186 5187 //Elastic 5188 _createElastic = function(n, f, def) { 5189 var C = _class("easing." + n, function(amplitude, period) { 5190 this._p1 = amplitude || 1; 5191 this._p2 = period || def; 5192 this._p3 = this._p2 / _2PI * (Math.asin(1 / this._p1) || 0); 5193 }, true), 5194 p = C.prototype = new Ease(); 5195 p.constructor = C; 5196 p.getRatio = f; 5197 p.config = function(amplitude, period) { 5198 return new C(amplitude, period); 5199 }; 5200 return C; 5201 }; 5202 _wrap("Elastic", 5203 _createElastic("ElasticOut", function(p) { 5204 return this._p1 * Math.pow(2, -10 * p) * Math.sin( (p - this._p3) * _2PI / this._p2 ) + 1; 5205 }, 0.3), 5206 _createElastic("ElasticIn", function(p) { 5207 return -(this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 )); 5208 }, 0.3), 5209 _createElastic("ElasticInOut", function(p) { 5210 return ((p *= 2) < 1) ? -0.5 * (this._p1 * Math.pow(2, 10 * (p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2)) : this._p1 * Math.pow(2, -10 *(p -= 1)) * Math.sin( (p - this._p3) * _2PI / this._p2 ) *0.5 + 1; 5211 }, 0.45) 5212 ); 5213 5214 5215 //Expo 5216 _wrap("Expo", 5217 _create("ExpoOut", function(p) { 5218 return 1 - Math.pow(2, -10 * p); 5219 }), 5220 _create("ExpoIn", function(p) { 5221 return Math.pow(2, 10 * (p - 1)) - 0.001; 5222 }), 5223 _create("ExpoInOut", function(p) { 5224 return ((p *= 2) < 1) ? 0.5 * Math.pow(2, 10 * (p - 1)) : 0.5 * (2 - Math.pow(2, -10 * (p - 1))); 5225 }) 5226 ); 5227 5228 5229 //Sine 5230 _wrap("Sine", 5231 _create("SineOut", function(p) { 5232 return Math.sin(p * _HALF_PI); 5233 }), 5234 _create("SineIn", function(p) { 5235 return -Math.cos(p * _HALF_PI) + 1; 5236 }), 5237 _create("SineInOut", function(p) { 5238 return -0.5 * (Math.cos(Math.PI * p) - 1); 5239 }) 5240 ); 5241 5242 _class("easing.EaseLookup", { 5243 find:function(s) { 5244 return Ease.map[s]; 5245 } 5246 }, true); 5247 5248 //register the non-standard eases 5249 _easeReg(w.SlowMo, "SlowMo", "ease,"); 5250 _easeReg(RoughEase, "RoughEase", "ease,");
5251 _easeReg(SteppedEase, "SteppedEase", "ease,"); 5252 5253 return Back; 5254 5255 }, true); 5256 5257 5258}); 5259 5260if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); } //necessary in case TweenLite was already loaded separately. 5261 5262 5263 5264 5265 5266 5267 5268 5269 5270 5271 5272/* 5273 * ---------------------------------------------------------------- 5274 * Base classes like TweenLite, SimpleTimeline, Ease, Ticker, etc. 5275 * ---------------------------------------------------------------- 5276 */ 5277(function(window, moduleName) { 5278 5279 "use strict"; 5280 var _globals = window.GreenSockGlobals = window.GreenSockGlobals || window; 5281 if (_globals.TweenLite) { 5282 return; //in case the core set of classes is already loaded, don't instantiate twice. 5283 } 5284 var _namespace = function(ns) { 5285 var a = ns.split("."), 5286 p = _globals, i; 5287 for (i = 0; i < a.length; i++) { 5288 p[a[i]] = p = p[a[i]] || {}; 5289 } 5290 return p; 5291 }, 5292 gs = _namespace("com.greensock"), 5293 _tinyNum = 0.0000000001, 5294 _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() 5295 var b = [], 5296 l = a.length, 5297 i; 5298 for (i = 0; i !== l; b.push(a[i++])); 5299 return b; 5300 }, 5301 _emptyFunc = function() {}, 5302 _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) 5303 var toString = Object.prototype.toString, 5304 array = toString.call([]); 5305 return function(obj) { 5306 return obj != null && (obj instanceof Array || (typeof(obj) === "object" && !!obj.push && toString.call(obj) === array)); 5307 }; 5308 }()), 5309 a, i, p, _ticker, _tickerActive, 5310 _defLookup = {}, 5311 5312 /** 5313 * @constructor 5314 * Defines a GreenSock class, optionally with an array of dependencies that must be instantiated first and passed into the definition. 5315 * This allows users to load GreenSock JS files in any order even if they have interdependencies (like CSSPlugin extends TweenPlugin which is 5316 * inside TweenLite.js, but if CSSPlugin is loaded first, it should wait to run its code until TweenLite.js loads and instantiates TweenPlugin 5317 * and then pass TweenPlugin to CSSPlugin's definition). This is all done automatically and internally. 5318 * 5319 * Every definition will be added to a "com.greensock" global object (typically window, but if a window.GreenSockGlobals object is found, 5320 * 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, 5321 * it is ALSO referenced at window.TweenLite. However some classes aren't considered global, like the base com.greensock.core.Animation class, so 5322 * those will only be at the package like window.com.greensock.core.Animation. Again, if you define a GreenSockGlobals object on the window, everything 5323 * gets tucked neatly inside there instead of on the window directly. This allows you to do advanced things like load multiple versions of GreenSock 5324 * 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 5325 * sandbox the banner one like: 5326 * 5327 * <script> 5328 * 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. 5329 * </script> 5330 * <script src="js/greensock/v1.7/TweenMax.js"></script> 5331 * <script> 5332 * 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(...) 5333 * </script> 5334 * <script src="js/greensock/v1.6/TweenMax.js"></script> 5335 * <script> 5336 * gs.TweenLite.to(...); //would use v1.7 5337 * TweenLite.to(...); //would use v1.6 5338 * </script> 5339 * 5340 * @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". 5341 * @param {!Array.<string>}
5341 dependencies An array of dependencies (described as their namespaces minus "com.greensock." prefix). For example ["TweenLite","plugins.TweenPlugin","core.Animation"] 5342 * @param {!function():Object} func The function that should be called and passed the resolved dependencies which will return the actual class for this definition. 5343 * @param {boolean=} global If true, the class will be added to the global scope (typically window unless you define a window.GreenSockGlobals object) 5344 */ 5345 Definition = function(ns, dependencies, func, global) { 5346 this.sc = (_defLookup[ns]) ? _defLookup[ns].sc : []; //subclasses 5347 _defLookup[ns] = this; 5348 this.gsClass = null; 5349 this.func = func; 5350 var _classes = []; 5351 this.check = function(init) { 5352 var i = dependencies.length, 5353 missing = i, 5354 cur, a, n, cl; 5355 while (--i > -1) { 5356 if ((cur = _defLookup[dependencies[i]] || new Definition(dependencies[i], [])).gsClass) { 5357 _classes[i] = cur.gsClass; 5358 missing--; 5359 } else if (init) { 5360 cur.sc.push(this); 5361 } 5362 } 5363 if (missing === 0 && func) { 5364 a = ("com.greensock." + ns).split("."); 5365 n = a.pop(); 5366 cl = _namespace(a.join("."))[n] = this.gsClass = func.apply(func, _classes); 5367 5368 //exports to multiple environments 5369 if (global) { 5370 _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.) 5371 if (typeof(define) === "function" && define.amd){ //AMD 5372 define((window.GreenSockAMDPath ? window.GreenSockAMDPath + "/" : "") + ns.split(".").pop(), [], function() { return cl; }); 5373 } else if (ns === moduleName && typeof(module) !== "undefined" && module.exports){ //node 5374 module.exports = cl; 5375 } 5376 } 5377 for (i = 0; i < this.sc.length; i++) { 5378 this.sc[i].check(); 5379 } 5380 } 5381 }; 5382 this.check(true); 5383 }, 5384 5385 //used to create Definition instances (which basically registers a class that has dependencies). 5386 _gsDefine = window._gsDefine = function(ns, dependencies, func, global) { 5387 return new Definition(ns, dependencies, func, global); 5388 }, 5389 5390 //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). 5391 _class = gs._class = function(ns, func, global) { 5392 func = func || function() {}; 5393 _gsDefine(ns, [], function(){ return func; }, global); 5394 return func; 5395 }; 5396 5397 _gsDefine.globals = _globals; 5398 5399 5400 5401/* 5402 * ---------------------------------------------------------------- 5403 * Ease 5404 * ---------------------------------------------------------------- 5405 */ 5406 var _baseParams = [0, 0, 1, 1], 5407 _blankArray = [], 5408 Ease = _class("easing.Ease", function(func, extraParams, type, power) { 5409 this._func = func; 5410 this._type = type || 0; 5411 this._power = power || 0; 5412 this._params = extraParams ? _baseParams.concat(extraParams) : _baseParams; 5413 }, true), 5414 _easeMap = Ease.map = {}, 5415 _easeReg = Ease.register = function(ease, names, types, create) { 5416 var na = names.split(","), 5417 i = na.length, 5418 ta = (types || "easeIn,easeOut,easeInOut").split(","), 5419 e, name, j, type; 5420 while (--i > -1) { 5421 name = na[i]; 5422 e = create ? _class("easing."+name, null, true) : gs.easing[name] || {}; 5423 j = ta.length; 5424 while (--j > -1) { 5425 type = ta[j]; 5426 _easeMap[name + "." + type] = _easeMap[type + name] = e[type] = ease.getRatio ? ease : ease[type] || new ease(); 5427 } 5428 } 5429 }; 5430 5431 p = Ease.prototype; 5432 p._calcEnd = false;
5433 p.getRatio = function(p) { 5434 if (this._func) { 5435 this._params[0] = p; 5436 return this._func.apply(null, this._params); 5437 } 5438 var t = this._type, 5439 pw = this._power, 5440 r = (t === 1) ? 1 - p : (t === 2) ? p : (p < 0.5) ? p * 2 : (1 - p) * 2; 5441 if (pw === 1) { 5442 r *= r; 5443 } else if (pw === 2) { 5444 r *= r * r; 5445 } else if (pw === 3) { 5446 r *= r * r * r; 5447 } else if (pw === 4) { 5448 r *= r * r * r * r; 5449 } 5450 return (t === 1) ? 1 - r : (t === 2) ? r : (p < 0.5) ? r / 2 : 1 - (r / 2); 5451 }; 5452 5453 //create all the standard eases like Linear, Quad, Cubic, Quart, Quint, Strong, Power0, Power1, Power2, Power3, and Power4 (each with easeIn, easeOut, and easeInOut) 5454 a = ["Linear","Quad","Cubic","Quart","Quint,Strong"]; 5455 i = a.length; 5456 while (--i > -1) { 5457 p = a[i]+",Power"+i; 5458 _easeReg(new Ease(null,null,1,i), p, "easeOut", true); 5459 _easeReg(new Ease(null,null,2,i), p, "easeIn" + ((i === 0) ? ",easeNone" : "")); 5460 _easeReg(new Ease(null,null,3,i), p, "easeInOut"); 5461 } 5462 _easeMap.linear = gs.easing.Linear.easeIn; 5463 _easeMap.swing = gs.easing.Quad.easeInOut; //for jQuery folks 5464 5465 5466/* 5467 * ---------------------------------------------------------------- 5468 * EventDispatcher 5469 * ---------------------------------------------------------------- 5470 */ 5471 var EventDispatcher = _class("events.EventDispatcher", function(target) { 5472 this._listeners = {}; 5473 this._eventTarget = target || this; 5474 }); 5475 p = EventDispatcher.prototype; 5476 5477 p.addEventListener = function(type, callback, scope, useParam, priority) { 5478 priority = priority || 0; 5479 var list = this._listeners[type], 5480 index = 0, 5481 listener, i; 5482 if (list == null) { 5483 this._listeners[type] = list = []; 5484 } 5485 i = list.length; 5486 while (--i > -1) { 5487 listener = list[i]; 5488 if (listener.c === callback && listener.s === scope) { 5489 list.splice(i, 1); 5490 } else if (index === 0 && listener.pr < priority) { 5491 index = i + 1; 5492 } 5493 } 5494 list.splice(index, 0, {c:callback, s:scope, up:useParam, pr:priority}); 5495 if (this === _ticker && !_tickerActive) { 5496 _ticker.wake(); 5497 } 5498 }; 5499 5500 p.removeEventListener = function(type, callback) { 5501 var list = this._listeners[type], i; 5502 if (list) { 5503 i = list.length; 5504 while (--i > -1) { 5505 if (list[i].c === callback) { 5506 list.splice(i, 1); 5507 return; 5508 } 5509 } 5510 } 5511 }; 5512 5513 p.dispatchEvent = function(type) { 5514 var list = this._listeners[type], 5515 i, t, listener; 5516 if (list) { 5517 i = list.length; 5518 t = this._eventTarget; 5519 while (--i > -1) { 5520 listener = list[i]; 5521 if (listener) { 5522 if (listener.up) { 5523 listener.c.call(listener.s || t, {type:type, target:t}); 5524 } else { 5525 listener.c.call(listener.s || t); 5526 } 5527 } 5528 } 5529 } 5530 }; 5531 5532 5533/* 5534 * ---------------------------------------------------------------- 5535 * Ticker 5536 * ---------------------------------------------------------------- 5537 */ 5538 var _reqAnimFrame = window.requestAnimationFrame, 5539 _cancelAnimFrame = window.cancelAnimationFrame, 5540 _getTime = Date.now || function() {return new Date().getTime();}, 5541 _lastUpdate = _getTime(); 5542 5543 //now try to determine the requestAnimationFrame and cancelAnimationFrame functions and if none are found, we'll use a setTimeout()/clearTimeout() polyfill. 5544 a = ["ms","moz","webkit","o"]; 5545 i = a.length; 5546 while (--i > -1 && !_reqAnimFrame) { 5547 _reqAnimFrame = window[a[i] + "RequestAnimationFrame"]; 5548 _cancelAnimFrame = window[a[i] + "CancelAnimationFrame"] || window[a[i] + "CancelRequestAnimationFrame"]; 5549 } 5550 5551 _class("Ticker", function(fps, useRAF) { 5552 var _self = this, 5553 _startTime = _getTime(), 5554 _useRAF = (useRAF !== false && _reqAnimFrame), 5555 _lagThreshold = 500, 5556 _adjustedLag = 33, 5557 _fps, _req, _id, _gap, _nextTime, 5558 _tick = function(manual) { 5559 var elapsed = _getTime() - _lastUpdate, 5560 overlap, dispatch; 5561 if (elapsed > _lagThreshold) { 5562 _startTime += elapsed - _adjustedLag; 5563 } 5564 _lastUpdate += elapsed; 5565 _self.time = (_lastUpdate - _startTime) / 1000; 5566 overlap = _self.time - _nextTime; 5567 if (!_fps || overlap > 0 || manual === true) { 5568 _self.frame++; 5569 _nextTime += overlap + (overlap >= _gap ? 0.004 : _gap - overlap); 5570 dispatch = true; 5571 } 5572 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. 5573 _id = _req(_tick); 5574 }
5575 if (dispatch) { 5576 _self.dispatchEvent("tick"); 5577 } 5578 }; 5579 5580 EventDispatcher.call(_self); 5581 _self.time = _self.frame = 0; 5582 _self.tick = function() { 5583 _tick(true); 5584 }; 5585 5586 _self.lagSmoothing = function(threshold, adjustedLag) { 5587 _lagThreshold = threshold || (1 / _tinyNum); //zero should be interpreted as basically unlimited 5588 _adjustedLag = Math.min(adjustedLag, _lagThreshold, 0); 5589 }; 5590 5591 _self.sleep = function() { 5592 if (_id == null) { 5593 return; 5594 } 5595 if (!_useRAF || !_cancelAnimFrame) { 5596 clearTimeout(_id); 5597 } else { 5598 _cancelAnimFrame(_id); 5599 } 5600 _req = _emptyFunc; 5601 _id = null; 5602 if (_self === _ticker) { 5603 _tickerActive = false; 5604 } 5605 }; 5606 5607 _self.wake = function() { 5608 if (_id !== null) { 5609 _self.sleep(); 5610 } 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(). 5611 _lastUpdate = _getTime() - _lagThreshold + 5; 5612 } 5613 _req = (_fps === 0) ? _emptyFunc : (!_useRAF || !_reqAnimFrame) ? function(f) { return setTimeout(f, ((_nextTime - _self.time) * 1000 + 1) | 0); } : _reqAnimFrame; 5614 if (_self === _ticker) { 5615 _tickerActive = true; 5616 } 5617 _tick(2); 5618 }; 5619 5620 _self.fps = function(value) { 5621 if (!arguments.length) { 5622 return _fps; 5623 } 5624 _fps = value; 5625 _gap = 1 / (_fps || 60); 5626 _nextTime = this.time + _gap; 5627 _self.wake(); 5628 }; 5629 5630 _self.useRAF = function(value) { 5631 if (!arguments.length) { 5632 return _useRAF; 5633 } 5634 _self.sleep(); 5635 _useRAF = value; 5636 _self.fps(_fps); 5637 }; 5638 _self.fps(fps); 5639 5640 //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. 5641 setTimeout(function() { 5642 if (_useRAF && (!_id || _self.frame < 5)) { 5643 _self.useRAF(false); 5644 } 5645 }, 1500); 5646 }); 5647 5648 p = gs.Ticker.prototype = new gs.events.EventDispatcher(); 5649 p.constructor = gs.Ticker; 5650 5651 5652/* 5653 * ---------------------------------------------------------------- 5654 * Animation 5655 * ---------------------------------------------------------------- 5656 */ 5657 var Animation = _class("core.Animation", function(duration, vars) { 5658 this.vars = vars = vars || {}; 5659 this._duration = this._totalDuration = duration || 0; 5660 this._delay = Number(vars.delay) || 0; 5661 this._timeScale = 1; 5662 this._active = (vars.immediateRender === true); 5663 this.data = vars.data; 5664 this._reversed = (vars.reversed === true); 5665 5666 if (!_rootTimeline) { 5667 return; 5668 } 5669 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. 5670 _ticker.wake(); 5671 } 5672 5673 var tl = this.vars.useFrames ? _rootFramesTimeline : _rootTimeline; 5674 tl.add(this, tl._time); 5675 5676 if (this.vars.paused) { 5677 this.paused(true); 5678 } 5679 }); 5680 5681 _ticker = Animation.ticker = new gs.Ticker(); 5682 p = Animation.prototype; 5683 p._dirty = p._gc = p._initted = p._paused = false; 5684 p._totalTime = p._time = 0; 5685 p._rawPrevTime = -1; 5686 p._next = p._last = p._onUpdate = p._timeline = p.timeline = null; 5687 p._paused = false; 5688 5689 5690 //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. 5691 var _checkTimeout = function() { 5692 if (_tickerActive && _getTime() - _lastUpdate > 2000) { 5693 _ticker.wake(); 5694 } 5695 setTimeout(_checkTimeout, 2000); 5696 }; 5697 _checkTimeout(); 5698 5699 5700 p.play = function(from, suppressEvents) { 5701 if (from != null) { 5702 this.seek(from, suppressEvents); 5703 } 5704 return this.reversed(false).paused(false); 5705 }; 5706 5707 p.pause = function(atTime, suppressEvents) { 5708 if (atTime != null) { 5709 this.seek(atTime, suppressEvents); 5710 } 5711 return this.paused(true); 5712 }; 5713 5714 p.resume = function(from, suppressEvents) { 5715 if (from != null) { 5716 this.seek(from, suppressEvents); 5717 } 5718 return this.paused(false); 5719 }; 5720 5721 p.seek = function(time, suppressEvents) { 5722 return this.totalTime(Number(time), suppressEvents !== false); 5723 }; 5724 5725 p.restart = function(includeDelay, suppressEvents) { 5726 return this.reversed(false).paused(false).totalTime(includeDelay ? -this._delay : 0, (suppressEvents !== false), true); 5727 }; 5728 5729 p.reverse = function(from, suppressEvents) { 5730 if (from != null) { 5731 this.seek((from || this.totalDuration()), suppressEvents); 5732 } 5733 return this.reversed(true).paused(false); 5734 }; 5735 5736 p.render = function(time, suppressEvents, force) { 5737 //stub - we override this method in subclasses. 5738 }; 5739 5740 p.invalidate = function() { 5741 this._time = this._totalTime = 0; 5742 this._initted = this._gc = false;
5743 this._rawPrevTime = -1; 5744 if (this._gc || !this.timeline) { 5745 this._enabled(true); 5746 } 5747 return this; 5748 }; 5749 5750 p.isActive = function() { 5751 var tl = this._timeline, //the 2 root timelines won't have a _timeline; they're always active. 5752 startTime = this._startTime, 5753 rawTime; 5754 return (!tl || (!this._gc && !this._paused && tl.isActive() && (rawTime = tl.rawTime()) >= startTime && rawTime < startTime + this.totalDuration() / this._timeScale)); 5755 }; 5756 5757 p._enabled = function (enabled, ignoreTimeline) { 5758 if (!_tickerActive) { 5759 _ticker.wake(); 5760 } 5761 this._gc = !enabled; 5762 this._active = this.isActive(); 5763 if (ignoreTimeline !== true) { 5764 if (enabled && !this.timeline) { 5765 this._timeline.add(this, this._startTime - this._delay); 5766 } else if (!enabled && this.timeline) { 5767 this._timeline._remove(this, true); 5768 } 5769 } 5770 return false; 5771 }; 5772 5773 5774 p._kill = function(vars, target) { 5775 return this._enabled(false, false); 5776 }; 5777 5778 p.kill = function(vars, target) { 5779 this._kill(vars, target); 5780 return this; 5781 }; 5782 5783 p._uncache = function(includeSelf) { 5784 var tween = includeSelf ? this : this.timeline; 5785 while (tween) { 5786 tween._dirty = true; 5787 tween = tween.timeline; 5788 } 5789 return this; 5790 }; 5791 5792 p._swapSelfInParams = function(params) { 5793 var i = params.length, 5794 copy = params.concat(); 5795 while (--i > -1) { 5796 if (params[i] === "{self}") { 5797 copy[i] = this; 5798 } 5799 } 5800 return copy; 5801 }; 5802 5803//----Animation getters/setters -------------------------------------------------------- 5804 5805 p.eventCallback = function(type, callback, params, scope) { 5806 if ((type || "").substr(0,2) === "on") { 5807 var v = this.vars; 5808 if (arguments.length === 1) { 5809 return v[type]; 5810 } 5811 if (callback == null) { 5812 delete v[type]; 5813 } else { 5814 v[type] = callback; 5815 v[type + "Params"] = (_isArray(params) && params.join("").indexOf("{self}") !== -1) ? this._swapSelfInParams(params) : params; 5816 v[type + "Scope"] = scope; 5817 } 5818 if (type === "onUpdate") { 5819 this._onUpdate = callback; 5820 } 5821 } 5822 return this; 5823 }; 5824 5825 p.delay = function(value) { 5826 if (!arguments.length) { 5827 return this._delay; 5828 } 5829 if (this._timeline.smoothChildTiming) { 5830 this.startTime( this._startTime + value - this._delay ); 5831 } 5832 this._delay = value; 5833 return this; 5834 }; 5835 5836 p.duration = function(value) { 5837 if (!arguments.length) { 5838 this._dirty = false; 5839 return this._duration; 5840 } 5841 this._duration = this._totalDuration = value; 5842 this._uncache(true); //true in case it's a TweenMax or TimelineMax that has a repeat - we'll need to refresh the totalDuration. 5843 if (this._timeline.smoothChildTiming) if (this._time > 0) if (this._time < this._duration) if (value !== 0) { 5844 this.totalTime(this._totalTime * (value / this._duration), true); 5845 } 5846 return this; 5847 }; 5848 5849 p.totalDuration = function(value) { 5850 this._dirty = false; 5851 return (!arguments.length) ? this._totalDuration : this.duration(value); 5852 }; 5853 5854 p.time = function(value, suppressEvents) { 5855 if (!arguments.length) { 5856 return this._time; 5857 } 5858 if (this._dirty) { 5859 this.totalDuration(); 5860 } 5861 return this.totalTime((value > this._duration) ? this._duration : value, suppressEvents); 5862 }; 5863 5864 p.totalTime = function(time, suppressEvents, uncapped) { 5865 if (!_tickerActive) { 5866 _ticker.wake(); 5867 } 5868 if (!arguments.length) { 5869 return this._totalTime; 5870 } 5871 if (this._timeline) { 5872 if (time < 0 && !uncapped) { 5873 time += this.totalDuration(); 5874 } 5875 if (this._timeline.smoothChildTiming) { 5876 if (this._dirty) { 5877 this.totalDuration(); 5878 } 5879 var totalDuration = this._totalDuration, 5880 tl = this._timeline; 5881 if (time > totalDuration && !uncapped) { 5882 time = totalDuration; 5883 } 5884 this._startTime = (this._paused ? this._pauseTime : tl._time) - ((!this._reversed ? time : totalDuration - time) / this._timeScale); 5885 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. 5886 this._uncache(false); 5887 } 5888 //in case any of the ancestor timelines had completed but should now be enabled, we should reset the
5888ir 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. 5889 if (tl._timeline) { 5890 while (tl._timeline) { 5891 if (tl._timeline._time !== (tl._startTime + tl._totalTime) / tl._timeScale) { 5892 tl.totalTime(tl._totalTime, true); 5893 } 5894 tl = tl._timeline; 5895 } 5896 } 5897 } 5898 if (this._gc) { 5899 this._enabled(true, false); 5900 } 5901 if (this._totalTime !== time || this._duration === 0) { 5902 this.render(time, suppressEvents, false); 5903 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. 5904 _lazyRender(); 5905 } 5906 } 5907 } 5908 return this; 5909 }; 5910 5911 p.progress = p.totalProgress = function(value, suppressEvents) { 5912 return (!arguments.length) ? this._time / this.duration() : this.totalTime(this.duration() * value, suppressEvents); 5913 }; 5914 5915 p.startTime = function(value) { 5916 if (!arguments.length) { 5917 return this._startTime; 5918 } 5919 if (value !== this._startTime) { 5920 this._startTime = value; 5921 if (this.timeline) if (this.timeline._sortChildren) { 5922 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. 5923 } 5924 } 5925 return this; 5926 }; 5927 5928 p.endTime = function(includeRepeats) { 5929 return this._startTime + ((includeRepeats != false) ? this.totalDuration() : this.duration()) / this._timeScale; 5930 }; 5931 5932 p.timeScale = function(value) { 5933 if (!arguments.length) { 5934 return this._timeScale; 5935 } 5936 value = value || _tinyNum; //can't allow zero because it'll throw the math off 5937 if (this._timeline && this._timeline.smoothChildTiming) { 5938 var pauseTime = this._pauseTime, 5939 t = (pauseTime || pauseTime === 0) ? pauseTime : this._timeline.totalTime(); 5940 this._startTime = t - ((t - this._startTime) * this._timeScale / value); 5941 } 5942 this._timeScale = value; 5943 return this._uncache(false); 5944 }; 5945 5946 p.reversed = function(value) { 5947 if (!arguments.length) { 5948 return this._reversed; 5949 } 5950 if (value != this._reversed) { 5951 this._reversed = value; 5952 this.totalTime(((this._timeline && !this._timeline.smoothChildTiming) ? this.totalDuration() - this._totalTime : this._totalTime), true); 5953 } 5954 return this; 5955 }; 5956 5957 p.paused = function(value) { 5958 if (!arguments.length) { 5959 return this._paused; 5960 } 5961 if (value != this._paused) if (this._timeline) { 5962 if (!_tickerActive && !value) { 5963 _ticker.wake(); 5964 } 5965 var tl = this._timeline, 5966 raw = tl.rawTime(), 5967 elapsed = raw - this._pauseTime; 5968 if (!value && tl.smoothChildTiming) { 5969 this._startTime += elapsed; 5970 this._uncache(false); 5971 } 5972 this._pauseTime = value ? raw : null; 5973 this._paused = value; 5974 this._active = this.isActive(); 5975 if (!value && elapsed !== 0 && this._initted && this.duration()) { 5976 this.render((tl.smoothChildTiming ? this._totalTime : (raw - this._startTime) / this._timeScale), true, true); //in case the target's properties changed via some other tween or manual update by the user, we should force a render. 5977 } 5978 } 5979 if (this._gc && !value) { 5980 this._enabled(true, false); 5981 } 5982 return this; 5983 }; 5984 5985 5986/* 5987 * ---------------------------------------------------------------- 5988 * SimpleTimeline 5989 * ---------------------------------------------------------------- 5990 */ 5991 var SimpleTimeline = _class("core.SimpleTimeline", function(vars) { 5992 Animation.call(this, 0, vars); 5993 this.autoRemoveChildren = this.smoothChildTiming = true; 5994 }); 5995 5996 p = SimpleTimeline.prototype = new Animation(); 5997 p.constructor = SimpleTimeline; 5998 p.kill()._gc = false;
5999 p._first = p._last = p._recent = null; 6000 p._sortChildren = false; 6001 6002 p.add = p.insert = function(child, position, align, stagger) { 6003 var prevTween, st; 6004 child._startTime = Number(position || 0) + child._delay; 6005 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). 6006 child._pauseTime = child._startTime + ((this.rawTime() - child._startTime) / child._timeScale); 6007 } 6008 if (child.timeline) { 6009 child.timeline._remove(child, true); //removes from existing timeline so that it can be properly added to this one. 6010 } 6011 child.timeline = child._timeline = this; 6012 if (child._gc) { 6013 child._enabled(true, true); 6014 } 6015 prevTween = this._last; 6016 if (this._sortChildren) { 6017 st = child._startTime; 6018 while (prevTween && prevTween._startTime > st) { 6019 prevTween = prevTween._prev; 6020 } 6021 } 6022 if (prevTween) { 6023 child._next = prevTween._next; 6024 prevTween._next = child; 6025 } else { 6026 child._next = this._first; 6027 this._first = child; 6028 } 6029 if (child._next) { 6030 child._next._prev = child; 6031 } else { 6032 this._last = child; 6033 } 6034 child._prev = prevTween; 6035 this._recent = child; 6036 if (this._timeline) { 6037 this._uncache(true); 6038 } 6039 return this; 6040 }; 6041 6042 p._remove = function(tween, skipDisable) { 6043 if (tween.timeline === this) { 6044 if (!skipDisable) { 6045 tween._enabled(false, true); 6046 } 6047 6048 if (tween._prev) { 6049 tween._prev._next = tween._next; 6050 } else if (this._first === tween) { 6051 this._first = tween._next; 6052 } 6053 if (tween._next) { 6054 tween._next._prev = tween._prev; 6055 } else if (this._last === tween) { 6056 this._last = tween._prev; 6057 } 6058 tween._next = tween._prev = tween.timeline = null; 6059 if (tween === this._recent) { 6060 this._recent = this._last; 6061 } 6062 6063 if (this._timeline) { 6064 this._uncache(true); 6065 } 6066 } 6067 return this; 6068 }; 6069 6070 p.render = function(time, suppressEvents, force) { 6071 var tween = this._first, 6072 next; 6073 this._totalTime = this._time = this._rawPrevTime = time; 6074 while (tween) { 6075 next = tween._next; //record it here because the value could change after rendering... 6076 if (tween._active || (time >= tween._startTime && !tween._paused)) { 6077 if (!tween._reversed) { 6078 tween.render((time - tween._startTime) * tween._timeScale, suppressEvents, force); 6079 } else { 6080 tween.render(((!tween._dirty) ? tween._totalDuration : tween.totalDuration()) - ((time - tween._startTime) * tween._timeScale), suppressEvents, force); 6081 } 6082 } 6083 tween = next; 6084 } 6085 }; 6086 6087 p.rawTime = function() { 6088 if (!_tickerActive) { 6089 _ticker.wake(); 6090 } 6091 return this._totalTime; 6092 }; 6093 6094/* 6095 * ---------------------------------------------------------------- 6096 * TweenLite 6097 * ---------------------------------------------------------------- 6098 */ 6099 var TweenLite = _class("TweenLite", function(target, duration, vars) { 6100 Animation.call(this, duration, vars); 6101 this.render = TweenLite.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method) 6102 6103 if (target == null) { 6104 throw "Cannot tween a null target."; 6105 } 6106 6107 this.target = target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target; 6108 6109 var isSelector = (target.jquery || (target.length && target !== window && target[0] && (target[0] === window || (target[0].nodeType && target[0].style && !target.nodeType)))), 6110 overwrite = this.vars.overwrite, 6111 i, targ, targets; 6112 6113 this._overwrite = overwrite = (overwrite == null) ? _overwriteLookup[TweenLite.defaultOverwrite] : (typeof(overwrite) === "number") ? overwrite >> 0 : _overwriteLookup[overwrite]; 6114 6115 if ((isSelector || target instanceof Array || (target.push && _isArray(target))) && typeof(target[0]) !== "number") { 6116 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() 6117 this._propLookup = []; 6118 this._siblings = []; 6119 for (i = 0; i < targets.length; i++) { 6120 targ = targets[i]; 6121 if (!targ) { 6122 targets.splice(i--, 1); 6123 continue; 6124 } else if (typeof(targ) === "string") { 6125 targ = targets[i--] = TweenLite.selector(targ);
6125 //in case it's an array of strings 6126 if (typeof(targ) === "string") { 6127 targets.splice(i+1, 1); //to avoid an endless loop (can't imagine why the selector would return a string, but just in case) 6128 } 6129 continue; 6130 } 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. 6131 targets.splice(i--, 1); 6132 this._targets = targets = targets.concat(_slice(targ)); 6133 continue; 6134 } 6135 this._siblings[i] = _register(targ, this, false); 6136 if (overwrite === 1) if (this._siblings[i].length > 1) { 6137 _applyOverwrite(targ, this, null, 1, this._siblings[i]); 6138 } 6139 } 6140 6141 } else { 6142 this._propLookup = {}; 6143 this._siblings = _register(target, this, false); 6144 if (overwrite === 1) if (this._siblings.length > 1) { 6145 _applyOverwrite(target, this, null, 1, this._siblings); 6146 } 6147 } 6148 if (this.vars.immediateRender || (duration === 0 && this._delay === 0 && this.vars.immediateRender !== false)) { 6149 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) 6150 this.render(-this._delay); 6151 } 6152 }, true), 6153 _isSelector = function(v) { 6154 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. 6155 }, 6156 _autoCSS = function(vars, target) { 6157 var css = {}, 6158 p; 6159 for (p in vars) { 6160 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. 6161 css[p] = vars[p]; 6162 delete vars[p]; 6163 } 6164 } 6165 vars.css = css; 6166 }; 6167 6168 p = TweenLite.prototype = new Animation(); 6169 p.constructor = TweenLite; 6170 p.kill()._gc = false; 6171 6172//----TweenLite defaults, overwrite management, and root updates ---------------------------------------------------- 6173 6174 p.ratio = 0; 6175 p._firstPT = p._targets = p._overwrittenProps = p._startAt = null; 6176 p._notifyPluginsOfEnabled = p._lazy = false; 6177 6178 TweenLite.version = "1.14.2"; 6179 TweenLite.defaultEase = p._ease = new Ease(null, null, 1, 1); 6180 TweenLite.defaultOverwrite = "auto"; 6181 TweenLite.ticker = _ticker; 6182 TweenLite.autoSleep = true; 6183 TweenLite.lagSmoothing = function(threshold, adjustedLag) { 6184 _ticker.lagSmoothing(threshold, adjustedLag); 6185 }; 6186 6187 TweenLite.selector = window.$ || window.jQuery || function(e) { 6188 var selector = window.$ || window.jQuery; 6189 if (selector) { 6190 TweenLite.selector = selector; 6191 return selector(e); 6192 } 6193 return (typeof(document) === "undefined") ? e : (document.querySelectorAll ? document.querySelectorAll(e) : document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e)); 6194 }; 6195 6196 var _lazyTweens = [], 6197 _lazyLookup = {}, 6198 _internals = TweenLite._internals = {isArray:_isArray, isSelector:_isSelector, lazyTweens:_lazyTweens}, //gives us a way to expose certain private values to other GreenSock classes without contaminating tha main TweenLite object. 6199 _plugins = TweenLite._plugins = {}, 6200 _tweenLookup = _internals.tweenLookup = {}, 6201 _tweenLookupNum = 0, 6202 _reservedProps = _internals.reservedProps = {ease:1, delay:1, overwrite:1, onComplete:1, onCompleteParams:1, onCompleteScope:1, useFrames:1, runBackwards:1, startAt:1, onUp
6202date: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}, 6203 _overwriteLookup = {none:0, all:1, auto:2, concurrent:3, allOnStart:4, preexisting:5, "true":1, "false":0}, 6204 _rootFramesTimeline = Animation._rootFramesTimeline = new SimpleTimeline(), 6205 _rootTimeline = Animation._rootTimeline = new SimpleTimeline(), 6206 _lazyRender = _internals.lazyRender = function() { 6207 var i = _lazyTweens.length, 6208 tween; 6209 _lazyLookup = {}; 6210 while (--i > -1) { 6211 tween = _lazyTweens[i]; 6212 if (tween && tween._lazy !== false) { 6213 tween.render(tween._lazy[0], tween._lazy[1], true); 6214 tween._lazy = false; 6215 } 6216 } 6217 _lazyTweens.length = 0; 6218 }; 6219 6220 _rootTimeline._startTime = _ticker.time; 6221 _rootFramesTimeline._startTime = _ticker.frame; 6222 _rootTimeline._active = _rootFramesTimeline._active = true; 6223 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". 6224 6225 Animation._updateRoot = TweenLite.render = function() { 6226 var i, a, p; 6227 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. 6228 _lazyRender(); 6229 } 6230 _rootTimeline.render((_ticker.time - _rootTimeline._startTime) * _rootTimeline._timeScale, false, false); 6231 _rootFramesTimeline.render((_ticker.frame - _rootFramesTimeline._startTime) * _rootFramesTimeline._timeScale, false, false); 6232 if (_lazyTweens.length) { 6233 _lazyRender(); 6234 } 6235 if (!(_ticker.frame % 120)) { //dump garbage every 120 frames... 6236 for (p in _tweenLookup) { 6237 a = _tweenLookup[p].tweens; 6238 i = a.length; 6239 while (--i > -1) { 6240 if (a[i]._gc) { 6241 a.splice(i, 1); 6242 } 6243 } 6244 if (a.length === 0) { 6245 delete _tweenLookup[p]; 6246 } 6247 } 6248 //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 6249 p = _rootTimeline._first; 6250 if (!p || p._paused) if (TweenLite.autoSleep && !_rootFramesTimeline._first && _ticker._listeners.tick.length === 1) { 6251 while (p && p._paused) { 6252 p = p._next; 6253 } 6254 if (!p) { 6255 _ticker.sleep(); 6256 } 6257 } 6258 } 6259 }; 6260 6261 _ticker.addEventListener("tick", Animation._updateRoot); 6262 6263 var _register = function(target, tween, scrub) { 6264 var id = target._gsTweenID, a, i; 6265 if (!_tweenLookup[id || (target._gsTweenID = id = "t" + (_tweenLookupNum++))]) { 6266 _tweenLookup[id] = {target:target, tweens:[]}; 6267 } 6268 if (tween) { 6269 a = _tweenLookup[id].tweens; 6270 a[(i = a.length)] = tween; 6271 if (scrub) { 6272 while (--i > -1) { 6273 if (a[i] === tween) { 6274 a.splice(i, 1); 6275 } 6276 } 6277 } 6278 } 6279 return _tweenLookup[id].tweens; 6280 }, 6281 6282 _onOverwrite = function(overwrittenTween, overwritingTween, target, killedProps) { 6283 var func = overwrittenTween.vars.onOverwrite, r1, r2; 6284 if (func) { 6285 r1 = func(overwrittenTween, overwritingTween, target, killedProps); 6286 } 6287 func = TweenLite.onOverwrite; 6288 if (func) { 6289 r2 = func(overwrittenTween, overwritingTween, target, killedProps); 6290 } 6291 return (r1 !== false && r2 !== false); 6292 }, 6293 _applyOverwrite = function(target, tween, props, mode, siblings) { 6294 var i, changed, curTween, l; 6295 if (mode === 1 || mode >= 4) { 6296 l = siblings.length; 6297 for (i = 0; i < l; i++) { 6298 if ((curTween = siblings[i]) !== tween) { 6299 if (!curTween._gc) { 6300 if (_onOverwrite(curTween, tween) && curTween._enabled(false, false)) { 6301 changed = true; 6302 } 6303 } 6304 } else if (mode === 5) { 6305 break; 6306 } 6307 } 6308 return changed; 6309 } 6310 //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) 6311 var startTime = tween._startTime + _tinyNum, 6312 overlaps = [], 6313 oCount = 0, 6314 zeroDur = (tween._duration === 0), 6315 globalStart; 6316 i = siblings.length; 6317 while (--i > -1) { 6318 if ((curTween = siblings[i]) === tween || curTween._gc || curTween._paused) { 6319 //ignore 6320 } else if (curTween._timeline !== tween._timeline) { 6321 globalStart = globalStart || _checkOverlap(tween, 0, zeroDur); 6322 if (_checkOverlap(curTween, globalStart, zeroDur) === 0) { 6323 overlaps[oCount++] = curTween; 6324 } 6325 } else if (curTween._startTime <= startTime) if (curTween._startTime + curTween.totalDuration() / curTween._timeScale > startTime) if (!((zeroDur || !curTween._initted) && startTime - curTween._startTime <= 0.0000000002)) { 6326 overlaps[oCount++] = curTween; 6327 } 6328 } 6329 6330 i = oCount; 6331 while (--i > -1) { 6332 curTween = overlaps[i]; 6333 if (mode === 2) if (curTween._kill(props, target, tween)) { 6334 changed = true; 6335 } 6336 if (mode !== 2 || (!curTween._firstPT && curTween._initted)) { 6337 if (mode !== 2 && !_onOverwrite(curTween, tween)) { 6338 continue; 6339 } 6340 if (curTween._enabled(false, false)) { //if all property tweens have been overwritten, kill the tween. 6341 changed = true; 6342 } 6343 } 6344 } 6345 return changed; 6346 }, 6347 6348 _checkOverlap = function(tween, reference, zeroDur) { 6349 var tl = tween._timeline, 6350 ts = tl._timeScale, 6351 t = tween._startTime; 6352 while (tl._timeline) { 6353 t += tl._startTime; 6354 ts *= tl._timeScale; 6355 if (tl._paused) { 6356 return -100; 6357 } 6358 tl = tl._timeline; 6359 } 6360 t /= ts; 6361 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; 6362 }; 6363 6364 6365//---- TweenLite instance methods ----------------------------------------------------------------------------- 6366 6367 p._init = function() { 6368 var v = this.vars, 6369 op = this._overwrittenProps, 6370 dur = this._duration, 6371 immediate = !!v.immediateRender, 6372 ease = v.ease, 6373 i, initPlugins, pt, p, startVars; 6374 if (v.startAt) { 6375 if (this._startAt) { 6376 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. 6377 this._startAt.kill(); 6378 } 6379 startVars = {}; 6380 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); 6381 startVars[p] = v.startAt[p]; 6382 } 6383 startVars.overwrite = false;
6384 startVars.immediateRender = true; 6385 startVars.lazy = (immediate && v.lazy !== false); 6386 startVars.startAt = startVars.delay = null; //no nesting of startAt objects allowed (otherwise it could cause an infinite loop). 6387 this._startAt = TweenLite.to(this.target, 0, startVars); 6388 if (immediate) { 6389 if (this._time > 0) { 6390 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()). 6391 } else if (dur !== 0) { 6392 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. 6393 } 6394 } 6395 } else if (v.runBackwards && dur !== 0) { 6396 //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) 6397 if (this._startAt) { 6398 this._startAt.render(-1, true); 6399 this._startAt.kill(); 6400 this._startAt = null; 6401 } else { 6402 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 6403 immediate = false; 6404 } 6405 pt = {}; 6406 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. 6407 if (!_reservedProps[p] || p === "autoCSS") { 6408 pt[p] = v[p]; 6409 } 6410 } 6411 pt.overwrite = 0; 6412 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. 6413 pt.lazy = (immediate && v.lazy !== false); 6414 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) 6415 this._startAt = TweenLite.to(this.target, 0, pt); 6416 if (!immediate) { 6417 this._startAt._init(); //ensures that the initial values are recorded 6418 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. 6419 if (this.vars.immediateRender) { 6420 this._startAt = null; 6421 } 6422 } else if (this._time === 0) { 6423 return; 6424 } 6425 } 6426 } 6427 this._ease = ease = (!ease) ? TweenLite.defaultEase : (ease instanceof Ease) ? ease : (typeof(ease) === "function") ? new Ease(ease, v.easeParams) : _easeMap[ease] || TweenLite.defaultEase; 6428 if (v.easeParams instanceof Array && ease.config) { 6429 this._ease = ease.config.apply(ease, v.easeParams); 6430 } 6431 this._easeType = this._ease._type; 6432 this._easePower = this._ease._power; 6433 this._firstPT = null; 6434 6435 if (this._targets) { 6436 i = this._targets.length; 6437 while (--i > -1) { 6438 if ( this._initProps( this._targets[i], (this._propLookup[i] = {}), this._siblings[i], (op ? op[i] : null)) ) { 6439 initPlugins = true; 6440 } 6441 } 6442 } else { 6443 initPlugins = this._initProps(this.target, this._propLookup, this._siblings, op); 6444 } 6445 6446 if (initPlugins) { 6447 TweenLite._onPluginEvent("_onInitAllProps", this); //reorders the array in order of priority. Uses a static TweenPlugin method in order to minimize file size in TweenLite 6448 } 6449 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. 6450 this._enabled(false, false); 6451 } 6452 if (v.runBackwards) { 6453 pt = this._firstPT; 6454 while (pt) { 6455 pt.s += pt.c; 6456 pt.c = -pt.c; 6457 pt = pt._next; 6458 } 6459 } 6460 this._onUpdate = v.onUpdate; 6461 this._initted = true; 6462 }; 6463 6464 p._initProps = function(target, propLookup, siblings, overwrittenProps) { 6465 var p, i, initPlugins, plugin, pt, v; 6466 if (target == null) { 6467 return false;
6468 } 6469 6470 if (_lazyLookup[target._gsTweenID]) { 6471 _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) 6472 } 6473 6474 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. 6475 _autoCSS(this.vars, target); 6476 } 6477 for (p in this.vars) { 6478 v = this.vars[p]; 6479 if (_reservedProps[p]) { 6480 if (v) if ((v instanceof Array) || (v.push && _isArray(v))) if (v.join("").indexOf("{self}") !== -1) { 6481 this.vars[p] = v = this._swapSelfInParams(v, this); 6482 } 6483 6484 } else if (_plugins[p] && (plugin = new _plugins[p]())._onInitTween(target, this.vars[p], this)) { 6485 6486 //t - target [object] 6487 //p - property [string] 6488 //s - start [number] 6489 //c - change [number] 6490 //f - isFunction [boolean] 6491 //n - name [string] 6492 //pg - isPlugin [boolean] 6493 //pr - priority [number] 6494 this._firstPT = pt = {_next:this._firstPT, t:plugin, p:"setRatio", s:0, c:1, f:true, n:p, pg:true, pr:plugin._priority}; 6495 i = plugin._overwriteProps.length; 6496 while (--i > -1) { 6497 propLookup[plugin._overwriteProps[i]] = this._firstPT; 6498 } 6499 if (plugin._priority || plugin._onInitAllProps) { 6500 initPlugins = true; 6501 } 6502 if (plugin._onDisable || plugin._onEnable) { 6503 this._notifyPluginsOfEnabled = true; 6504 } 6505 6506 } else { 6507 this._firstPT = propLookup[p] = pt = {_next:this._firstPT, t:target, p:p, f:(typeof(target[p]) === "function"), n:p, pg:false, pr:0}; 6508 pt.s = (!pt.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ](); 6509 pt.c = (typeof(v) === "string" && v.charAt(1) === "=") ? parseInt(v.charAt(0) + "1", 10) * Number(v.substr(2)) : (Number(v) - pt.s) || 0; 6510 } 6511 if (pt) if (pt._next) { 6512 pt._next._prev = pt; 6513 } 6514 } 6515 6516 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) 6517 return this._initProps(target, propLookup, siblings, overwrittenProps); 6518 } 6519 if (this._overwrite > 1) if (this._firstPT) if (siblings.length > 1) if (_applyOverwrite(target, this, propLookup, this._overwrite, siblings)) { 6520 this._kill(propLookup, target); 6521 return this._initProps(target, propLookup, siblings, overwrittenProps); 6522 } 6523 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. 6524 _lazyLookup[target._gsTweenID] = true; 6525 } 6526 return initPlugins; 6527 }; 6528 6529 p.render = function(time, suppressEvents, force) { 6530 var prevTime = this._time, 6531 duration = this._duration, 6532 prevRawPrevTime = this._rawPrevTime, 6533 isComplete, callback, pt, rawPrevTime; 6534 if (time >= duration) { 6535 this._totalTime = this._time = duration; 6536 this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1; 6537 if (!this._reversed ) { 6538 isComplete = true; 6539 callback = "onComplete"; 6540 } 6541 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. 6542 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
6542ding 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. 6543 time = 0; 6544 } 6545 if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) { 6546 force = true; 6547 if (prevRawPrevTime > _tinyNum) { 6548 callback = "onReverseComplete"; 6549 } 6550 } 6551 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. 6552 } 6553 6554 } else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0. 6555 this._totalTime = this._time = 0; 6556 this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0; 6557 if (prevTime !== 0 || (duration === 0 && prevRawPrevTime > 0 && prevRawPrevTime !== _tinyNum)) { 6558 callback = "onReverseComplete"; 6559 isComplete = this._reversed; 6560 } 6561 if (time < 0) { 6562 this._active = false; 6563 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. 6564 if (prevRawPrevTime >= 0) { 6565 force = true; 6566 } 6567 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. 6568 } 6569 } 6570 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. 6571 force = true; 6572 } 6573 } else { 6574 this._totalTime = this._time = time; 6575 6576 if (this._easeType) { 6577 var r = time / duration, type = this._easeType, pow = this._easePower; 6578 if (type === 1 || (type === 3 && r >= 0.5)) { 6579 r = 1 - r; 6580 } 6581 if (type === 3) { 6582 r *= 2; 6583 } 6584 if (pow === 1) { 6585 r *= r; 6586 } else if (pow === 2) { 6587 r *= r * r; 6588 } else if (pow === 3) { 6589 r *= r * r * r; 6590 } else if (pow === 4) { 6591 r *= r * r * r * r; 6592 } 6593 6594 if (type === 1) { 6595 this.ratio = 1 - r; 6596 } else if (type === 2) { 6597 this.ratio = r; 6598 } else if (time / duration < 0.5) { 6599 this.ratio = r / 2; 6600 } else { 6601 this.ratio = 1 - (r / 2); 6602 } 6603 6604 } else { 6605 this.ratio = this._ease.getRatio(time / duration); 6606 } 6607 } 6608 6609 if (this._time === prevTime && !force) { 6610 return; 6611 } else if (!this._initted) { 6612 this._init(); 6613 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
6613writing 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. 6614 return; 6615 } else if (!force && this._firstPT && ((this.vars.lazy !== false && this._duration) || (this.vars.lazy && !this._duration))) { 6616 this._time = this._totalTime = prevTime; 6617 this._rawPrevTime = prevRawPrevTime; 6618 _lazyTweens.push(this); 6619 this._lazy = [time, suppressEvents]; 6620 return; 6621 } 6622 //_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. 6623 if (this._time && !isComplete) { 6624 this.ratio = this._ease.getRatio(this._time / duration); 6625 } else if (isComplete && this._ease._calcEnd) { 6626 this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1); 6627 } 6628 } 6629 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. 6630 this._lazy = false; 6631 } 6632 if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) { 6633 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. 6634 } 6635 if (prevTime === 0) { 6636 if (this._startAt) { 6637 if (time >= 0) { 6638 this._startAt.render(time, suppressEvents, force); 6639 } else if (!callback) { 6640 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. 6641 } 6642 } 6643 if (this.vars.onStart) if (this._time !== 0 || duration === 0) if (!suppressEvents) { 6644 this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray); 6645 } 6646 } 6647 pt = this._firstPT; 6648 while (pt) { 6649 if (pt.f) { 6650 pt.t[pt.p](pt.c * this.ratio + pt.s); 6651 } else { 6652 pt.t[pt.p] = pt.c * this.ratio + pt.s; 6653 } 6654 pt = pt._next; 6655 } 6656 6657 if (this._onUpdate) { 6658 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. 6659 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. 6660 } 6661 if (!suppressEvents) if (this._time !== prevTime || isComplete) { 6662 this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray); 6663 } 6664 } 6665 6666 if (callback) if (!this._gc || force) { //check _gc because there's a chance that kill() could be called in an onUpdate 6667 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. 6668 this._startAt.render(time, suppressEvents, force); 6669 } 6670 if (isComplete) { 6671 if (this._timeline.autoRemoveChildren) { 6672 this._enabled(false, false); 6673 } 6674 this._active = false;
6675 } 6676 if (!suppressEvents && this.vars[callback]) { 6677 this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray); 6678 } 6679 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. 6680 this._rawPrevTime = 0; 6681 } 6682 } 6683 }; 6684 6685 p._kill = function(vars, target, overwritingTween) { 6686 if (vars === "all") { 6687 vars = null; 6688 } 6689 if (vars == null) if (target == null || target === this.target) { 6690 this._lazy = false; 6691 return this._enabled(false, false); 6692 } 6693 target = (typeof(target) !== "string") ? (target || this._targets || this.target) : TweenLite.selector(target) || target; 6694 var i, overwrittenProps, p, pt, propLookup, changed, killProps, record, killed; 6695 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") { 6696 i = target.length; 6697 while (--i > -1) { 6698 if (this._kill(vars, target[i])) { 6699 changed = true; 6700 } 6701 } 6702 } else { 6703 if (this._targets) { 6704 i = this._targets.length; 6705 while (--i > -1) { 6706 if (target === this._targets[i]) { 6707 propLookup = this._propLookup[i] || {}; 6708 this._overwrittenProps = this._overwrittenProps || []; 6709 overwrittenProps = this._overwrittenProps[i] = vars ? this._overwrittenProps[i] || {} : "all"; 6710 break; 6711 } 6712 } 6713 } else if (target !== this.target) { 6714 return false; 6715 } else { 6716 propLookup = this._propLookup; 6717 overwrittenProps = this._overwrittenProps = vars ? this._overwrittenProps || {} : "all"; 6718 } 6719 6720 if (propLookup) { 6721 killProps = vars || propLookup; 6722 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) 6723 if (overwritingTween && (TweenLite.onOverwrite || this.vars.onOverwrite)) { 6724 for (p in killProps) { 6725 if (propLookup[p]) { 6726 if (!killed) { 6727 killed = []; 6728 } 6729 killed.push(p); 6730 } 6731 } 6732 if (!_onOverwrite(this, overwritingTween, target, killed)) { //if the onOverwrite returned false, that means the user wants to override the overwriting (cancel it). 6733 return false; 6734 } 6735 } 6736 6737 for (p in killProps) { 6738 if ((pt = propLookup[p])) { 6739 if (pt.pg && pt.t._kill(killProps)) { 6740 changed = true; //some plugins need to be notified so they can perform cleanup tasks first 6741 } 6742 if (!pt.pg || pt.t._overwriteProps.length === 0) { 6743 if (pt._prev) { 6744 pt._prev._next = pt._next; 6745 } else if (pt === this._firstPT) { 6746 this._firstPT = pt._next; 6747 } 6748 if (pt._next) { 6749 pt._next._prev = pt._prev; 6750 } 6751 pt._next = pt._prev = null; 6752 } 6753 delete propLookup[p]; 6754 } 6755 if (record) { 6756 overwrittenProps[p] = 1; 6757 } 6758 } 6759 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. 6760 this._enabled(false, false); 6761 } 6762 } 6763 } 6764 return changed; 6765 }; 6766 6767 p.invalidate = function() { 6768 if (this._notifyPluginsOfEnabled) { 6769 TweenLite._onPluginEvent("_onDisable", this); 6770 } 6771 this._firstPT = this._overwrittenProps = this._startAt = this._onUpdate = null; 6772 this._notifyPluginsOfEnabled = this._active = this._lazy = false;
6773 this._propLookup = (this._targets) ? {} : []; 6774 Animation.prototype.invalidate.call(this); 6775 if (this.vars.immediateRender) { 6776 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) 6777 this.render(-this._delay); 6778 } 6779 return this; 6780 }; 6781 6782 p._enabled = function(enabled, ignoreTimeline) { 6783 if (!_tickerActive) { 6784 _ticker.wake(); 6785 } 6786 if (enabled && this._gc) { 6787 var targets = this._targets, 6788 i; 6789 if (targets) { 6790 i = targets.length; 6791 while (--i > -1) { 6792 this._siblings[i] = _register(targets[i], this, true); 6793 } 6794 } else { 6795 this._siblings = _register(this.target, this, true); 6796 } 6797 } 6798 Animation.prototype._enabled.call(this, enabled, ignoreTimeline); 6799 if (this._notifyPluginsOfEnabled) if (this._firstPT) { 6800 return TweenLite._onPluginEvent((enabled ? "_onEnable" : "_onDisable"), this); 6801 } 6802 return false; 6803 }; 6804 6805 6806//----TweenLite static methods ----------------------------------------------------- 6807 6808 TweenLite.to = function(target, duration, vars) { 6809 return new TweenLite(target, duration, vars); 6810 }; 6811 6812 TweenLite.from = function(target, duration, vars) { 6813 vars.runBackwards = true; 6814 vars.immediateRender = (vars.immediateRender != false); 6815 return new TweenLite(target, duration, vars); 6816 }; 6817 6818 TweenLite.fromTo = function(target, duration, fromVars, toVars) { 6819 toVars.startAt = fromVars; 6820 toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false); 6821 return new TweenLite(target, duration, toVars); 6822 }; 6823 6824 TweenLite.delayedCall = function(delay, callback, params, scope, useFrames) { 6825 return new TweenLite(callback, 0, {delay:delay, onComplete:callback, onCompleteParams:params, onCompleteScope:scope, onReverseComplete:callback, onReverseCompleteParams:params, onReverseCompleteScope:scope, immediateRender:false, useFrames:useFrames, overwrite:0}); 6826 }; 6827 6828 TweenLite.set = function(target, vars) { 6829 return new TweenLite(target, 0, vars); 6830 }; 6831 6832 TweenLite.getTweensOf = function(target, onlyActive) { 6833 if (target == null) { return []; } 6834 target = (typeof(target) !== "string") ? target : TweenLite.selector(target) || target; 6835 var i, a, j, t; 6836 if ((_isArray(target) || _isSelector(target)) && typeof(target[0]) !== "number") { 6837 i = target.length; 6838 a = []; 6839 while (--i > -1) { 6840 a = a.concat(TweenLite.getTweensOf(target[i], onlyActive)); 6841 } 6842 i = a.length; 6843 //now get rid of any duplicates (tweens of arrays of objects could cause duplicates) 6844 while (--i > -1) { 6845 t = a[i]; 6846 j = i; 6847 while (--j > -1) { 6848 if (t === a[j]) { 6849 a.splice(i, 1); 6850 } 6851 } 6852 } 6853 } else { 6854 a = _register(target).concat(); 6855 i = a.length; 6856 while (--i > -1) { 6857 if (a[i]._gc || (onlyActive && !a[i].isActive())) { 6858 a.splice(i, 1); 6859 } 6860 } 6861 } 6862 return a; 6863 }; 6864 6865 TweenLite.killTweensOf = TweenLite.killDelayedCallsTo = function(target, onlyActive, vars) { 6866 if (typeof(onlyActive) === "object") { 6867 vars = onlyActive; //for backwards compatibility (before "onlyActive" parameter was inserted) 6868 onlyActive = false; 6869 } 6870 var a = TweenLite.getTweensOf(target, onlyActive), 6871 i = a.length; 6872 while (--i > -1) { 6873 a[i]._kill(vars, target); 6874 } 6875 }; 6876 6877 6878 6879/* 6880 * ---------------------------------------------------------------- 6881 * 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) 6882 * ---------------------------------------------------------------- 6883 */ 6884 var TweenPlugin = _class("plugins.TweenPlugin", function(props, priority) { 6885 this._overwriteProps = (props || "").split(","); 6886 this._propName = this._overwriteProps[0]; 6887 this._priority = priority || 0; 6888 this._super = TweenPlugin.prototype; 6889 }, true); 6890 6891 p = TweenPlugin.prototype; 6892 TweenPlugin.version = "1.10.1"; 6893 TweenPlugin.API = 2; 6894 p._firstPT = null; 6895 6896 p._addTween = function(target, prop, start, end, overwriteProp, round) { 6897 var c, pt; 6898 if (end != null && (c = (typeof(end) === "number" || end.charAt(1) !== "=") ? Number(end) - start : parseInt(end.charAt(0) + "1", 10) * Number(end.substr(2)))) { 6899 this._firstPT = pt = {_next:this._firstPT, t:target, p:prop, s:start, c:c, f:(typeof(target[prop]) === "function"), n:overwriteProp || prop, r:round}; 6900 if (pt._next) { 6901 pt._next._prev = pt; 6902 } 6903 return pt; 6904 } 6905 }; 6906 6907 p.setRatio = function(v) { 6908 var pt = this._firstPT, 6909 min = 0.000001, 6910 val; 6911 while (pt) { 6912 val = pt.c * v + pt.s; 6913 if (pt.r) { 6914 val = Math.round(val); 6915 } else if (val < min) if (val >
6915 -min) { //prevents issues with converting very small numbers to strings in the browser 6916 val = 0; 6917 } 6918 if (pt.f) { 6919 pt.t[pt.p](val); 6920 } else { 6921 pt.t[pt.p] = val; 6922 } 6923 pt = pt._next; 6924 } 6925 }; 6926 6927 p._kill = function(lookup) { 6928 var a = this._overwriteProps, 6929 pt = this._firstPT, 6930 i; 6931 if (lookup[this._propName] != null) { 6932 this._overwriteProps = []; 6933 } else { 6934 i = a.length; 6935 while (--i > -1) { 6936 if (lookup[a[i]] != null) { 6937 a.splice(i, 1); 6938 } 6939 } 6940 } 6941 while (pt) { 6942 if (lookup[pt.n] != null) { 6943 if (pt._next) { 6944 pt._next._prev = pt._prev; 6945 } 6946 if (pt._prev) { 6947 pt._prev._next = pt._next; 6948 pt._prev = null; 6949 } else if (this._firstPT === pt) { 6950 this._firstPT = pt._next; 6951 } 6952 } 6953 pt = pt._next; 6954 } 6955 return false; 6956 }; 6957 6958 p._roundProps = function(lookup, value) { 6959 var pt = this._firstPT; 6960 while (pt) { 6961 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. 6962 pt.r = value; 6963 } 6964 pt = pt._next; 6965 } 6966 }; 6967 6968 TweenLite._onPluginEvent = function(type, tween) { 6969 var pt = tween._firstPT, 6970 changed, pt2, first, last, next; 6971 if (type === "_onInitAllProps") { 6972 //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. 6973 while (pt) { 6974 next = pt._next; 6975 pt2 = first; 6976 while (pt2 && pt2.pr > pt.pr) { 6977 pt2 = pt2._next; 6978 } 6979 if ((pt._prev = pt2 ? pt2._prev : last)) { 6980 pt._prev._next = pt; 6981 } else { 6982 first = pt; 6983 } 6984 if ((pt._next = pt2)) { 6985 pt2._prev = pt; 6986 } else { 6987 last = pt; 6988 } 6989 pt = next; 6990 } 6991 pt = tween._firstPT = first; 6992 } 6993 while (pt) { 6994 if (pt.pg) if (typeof(pt.t[type]) === "function") if (pt.t[type]()) { 6995 changed = true; 6996 } 6997 pt = pt._next; 6998 } 6999 return changed; 7000 }; 7001 7002 TweenPlugin.activate = function(plugins) { 7003 var i = plugins.length; 7004 while (--i > -1) { 7005 if (plugins[i].API === TweenPlugin.API) { 7006 _plugins[(new plugins[i]())._propName] = plugins[i]; 7007 } 7008 } 7009 return true; 7010 }; 7011 7012 //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. 7013 _gsDefine.plugin = function(config) { 7014 if (!config || !config.propName || !config.init || !config.API) { throw "illegal plugin definition."; } 7015 var propName = config.propName, 7016 priority = config.priority || 0, 7017 overwriteProps = config.overwriteProps, 7018 map = {init:"_onInitTween", set:"setRatio", kill:"_kill", round:"_roundProps", initAll:"_onInitAllProps"}, 7019 Plugin = _class("plugins." + propName.charAt(0).toUpperCase() + propName.substr(1) + "Plugin", 7020 function() { 7021 TweenPlugin.call(this, propName, priority); 7022 this._overwriteProps = overwriteProps || []; 7023 }, (config.global === true)), 7024 p = Plugin.prototype = new TweenPlugin(propName), 7025 prop; 7026 p.constructor = Plugin; 7027 Plugin.API = config.API; 7028 for (prop in map) { 7029 if (typeof(config[prop]) === "function") { 7030 p[map[prop]] = config[prop]; 7031 } 7032 } 7033 Plugin.version = config.version; 7034 TweenPlugin.activate([Plugin]); 7035 return Plugin; 7036 }; 7037 7038 7039 //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. 7040 a = window._gsQueue; 7041 if (a) { 7042 for (i = 0; i < a.length; i++) { 7043 a[i](); 7044 } 7045 for (p in _defLookup) { 7046 if (!_defLookup[p].func) { 7047 window.console.log("GSAP encountered missing dependency: com.greensock." + p); 7048 } 7049 } 7050 } 7051 7052 _tickerActive = false; //ensures that the first official animation forces a ticker.tick() to update the time when it is instantiated 7053 7054})((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.