gaf-mobile
Version:
GAF mobile Web site
1,030 lines (940 loc) • 329 kB
JavaScript
/*!
* VERSION: 1.16.1
* DATE: 2015-03-13
* UPDATES AND DOCS AT: http://greensock.com
*
* Includes all of the following: TweenLite, TweenMax, TimelineLite, TimelineMax, EasePack, CSSPlugin, RoundPropsPlugin, BezierPlugin, AttrPlugin, DirectionalRotationPlugin
*
* @license Copyright (c) 2008-2015, GreenSock. All rights reserved.
* This work is subject to the terms at http://greensock.com/standard-license or for
* Club GreenSock members, the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
**/
var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node
(_gsScope._gsQueue || (_gsScope._gsQueue = [])).push( function() {
"use strict";
_gsScope._gsDefine("TweenMax", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
var _slice = function(a) { //don't use [].slice because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
var b = [],
l = a.length,
i;
for (i = 0; i !== l; b.push(a[i++]));
return b;
},
TweenMax = function(target, duration, vars) {
TweenLite.call(this, target, duration, vars);
this._cycle = 0;
this._yoyo = (this.vars.yoyo === true);
this._repeat = this.vars.repeat || 0;
this._repeatDelay = this.vars.repeatDelay || 0;
this._dirty = true; //ensures that if there is any repeat, the totalDuration will get recalculated to accurately report it.
this.render = TweenMax.prototype.render; //speed optimization (avoid prototype lookup on this "hot" method)
},
_tinyNum = 0.0000000001,
TweenLiteInternals = TweenLite._internals,
_isSelector = TweenLiteInternals.isSelector,
_isArray = TweenLiteInternals.isArray,
p = TweenMax.prototype = TweenLite.to({}, 0.1, {}),
_blankArray = [];
TweenMax.version = "1.16.1";
p.constructor = TweenMax;
p.kill()._gc = false;
TweenMax.killTweensOf = TweenMax.killDelayedCallsTo = TweenLite.killTweensOf;
TweenMax.getTweensOf = TweenLite.getTweensOf;
TweenMax.lagSmoothing = TweenLite.lagSmoothing;
TweenMax.ticker = TweenLite.ticker;
TweenMax.render = TweenLite.render;
p.invalidate = function() {
this._yoyo = (this.vars.yoyo === true);
this._repeat = this.vars.repeat || 0;
this._repeatDelay = this.vars.repeatDelay || 0;
this._uncache(true);
return TweenLite.prototype.invalidate.call(this);
};
p.updateTo = function(vars, resetDuration) {
var curRatio = this.ratio,
immediate = this.vars.immediateRender || vars.immediateRender,
p;
if (resetDuration && this._startTime < this._timeline._time) {
this._startTime = this._timeline._time;
this._uncache(false);
if (this._gc) {
this._enabled(true, false);
} else {
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.
}
}
for (p in vars) {
this.vars[p] = vars[p];
}
if (this._initted || immediate) {
if (resetDuration) {
this._initted = false;
if (immediate) {
this.render(0, true, true);
}
} else {
if (this._gc) {
this._enabled(true, false);
}
if (this._notifyPluginsOfEnabled && this._firstPT) {
TweenLite._onPluginEvent("_onDisable", this); //in case a plugin like MotionBlur must perform some cleanup tasks
}
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.
var prevTime = this._time;
this.render(0, true, false);
this._initted = false;
this.render(prevTime, true, false);
} else if (this._time > 0 || immediate) {
this._initted = false;
this._init();
var inv = 1 / (1 - curRatio),
pt = this._firstPT, endValue;
while (pt) {
endValue = pt.s + pt.c;
pt.c *= inv;
pt.s = endValue - pt.c;
pt = pt._next;
}
}
}
}
return this;
};
p.render = function(time, suppressEvents, force) {
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.
this.invalidate();
}
var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
prevTime = this._time,
prevTotalTime = this._totalTime,
prevCycle = this._cycle,
duration = this._duration,
prevRawPrevTime = this._rawPrevTime,
isComplete, callback, pt, cycleDuration, r, type, pow, rawPrevTime;
if (time >= totalDur) {
this._totalTime = totalDur;
this._cycle = this._repeat;
if (this._yoyo && (this._cycle & 1) !== 0) {
this._time = 0;
this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
} else {
this._time = duration;
this.ratio = this._ease._calcEnd ? this._ease.getRatio(1) : 1;
}
if (!this._reversed) {
isComplete = true;
callback = "onComplete";
force = (force || this._timeline.autoRemoveChildren); //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline.
}
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.
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.
time = 0;
}
if (time === 0 || prevRawPrevTime < 0 || prevRawPrevTime === _tinyNum) if (prevRawPrevTime !== time) {
force = true;
if (prevRawPrevTime > _tinyNum) {
callback = "onReverseComplete";
}
}
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.
}
} else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
this._totalTime = this._time = this._cycle = 0;
this.ratio = this._ease._calcEnd ? this._ease.getRatio(0) : 0;
if (prevTotalTime !== 0 || (duration === 0 && prevRawPrevTime > 0)) {
callback = "onReverseComplete";
isComplete = this._reversed;
}
if (time < 0) {
this._active = false;
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.
if (prevRawPrevTime >= 0) {
force = true;
}
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.
}
}
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.
force = true;
}
} else {
this._totalTime = this._time = time;
if (this._repeat !== 0) {
cycleDuration = duration + this._repeatDelay;
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!)
if (this._cycle !== 0) if (this._cycle === this._totalTime / cycleDuration) {
this._cycle--; //otherwise when rendered exactly at the end time, it will act as though it is repeating (at the beginning)
}
this._time = this._totalTime - (this._cycle * cycleDuration);
if (this._yoyo) if ((this._cycle & 1) !== 0) {
this._time = duration - this._time;
}
if (this._time > duration) {
this._time = duration;
} else if (this._time < 0) {
this._time = 0;
}
}
if (this._easeType) {
r = this._time / duration;
type = this._easeType;
pow = this._easePower;
if (type === 1 || (type === 3 && r >= 0.5)) {
r = 1 - r;
}
if (type === 3) {
r *= 2;
}
if (pow === 1) {
r *= r;
} else if (pow === 2) {
r *= r * r;
} else if (pow === 3) {
r *= r * r * r;
} else if (pow === 4) {
r *= r * r * r * r;
}
if (type === 1) {
this.ratio = 1 - r;
} else if (type === 2) {
this.ratio = r;
} else if (this._time / duration < 0.5) {
this.ratio = r / 2;
} else {
this.ratio = 1 - (r / 2);
}
} else {
this.ratio = this._ease.getRatio(this._time / duration);
}
}
if (prevTime === this._time && !force && prevCycle === this._cycle) {
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.
this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
}
return;
} else if (!this._initted) {
this._init();
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 overwriting 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.
return;
} 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.
this._time = prevTime;
this._totalTime = prevTotalTime;
this._rawPrevTime = prevRawPrevTime;
this._cycle = prevCycle;
TweenLiteInternals.lazyTweens.push(this);
this._lazy = [time, suppressEvents];
return;
}
//_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.
if (this._time && !isComplete) {
this.ratio = this._ease.getRatio(this._time / duration);
} else if (isComplete && this._ease._calcEnd) {
this.ratio = this._ease.getRatio((this._time === 0) ? 0 : 1);
}
}
if (this._lazy !== false) {
this._lazy = false;
}
if (!this._active) if (!this._paused && this._time !== prevTime && time >= 0) {
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.
}
if (prevTotalTime === 0) {
if (this._initted === 2 && time > 0) {
//this.invalidate();
this._init(); //will just apply overwriting since _initted of (2) means it was a from() tween that had immediateRender:true
}
if (this._startAt) {
if (time >= 0) {
this._startAt.render(time, suppressEvents, force);
} else if (!callback) {
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.
}
}
if (this.vars.onStart) if (this._totalTime !== 0 || duration === 0) if (!suppressEvents) {
this.vars.onStart.apply(this.vars.onStartScope || this, this.vars.onStartParams || _blankArray);
}
}
pt = this._firstPT;
while (pt) {
if (pt.f) {
pt.t[pt.p](pt.c * this.ratio + pt.s);
} else {
pt.t[pt.p] = pt.c * this.ratio + pt.s;
}
pt = pt._next;
}
if (this._onUpdate) {
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.
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.
}
if (!suppressEvents) if (this._totalTime !== prevTotalTime || isComplete) {
this._onUpdate.apply(this.vars.onUpdateScope || this, this.vars.onUpdateParams || _blankArray);
}
}
if (this._cycle !== prevCycle) if (!suppressEvents) if (!this._gc) if (this.vars.onRepeat) {
this.vars.onRepeat.apply(this.vars.onRepeatScope || this, this.vars.onRepeatParams || _blankArray);
}
if (callback) if (!this._gc || force) { //check gc because there's a chance that kill() could be called in an onUpdate
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.
this._startAt.render(time, suppressEvents, force);
}
if (isComplete) {
if (this._timeline.autoRemoveChildren) {
this._enabled(false, false);
}
this._active = false;
}
if (!suppressEvents && this.vars[callback]) {
this.vars[callback].apply(this.vars[callback + "Scope"] || this, this.vars[callback + "Params"] || _blankArray);
}
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.
this._rawPrevTime = 0;
}
}
};
//---- STATIC FUNCTIONS -----------------------------------------------------------------------------------------------------------
TweenMax.to = function(target, duration, vars) {
return new TweenMax(target, duration, vars);
};
TweenMax.from = function(target, duration, vars) {
vars.runBackwards = true;
vars.immediateRender = (vars.immediateRender != false);
return new TweenMax(target, duration, vars);
};
TweenMax.fromTo = function(target, duration, fromVars, toVars) {
toVars.startAt = fromVars;
toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
return new TweenMax(target, duration, toVars);
};
TweenMax.staggerTo = TweenMax.allTo = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
stagger = stagger || 0;
var delay = vars.delay || 0,
a = [],
finalComplete = function() {
if (vars.onComplete) {
vars.onComplete.apply(vars.onCompleteScope || this, arguments);
}
onCompleteAll.apply(onCompleteAllScope || this, onCompleteAllParams || _blankArray);
},
l, copy, i, p;
if (!_isArray(targets)) {
if (typeof(targets) === "string") {
targets = TweenLite.selector(targets) || targets;
}
if (_isSelector(targets)) {
targets = _slice(targets);
}
}
targets = targets || [];
if (stagger < 0) {
targets = _slice(targets);
targets.reverse();
stagger *= -1;
}
l = targets.length - 1;
for (i = 0; i <= l; i++) {
copy = {};
for (p in vars) {
copy[p] = vars[p];
}
copy.delay = delay;
if (i === l && onCompleteAll) {
copy.onComplete = finalComplete;
}
a[i] = new TweenMax(targets[i], duration, copy);
delay += stagger;
}
return a;
};
TweenMax.staggerFrom = TweenMax.allFrom = function(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
vars.runBackwards = true;
vars.immediateRender = (vars.immediateRender != false);
return TweenMax.staggerTo(targets, duration, vars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
};
TweenMax.staggerFromTo = TweenMax.allFromTo = function(targets, duration, fromVars, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
toVars.startAt = fromVars;
toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
return TweenMax.staggerTo(targets, duration, toVars, stagger, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
};
TweenMax.delayedCall = function(delay, callback, params, scope, useFrames) {
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});
};
TweenMax.set = function(target, vars) {
return new TweenMax(target, 0, vars);
};
TweenMax.isTweening = function(target) {
return (TweenLite.getTweensOf(target, true).length > 0);
};
var _getChildrenOf = function(timeline, includeTimelines) {
var a = [],
cnt = 0,
tween = timeline._first;
while (tween) {
if (tween instanceof TweenLite) {
a[cnt++] = tween;
} else {
if (includeTimelines) {
a[cnt++] = tween;
}
a = a.concat(_getChildrenOf(tween, includeTimelines));
cnt = a.length;
}
tween = tween._next;
}
return a;
},
getAllTweens = TweenMax.getAllTweens = function(includeTimelines) {
return _getChildrenOf(Animation._rootTimeline, includeTimelines).concat( _getChildrenOf(Animation._rootFramesTimeline, includeTimelines) );
};
TweenMax.killAll = function(complete, tweens, delayedCalls, timelines) {
if (tweens == null) {
tweens = true;
}
if (delayedCalls == null) {
delayedCalls = true;
}
var a = getAllTweens((timelines != false)),
l = a.length,
allTrue = (tweens && delayedCalls && timelines),
isDC, tween, i;
for (i = 0; i < l; i++) {
tween = a[i];
if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
if (complete) {
tween.totalTime(tween._reversed ? 0 : tween.totalDuration());
} else {
tween._enabled(false, false);
}
}
}
};
TweenMax.killChildTweensOf = function(parent, complete) {
if (parent == null) {
return;
}
var tl = TweenLiteInternals.tweenLookup,
a, curParent, p, i, l;
if (typeof(parent) === "string") {
parent = TweenLite.selector(parent) || parent;
}
if (_isSelector(parent)) {
parent = _slice(parent);
}
if (_isArray(parent)) {
i = parent.length;
while (--i > -1) {
TweenMax.killChildTweensOf(parent[i], complete);
}
return;
}
a = [];
for (p in tl) {
curParent = tl[p].target.parentNode;
while (curParent) {
if (curParent === parent) {
a = a.concat(tl[p].tweens);
}
curParent = curParent.parentNode;
}
}
l = a.length;
for (i = 0; i < l; i++) {
if (complete) {
a[i].totalTime(a[i].totalDuration());
}
a[i]._enabled(false, false);
}
};
var _changePause = function(pause, tweens, delayedCalls, timelines) {
tweens = (tweens !== false);
delayedCalls = (delayedCalls !== false);
timelines = (timelines !== false);
var a = getAllTweens(timelines),
allTrue = (tweens && delayedCalls && timelines),
i = a.length,
isDC, tween;
while (--i > -1) {
tween = a[i];
if (allTrue || (tween instanceof SimpleTimeline) || ((isDC = (tween.target === tween.vars.onComplete)) && delayedCalls) || (tweens && !isDC)) {
tween.paused(pause);
}
}
};
TweenMax.pauseAll = function(tweens, delayedCalls, timelines) {
_changePause(true, tweens, delayedCalls, timelines);
};
TweenMax.resumeAll = function(tweens, delayedCalls, timelines) {
_changePause(false, tweens, delayedCalls, timelines);
};
TweenMax.globalTimeScale = function(value) {
var tl = Animation._rootTimeline,
t = TweenLite.ticker.time;
if (!arguments.length) {
return tl._timeScale;
}
value = value || _tinyNum; //can't allow zero because it'll throw the math off
tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
tl = Animation._rootFramesTimeline;
t = TweenLite.ticker.frame;
tl._startTime = t - ((t - tl._startTime) * tl._timeScale / value);
tl._timeScale = Animation._rootTimeline._timeScale = value;
return value;
};
//---- GETTERS / SETTERS ----------------------------------------------------------------------------------------------------------
p.progress = function(value) {
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);
};
p.totalProgress = function(value) {
return (!arguments.length) ? this._totalTime / this.totalDuration() : this.totalTime( this.totalDuration() * value, false);
};
p.time = function(value, suppressEvents) {
if (!arguments.length) {
return this._time;
}
if (this._dirty) {
this.totalDuration();
}
if (value > this._duration) {
value = this._duration;
}
if (this._yoyo && (this._cycle & 1) !== 0) {
value = (this._duration - value) + (this._cycle * (this._duration + this._repeatDelay));
} else if (this._repeat !== 0) {
value += this._cycle * (this._duration + this._repeatDelay);
}
return this.totalTime(value, suppressEvents);
};
p.duration = function(value) {
if (!arguments.length) {
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.
}
return Animation.prototype.duration.call(this, value);
};
p.totalDuration = function(value) {
if (!arguments.length) {
if (this._dirty) {
//instead of Infinity, we use 999999999999 so that we can accommodate reverses
this._totalDuration = (this._repeat === -1) ? 999999999999 : this._duration * (this._repeat + 1) + (this._repeatDelay * this._repeat);
this._dirty = false;
}
return this._totalDuration;
}
return (this._repeat === -1) ? this : this.duration( (value - (this._repeat * this._repeatDelay)) / (this._repeat + 1) );
};
p.repeat = function(value) {
if (!arguments.length) {
return this._repeat;
}
this._repeat = value;
return this._uncache(true);
};
p.repeatDelay = function(value) {
if (!arguments.length) {
return this._repeatDelay;
}
this._repeatDelay = value;
return this._uncache(true);
};
p.yoyo = function(value) {
if (!arguments.length) {
return this._yoyo;
}
this._yoyo = value;
return this;
};
return TweenMax;
}, true);
/*
* ----------------------------------------------------------------
* TimelineLite
* ----------------------------------------------------------------
*/
_gsScope._gsDefine("TimelineLite", ["core.Animation","core.SimpleTimeline","TweenLite"], function(Animation, SimpleTimeline, TweenLite) {
var TimelineLite = function(vars) {
SimpleTimeline.call(this, vars);
this._labels = {};
this.autoRemoveChildren = (this.vars.autoRemoveChildren === true);
this.smoothChildTiming = (this.vars.smoothChildTiming === true);
this._sortChildren = true;
this._onUpdate = this.vars.onUpdate;
var v = this.vars,
val, p;
for (p in v) {
val = v[p];
if (_isArray(val)) if (val.join("").indexOf("{self}") !== -1) {
v[p] = this._swapSelfInParams(val);
}
}
if (_isArray(v.tweens)) {
this.add(v.tweens, 0, v.align, v.stagger);
}
},
_tinyNum = 0.0000000001,
TweenLiteInternals = TweenLite._internals,
_internals = TimelineLite._internals = {},
_isSelector = TweenLiteInternals.isSelector,
_isArray = TweenLiteInternals.isArray,
_lazyTweens = TweenLiteInternals.lazyTweens,
_lazyRender = TweenLiteInternals.lazyRender,
_blankArray = [],
_globals = _gsScope._gsDefine.globals,
_copy = function(vars) {
var copy = {}, p;
for (p in vars) {
copy[p] = vars[p];
}
return copy;
},
_pauseCallback = _internals.pauseCallback = function(tween, callback, params, scope) {
var tl = tween._timeline,
time = tl._totalTime,
startTime = tween._startTime,
reversed = (tween._rawPrevTime < 0 || (tween._rawPrevTime === 0 && tl._reversed)),//don't use tween.ratio because if the playhead lands exactly on top of the addPause(), ratio will be 1 even if the master timeline was reversed (which is correct). The key here is to sense the direction of the playhead.
next = reversed ? 0 : _tinyNum,
prev = reversed ? _tinyNum : 0,
sibling;
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.
tl.pause(startTime);
//now find sibling tweens that are EXACTLY at the same spot on the timeline and adjust the _rawPrevTime so that they fire (or don't fire) correctly on the next render. This is primarily to accommodate zero-duration tweens/callbacks that are positioned right on top of a pause. For example, tl.to(...).call(...).addPause(...).call(...) - notice that there's a call() on each side of the pause, so when it's running forward it should call the first one and then pause, and then when resumed, call the other. Zero-duration tweens use _rawPrevTime to sense momentum figure out if events were suppressed when arriving directly on top of that time.
sibling = tween._prev;
while (sibling && sibling._startTime === startTime) {
sibling._rawPrevTime = prev;
sibling = sibling._prev;
}
sibling = tween._next;
while (sibling && sibling._startTime === startTime) {
sibling._rawPrevTime = next;
sibling = sibling._next;
}
if (callback) {
callback.apply(scope || tl, params || _blankArray);
}
if (this._forcingPlayhead || !tl._paused) { //the callback could have called resume().
tl.seek(time);
}
}
},
_slice = function(a) { //don't use [].slice because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
var b = [],
l = a.length,
i;
for (i = 0; i !== l; b.push(a[i++]));
return b;
},
p = TimelineLite.prototype = new SimpleTimeline();
TimelineLite.version = "1.16.1";
p.constructor = TimelineLite;
p.kill()._gc = p._forcingPlayhead = false;
/* might use later...
//translates a local time inside an animation to the corresponding time on the root/global timeline, factoring in all nesting and timeScales.
function localToGlobal(time, animation) {
while (animation) {
time = (time / animation._timeScale) + animation._startTime;
animation = animation.timeline;
}
return time;
}
//translates the supplied time on the root/global timeline into the corresponding local time inside a particular animation, factoring in all nesting and timeScales
function globalToLocal(time, animation) {
var scale = 1;
time -= localToGlobal(0, animation);
while (animation) {
scale *= animation._timeScale;
animation = animation.timeline;
}
return time * scale;
}
*/
p.to = function(target, duration, vars, position) {
var Engine = (vars.repeat && _globals.TweenMax) || TweenLite;
return duration ? this.add( new Engine(target, duration, vars), position) : this.set(target, vars, position);
};
p.from = function(target, duration, vars, position) {
return this.add( ((vars.repeat && _globals.TweenMax) || TweenLite).from(target, duration, vars), position);
};
p.fromTo = function(target, duration, fromVars, toVars, position) {
var Engine = (toVars.repeat && _globals.TweenMax) || TweenLite;
return duration ? this.add( Engine.fromTo(target, duration, fromVars, toVars), position) : this.set(target, toVars, position);
};
p.staggerTo = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
var tl = new TimelineLite({onComplete:onCompleteAll, onCompleteParams:onCompleteAllParams, onCompleteScope:onCompleteAllScope, smoothChildTiming:this.smoothChildTiming}),
i;
if (typeof(targets) === "string") {
targets = TweenLite.selector(targets) || targets;
}
targets = targets || [];
if (_isSelector(targets)) { //senses if the targets object is a selector. If it is, we should translate it into an array.
targets = _slice(targets);
}
stagger = stagger || 0;
if (stagger < 0) {
targets = _slice(targets);
targets.reverse();
stagger *= -1;
}
for (i = 0; i < targets.length; i++) {
if (vars.startAt) {
vars.startAt = _copy(vars.startAt);
}
tl.to(targets[i], duration, _copy(vars), i * stagger);
}
return this.add(tl, position);
};
p.staggerFrom = function(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
vars.immediateRender = (vars.immediateRender != false);
vars.runBackwards = true;
return this.staggerTo(targets, duration, vars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
};
p.staggerFromTo = function(targets, duration, fromVars, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope) {
toVars.startAt = fromVars;
toVars.immediateRender = (toVars.immediateRender != false && fromVars.immediateRender != false);
return this.staggerTo(targets, duration, toVars, stagger, position, onCompleteAll, onCompleteAllParams, onCompleteAllScope);
};
p.call = function(callback, params, scope, position) {
return this.add( TweenLite.delayedCall(0, callback, params, scope), position);
};
p.set = function(target, vars, position) {
position = this._parseTimeOrLabel(position, 0, true);
if (vars.immediateRender == null) {
vars.immediateRender = (position === this._time && !this._paused);
}
return this.add( new TweenLite(target, 0, vars), position);
};
TimelineLite.exportRoot = function(vars, ignoreDelayedCalls) {
vars = vars || {};
if (vars.smoothChildTiming == null) {
vars.smoothChildTiming = true;
}
var tl = new TimelineLite(vars),
root = tl._timeline,
tween, next;
if (ignoreDelayedCalls == null) {
ignoreDelayedCalls = true;
}
root._remove(tl, true);
tl._startTime = 0;
tl._rawPrevTime = tl._time = tl._totalTime = root._time;
tween = root._first;
while (tween) {
next = tween._next;
if (!ignoreDelayedCalls || !(tween instanceof TweenLite && tween.target === tween.vars.onComplete)) {
tl.add(tween, tween._startTime - tween._delay);
}
tween = next;
}
root.add(tl, 0);
return tl;
};
p.add = function(value, position, align, stagger) {
var curTime, l, i, child, tl, beforeRawTime;
if (typeof(position) !== "number") {
position = this._parseTimeOrLabel(position, 0, true, value);
}
if (!(value instanceof Animation)) {
if ((value instanceof Array) || (value && value.push && _isArray(value))) {
align = align || "normal";
stagger = stagger || 0;
curTime = position;
l = value.length;
for (i = 0; i < l; i++) {
if (_isArray(child = value[i])) {
child = new TimelineLite({tweens:child});
}
this.add(child, curTime);
if (typeof(child) !== "string" && typeof(child) !== "function") {
if (align === "sequence") {
curTime = child._startTime + (child.totalDuration() / child._timeScale);
} else if (align === "start") {
child._startTime -= child.delay();
}
}
curTime += stagger;
}
return this._uncache(true);
} else if (typeof(value) === "string") {
return this.addLabel(value, position);
} else if (typeof(value) === "function") {
value = TweenLite.delayedCall(0, value);
} else {
throw("Cannot add " + value + " into the timeline; it is not a tween, timeline, function, or string.");
}
}
SimpleTimeline.prototype.add.call(this, value, position);
//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.
if (this._gc || this._time === this._duration) if (!this._paused) if (this._duration < this.duration()) {
//in case any of the ancestors had completed but should now be enabled...
tl = this;
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.
while (tl._timeline) {
if (beforeRawTime && tl._timeline.smoothChildTiming) {
tl.totalTime(tl._totalTime, true); //moves the timeline (shifts its startTime) if necessary, and also enables it.
} else if (tl._gc) {
tl._enabled(true, false);
}
tl = tl._timeline;
}
}
return this;
};
p.remove = function(value) {
if (value instanceof Animation) {
return this._remove(value, false);
} else if (value instanceof Array || (value && value.push && _isArray(value))) {
var i = value.length;
while (--i > -1) {
this.remove(value[i]);
}
return this;
} else if (typeof(value) === "string") {
return this.removeLabel(value);
}
return this.kill(null, value);
};
p._remove = function(tween, skipDisable) {
SimpleTimeline.prototype._remove.call(this, tween, skipDisable);
var last = this._last;
if (!last) {
this._time = this._totalTime = this._duration = this._totalDuration = 0;
} else if (this._time > last._startTime + last._totalDuration / last._timeScale) {
this._time = this.duration();
this._totalTime = this._totalDuration;
}
return this;
};
p.append = function(value, offsetOrLabel) {
return this.add(value, this._parseTimeOrLabel(null, offsetOrLabel, true, value));
};
p.insert = p.insertMultiple = function(value, position, align, stagger) {
return this.add(value, position || 0, align, stagger);
};
p.appendMultiple = function(tweens, offsetOrLabel, align, stagger) {
return this.add(tweens, this._parseTimeOrLabel(null, offsetOrLabel, true, tweens), align, stagger);
};
p.addLabel = function(label, position) {
this._labels[label] = this._parseTimeOrLabel(position);
return this;
};
p.addPause = function(position, callback, params, scope) {
var t = TweenLite.delayedCall(0, _pauseCallback, ["{self}", callback, params, scope], this);
t.data = "isPause"; // we use this flag in TweenLite's render() method to identify it as a special case that shouldn't be triggered when the virtual playhead is LEAVING the exact position where the pause is, otherwise timeline.addPause(1).play(1) would end up paused on the very next tick.
return this.add(t, position);
};
p.removeLabel = function(label) {
delete this._labels[label];
return this;
};
p.getLabelTime = function(label) {
return (this._labels[label] != null) ? this._labels[label] : -1;
};
p._parseTimeOrLabel = function(timeOrLabel, offsetOrLabel, appendIfAbsent, ignore) {
var i;
//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().
if (ignore instanceof Animation && ignore.timeline === this) {
this.remove(ignore);
} else if (ignore && ((ignore instanceof Array) || (ignore.push && _isArray(ignore)))) {
i = ignore.length;
while (--i > -1) {
if (ignore[i] instanceof Animation && ignore[i].timeline === this) {
this.remove(ignore[i]);
}
}
}
if (typeof(offsetOrLabel) === "string") {
return this._parseTimeOrLabel(offsetOrLabel, (appendIfAbsent && typeof(timeOrLabel) === "number" && this._labels[offsetOrLabel] == null) ? timeOrLabel - this.duration() : 0, appendIfAbsent);
}
offsetOrLabel = offsetOrLabel || 0;
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).
i = timeOrLabel.indexOf("=");
if (i === -1) {
if (this._labels[timeOrLabel] == null) {
return appendIfAbsent ? (this._labels[timeOrLabel] = this.duration() + offsetOrLabel) : offsetOrLabel;
}
return this._labels[timeOrLabel] + offsetOrLabel;
}
offsetOrLabel = parseInt(timeOrLabel.charAt(i-1) + "1", 10) * Number(timeOrLabel.substr(i+1));
timeOrLabel = (i > 1) ? this._parseTimeOrLabel(timeOrLabel.substr(0, i-1), 0, appendIfAbsent) : this.duration();
} else if (timeOrLabel == null) {
timeOrLabel = this.duration();
}
return Number(timeOrLabel) + offsetOrLabel;
};
p.seek = function(position, suppressEvents) {
return this.totalTime((typeof(position) === "number") ? position : this._parseTimeOrLabel(position), (suppressEvents !== false));
};
p.stop = function() {
return this.paused(true);
};
p.gotoAndPlay = function(position, suppressEvents) {
return this.play(position, suppressEvents);
};
p.gotoAndStop = function(position, suppressEvents) {
return this.pause(position, suppressEvents);
};
p.render = function(time, suppressEvents, force) {
if (this._gc) {
this._enabled(true, false);
}
var totalDur = (!this._dirty) ? this._totalDuration : this.totalDuration(),
prevTime = this._time,
prevStart = this._startTime,
prevTimeScale = this._timeScale,
prevPaused = this._paused,
tween, isComplete, next, callback, internalForce;
if (time >= totalDur) {
this._totalTime = this._time = totalDur;
if (!this._reversed) if (!this._hasPausedChild()) {
isComplete = true;
callback = "onComplete";
internalForce = !!this._timeline.autoRemoveChildren; //otherwise, if the animation is unpaused/activated after it's already finished, it doesn't get removed from the parent timeline.
if (this._duration === 0) if (time === 0 || this._rawPrevTime < 0 || this._rawPrevTime === _tinyNum) if (this._rawPrevTime !== time && this._first) {
internalForce = true;
if (this._rawPrevTime > _tinyNum) {
callback = "onReverseComplete";
}
}
}
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.
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.
} else if (time < 0.0000001) { //to work around occasional floating point math artifacts, round super small values to 0.
this._totalTime = this._time = 0;
if (prevTime !== 0 || (this._duration === 0 && this._rawPrevTime !== _tinyNum && (this._rawPrevTime > 0 || (time < 0 && this._rawPrevTime >= 0)))) {
callback = "onReverseComplete";
isComplete = this._reversed;
}
if (time < 0) {
this._active = false;
if (this._timeline.autoRemoveChildren && this._reversed) { //ensures proper GC if a timeline is resumed after it's finished reversing.
internalForce = isComplete = true;
callback = "onReverseComplete";
} else if (this._rawPrevTime >= 0 && this._first) { //when going back beyond the start, force a render so that zero-duration tweens that sit at the very beginning render their start values properly. Otherwise, if the parent timeline's playhead lands exactly at this timeline's startTime, and then moves backwards, the zero-duration tweens at the beginning would still be at their end state.
internalForce = true;
}
this._rawPrevTime = time;
} else {
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.
if (time === 0 && isComplete) { //if there's a zero-duration tween at the very beginning of a timeline and the playhead lands EXACTLY at time 0, that tween will correctly render its end values, but we need to keep the timeline alive for one more render so that the beginning values render properly as the parent's playhead keeps moving beyond the begining. Imagine obj.x starts at 0 and then we do tl.set(obj, {x:100}).to(obj, 1, {x:200}) and then later we tl.reverse()...the goal is to have obj.x revert to 0. If the playhead happens to land on exactly 0, without this chunk of code, it'd complete the timeline and remove it from the rendering queue (not good).
tween = this._first;
while (tween && tween._startTime === 0) {
if (!tween._duration) {
isComplete = false;
}
tween = tween._next;
}
}
time = 0; //to avoid occasional floating point rounding errors (could cause problems especially with zero-duration tweens at the very beginning of the timeline)
if (!this._initted) {
internalForce = true;
}
}
} else {
this._totalTime = this._time = this._rawPrevTime = time;
}
if ((this._time === prevTime || !this._first) && !force && !internalForce) {
return;
} else if (!this._initted) {
this._initted = true;
}
if (!this._active) if (!this._paused && this._time !== prevTime && time > 0) {
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