UNPKG

gsap

Version:

GSAP is a framework-agnostic JavaScript animation library that turns developers into animation superheroes. Build high-performance animations that work in **every** major browser. Animate CSS, SVG, canvas, React, Vue, WebGL, colors, strings, motion paths,

1,317 lines (1,148 loc) 172 kB
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } /*! * GSAP 3.13.0 * https://gsap.com * * @license Copyright 2008-2025, GreenSock. All rights reserved. * Subject to the terms at https://gsap.com/standard-license * @author: Jack Doyle, jack@greensock.com */ /* eslint-disable */ var _config = { autoSleep: 120, force3D: "auto", nullTargetWarn: 1, units: { lineHeight: "" } }, _defaults = { duration: .5, overwrite: false, delay: 0 }, _suppressOverwrites, _reverting, _context, _bigNum = 1e8, _tinyNum = 1 / _bigNum, _2PI = Math.PI * 2, _HALF_PI = _2PI / 4, _gsID = 0, _sqrt = Math.sqrt, _cos = Math.cos, _sin = Math.sin, _isString = function _isString(value) { return typeof value === "string"; }, _isFunction = function _isFunction(value) { return typeof value === "function"; }, _isNumber = function _isNumber(value) { return typeof value === "number"; }, _isUndefined = function _isUndefined(value) { return typeof value === "undefined"; }, _isObject = function _isObject(value) { return typeof value === "object"; }, _isNotFalse = function _isNotFalse(value) { return value !== false; }, _windowExists = function _windowExists() { return typeof window !== "undefined"; }, _isFuncOrString = function _isFuncOrString(value) { return _isFunction(value) || _isString(value); }, _isTypedArray = typeof ArrayBuffer === "function" && ArrayBuffer.isView || function () {}, // note: IE10 has ArrayBuffer, but NOT ArrayBuffer.isView(). _isArray = Array.isArray, _strictNumExp = /(?:-?\.?\d|\.)+/gi, //only numbers (including negatives and decimals) but NOT relative values. _numExp = /[-+=.]*\d+[.e\-+]*\d*[e\-+]*\d*/g, //finds any numbers, including ones that start with += or -=, negative numbers, and ones in scientific notation like 1e-8. _numWithUnitExp = /[-+=.]*\d+[.e-]*\d*[a-z%]*/g, _complexStringNumExp = /[-+=.]*\d+\.?\d*(?:e-|e\+)?\d*/gi, //duplicate so that while we're looping through matches from exec(), it doesn't contaminate the lastIndex of _numExp which we use to search for colors too. _relExp = /[+-]=-?[.\d]+/, _delimitedValueExp = /[^,'"\[\]\s]+/gi, // previously /[#\-+.]*\b[a-z\d\-=+%.]+/gi but didn't catch special characters. _unitExp = /^[+\-=e\s\d]*\d+[.\d]*([a-z]*|%)\s*$/i, _globalTimeline, _win, _coreInitted, _doc, _globals = {}, _installScope = {}, _coreReady, _install = function _install(scope) { return (_installScope = _merge(scope, _globals)) && gsap; }, _missingPlugin = function _missingPlugin(property, value) { return console.warn("Invalid property", property, "set to", value, "Missing plugin? gsap.registerPlugin()"); }, _warn = function _warn(message, suppress) { return !suppress && console.warn(message); }, _addGlobal = function _addGlobal(name, obj) { return name && (_globals[name] = obj) && _installScope && (_installScope[name] = obj) || _globals; }, _emptyFunc = function _emptyFunc() { return 0; }, _startAtRevertConfig = { suppressEvents: true, isStart: true, kill: false }, _revertConfigNoKill = { suppressEvents: true, kill: false }, _revertConfig = { suppressEvents: true }, _reservedProps = {}, _lazyTweens = [], _lazyLookup = {}, _lastRenderedFrame, _plugins = {}, _effects = {}, _nextGCFrame = 30, _harnessPlugins = [], _callbackNames = "", _harness = function _harness(targets) { var target = targets[0], harnessPlugin, i; _isObject(target) || _isFunction(target) || (targets = [targets]); if (!(harnessPlugin = (target._gsap || {}).harness)) { // find the first target with a harness. We assume targets passed into an animation will be of similar type, meaning the same kind of harness can be used for them all (performance optimization) i = _harnessPlugins.length; while (i-- && !_harnessPlugins[i].targetTest(target)) {} harnessPlugin = _harnessPlugins[i]; } i = targets.length; while (i--) { targets[i] && (targets[i]._gsap || (targets[i]._gsap = new GSCache(targets[i], harnessPlugin))) || targets.splice(i, 1); } return targets; }, _getCache = function _getCache(target) { return target._gsap || _harness(toArray(target))[0]._gsap; }, _getProperty = function _getProperty(target, property, v) { return (v = target[property]) && _isFunction(v) ? target[property]() : _isUndefined(v) && target.getAttribute && target.getAttribute(property) || v; }, _forEachName = function _forEachName(names, func) { return (names = names.split(",")).forEach(func) || names; }, //split a comma-delimited list of names into an array, then run a forEach() function and return the split array (this is just a way to consolidate/shorten some code). _round = function _round(value) { return Math.round(value * 100000) / 100000 || 0; }, _roundPrecise = function _roundPrecise(value) { return Math.round(value * 10000000) / 10000000 || 0; }, // increased precision mostly for timing values. _parseRelative = function _parseRelative(start, value) { var operator = value.charAt(0), end = parseFloat(value.substr(2)); start = parseFloat(start); return operator === "+" ? start + end : operator === "-" ? start - end : operator === "*" ? start * end : start / end; }, _arrayContainsAny = function _arrayContainsAny(toSearch, toFind) { //searches one array to find matches for any of the items in the toFind array. As soon as one is found, it returns true. It does NOT return all the matches; it's simply a boolean search. var l = toFind.length, i = 0; for (; toSearch.indexOf(toFind[i]) < 0 && ++i < l;) {} return i < l; }, _lazyRender = function _lazyRender() { var l = _lazyTweens.length, a = _lazyTweens.slice(0), i, tween; _lazyLookup = {}; _lazyTweens.length = 0; for (i = 0; i < l; i++) { tween = a[i]; tween && tween._lazy && (tween.render(tween._lazy[0], tween._lazy[1], true)._lazy = 0); } }, _isRevertWorthy = function _isRevertWorthy(animation) { return !!(animation._initted || animation._startAt || animation.add); }, _lazySafeRender = function _lazySafeRender(animation, time, suppressEvents, force) { _lazyTweens.length && !_reverting && _lazyRender(); animation.render(time, suppressEvents, force || !!(_reverting && time < 0 && _isRevertWorthy(animation))); _lazyTweens.length && !_reverting && _lazyRender(); //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. }, _numericIfPossible = function _numericIfPossible(value) { var n = parseFloat(value); return (n || n === 0) && (value + "").match(_delimitedValueExp).length < 2 ? n : _isString(value) ? value.trim() : value; }, _passThrough = function _passThrough(p) { return p; }, _setDefaults = function _setDefaults(obj, defaults) { for (var p in defaults) { p in obj || (obj[p] = defaults[p]); } return obj; }, _setKeyframeDefaults = function _setKeyframeDefaults(excludeDuration) { return function (obj, defaults) { for (var p in defaults) { p in obj || p === "duration" && excludeDuration || p === "ease" || (obj[p] = defaults[p]); } }; }, _merge = function _merge(base, toMerge) { for (var p in toMerge) { base[p] = toMerge[p]; } return base; }, _mergeDeep = function _mergeDeep(base, toMerge) { for (var p in toMerge) { p !== "__proto__" && p !== "constructor" && p !== "prototype" && (base[p] = _isObject(toMerge[p]) ? _mergeDeep(base[p] || (base[p] = {}), toMerge[p]) : toMerge[p]); } return base; }, _copyExcluding = function _copyExcluding(obj, excluding) { var copy = {}, p; for (p in obj) { p in excluding || (copy[p] = obj[p]); } return copy; }, _inheritDefaults = function _inheritDefaults(vars) { var parent = vars.parent || _globalTimeline, func = vars.keyframes ? _setKeyframeDefaults(_isArray(vars.keyframes)) : _setDefaults; if (_isNotFalse(vars.inherit)) { while (parent) { func(vars, parent.vars.defaults); parent = parent.parent || parent._dp; } } return vars; }, _arraysMatch = function _arraysMatch(a1, a2) { var i = a1.length, match = i === a2.length; while (match && i-- && a1[i] === a2[i]) {} return i < 0; }, _addLinkedListItem = function _addLinkedListItem(parent, child, firstProp, lastProp, sortBy) { if (firstProp === void 0) { firstProp = "_first"; } if (lastProp === void 0) { lastProp = "_last"; } var prev = parent[lastProp], t; if (sortBy) { t = child[sortBy]; while (prev && prev[sortBy] > t) { prev = prev._prev; } } if (prev) { child._next = prev._next; prev._next = child; } else { child._next = parent[firstProp]; parent[firstProp] = child; } if (child._next) { child._next._prev = child; } else { parent[lastProp] = child; } child._prev = prev; child.parent = child._dp = parent; return child; }, _removeLinkedListItem = function _removeLinkedListItem(parent, child, firstProp, lastProp) { if (firstProp === void 0) { firstProp = "_first"; } if (lastProp === void 0) { lastProp = "_last"; } var prev = child._prev, next = child._next; if (prev) { prev._next = next; } else if (parent[firstProp] === child) { parent[firstProp] = next; } if (next) { next._prev = prev; } else if (parent[lastProp] === child) { parent[lastProp] = prev; } child._next = child._prev = child.parent = null; // don't delete the _dp just so we can revert if necessary. But parent should be null to indicate the item isn't in a linked list. }, _removeFromParent = function _removeFromParent(child, onlyIfParentHasAutoRemove) { child.parent && (!onlyIfParentHasAutoRemove || child.parent.autoRemoveChildren) && child.parent.remove && child.parent.remove(child); child._act = 0; }, _uncache = function _uncache(animation, child) { if (animation && (!child || child._end > animation._dur || child._start < 0)) { // performance optimization: if a child animation is passed in we should only uncache if that child EXTENDS the animation (its end time is beyond the end) var a = animation; while (a) { a._dirty = 1; a = a.parent; } } return animation; }, _recacheAncestors = function _recacheAncestors(animation) { var parent = animation.parent; while (parent && parent.parent) { //sometimes we must force a re-sort of all children and update the duration/totalDuration of all ancestor timelines immediately in case, for example, in the middle of a render loop, one tween alters another tween's timeScale which shoves its startTime before 0, forcing the parent timeline to shift around and shiftChildren() which could affect that next tween's render (startTime). Doesn't matter for the root timeline though. parent._dirty = 1; parent.totalDuration(); parent = parent.parent; } return animation; }, _rewindStartAt = function _rewindStartAt(tween, totalTime, suppressEvents, force) { return tween._startAt && (_reverting ? tween._startAt.revert(_revertConfigNoKill) : tween.vars.immediateRender && !tween.vars.autoRevert || tween._startAt.render(totalTime, true, force)); }, _hasNoPausedAncestors = function _hasNoPausedAncestors(animation) { return !animation || animation._ts && _hasNoPausedAncestors(animation.parent); }, _elapsedCycleDuration = function _elapsedCycleDuration(animation) { return animation._repeat ? _animationCycle(animation._tTime, animation = animation.duration() + animation._rDelay) * animation : 0; }, // feed in the totalTime and cycleDuration and it'll return the cycle (iteration minus 1) and if the playhead is exactly at the very END, it will NOT bump up to the next cycle. _animationCycle = function _animationCycle(tTime, cycleDuration) { var whole = Math.floor(tTime = _roundPrecise(tTime / cycleDuration)); return tTime && whole === tTime ? whole - 1 : whole; }, _parentToChildTotalTime = function _parentToChildTotalTime(parentTime, child) { return (parentTime - child._start) * child._ts + (child._ts >= 0 ? 0 : child._dirty ? child.totalDuration() : child._tDur); }, _setEnd = function _setEnd(animation) { return animation._end = _roundPrecise(animation._start + (animation._tDur / Math.abs(animation._ts || animation._rts || _tinyNum) || 0)); }, _alignPlayhead = function _alignPlayhead(animation, totalTime) { // adjusts the animation's _start and _end according to the provided totalTime (only if the parent's smoothChildTiming is true and the animation isn't paused). It doesn't do any rendering or forcing things back into parent timelines, etc. - that's what totalTime() is for. var parent = animation._dp; if (parent && parent.smoothChildTiming && animation._ts) { animation._start = _roundPrecise(parent._time - (animation._ts > 0 ? totalTime / animation._ts : ((animation._dirty ? animation.totalDuration() : animation._tDur) - totalTime) / -animation._ts)); _setEnd(animation); parent._dirty || _uncache(parent, animation); //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. } return animation; }, /* _totalTimeToTime = (clampedTotalTime, duration, repeat, repeatDelay, yoyo) => { let cycleDuration = duration + repeatDelay, time = _round(clampedTotalTime % cycleDuration); if (time > duration) { time = duration; } return (yoyo && (~~(clampedTotalTime / cycleDuration) & 1)) ? duration - time : time; }, */ _postAddChecks = function _postAddChecks(timeline, child) { var t; if (child._time || !child._dur && child._initted || child._start < timeline._time && (child._dur || !child.add)) { // in case, for example, the _start is moved on a tween that has already rendered, or if it's being inserted into a timeline BEFORE where the playhead is currently. Imagine it's at its end state, then the startTime is moved WAY later (after the end of this timeline), it should render at its beginning. Special case: if it's a timeline (has .add() method) and no duration, we can skip rendering because the user may be populating it AFTER adding it to a parent timeline (unconventional, but possible, and we wouldn't want it to get removed if the parent's autoRemoveChildren is true). t = _parentToChildTotalTime(timeline.rawTime(), child); if (!child._dur || _clamp(0, child.totalDuration(), t) - child._tTime > _tinyNum) { child.render(t, true); } } //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 (_uncache(timeline, child)._dp && timeline._initted && timeline._time >= timeline._dur && timeline._ts) { //in case any of the ancestors had completed but should now be enabled... if (timeline._dur < timeline.duration()) { t = timeline; while (t._dp) { t.rawTime() >= 0 && t.totalTime(t._tTime); //moves the timeline (shifts its startTime) if necessary, and also enables it. If it's currently zero, though, it may not be scheduled to render until later so there's no need to force it to align with the current playhead position. Only move to catch up with the playhead. t = t._dp; } } timeline._zTime = -_tinyNum; // helps ensure that the next render() will be forced (crossingStart = true in render()), even if the duration hasn't changed (we're adding a child which would need to get rendered). Definitely an edge case. Note: we MUST do this AFTER the loop above where the totalTime() might trigger a render() because this _addToTimeline() method gets called from the Animation constructor, BEFORE tweens even record their targets, etc. so we wouldn't want things to get triggered in the wrong order. } }, _addToTimeline = function _addToTimeline(timeline, child, position, skipChecks) { child.parent && _removeFromParent(child); child._start = _roundPrecise((_isNumber(position) ? position : position || timeline !== _globalTimeline ? _parsePosition(timeline, position, child) : timeline._time) + child._delay); child._end = _roundPrecise(child._start + (child.totalDuration() / Math.abs(child.timeScale()) || 0)); _addLinkedListItem(timeline, child, "_first", "_last", timeline._sort ? "_start" : 0); _isFromOrFromStart(child) || (timeline._recent = child); skipChecks || _postAddChecks(timeline, child); timeline._ts < 0 && _alignPlayhead(timeline, timeline._tTime); // if the timeline is reversed and the new child makes it longer, we may need to adjust the parent's _start (push it back) return timeline; }, _scrollTrigger = function _scrollTrigger(animation, trigger) { return (_globals.ScrollTrigger || _missingPlugin("scrollTrigger", trigger)) && _globals.ScrollTrigger.create(trigger, animation); }, _attemptInitTween = function _attemptInitTween(tween, time, force, suppressEvents, tTime) { _initTween(tween, time, tTime); if (!tween._initted) { return 1; } if (!force && tween._pt && !_reverting && (tween._dur && tween.vars.lazy !== false || !tween._dur && tween.vars.lazy) && _lastRenderedFrame !== _ticker.frame) { _lazyTweens.push(tween); tween._lazy = [tTime, suppressEvents]; return 1; } }, _parentPlayheadIsBeforeStart = function _parentPlayheadIsBeforeStart(_ref) { var parent = _ref.parent; return parent && parent._ts && parent._initted && !parent._lock && (parent.rawTime() < 0 || _parentPlayheadIsBeforeStart(parent)); }, // check parent's _lock because when a timeline repeats/yoyos and does its artificial wrapping, we shouldn't force the ratio back to 0 _isFromOrFromStart = function _isFromOrFromStart(_ref2) { var data = _ref2.data; return data === "isFromStart" || data === "isStart"; }, _renderZeroDurationTween = function _renderZeroDurationTween(tween, totalTime, suppressEvents, force) { var prevRatio = tween.ratio, ratio = totalTime < 0 || !totalTime && (!tween._start && _parentPlayheadIsBeforeStart(tween) && !(!tween._initted && _isFromOrFromStart(tween)) || (tween._ts < 0 || tween._dp._ts < 0) && !_isFromOrFromStart(tween)) ? 0 : 1, // if the tween or its parent is reversed and the totalTime is 0, we should go to a ratio of 0. Edge case: if a from() or fromTo() stagger tween is placed later in a timeline, the "startAt" zero-duration tween could initially render at a time when the parent timeline's playhead is technically BEFORE where this tween is, so make sure that any "from" and "fromTo" startAt tweens are rendered the first time at a ratio of 1. repeatDelay = tween._rDelay, tTime = 0, pt, iteration, prevIteration; if (repeatDelay && tween._repeat) { // in case there's a zero-duration tween that has a repeat with a repeatDelay tTime = _clamp(0, tween._tDur, totalTime); iteration = _animationCycle(tTime, repeatDelay); tween._yoyo && iteration & 1 && (ratio = 1 - ratio); if (iteration !== _animationCycle(tween._tTime, repeatDelay)) { // if iteration changed prevRatio = 1 - ratio; tween.vars.repeatRefresh && tween._initted && tween.invalidate(); } } if (ratio !== prevRatio || _reverting || force || tween._zTime === _tinyNum || !totalTime && tween._zTime) { if (!tween._initted && _attemptInitTween(tween, totalTime, force, suppressEvents, tTime)) { // 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. return; } prevIteration = tween._zTime; tween._zTime = totalTime || (suppressEvents ? _tinyNum : 0); // 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. suppressEvents || (suppressEvents = totalTime && !prevIteration); // if it was rendered previously at exactly 0 (_zTime) and now the playhead is moving away, DON'T fire callbacks otherwise they'll seem like duplicates. tween.ratio = ratio; tween._from && (ratio = 1 - ratio); tween._time = 0; tween._tTime = tTime; pt = tween._pt; while (pt) { pt.r(ratio, pt.d); pt = pt._next; } totalTime < 0 && _rewindStartAt(tween, totalTime, suppressEvents, true); tween._onUpdate && !suppressEvents && _callback(tween, "onUpdate"); tTime && tween._repeat && !suppressEvents && tween.parent && _callback(tween, "onRepeat"); if ((totalTime >= tween._tDur || totalTime < 0) && tween.ratio === ratio) { ratio && _removeFromParent(tween, 1); if (!suppressEvents && !_reverting) { _callback(tween, ratio ? "onComplete" : "onReverseComplete", true); tween._prom && tween._prom(); } } } else if (!tween._zTime) { tween._zTime = totalTime; } }, _findNextPauseTween = function _findNextPauseTween(animation, prevTime, time) { var child; if (time > prevTime) { child = animation._first; while (child && child._start <= time) { if (child.data === "isPause" && child._start > prevTime) { return child; } child = child._next; } } else { child = animation._last; while (child && child._start >= time) { if (child.data === "isPause" && child._start < prevTime) { return child; } child = child._prev; } } }, _setDuration = function _setDuration(animation, duration, skipUncache, leavePlayhead) { var repeat = animation._repeat, dur = _roundPrecise(duration) || 0, totalProgress = animation._tTime / animation._tDur; totalProgress && !leavePlayhead && (animation._time *= dur / animation._dur); animation._dur = dur; animation._tDur = !repeat ? dur : repeat < 0 ? 1e10 : _roundPrecise(dur * (repeat + 1) + animation._rDelay * repeat); totalProgress > 0 && !leavePlayhead && _alignPlayhead(animation, animation._tTime = animation._tDur * totalProgress); animation.parent && _setEnd(animation); skipUncache || _uncache(animation.parent, animation); return animation; }, _onUpdateTotalDuration = function _onUpdateTotalDuration(animation) { return animation instanceof Timeline ? _uncache(animation) : _setDuration(animation, animation._dur); }, _zeroPosition = { _start: 0, endTime: _emptyFunc, totalDuration: _emptyFunc }, _parsePosition = function _parsePosition(animation, position, percentAnimation) { var labels = animation.labels, recent = animation._recent || _zeroPosition, clippedDuration = animation.duration() >= _bigNum ? recent.endTime(false) : animation._dur, //in case there's a child that infinitely repeats, users almost never intend for the insertion point of a new child to be based on a SUPER long value like that so we clip it and assume the most recently-added child's endTime should be used instead. i, offset, isPercent; if (_isString(position) && (isNaN(position) || position in labels)) { //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). offset = position.charAt(0); isPercent = position.substr(-1) === "%"; i = position.indexOf("="); if (offset === "<" || offset === ">") { i >= 0 && (position = position.replace(/=/, "")); return (offset === "<" ? recent._start : recent.endTime(recent._repeat >= 0)) + (parseFloat(position.substr(1)) || 0) * (isPercent ? (i < 0 ? recent : percentAnimation).totalDuration() / 100 : 1); } if (i < 0) { position in labels || (labels[position] = clippedDuration); return labels[position]; } offset = parseFloat(position.charAt(i - 1) + position.substr(i + 1)); if (isPercent && percentAnimation) { offset = offset / 100 * (_isArray(percentAnimation) ? percentAnimation[0] : percentAnimation).totalDuration(); } return i > 1 ? _parsePosition(animation, position.substr(0, i - 1), percentAnimation) + offset : clippedDuration + offset; } return position == null ? clippedDuration : +position; }, _createTweenType = function _createTweenType(type, params, timeline) { var isLegacy = _isNumber(params[1]), varsIndex = (isLegacy ? 2 : 1) + (type < 2 ? 0 : 1), vars = params[varsIndex], irVars, parent; isLegacy && (vars.duration = params[1]); vars.parent = timeline; if (type) { irVars = vars; parent = timeline; while (parent && !("immediateRender" in irVars)) { // inheritance hasn't happened yet, but someone may have set a default in an ancestor timeline. We could do vars.immediateRender = _isNotFalse(_inheritDefaults(vars).immediateRender) but that'd exact a slight performance penalty because _inheritDefaults() also runs in the Tween constructor. We're paying a small kb price here to gain speed. irVars = parent.vars.defaults || {}; parent = _isNotFalse(parent.vars.inherit) && parent.parent; } vars.immediateRender = _isNotFalse(irVars.immediateRender); type < 2 ? vars.runBackwards = 1 : vars.startAt = params[varsIndex - 1]; // "from" vars } return new Tween(params[0], vars, params[varsIndex + 1]); }, _conditionalReturn = function _conditionalReturn(value, func) { return value || value === 0 ? func(value) : func; }, _clamp = function _clamp(min, max, value) { return value < min ? min : value > max ? max : value; }, getUnit = function getUnit(value, v) { return !_isString(value) || !(v = _unitExp.exec(value)) ? "" : v[1]; }, // note: protect against padded numbers as strings, like "100.100". That shouldn't return "00" as the unit. If it's numeric, return no unit. clamp = function clamp(min, max, value) { return _conditionalReturn(value, function (v) { return _clamp(min, max, v); }); }, _slice = [].slice, _isArrayLike = function _isArrayLike(value, nonEmpty) { return value && _isObject(value) && "length" in value && (!nonEmpty && !value.length || value.length - 1 in value && _isObject(value[0])) && !value.nodeType && value !== _win; }, _flatten = function _flatten(ar, leaveStrings, accumulator) { if (accumulator === void 0) { accumulator = []; } return ar.forEach(function (value) { var _accumulator; return _isString(value) && !leaveStrings || _isArrayLike(value, 1) ? (_accumulator = accumulator).push.apply(_accumulator, toArray(value)) : accumulator.push(value); }) || accumulator; }, //takes any value and returns an array. If it's a string (and leaveStrings isn't true), it'll use document.querySelectorAll() and convert that to an array. It'll also accept iterables like jQuery objects. toArray = function toArray(value, scope, leaveStrings) { return _context && !scope && _context.selector ? _context.selector(value) : _isString(value) && !leaveStrings && (_coreInitted || !_wake()) ? _slice.call((scope || _doc).querySelectorAll(value), 0) : _isArray(value) ? _flatten(value, leaveStrings) : _isArrayLike(value) ? _slice.call(value, 0) : value ? [value] : []; }, selector = function selector(value) { value = toArray(value)[0] || _warn("Invalid scope") || {}; return function (v) { var el = value.current || value.nativeElement || value; return toArray(v, el.querySelectorAll ? el : el === value ? _warn("Invalid scope") || _doc.createElement("div") : value); }; }, shuffle = function shuffle(a) { return a.sort(function () { return .5 - Math.random(); }); }, // alternative that's a bit faster and more reliably diverse but bigger: for (let j, v, i = a.length; i; j = (Math.random() * i) | 0, v = a[--i], a[i] = a[j], a[j] = v); return a; //for distributing values across an array. Can accept a number, a function or (most commonly) a function which can contain the following properties: {base, amount, from, ease, grid, axis, length, each}. Returns a function that expects the following parameters: index, target, array. Recognizes the following distribute = function distribute(v) { if (_isFunction(v)) { return v; } var vars = _isObject(v) ? v : { each: v }, //n:1 is just to indicate v was a number; we leverage that later to set v according to the length we get. If a number is passed in, we treat it like the old stagger value where 0.1, for example, would mean that things would be distributed with 0.1 between each element in the array rather than a total "amount" that's chunked out among them all. ease = _parseEase(vars.ease), from = vars.from || 0, base = parseFloat(vars.base) || 0, cache = {}, isDecimal = from > 0 && from < 1, ratios = isNaN(from) || isDecimal, axis = vars.axis, ratioX = from, ratioY = from; if (_isString(from)) { ratioX = ratioY = { center: .5, edges: .5, end: 1 }[from] || 0; } else if (!isDecimal && ratios) { ratioX = from[0]; ratioY = from[1]; } return function (i, target, a) { var l = (a || vars).length, distances = cache[l], originX, originY, x, y, d, j, max, min, wrapAt; if (!distances) { wrapAt = vars.grid === "auto" ? 0 : (vars.grid || [1, _bigNum])[1]; if (!wrapAt) { max = -_bigNum; while (max < (max = a[wrapAt++].getBoundingClientRect().left) && wrapAt < l) {} wrapAt < l && wrapAt--; } distances = cache[l] = []; originX = ratios ? Math.min(wrapAt, l) * ratioX - .5 : from % wrapAt; originY = wrapAt === _bigNum ? 0 : ratios ? l * ratioY / wrapAt - .5 : from / wrapAt | 0; max = 0; min = _bigNum; for (j = 0; j < l; j++) { x = j % wrapAt - originX; y = originY - (j / wrapAt | 0); distances[j] = d = !axis ? _sqrt(x * x + y * y) : Math.abs(axis === "y" ? y : x); d > max && (max = d); d < min && (min = d); } from === "random" && shuffle(distances); distances.max = max - min; distances.min = min; distances.v = l = (parseFloat(vars.amount) || parseFloat(vars.each) * (wrapAt > l ? l - 1 : !axis ? Math.max(wrapAt, l / wrapAt) : axis === "y" ? l / wrapAt : wrapAt) || 0) * (from === "edges" ? -1 : 1); distances.b = l < 0 ? base - l : base; distances.u = getUnit(vars.amount || vars.each) || 0; //unit ease = ease && l < 0 ? _invertEase(ease) : ease; } l = (distances[i] - distances.min) / distances.max || 0; return _roundPrecise(distances.b + (ease ? ease(l) : l) * distances.v) + distances.u; //round in order to work around floating point errors }; }, _roundModifier = function _roundModifier(v) { //pass in 0.1 get a function that'll round to the nearest tenth, or 5 to round to the closest 5, or 0.001 to the closest 1000th, etc. var p = Math.pow(10, ((v + "").split(".")[1] || "").length); //to avoid floating point math errors (like 24 * 0.1 == 2.4000000000000004), we chop off at a specific number of decimal places (much faster than toFixed()) return function (raw) { var n = _roundPrecise(Math.round(parseFloat(raw) / v) * v * p); return (n - n % 1) / p + (_isNumber(raw) ? 0 : getUnit(raw)); // n - n % 1 replaces Math.floor() in order to handle negative values properly. For example, Math.floor(-150.00000000000003) is 151! }; }, snap = function snap(snapTo, value) { var isArray = _isArray(snapTo), radius, is2D; if (!isArray && _isObject(snapTo)) { radius = isArray = snapTo.radius || _bigNum; if (snapTo.values) { snapTo = toArray(snapTo.values); if (is2D = !_isNumber(snapTo[0])) { radius *= radius; //performance optimization so we don't have to Math.sqrt() in the loop. } } else { snapTo = _roundModifier(snapTo.increment); } } return _conditionalReturn(value, !isArray ? _roundModifier(snapTo) : _isFunction(snapTo) ? function (raw) { is2D = snapTo(raw); return Math.abs(is2D - raw) <= radius ? is2D : raw; } : function (raw) { var x = parseFloat(is2D ? raw.x : raw), y = parseFloat(is2D ? raw.y : 0), min = _bigNum, closest = 0, i = snapTo.length, dx, dy; while (i--) { if (is2D) { dx = snapTo[i].x - x; dy = snapTo[i].y - y; dx = dx * dx + dy * dy; } else { dx = Math.abs(snapTo[i] - x); } if (dx < min) { min = dx; closest = i; } } closest = !radius || min <= radius ? snapTo[closest] : raw; return is2D || closest === raw || _isNumber(raw) ? closest : closest + getUnit(raw); }); }, random = function random(min, max, roundingIncrement, returnFunction) { return _conditionalReturn(_isArray(min) ? !max : roundingIncrement === true ? !!(roundingIncrement = 0) : !returnFunction, function () { return _isArray(min) ? min[~~(Math.random() * min.length)] : (roundingIncrement = roundingIncrement || 1e-5) && (returnFunction = roundingIncrement < 1 ? Math.pow(10, (roundingIncrement + "").length - 2) : 1) && Math.floor(Math.round((min - roundingIncrement / 2 + Math.random() * (max - min + roundingIncrement * .99)) / roundingIncrement) * roundingIncrement * returnFunction) / returnFunction; }); }, pipe = function pipe() { for (var _len = arguments.length, functions = new Array(_len), _key = 0; _key < _len; _key++) { functions[_key] = arguments[_key]; } return function (value) { return functions.reduce(function (v, f) { return f(v); }, value); }; }, unitize = function unitize(func, unit) { return function (value) { return func(parseFloat(value)) + (unit || getUnit(value)); }; }, normalize = function normalize(min, max, value) { return mapRange(min, max, 0, 1, value); }, _wrapArray = function _wrapArray(a, wrapper, value) { return _conditionalReturn(value, function (index) { return a[~~wrapper(index)]; }); }, wrap = function wrap(min, max, value) { // NOTE: wrap() CANNOT be an arrow function! A very odd compiling bug causes problems (unrelated to GSAP). var range = max - min; return _isArray(min) ? _wrapArray(min, wrap(0, min.length), max) : _conditionalReturn(value, function (value) { return (range + (value - min) % range) % range + min; }); }, wrapYoyo = function wrapYoyo(min, max, value) { var range = max - min, total = range * 2; return _isArray(min) ? _wrapArray(min, wrapYoyo(0, min.length - 1), max) : _conditionalReturn(value, function (value) { value = (total + (value - min) % total) % total || 0; return min + (value > range ? total - value : value); }); }, _replaceRandom = function _replaceRandom(value) { //replaces all occurrences of random(...) in a string with the calculated random value. can be a range like random(-100, 100, 5) or an array like random([0, 100, 500]) var prev = 0, s = "", i, nums, end, isArray; while (~(i = value.indexOf("random(", prev))) { end = value.indexOf(")", i); isArray = value.charAt(i + 7) === "["; nums = value.substr(i + 7, end - i - 7).match(isArray ? _delimitedValueExp : _strictNumExp); s += value.substr(prev, i - prev) + random(isArray ? nums : +nums[0], isArray ? 0 : +nums[1], +nums[2] || 1e-5); prev = end + 1; } return s + value.substr(prev, value.length - prev); }, mapRange = function mapRange(inMin, inMax, outMin, outMax, value) { var inRange = inMax - inMin, outRange = outMax - outMin; return _conditionalReturn(value, function (value) { return outMin + ((value - inMin) / inRange * outRange || 0); }); }, interpolate = function interpolate(start, end, progress, mutate) { var func = isNaN(start + end) ? 0 : function (p) { return (1 - p) * start + p * end; }; if (!func) { var isString = _isString(start), master = {}, p, i, interpolators, l, il; progress === true && (mutate = 1) && (progress = null); if (isString) { start = { p: start }; end = { p: end }; } else if (_isArray(start) && !_isArray(end)) { interpolators = []; l = start.length; il = l - 2; for (i = 1; i < l; i++) { interpolators.push(interpolate(start[i - 1], start[i])); //build the interpolators up front as a performance optimization so that when the function is called many times, it can just reuse them. } l--; func = function func(p) { p *= l; var i = Math.min(il, ~~p); return interpolators[i](p - i); }; progress = end; } else if (!mutate) { start = _merge(_isArray(start) ? [] : {}, start); } if (!interpolators) { for (p in end) { _addPropTween.call(master, start, p, "get", end[p]); } func = function func(p) { return _renderPropTweens(p, master) || (isString ? start.p : start); }; } } return _conditionalReturn(progress, func); }, _getLabelInDirection = function _getLabelInDirection(timeline, fromTime, backward) { //used for nextLabel() and previousLabel() var labels = timeline.labels, min = _bigNum, p, distance, label; for (p in labels) { distance = labels[p] - fromTime; if (distance < 0 === !!backward && distance && min > (distance = Math.abs(distance))) { label = p; min = distance; } } return label; }, _callback = function _callback(animation, type, executeLazyFirst) { var v = animation.vars, callback = v[type], prevContext = _context, context = animation._ctx, params, scope, result; if (!callback) { return; } params = v[type + "Params"]; scope = v.callbackScope || animation; executeLazyFirst && _lazyTweens.length && _lazyRender(); //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. context && (_context = context); result = params ? callback.apply(scope, params) : callback.call(scope); _context = prevContext; return result; }, _interrupt = function _interrupt(animation) { _removeFromParent(animation); animation.scrollTrigger && animation.scrollTrigger.kill(!!_reverting); animation.progress() < 1 && _callback(animation, "onInterrupt"); return animation; }, _quickTween, _registerPluginQueue = [], _createPlugin = function _createPlugin(config) { if (!config) return; config = !config.name && config["default"] || config; // UMD packaging wraps things oddly, so for example MotionPathHelper becomes {MotionPathHelper:MotionPathHelper, default:MotionPathHelper}. if (_windowExists() || config.headless) { // edge case: some build tools may pass in a null/undefined value var name = config.name, isFunc = _isFunction(config), Plugin = name && !isFunc && config.init ? function () { this._props = []; } : config, //in case someone passes in an object that's not a plugin, like CustomEase instanceDefaults = { init: _emptyFunc, render: _renderPropTweens, add: _addPropTween, kill: _killPropTweensOf, modifier: _addPluginModifier, rawVars: 0 }, statics = { targetTest: 0, get: 0, getSetter: _getSetter, aliases: {}, register: 0 }; _wake(); if (config !== Plugin) { if (_plugins[name]) { return; } _setDefaults(Plugin, _setDefaults(_copyExcluding(config, instanceDefaults), statics)); //static methods _merge(Plugin.prototype, _merge(instanceDefaults, _copyExcluding(config, statics))); //instance methods _plugins[Plugin.prop = name] = Plugin; if (config.targetTest) { _harnessPlugins.push(Plugin); _reservedProps[name] = 1; } name = (name === "css" ? "CSS" : name.charAt(0).toUpperCase() + name.substr(1)) + "Plugin"; //for the global name. "motionPath" should become MotionPathPlugin } _addGlobal(name, Plugin); config.register && config.register(gsap, Plugin, PropTween); } else { _registerPluginQueue.push(config); } }, /* * -------------------------------------------------------------------------------------- * COLORS * -------------------------------------------------------------------------------------- */ _255 = 255, _colorLookup = { aqua: [0, _255, _255], lime: [0, _255, 0], silver: [192, 192, 192], black: [0, 0, 0], maroon: [128, 0, 0], teal: [0, 128, 128], blue: [0, 0, _255], navy: [0, 0, 128], white: [_255, _255, _255], olive: [128, 128, 0], yellow: [_255, _255, 0], orange: [_255, 165, 0], gray: [128, 128, 128], purple: [128, 0, 128], green: [0, 128, 0], red: [_255, 0, 0], pink: [_255, 192, 203], cyan: [0, _255, _255], transparent: [_255, _255, _255, 0] }, // possible future idea to replace the hard-coded color name values - put this in the ticker.wake() where we set the _doc: // let ctx = _doc.createElement("canvas").getContext("2d"); // _forEachName("aqua,lime,silver,black,maroon,teal,blue,navy,white,olive,yellow,orange,gray,purple,green,red,pink,cyan", color => {ctx.fillStyle = color; _colorLookup[color] = splitColor(ctx.fillStyle)}); _hue = function _hue(h, m1, m2) { h += h < 0 ? 1 : h > 1 ? -1 : 0; return (h * 6 < 1 ? m1 + (m2 - m1) * h * 6 : h < .5 ? m2 : h * 3 < 2 ? m1 + (m2 - m1) * (2 / 3 - h) * 6 : m1) * _255 + .5 | 0; }, splitColor = function splitColor(v, toHSL, forceAlpha) { var a = !v ? _colorLookup.black : _isNumber(v) ? [v >> 16, v >> 8 & _255, v & _255] : 0, r, g, b, h, s, l, max, min, d, wasHSL; if (!a) { if (v.substr(-1) === ",") { //sometimes a trailing comma is included and we should chop it off (typically from a comma-delimited list of values like a textShadow:"2px 2px 2px blue, 5px 5px 5px rgb(255,0,0)" - in this example "blue," has a trailing comma. We could strip it out inside parseComplex() but we'd need to do it to the beginning and ending values plus it wouldn't provide protection from other potential scenarios like if the user passes in a similar value. v = v.substr(0, v.length - 1); } if (_colorLookup[v]) { a = _colorLookup[v]; } else if (v.charAt(0) === "#") { if (v.length < 6) { //for shorthand like #9F0 or #9F0F (could have alpha) r = v.charAt(1); g = v.charAt(2); b = v.charAt(3); v = "#" + r + r + g + g + b + b + (v.length === 5 ? v.charAt(4) + v.charAt(4) : ""); } if (v.length === 9) { // hex with alpha, like #fd5e53ff a = parseInt(v.substr(1, 6), 16); return [a >> 16, a >> 8 & _255, a & _255, parseInt(v.substr(7), 16) / 255]; } v = parseInt(v.substr(1), 16); a = [v >> 16, v >> 8 & _255, v & _255]; } else if (v.substr(0, 3) === "hsl") { a = wasHSL = v.match(_strictNumExp); if (!toHSL) { h = +a[0] % 360 / 360; s = +a[1] / 100; l = +a[2] / 100; g = l <= .5 ? l * (s + 1) : l + s - l * s; r = l * 2 - g; a.length > 3 && (a[3] *= 1); //cast as number a[0] = _hue(h + 1 / 3, r, g); a[1] = _hue(h, r, g); a[2] = _hue(h - 1 / 3, r, g); } else if (~v.indexOf("=")) { //if relative values are found, just return the raw strings with the relative prefixes in place. a = v.match(_numExp); forceAlpha && a.length < 4 && (a[3] = 1); return a; } } else { a = v.match(_strictNumExp) || _colorLookup.transparent; } a = a.map(Number); } if (toHSL && !wasHSL) { r = a[0] / _255; g = a[1] / _255; b = a[2] / _255; max = Math.max(r, g, b); min = Math.min(r, g, b); l = (max + min) / 2; if (max === min) { h = s = 0; } else { d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); h = max === r ? (g - b) / d + (g < b ? 6 : 0) : max === g ? (b - r) / d + 2 : (r - g) / d + 4; h *= 60; } a[0] = ~~(h + .5); a[1] = ~~(s * 100 + .5); a[2] = ~~(l * 100 + .5); } forceAlpha && a.length < 4 && (a[3] = 1); return a; }, _colorOrderData = function _colorOrderData(v) { // strips out the colors from the string, finds all the numeric slots (with units) and returns an array of those. The Array also has a "c" property which is an Array of the index values where the colors belong. This is to help work around issues where there's a mis-matched order of color/numeric data like drop-shadow(#f00 0px 1px 2px) and drop-shadow(0x 1px 2px #f00). This is basically a helper function used in _formatColors() var values = [], c = [], i = -1; v.split(_colorExp).forEach(function (v) { var a = v.match(_numWithUnitExp) || []; values.push.apply(values, a); c.push(i += a.length + 1); }); values.c = c; return values; }, _formatColors = function _formatColors(s, toHSL, orderMatchData) { var result = "", colors = (s + result).match(_colorExp), type = toHSL ? "hsla(" : "rgba(", i = 0, c, shell, d, l; if (!colors) { return s; } colors = colors.map(function (color) { return (color = splitColor(color, toHSL, 1)) && type + (toHSL ? color[0] + "," + color[1] + "%," + color[2] + "%," + color[3] : color.join(",")) + ")"; }); if (orderMatchData) { d = _colorOrderData(s); c = orderMatchData.c; if (c.join(result) !== d.c.join(result)) { shell = s.replace(_colorExp, "1").split(_numWithUnitExp); l = shell.length - 1; for (; i < l; i++) { result += shell[i] + (~c.indexOf(i) ? colors.shift() || type + "0,0,0,0)" : (d.length ? d : colors.length ? colors : orderMatchData).shift()); } } } if (!shell) { shell = s.split(_colorExp); l = shell.length - 1; for (; i < l; i++) { result += shell[i] + colors[i]; } } return result + shell[l]; }, _colorExp = function () { var s = "(?:\\b(?:(?:rgb|rgba|hsl|hsla)\\(.+?\\))|\\B#(?:[0-9a-f]{3,4}){1,2}\\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., p; for (p in _colorLookup) { s += "|" + p + "\\b"; } return new RegExp(s + ")", "gi"); }(), _hslExp = /hsl[a]?\(/, _colorStringFilter = function _colorStringFilter(a) { var combined = a.join(" "), toHSL; _colorExp.lastIndex = 0; if (_colorExp.test(combined)) { toHSL = _hslExp.test(combined); a[1] = _formatColors(a[1], toHSL); a[0] = _formatColors(a[0], toHSL, _colorOrderData(a[1])); // make sure the order of numbers/colors match with the END value. return true; } }, /* * -------------------------------------------------------------------------------------- * TICKER * -------------------------------------------------------------------------------------- */ _tickerActive, _ticker = function () { var _getTime = Date.now, _lagThreshold = 500, _adjustedLag = 33, _startTime = _getTime(), _lastUpdate = _startTime, _gap = 1000 / 240, _nextTime = _gap, _listeners = [], _id, _req, _raf, _self, _delta, _i, _tick = function _tick(v) { var elapsed = _getTime() - _lastUpdate, manual = v === true, overlap, dispatch, time, frame; (elapsed > _lagThreshold || elapsed < 0) && (_startTime += elapsed - _adjustedLag); _lastUpdate += elapsed; time = _lastUpdate - _startTime; overlap = time - _nextTime; if (overlap > 0 || manual) { frame = ++_self.frame; _delta = time - _self.time * 1000; _self.time = time = time / 1000; _nextTime += overlap + (overlap >= _gap ? 4 : _gap - overlap); dispatch = 1; } manual || (_id = _req(_tick)); //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. if (dispatch) { for (_i = 0; _i < _listeners.length; _i++) { // use _i and check _listeners.length instead of a variable because a listener could get