Added mousewheel support for PixiJS Lists.

This commit is contained in:
2019-03-29 11:40:01 +01:00
parent 6c2ae3b433
commit 1292fd23f0
116 changed files with 55687 additions and 6 deletions
@@ -0,0 +1,152 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-08-27
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, 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
**/
/* eslint-disable */
import { _gsScope, globals } from "gsap/TweenLite.js";
import CustomEase from "./CustomEase.js";
_gsScope._gsDefine("easing.CustomBounce", ["easing.CustomEase"], function() {
var _normalizeX = function (a) { //scales all the x values in an array [x, y, x, y...] AND rounds them to the closest hundredth (decimal)
var l = a.length,
s = 1 / a[l - 2],
rnd = 1000,
i;
for (i = 2; i < l; i += 2) {
a[i] = ((a[i] * s * rnd) | 0) / rnd;
}
a[l - 2] = 1; //in case there are any rounding errors. x should always end at 1.
},
CustomBounce = function(id, vars) {
this.vars = vars = vars || {};
if (vars.squash) {
this.squash = new CustomEase(vars.squashID || (id + "-squash"));
}
CustomEase.call(this, id);
this.bounce = this;
this.update(vars);
},
p;
CustomBounce.prototype = p = new CustomEase();
p.constructor = CustomBounce;
p.update = function(vars) {
vars = vars || this.vars;
var max = 0.999,
decay = Math.min(max, vars.strength || 0.7), // Math.min(0.999, 1 - 0.3 / (vars.strength || 1)),
decayX = decay,
gap = (vars.squash || 0) / 100,
originalGap = gap,
slope = 1 / 0.03,
w = 0.2,
h = 1,
prevX = 0.1,
path = [0, 0, 0.07, 0, 0.1, 1, 0.1, 1],
squashPath = [0, 0, 0, 0, 0.1, 0, 0.1, 0],
cp1, cp2, x, y, i, nextX, squishMagnitude;
for (i = 0; i < 200; i++) {
w *= decayX * ((decayX + 1) / 2);
h *= decay * decay;
nextX = prevX + w;
x = prevX + w * 0.49;
y = 1 - h;
cp1 = prevX + h / slope;
cp2 = x + (x - cp1) * 0.8;
if (gap) {
prevX += gap;
cp1 += gap;
x += gap;
cp2 += gap;
nextX += gap;
squishMagnitude = gap / originalGap;
squashPath.push(
prevX - gap, 0,
prevX - gap, squishMagnitude,
prevX - gap / 2, squishMagnitude, //center peak anchor
prevX, squishMagnitude,
prevX, 0,
prevX, 0, //base anchor
prevX, squishMagnitude * -0.6,
prevX + (nextX - prevX) / 6, 0,
nextX, 0
);
path.push(prevX - gap, 1,
prevX, 1,
prevX, 1);
gap *= decay * decay;
}
path.push(prevX, 1,
cp1, y,
x, y,
cp2, y,
nextX, 1,
nextX, 1);
decay *= 0.95;
slope = h / (nextX - cp2);
prevX = nextX;
if (y > max) {
break;
}
}
if (vars.endAtStart) {
x = -0.1;
path.unshift(x, 1, x, 1, -0.07, 0);
if (originalGap) {
gap = originalGap * 2.5; //make the initial anticipation squash longer (more realistic)
x -= gap;
path.unshift(x, 1, x, 1, x, 1);
squashPath.splice(0, 6);
squashPath.unshift(x, 0, x, 0, x, 1, x + gap / 2, 1, x + gap, 1, x + gap, 0, x + gap, 0, x + gap, -0.6, x + gap + 0.033, 0);
for (i = 0; i < squashPath.length; i+=2) {
squashPath[i] -= x;
}
}
for (i = 0; i < path.length; i+=2) {
path[i] -= x;
path[i+1] = 1 - path[i+1];
}
}
if (gap) {
_normalizeX(squashPath);
squashPath[2] = "C" + squashPath[2];
if (!this.squash) {
this.squash = new CustomEase(vars.squashID || (this.id + "-squash"));
}
this.squash.setData("M" + squashPath.join(","));
}
_normalizeX(path);
path[2] = "C" + path[2];
return this.setData("M" + path.join(","));
};
CustomBounce.create = function(id, vars) {
return new CustomBounce(id, vars);
};
CustomBounce.version = "0.2.1";
return CustomBounce;
}, true);
export var CustomBounce = globals.CustomBounce;
export { CustomBounce as default };
@@ -0,0 +1,379 @@
/*!
* VERSION: 0.2.2
* DATE: 2018-08-27
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, 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
**/
/* eslint-disable */
import { _gsScope, globals, Ease } from "gsap/TweenLite.js";
_gsScope._gsDefine("easing.CustomEase", ["easing.Ease"], function() {
var _numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_svgPathExp = /[achlmqstvz]|(-?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_scientific = /[\+\-]?\d*\.?\d+e[\+\-]?\d+/ig,
_needsParsingExp = /[cLlsS]/g,
_bezierError = "CustomEase only accepts Cubic Bezier data.",
_bezierToPoints = function (x1, y1, x2, y2, x3, y3, x4, y4, threshold, points, index) {
var x12 = (x1 + x2) / 2,
y12 = (y1 + y2) / 2,
x23 = (x2 + x3) / 2,
y23 = (y2 + y3) / 2,
x34 = (x3 + x4) / 2,
y34 = (y3 + y4) / 2,
x123 = (x12 + x23) / 2,
y123 = (y12 + y23) / 2,
x234 = (x23 + x34) / 2,
y234 = (y23 + y34) / 2,
x1234 = (x123 + x234) / 2,
y1234 = (y123 + y234) / 2,
dx = x4 - x1,
dy = y4 - y1,
d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx),
d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx),
length;
if (!points) {
points = [{x: x1, y: y1}, {x: x4, y: y4}];
index = 1;
}
points.splice(index || points.length - 1, 0, {x: x1234, y: y1234});
if ((d2 + d3) * (d2 + d3) > threshold * (dx * dx + dy * dy)) {
length = points.length;
_bezierToPoints(x1, y1, x12, y12, x123, y123, x1234, y1234, threshold, points, index);
_bezierToPoints(x1234, y1234, x234, y234, x34, y34, x4, y4, threshold, points, index + 1 + (points.length - length));
}
return points;
},
_pathDataToBezier = function (d) {
var a = (d + "").replace(_scientific, function (m) {
var n = +m;
return (n < 0.0001 && n > -0.0001) ? 0 : n;
}).match(_svgPathExp) || [], //some authoring programs spit out very small numbers in scientific notation like "1e-5", so make sure we round that down to 0 first.
path = [],
relativeX = 0,
relativeY = 0,
elements = a.length,
l = 2,
i, x, y, command, isRelative, segment, startX, startY, prevCommand, difX, difY;
for (i = 0; i < elements; i++) {
prevCommand = command;
if (isNaN(a[i])) {
command = a[i].toUpperCase();
isRelative = (command !== a[i]); //lower case means relative
} else { //commands like "C" can be strung together without any new command characters between.
i--;
}
x = +a[i + 1];
y = +a[i + 2];
if (isRelative) {
x += relativeX;
y += relativeY;
}
if (!i) {
startX = x;
startY = y;
}
if (command === "M") {
if (segment && segment.length < 8) { //if the path data was funky and just had a M with no actual drawing anywhere, skip it.
path.length -= 1;
l = 0;
}
relativeX = startX = x;
relativeY = startY = y;
segment = [x, y];
l = 2;
path.push(segment);
i += 2;
command = "L"; //an "M" with more than 2 values gets interpreted as "lineTo" commands ("L").
} else if (command === "C") {
if (!segment) {
segment = [0, 0];
}
segment[l++] = x;
segment[l++] = y;
if (!isRelative) {
relativeX = relativeY = 0;
}
segment[l++] = relativeX + a[i + 3] * 1; //note: "*1" is just a fast/short way to cast the value as a Number. WAAAY faster in Chrome, slightly slower in Firefox.
segment[l++] = relativeY + a[i + 4] * 1;
segment[l++] = relativeX = relativeX + a[i + 5] * 1;
segment[l++] = relativeY = relativeY + a[i + 6] * 1;
i += 6;
} else if (command === "S") {
if (prevCommand === "C" || prevCommand === "S") {
difX = relativeX - segment[l - 4];
difY = relativeY - segment[l - 3];
segment[l++] = relativeX + difX;
segment[l++] = relativeY + difY;
} else {
segment[l++] = relativeX;
segment[l++] = relativeY;
}
segment[l++] = x;
segment[l++] = y;
if (!isRelative) {
relativeX = relativeY = 0;
}
segment[l++] = relativeX = relativeX + a[i + 3] * 1;
segment[l++] = relativeY = relativeY + a[i + 4] * 1;
i += 4;
} else if (command === "L" || command === "Z") {
if (command === "Z") {
x = startX;
y = startY;
segment.closed = true;
}
if (command === "L" || Math.abs(relativeX - x) > 0.5 || Math.abs(relativeY - y) > 0.5) {
segment[l++] = relativeX + (x - relativeX) / 3;
segment[l++] = relativeY + (y - relativeY) / 3;
segment[l++] = relativeX + (x - relativeX) * 2 / 3;
segment[l++] = relativeY + (y - relativeY) * 2 / 3;
segment[l++] = x;
segment[l++] = y;
if (command === "L") {
i += 2;
}
}
relativeX = x;
relativeY = y;
} else {
throw _bezierError;
}
}
return path[0];
},
_findMinimum = function (values) {
var l = values.length,
min = 999999999999,
i;
for (i = 1; i < l; i += 6) {
if (+values[i] < min) {
min = +values[i];
}
}
return min;
},
_normalize = function (values, height, originY) { //takes all the points and translates/scales them so that the x starts at 0 and ends at 1.
if (!originY && originY !== 0) {
originY = Math.max(+values[values.length-1], +values[1]);
}
var tx = +values[0] * -1,
ty = -originY,
l = values.length,
sx = 1 / (+values[l - 2] + tx),
sy = -height || ((Math.abs(+values[l - 1] - +values[1]) < 0.01 * (+values[l - 2] - +values[0])) ? _findMinimum(values) + ty : +values[l - 1] + ty),
i;
if (sy) { //typically y ends at 1 (so that the end values are reached)
sy = 1 / sy;
} else { //in case the ease returns to its beginning value, scale everything proportionally
sy = -sx;
}
for (i = 0; i < l; i += 2) {
values[i] = (+values[i] + tx) * sx;
values[i + 1] = (+values[i + 1] + ty) * sy;
}
},
_getRatio = function (p) {
var point = this.lookup[(p * this.l) | 0] || this.lookup[this.l - 1];
if (point.nx < p) {
point = point.n;
}
return point.y + ((p - point.x) / point.cx) * point.cy;
},
CustomEase = function (id, data, config) {
this._calcEnd = true;
this.id = id;
if (id) {
Ease.map[id] = this;
}
this.getRatio = _getRatio; //speed optimization, faster lookups.
this.setData(data, config);
},
p = CustomEase.prototype = new Ease();
p.constructor = CustomEase;
p.setData = function(data, config) {
data = data || "0,0,1,1";
var values = data.match(_numbersExp),
closest = 1,
points = [],
l, a1, a2, i, inc, j, point, prevPoint, p, precision;
config = config || {};
precision = config.precision || 1;
this.data = data;
this.lookup = [];
this.points = points;
this.fast = (precision <= 1);
if (_needsParsingExp.test(data) || (data.indexOf("M") !== -1 && data.indexOf("C") === -1)) {
values = _pathDataToBezier(data);
}
l = values.length;
if (l === 4) {
values.unshift(0, 0);
values.push(1, 1);
l = 8;
} else if ((l - 2) % 6) {
throw _bezierError;
}
if (+values[0] !== 0 || +values[l - 2] !== 1) {
_normalize(values, config.height, config.originY);
}
this.rawBezier = values;
for (i = 2; i < l; i += 6) {
a1 = {x: +values[i - 2], y: +values[i - 1]};
a2 = {x: +values[i + 4], y: +values[i + 5]};
points.push(a1, a2);
_bezierToPoints(a1.x, a1.y, +values[i], +values[i + 1], +values[i + 2], +values[i + 3], a2.x, a2.y, 1 / (precision * 200000), points, points.length - 1);
}
l = points.length;
for (i = 0; i < l; i++) {
point = points[i];
prevPoint = points[i - 1] || point;
if (point.x > prevPoint.x || (prevPoint.y !== point.y && prevPoint.x === point.x) || point === prevPoint) { //if a point goes BACKWARD in time or is a duplicate, just drop it.
prevPoint.cx = point.x - prevPoint.x; //change in x between this point and the next point (performance optimization)
prevPoint.cy = point.y - prevPoint.y;
prevPoint.n = point;
prevPoint.nx = point.x; //next point's x value (performance optimization, making lookups faster in getRatio()). Remember, the lookup will always land on a spot where it's either this point or the very next one (never beyond that)
if (this.fast && i > 1 && Math.abs(prevPoint.cy / prevPoint.cx - points[i - 2].cy / points[i - 2].cx) > 2) { //if there's a sudden change in direction, prioritize accuracy over speed. Like a bounce ease - you don't want to risk the sampling chunks landing on each side of the bounce anchor and having it clipped off.
this.fast = false;
}
if (prevPoint.cx < closest) {
if (!prevPoint.cx) {
prevPoint.cx = 0.001; //avoids math problems in getRatio() (dividing by zero)
if (i === l - 1) { //in case the final segment goes vertical RIGHT at the end, make sure we end at the end.
prevPoint.x -= 0.001;
closest = Math.min(closest, 0.001);
this.fast = false;
}
} else {
closest = prevPoint.cx;
}
}
} else {
points.splice(i--, 1);
l--;
}
}
l = (1 / closest + 1) | 0;
this.l = l; //record for speed optimization
inc = 1 / l;
j = 0;
point = points[0];
if (this.fast) {
for (i = 0; i < l; i++) { //for fastest lookups, we just sample along the path at equal x (time) distance. Uses more memory and is slightly less accurate for anchors that don't land on the sampling points, but for the vast majority of eases it's excellent (and fast).
p = i * inc;
if (point.nx < p) {
point = points[++j];
}
a1 = point.y + ((p - point.x) / point.cx) * point.cy;
this.lookup[i] = {x: p, cx: inc, y: a1, cy: 0, nx: 9};
if (i) {
this.lookup[i - 1].cy = a1 - this.lookup[i - 1].y;
}
}
this.lookup[l - 1].cy = points[points.length - 1].y - a1;
} else { //this option is more accurate, ensuring that EVERY anchor is hit perfectly. Clipping across a bounce, for example, would never happen.
for (i = 0; i < l; i++) { //build a lookup table based on the smallest distance so that we can instantly find the appropriate point (well, it'll either be that point or the very next one). We'll look up based on the linear progress. So it's it's 0.5 and the lookup table has 100 elements, it'd be like lookup[Math.floor(0.5 * 100)]
if (point.nx < i * inc) {
point = points[++j];
}
this.lookup[i] = point;
}
if (j < points.length - 1) {
this.lookup[i-1] = points[points.length-2];
}
}
this._calcEnd = (points[points.length-1].y !== 1 || points[0].y !== 0); //ensures that we don't run into floating point errors. As long as we're starting at 0 and ending at 1, tell GSAP to skip the final calculation and use 0/1 as the factor.
return this;
};
p.getRatio = _getRatio;
p.getSVGData = function(config) {
return CustomEase.getSVGData(this, config);
};
CustomEase.create = function (id, data, config) {
return new CustomEase(id, data, config);
};
CustomEase.version = "0.2.2";
CustomEase.bezierToPoints = _bezierToPoints;
CustomEase.get = function (id) {
return Ease.map[id];
};
CustomEase.getSVGData = function(ease, config) {
config = config || {};
var rnd = 1000,
width = config.width || 100,
height = config.height || 100,
x = config.x || 0,
y = (config.y || 0) + height,
e = config.path,
a, slope, i, inc, tx, ty, precision, threshold, prevX, prevY;
if (config.invert) {
height = -height;
y = 0;
}
ease = ease.getRatio ? ease : Ease.map[ease] || console.log("No ease found: ", ease);
if (!ease.rawBezier) {
a = ["M" + x + "," + y];
precision = Math.max(5, (config.precision || 1) * 200);
inc = 1 / precision;
precision += 2;
threshold = 5 / precision;
prevX = (((x + inc * width) * rnd) | 0) / rnd;
prevY = (((y + ease.getRatio(inc) * -height) * rnd) | 0) / rnd;
slope = (prevY - y) / (prevX - x);
for (i = 2; i < precision; i++) {
tx = (((x + i * inc * width) * rnd) | 0) / rnd;
ty = (((y + ease.getRatio(i * inc) * -height) * rnd) | 0) / rnd;
if (Math.abs((ty - prevY) / (tx - prevX) - slope) > threshold || i === precision - 1) { //only add points when the slope changes beyond the threshold
a.push(prevX + "," + prevY);
slope = (ty - prevY) / (tx - prevX);
}
prevX = tx;
prevY = ty;
}
} else {
a = [];
precision = ease.rawBezier.length;
for (i = 0; i < precision; i += 2) {
a.push((((x + ease.rawBezier[i] * width) * rnd) | 0) / rnd + "," + (((y + ease.rawBezier[i + 1] * -height) * rnd) | 0) / rnd);
}
a[0] = "M" + a[0];
a[1] = "C" + a[1];
}
if (e) {
(typeof(e) === "string" ? document.querySelector(e) : e).setAttribute("d", a.join(" "));
}
return a.join(" ");
};
return CustomEase;
}, true);
export var CustomEase = globals.CustomEase;
export { CustomEase as default };
@@ -0,0 +1,113 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-08-27
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, 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
**/
/* eslint-disable */
import { _gsScope, globals, Ease } from "gsap/TweenLite.js";
import CustomEase from "./CustomEase.js";
_gsScope._gsDefine("easing.CustomWiggle", ["easing.CustomEase", "easing.Ease"], function() {
var eases = {
easeOut: new CustomEase("", "M0,1,C0.7,1,0.6,0,1,0"),
easeInOut: new CustomEase("", "M0,0,C0.104,0,0.242,1,0.444,1,0.644,1,0.608,0,1,0"),
anticipate: new CustomEase("", "M0,0,C0,0.222,0.024,0.386,0.06,0.402,0.181,0.455,0.647,0.646,0.7,0.67,0.9,0.76,1,0.846,1,1"),
uniform: new CustomEase("", "M0,0,C0,0.95,0.01,1,0.01,1,0.01,1,1,1,1,1,1,1,1,0.01,1,0")
},
_linearEase = new CustomEase(), //linear
_parseEase = function(ease, invertNonCustomEases) {
ease = ease.getRatio ? ease : Ease.map[ease] || new CustomEase("", ease);
return (ease.rawBezier || !invertNonCustomEases) ? ease : {getRatio:function(n) { return 1 - ease.getRatio(n); }};
},
CustomWiggle = function(id, vars) {
this.vars = vars || {};
CustomEase.call(this, id);
this.update(this.vars);
},
p;
CustomWiggle.prototype = p = new CustomEase();
p.constructor = CustomWiggle;
p.update = function(vars) {
vars = vars || this.vars;
var wiggles = (vars.wiggles || 10) | 0,
inc = 1 / wiggles,
x = inc / 2,
anticipate = (vars.type === "anticipate"),
yEase = eases[vars.type] || eases.easeOut,
xEase = _linearEase,
rnd = 1000,
nextX, nextY, angle, handleX, handleY, easedX, y, path, i;
if (anticipate) { //the anticipate ease is actually applied on the x-axis (timing) and uses easeOut for amplitude.
xEase = yEase;
yEase = eases.easeOut;
}
if (vars.timingEase) {
xEase = _parseEase(vars.timingEase);
}
if (vars.amplitudeEase) {
yEase = _parseEase(vars.amplitudeEase, true);
}
easedX = xEase.getRatio(x);
y = anticipate ? -yEase.getRatio(x) : yEase.getRatio(x);
path = [0, 0, easedX / 4, 0, easedX / 2, y, easedX, y];
if (vars.type === "random") { //if we just select random values on the y-axis and plug them into the "normal" algorithm, since the control points are always straight horizontal, it creates a bit of a slowdown at each anchor which just didn't seem as desirable, so we switched to an algorithm that bends the control points to be more in line with their context.
path.length = 4;
nextX = xEase.getRatio(inc);
nextY = Math.random() * 2 - 1;
for (i = 2; i < wiggles; i++) {
x = nextX;
y = nextY;
nextX = xEase.getRatio(inc * i);
nextY = Math.random() * 2 - 1;
angle = Math.atan2(nextY - path[path.length - 3], nextX - path[path.length - 4]);
handleX = Math.cos(angle) * inc;
handleY = Math.sin(angle) * inc;
path.push(x - handleX, y - handleY, x, y, x + handleX, y + handleY);
}
path.push(nextX, 0, 1, 0);
} else {
for (i = 1; i < wiggles; i++) {
path.push(xEase.getRatio(x + inc / 2), y);
x += inc;
y = ((y > 0) ? -1 : 1) * (yEase.getRatio(i * inc));
easedX = xEase.getRatio(x);
path.push(xEase.getRatio(x - inc / 2), y, easedX, y);
}
path.push(xEase.getRatio(x + inc / 4), y, xEase.getRatio(x + inc / 4), 0, 1, 0);
}
i = path.length;
while (--i > -1) {
path[i] = ((path[i] * rnd) | 0) / rnd; //round values to avoid odd strings for super tiny values
}
path[2] = "C" + path[2];
this.setData("M" + path.join(","));
};
CustomWiggle.create = function (id, vars) {
return new CustomWiggle(id, vars);
};
CustomWiggle.version = "0.2.1";
CustomWiggle.eases = eases;
return CustomWiggle;
}, true);
export var CustomWiggle = globals.CustomWiggle;
export { CustomWiggle as default };
@@ -0,0 +1,230 @@
/*!
* VERSION: 0.2.1
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* DrawSVGPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
import { _gsScope } from "gsap/TweenLite.js";
var _doc = _gsScope.document,
_computedStyleScope = (typeof(window) !== "undefined" ? window : _doc.defaultView || {getComputedStyle:function() {}}),
_getComputedStyle = function(e) {
return _computedStyleScope.getComputedStyle(e); //to avoid errors in Microsoft Edge, we need to call getComputedStyle() from a specific scope, typically window.
},
_numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_isEdge = (((_gsScope.navigator || {}).userAgent || "").indexOf("Edge") !== -1), //Microsoft Edge has a bug that causes it not to redraw the path correctly if the stroke-linecap is anything other than "butt" (like "round") and it doesn't match the stroke-linejoin. A way to trigger it is to change the stroke-miterlimit, so we'll only do that if/when we have to (to maximize performance)
_types = {rect:["width","height"], circle:["r","r"], ellipse:["rx","ry"], line:["x2","y2"]},
DrawSVGPlugin;
function getDistance(x1, y1, x2, y2, scaleX, scaleY) {
x2 = (parseFloat(x2 || 0) - parseFloat(x1 || 0)) * scaleX;
y2 = (parseFloat(y2 || 0) - parseFloat(y1 || 0)) * scaleY;
return Math.sqrt(x2 * x2 + y2 * y2);
}
function unwrap(element) {
if (typeof(element) === "string" || !element.nodeType) {
element = _gsScope.TweenLite.selector(element);
if (element.length) {
element = element[0];
}
}
return element;
}
//accepts values like "100%" or "20% 80%" or "20 50" and parses it into an absolute start and end position on the line/stroke based on its length. Returns an an array with the start and end values, like [0, 243]
function parse(value, length, defaultStart) {
var i = value.indexOf(" "),
s, e;
if (i === -1) {
s = defaultStart !== undefined ? defaultStart + "" : value;
e = value;
} else {
s = value.substr(0, i);
e = value.substr(i+1);
}
s = (s.indexOf("%") !== -1) ? (parseFloat(s) / 100) * length : parseFloat(s);
e = (e.indexOf("%") !== -1) ? (parseFloat(e) / 100) * length : parseFloat(e);
return (s > e) ? [e, s] : [s, e];
}
function getLength(element) {
if (!element) {
return 0;
}
element = unwrap(element);
var type = element.tagName.toLowerCase(),
scaleX = 1,
scaleY = 1,
length, bbox, points, prevPoint, i, rx, ry;
if (element.getAttribute("vector-effect") === "non-scaling-stroke") { //non-scaling-stroke basically scales the shape and then strokes it at the screen-level (after transforms), thus we need to adjust the length accordingly.
scaleY = element.getScreenCTM();
scaleX = Math.sqrt(scaleY.a * scaleY.a + scaleY.b * scaleY.b);
scaleY = Math.sqrt(scaleY.d * scaleY.d + scaleY.c * scaleY.c);
}
try { //IE bug: calling <path>.getTotalLength() locks the repaint area of the stroke to whatever its current dimensions are on that frame/tick. To work around that, we must call getBBox() to force IE to recalculate things.
bbox = element.getBBox(); //solely for fixing bug in IE - we don't actually use the bbox.
} catch (e) {
//firefox has a bug that throws an error if the element isn't visible.
console.log("Error: Some browsers like Firefox won't report measurements of invisible elements (like display:none or masks inside defs).");
}
if ((!bbox || (!bbox.width && !bbox.height)) && _types[type]) { //if the element isn't visible, try to discern width/height using its attributes.
bbox = {
width: parseFloat( element.getAttribute(_types[type][0]) ),
height: parseFloat( element.getAttribute(_types[type][1]) )
};
if (type !== "rect" && type !== "line") { //double the radius for circles and ellipses
bbox.width *= 2;
bbox.height *= 2;
}
if (type === "line") {
bbox.x = parseFloat( element.getAttribute("x1") );
bbox.y = parseFloat( element.getAttribute("y1") );
bbox.width = Math.abs(bbox.width - bbox.x);
bbox.height = Math.abs(bbox.height - bbox.y);
}
}
if (type === "path") {
prevPoint = element.style.strokeDasharray;
element.style.strokeDasharray = "none";
length = element.getTotalLength() || 0;
if (scaleX !== scaleY) {
console.log("Warning: <path> length cannot be measured accurately when vector-effect is non-scaling-stroke and the element isn't proportionally scaled.");
}
length *= (scaleX + scaleY) / 2;
element.style.strokeDasharray = prevPoint;
} else if (type === "rect") {
length = bbox.width * 2 * scaleX + bbox.height * 2 * scaleY;
} else if (type === "line") {
length = getDistance(bbox.x, bbox.y, bbox.x + bbox.width, bbox.y + bbox.height, scaleX, scaleY);
} else if (type === "polyline" || type === "polygon") {
points = element.getAttribute("points").match(_numbersExp) || [];
if (type === "polygon") {
points.push(points[0], points[1]);
}
length = 0;
for (i = 2; i < points.length; i+=2) {
length += getDistance(points[i-2], points[i-1], points[i], points[i+1], scaleX, scaleY) || 0;
}
} else if (type === "circle" || type === "ellipse") {
rx = (bbox.width / 2) * scaleX;
ry = (bbox.height / 2) * scaleY;
length = Math.PI * ( 3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry)) );
}
return length || 0;
}
function getPosition(element, length) {
if (!element) {
return [0, 0];
}
element = unwrap(element);
length = length || (getLength(element) + 1);
var cs = _getComputedStyle(element),
dash = cs.strokeDasharray || "",
offset = parseFloat(cs.strokeDashoffset),
i = dash.indexOf(",");
if (i < 0) {
i = dash.indexOf(" ");
}
dash = (i < 0) ? length : parseFloat(dash.substr(0, i)) || 0.00001;
if (dash > length) {
dash = length;
}
return [Math.max(0, -offset), Math.max(0, dash - offset)];
}
DrawSVGPlugin = _gsScope._gsDefine.plugin({
propName: "drawSVG",
API: 2,
version: "0.2.1",
global: true,
overwriteProps: ["drawSVG"],
init: function(target, value, tween, index) {
if (!target.getBBox) {
return false;
}
var length = getLength(target) + 1,
start, end, overage, cs;
this._style = target.style;
this._target = target;
if (typeof(value) === "function") {
value = value(index, target);
}
if (value === true || value === "true") {
value = "0 100%";
} else if (!value) {
value = "0 0";
} else if ((value + "").indexOf(" ") === -1) {
value = "0 " + value;
}
start = getPosition(target, length);
end = parse(value, length, start[0]);
this._length = length + 10;
if (start[0] === 0 && end[0] === 0) {
overage = Math.max(0.00001, end[1] - length); //allow people to go past the end, like values of 105% because for some paths, Firefox doesn't return an accurate getTotalLength(), so it could end up coming up short.
this._dash = length + overage;
this._offset = length - start[1] + overage;
this._offsetPT = this._addTween(this, "_offset", this._offset, length - end[1] + overage, "drawSVG");
} else {
this._dash = (start[1] - start[0]) || 0.000001; //some browsers render artifacts if dash is 0, so we use a very small number in that case.
this._offset = -start[0];
this._dashPT = this._addTween(this, "_dash", this._dash, (end[1] - end[0]) || 0.00001, "drawSVG");
this._offsetPT = this._addTween(this, "_offset", this._offset, -end[0], "drawSVG");
}
if (_isEdge) { //to work around a bug in Microsoft Edge, animate the stroke-miterlimit by 0.0001 just to trigger the repaint (unnecessary if it's "round" and stroke-linejoin is also "round"). Imperceptible, relatively high-performance, and effective. Another option was to set the "d" <path> attribute to its current value on every tick, but that seems like it'd be much less performant.
cs = _getComputedStyle(target);
if (cs.strokeLinecap !== cs.strokeLinejoin) {
end = parseFloat(cs.strokeMiterlimit);
this._addTween(target.style, "strokeMiterlimit", end, end + 0.0001, "strokeMiterlimit");
}
}
this._live = (target.getAttribute("vector-effect") === "non-scaling-stroke" || (value + "").indexOf("live") !== -1);
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
if (this._firstPT) {
//when the element has vector-effect="non-scaling-stroke" and the SVG is resized (like on a window resize), it actually changes the length of the stroke! So we must sense that and make the proper adjustments.
if (this._live) {
var length = getLength(this._target) + 11,
lengthRatio;
if (length !== this._length) {
lengthRatio = length / this._length;
this._length = length;
this._offsetPT.s *= lengthRatio;
this._offsetPT.c *= lengthRatio;
if (this._dashPT) {
this._dashPT.s *= lengthRatio;
this._dashPT.c *= lengthRatio;
} else {
this._dash *= lengthRatio;
}
}
}
this._super.setRatio.call(this, ratio);
this._style.strokeDashoffset = this._offset;
if (ratio === 1 || ratio === 0) {
this._style.strokeDasharray = (this._offset < 0.001 && this._length - this._dash <= 10) ? "none" : (this._offset === this._dash) ? "0px, 999999px" : this._dash + "px," + this._length + "px";
} else {
this._style.strokeDasharray = this._dash + "px," + this._length + "px";
}
}
}
});
DrawSVGPlugin.getLength = getLength;
DrawSVGPlugin.getPosition = getPosition;
export { DrawSVGPlugin, DrawSVGPlugin as default };
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,192 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-05-30
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* Physics2DPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
import { _gsScope } from "gsap/TweenLite.js";
var _DEG2RAD = Math.PI / 180,
Physics2DProp = function(target, p, velocity, acceleration, stepsPerTimeUnit) {
this.p = p;
this.f = (typeof(target[p]) === "function");
this.start = this.value = (!this.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
this.velocity = velocity || 0;
this.v = this.velocity / stepsPerTimeUnit;
if (acceleration || acceleration === 0) {
this.acceleration = acceleration;
this.a = this.acceleration / (stepsPerTimeUnit * stepsPerTimeUnit);
} else {
this.acceleration = this.a = 0;
}
},
_random = Math.random(),
_globals = _gsScope._gsDefine.globals,
_rootFramesTimeline = _globals.com.greensock.core.Animation._rootFramesTimeline,
Physics2DPlugin = _gsScope._gsDefine.plugin({
propName: "physics2D",
version: "0.2.1",
API: 2,
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
if (typeof(value) === "function") {
value = value(index, target);
}
this._target = target;
this._tween = tween;
this._runBackwards = (tween.vars.runBackwards === true);
this._step = 0;
var tl = tween._timeline,
angle = Number(value.angle) || 0,
velocity = Number(value.velocity) || 0,
acceleration = Number(value.acceleration) || 0,
xProp = value.xProp || "x",
yProp = value.yProp || "y",
aAngle = (value.accelerationAngle || value.accelerationAngle === 0) ? Number(value.accelerationAngle) : angle,
stepsPerTimeUnit;
while (tl._timeline) {
tl = tl._timeline;
}
this._stepsPerTimeUnit = stepsPerTimeUnit = (tl === _rootFramesTimeline) ? 1 : 30;
if (value.gravity) {
acceleration = Number(value.gravity);
aAngle = 90;
}
angle *= _DEG2RAD;
aAngle *= _DEG2RAD;
this._friction = 1 - Number(value.friction || 0);
this._overwriteProps.push(xProp);
this._overwriteProps.push(yProp);
this._x = new Physics2DProp(target, xProp, Math.cos(angle) * velocity, Math.cos(aAngle) * acceleration, stepsPerTimeUnit);
this._y = new Physics2DProp(target, yProp, Math.sin(angle) * velocity, Math.sin(aAngle) * acceleration, stepsPerTimeUnit);
this._skipX = this._skipY = false;
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
var time = this._tween._time,
xp = this._x,
yp = this._y,
x, y, tt, steps, remainder, i;
if (this._runBackwards === true) {
time = this._tween._duration - time;
}
if (this._friction === 1) {
tt = time * time * 0.5;
x = xp.start + ((xp.velocity * time) + (xp.acceleration * tt));
y = yp.start + ((yp.velocity * time) + (yp.acceleration * tt));
} else {
time *= this._stepsPerTimeUnit;
steps = i = (time | 0) - this._step;
remainder = (time % 1);
if (i >= 0) { //going forward
while (--i > -1) {
xp.v += xp.a;
yp.v += yp.a;
xp.v *= this._friction;
yp.v *= this._friction;
xp.value += xp.v;
yp.value += yp.v;
}
} else { //going backwards
i = -i;
while (--i > -1) {
xp.value -= xp.v;
yp.value -= yp.v;
xp.v /= this._friction;
yp.v /= this._friction;
xp.v -= xp.a;
yp.v -= yp.a;
}
}
x = xp.value + (xp.v * remainder);
y = yp.value + (yp.v * remainder);
this._step += steps;
}
if (!this._skipX) {
if (xp.m) {
x = xp.m(x, this._target);
}
if (xp.f) {
this._target[xp.p](x);
} else {
this._target[xp.p] = x;
}
}
if (!this._skipY) {
if (yp.m) {
y = yp.m(y, this._target);
}
if (yp.f) {
this._target[yp.p](y);
} else {
this._target[yp.p] = y;
}
}
}
}),
p = Physics2DPlugin.prototype;
p._kill = function(lookup) {
if (lookup[this._x.p] != null) {
this._skipX = true;
}
if (lookup[this._y.p] != null) {
this._skipY = true;
}
return this._super._kill.call(this, lookup);
};
p._mod = function(lookup) {
var val = lookup[this._x.p] || lookup.physics2D;
if (val && typeof(val) === "function") {
this._x.m = val;
}
val = lookup[this._y.p] || lookup.physics2D;
if (val && typeof(val) === "function") {
this._y.m = val;
}
};
Physics2DPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
Physics2DPlugin._cssRegister = function() {
var CSSPlugin = _globals.CSSPlugin;
if (!CSSPlugin) {
return;
}
var _internals = CSSPlugin._internals,
_parseToProxy = _internals._parseToProxy,
_setPluginRatio = _internals._setPluginRatio,
CSSPropTween = _internals.CSSPropTween;
_internals._registerComplexSpecialProp("physics2D", {parser:function(t, e, prop, cssp, pt, plugin) {
plugin = new Physics2DPlugin();
var xProp = e.xProp || "x",
yProp = e.yProp || "y",
vars = {},
data;
vars[xProp] = vars[yProp] = _random++; //doesn't really matter what values we put here because the plugin will determine end values, but it'd be best of the values don't match the current ones so that CSSPlugin doesn't skip creating a CSSPropTween.
data = _parseToProxy(t, vars, cssp, pt, plugin);
pt = new CSSPropTween(t, "physics2D", 0, 0, data.pt, 2);
pt.data = data;
pt.plugin = plugin;
pt.setRatio = _setPluginRatio;
plugin._onInitTween(data.proxy, e, cssp._tween);
return pt;
}});
};
export { Physics2DPlugin, Physics2DPlugin as default };
@@ -0,0 +1,200 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-05-30
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* PhysicsPropsPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
import { _gsScope } from "gsap/TweenLite.js";
var PhysicsProp = function(target, p, velocity, acceleration, friction, stepsPerTimeUnit) {
this.p = p;
this.f = (typeof(target[p]) === "function");
this.start = this.value = (!this.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
this.velocity = velocity || 0;
this.v = this.velocity / stepsPerTimeUnit;
if (acceleration || acceleration == 0) {
this.acceleration = acceleration;
this.a = this.acceleration / (stepsPerTimeUnit * stepsPerTimeUnit);
} else {
this.acceleration = this.a = 0;
}
this.friction = 1 - (friction || 0) ;
},
_random = Math.random(),
_globals = _gsScope._gsDefine.globals,
_rootFramesTimeline = _globals.com.greensock.core.Animation._rootFramesTimeline,
PhysicsPropsPlugin = _gsScope._gsDefine.plugin({
propName: "physicsProps",
version: "0.2.1",
API: 2,
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
if (typeof(value) === "function") {
value = value(target);
}
this._target = target;
this._tween = tween;
this._runBackwards = (tween.vars.runBackwards === true);
this._step = 0;
var tl = tween._timeline,
cnt = 0,
p, curProp;
while (tl._timeline) {
tl = tl._timeline;
}
this._stepsPerTimeUnit = (tl === _rootFramesTimeline) ? 1 : 30;
this._props = [];
for (p in value) {
curProp = value[p];
if (typeof(curProp) === "function") {
curProp = curProp(index, target);
}
if (curProp.velocity || curProp.acceleration) {
this._props[cnt++] = new PhysicsProp(target, p, curProp.velocity, curProp.acceleration, curProp.friction, this._stepsPerTimeUnit);
this._overwriteProps[cnt] = p;
if (curProp.friction) {
this._hasFriction = true;
}
}
}
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
var i = this._props.length,
time = this._tween._time,
target = this._target,
curProp, val, steps, remainder, j, tt;
if (this._runBackwards) {
time = this._tween._duration - time;
}
if (this._hasFriction) {
time *= this._stepsPerTimeUnit;
steps = (time | 0) - this._step;
remainder = time % 1;
if (steps >= 0) { //going forward
while (--i > -1) {
curProp = this._props[i];
j = steps;
while (--j > -1) {
curProp.v += curProp.a;
curProp.v *= curProp.friction;
curProp.value += curProp.v;
}
val = curProp.value + (curProp.v * remainder);
if (curProp.m) {
val = curProp.m(val, target);
}
if (curProp.f) {
target[curProp.p](val);
} else {
target[curProp.p] = val;
}
}
} else { //going backwards
while (--i > -1) {
curProp = this._props[i];
j = -steps;
while (--j > -1) {
curProp.value -= curProp.v;
curProp.v /= curProp.friction;
curProp.v -= curProp.a;
}
val = curProp.value + (curProp.v * remainder);
if (curProp.m) {
val = curProp.m(val, target);
}
if (curProp.f) {
target[curProp.p](val);
} else {
target[curProp.p] = val;
}
}
}
this._step += steps;
} else {
tt = time * time * 0.5;
while (--i > -1) {
curProp = this._props[i];
val = curProp.start + ((curProp.velocity * time) + (curProp.acceleration * tt));
if (curProp.m) {
val = curProp.m(val, target);
}
if (curProp.f) {
target[curProp.p](val);
} else {
target[curProp.p] = val;
}
}
}
}
}),
p = PhysicsPropsPlugin.prototype;
p._kill = function(lookup) {
var i = this._props.length;
while (--i > -1) {
if (this._props[i].p in lookup) {
this._props.splice(i, 1);
}
}
return this._super._kill.call(this, lookup);
};
p._mod = function(lookup) {
var i = this._props.length,
val;
while (--i > -1) {
val = lookup[this._props[i].p] || lookup.physicsProps;
if (typeof(val) === "function") {
this._props[i].m = val;
}
}
};
PhysicsPropsPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
PhysicsPropsPlugin._cssRegister = function() {
var CSSPlugin = _globals.CSSPlugin;
if (!CSSPlugin) {
return;
}
var _internals = CSSPlugin._internals,
_parseToProxy = _internals._parseToProxy,
_setPluginRatio = _internals._setPluginRatio,
CSSPropTween = _internals.CSSPropTween;
_internals._registerComplexSpecialProp("physicsProps", {parser:function(t, e, prop, cssp, pt, plugin) {
plugin = new PhysicsPropsPlugin();
var vars = {},
p, data;
if (e.scale) {
e.scaleX = e.scaleY = e.scale;
delete e.scale;
}
for (p in e) {
vars[p] = _random++; //doesn't really matter what values we put here because the plugin will determine end values, but it'd be best of the values don't match the current ones so that CSSPlugin doesn't skip creating a CSSPropTween.
}
data = _parseToProxy(t, vars, cssp, pt, plugin);
pt = new CSSPropTween(t, "physicsProps", 0, 0, data.pt, 2);
pt.data = data;
pt.plugin = plugin;
pt.setRatio = _setPluginRatio;
plugin._onInitTween(data.proxy, e, cssp._tween);
return pt;
}});
};
export { PhysicsPropsPlugin, PhysicsPropsPlugin as default };
@@ -0,0 +1,215 @@
/*!
* VERSION: 0.5.2
* DATE: 2018-09-11
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* ScrambleTextPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
import { _gsScope } from "gsap/TweenLite.js";
var _trimExp = /(^\s+|\s+$)/g,
_spacesExp = /\s+/g,
_getText = function(e) {
var type = e.nodeType,
result = "";
if (type === 1 || type === 9 || type === 11) {
if (typeof(e.textContent) === "string") {
return e.textContent;
} else {
for (e = e.firstChild; e; e = e.nextSibling ) {
result += _getText(e);
}
}
} else if (type === 3 || type === 4) {
return e.nodeValue;
}
return result;
},
_scrambleText = function(length, chars) {
var l = chars.length,
s = "";
while (--length > -1) {
s += chars[ ((Math.random() * l) | 0) ];
}
return s;
},
CharSet = function(chars) {
this.chars = _emojiSafeSplit(chars);
this.sets = [];
this.length = 50;
var i;
for (i = 0; i < 20; i++) {
this.sets[i] = _scrambleText(80, this.chars); //we create 20 strings that are 80 characters long, randomly chosen and pack them into an array. We then randomly choose the scrambled text from this array in order to greatly improve efficiency compared to creating new randomized text from scratch each and every time it's needed. This is a simple lookup whereas the other technique requires looping through as many times as there are characters needed, and calling Math.random() each time through the loop, building the string, etc.
}
this.grow = function(newLength) { //if we encounter a tween that has more than 80 characters, we'll need to add to the character sets accordingly. Once it's cached, it'll only need to grow again if we exceed that new length. Again, this is an efficiency tactic.
for (i = 0; i < 20; i++) {
this.sets[i] += _scrambleText(newLength - this.length, this.chars);
}
this.length = newLength;
};
},
_emoji = "[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2694-\u2697]|\uD83E[\uDD10-\uDD5D]|[\uD800-\uDBFF][\uDC00-\uDFFF]",
_emojiExp = new RegExp(_emoji),
_emojiAndCharsExp = new RegExp(_emoji + "|.", "g"),
_emojiSafeSplit = function(text, delimiter, trim) {
if (trim) {
text = text.replace(_trimExp, "");
}
return ((delimiter === "" || !delimiter) && _emojiExp.test(text)) ? text.match(_emojiAndCharsExp) : text.split(delimiter || "");
},
_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
_lower = _upper.toLowerCase(),
_charsLookup = {
upperCase: new CharSet(_upper),
lowerCase: new CharSet(_lower),
upperAndLowerCase: new CharSet(_upper + _lower)
},
ScrambleTextPlugin = _gsScope._gsDefine.plugin({
propName: "scrambleText",
version: "0.5.2",
API: 2,
overwriteProps:["scrambleText","text"],
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
this._prop = ("innerHTML" in target) ? "innerHTML" : ("textContent" in target) ? "textContent" : 0; // SVG text in IE doesn't have innerHTML, but it does have textContent.
if (!this._prop) {
return false;
}
if (typeof(value) === "function") {
value = value(index, target);
}
this._target = target;
if (typeof(value) !== "object") {
value = {text:value};
}
var text = value.text || value.value,
trim = (value.trim !== false),
delim, maxLength, charset, splitByChars;
this._delimiter = delim = value.delimiter || "";
this._original = _emojiSafeSplit(_getText(target).replace(_spacesExp, " ").split("&nbsp;").join(""), delim, trim);
if (text === "{original}" || text === true || text == null) {
text = this._original.join(delim);
}
this._text = _emojiSafeSplit((text || "").replace(_spacesExp, " "), delim, trim);
this._hasClass = false;
if (typeof(value.newClass) === "string") {
this._newClass = value.newClass;
this._hasClass = true;
}
if (typeof(value.oldClass) === "string") {
this._oldClass = value.oldClass;
this._hasClass = true;
}
splitByChars = (delim === "");
this._textHasEmoji = (_emojiExp.test(this._text.join(delim)) && splitByChars);
this._charsHaveEmoji = !!value.chars && _emojiExp.test(value.chars);
this._length = splitByChars ? this._original.length : this._original.join(delim).length;
this._lengthDif = (splitByChars ? this._text.length : this._text.join(delim).length) - this._length;
this._fillChar = value.fillChar || (value.chars && value.chars.indexOf(" ") !== -1) ? "&nbsp;" : "";
this._charSet = charset = _charsLookup[(value.chars || "upperCase")] || new CharSet(value.chars);
this._speed = 0.016 / (value.speed || 1);
this._prevScrambleTime = 0;
this._setIndex = (Math.random() * 20) | 0;
maxLength = this._length + Math.max(this._lengthDif, 0);
if (maxLength > charset.length) {
charset.grow(maxLength);
}
this._chars = charset.sets[this._setIndex];
this._revealDelay = value.revealDelay || 0;
this._tweenLength = (value.tweenLength !== false);
this._tween = tween;
this._rightToLeft = !!value.rightToLeft;
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
var l = this._text.length,
delim = this._delimiter,
time = this._tween._time,
timeDif = time - this._prevScrambleTime,
i, i2, startText, endText, applyNew, applyOld, str, startClass, endClass;
if (this._revealDelay) {
if (this._tween.vars.runBackwards) {
time = this._tween._duration - time; //invert the time for from() tweens
}
ratio = (time === 0) ? 0 : (time < this._revealDelay) ? 0.000001 : (time === this._tween._duration) ? 1 : this._tween._ease.getRatio((time - this._revealDelay) / (this._tween._duration - this._revealDelay));
}
if (ratio < 0) {
ratio = 0;
} else if (ratio > 1) {
ratio = 1;
}
if (this._rightToLeft) {
ratio = 1 - ratio;
}
i = (ratio * l + 0.5) | 0;
if (ratio) {
if (timeDif > this._speed || timeDif < -this._speed) {
this._setIndex = (this._setIndex + ((Math.random() * 19) | 0)) % 20;
this._chars = this._charSet.sets[this._setIndex];
this._prevScrambleTime += timeDif;
}
endText = this._chars;
} else {
endText = this._original.join(delim);
}
if (this._rightToLeft) {
if (ratio === 1 && (this._tween.vars.runBackwards || this._tween.data === "isFromStart")) { //special case for from() tweens
startText = "";
endText = this._original.join(delim);
} else {
str = this._text.slice(i).join(delim);
if (this._charsHaveEmoji) {
startText = _emojiSafeSplit(endText).slice(0, ((this._length + (this._tweenLength ? 1 - (ratio * ratio * ratio) : 1) * this._lengthDif) - ((this._textHasEmoji ? _emojiSafeSplit(str) : str).length) + 0.5) | 0).join("");
} else {
startText = endText.substr(0, ((this._length + (this._tweenLength ? 1 - (ratio * ratio * ratio) : 1) * this._lengthDif) - ((this._textHasEmoji ? _emojiSafeSplit(str) : str).length) + 0.5) | 0);
}
endText = str;
}
} else {
startText = this._text.slice(0, i).join(delim);
i2 = (this._textHasEmoji ? _emojiSafeSplit(startText) : startText).length;
if (this._charsHaveEmoji) {
endText = _emojiSafeSplit(endText).slice(i2, ((this._length + (this._tweenLength ? 1 - ((ratio = 1 - ratio) * ratio * ratio * ratio) : 1) * this._lengthDif) + 0.5) | 0).join("");
} else {
endText = endText.substr(i2, ((this._length + (this._tweenLength ? 1 - ((ratio = 1 - ratio) * ratio * ratio * ratio) : 1) * this._lengthDif) - i2 + 0.5) | 0);
}
}
if (this._hasClass) {
startClass = this._rightToLeft ? this._oldClass : this._newClass;
endClass = this._rightToLeft ? this._newClass : this._oldClass;
applyNew = (startClass && i !== 0);
applyOld = (endClass && i !== l);
str = (applyNew ? "<span class='" + startClass + "'>" : "") + startText + (applyNew ? "</span>" : "") + (applyOld ? "<span class='" + endClass + "'>" : "") + delim + endText + (applyOld ? "</span>" : "");
} else {
str = startText + delim + endText;
}
this._target[this._prop] = (this._fillChar === "&nbsp;" && str.indexOf(" ") !== -1) ? str.split(" ").join("&nbsp;&nbsp;") : str;
}
}),
p = ScrambleTextPlugin.prototype;
p._newClass = p._oldClass = "";
for (p in _charsLookup) {
_charsLookup[p.toLowerCase()] = _charsLookup[p];
_charsLookup[p.toUpperCase()] = _charsLookup[p];
}
export { ScrambleTextPlugin, ScrambleTextPlugin as default };
@@ -0,0 +1,565 @@
/*!
* VERSION: 0.7.0
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* SplitText is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
import { _gsScope, globals } from "gsap/TweenLite.js";
(function(window) {
"use strict";
var _globals = window.GreenSockGlobals || window,
_namespace = function(ns) {
var a = ns.split("."),
p = _globals, i;
for (i = 0; i < a.length; i++) {
p[a[i]] = p = p[a[i]] || {};
}
return p;
},
pkg = _namespace("com.greensock.utils"),
_getText = function(e) {
var type = e.nodeType,
result = "";
if (type === 1 || type === 9 || type === 11) {
if (typeof(e.textContent) === "string") {
return e.textContent;
} else {
for ( e = e.firstChild; e; e = e.nextSibling ) {
result += _getText(e);
}
}
} else if (type === 3 || type === 4) {
return e.nodeValue;
}
return result;
},
_doc = _gsScope.document || {},
_computedStyleScope = (typeof(window) !== "undefined" ? window : _doc.defaultView || {getComputedStyle:function() {}}),
_getComputedStyle = function(e) {
return _computedStyleScope.getComputedStyle(e); //to avoid errors in Microsoft Edge, we need to call getComputedStyle() from a specific scope, typically window.
},
_capsExp = /([A-Z])/g,
_getStyle = function(t, p, cs, str) {
var result;
if ((cs = cs || _getComputedStyle(t, null))) {
t = cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
result = (t || cs.length) ? t : cs[p]; //Opera behaves VERY strangely - length is usually 0 and cs[p] is the only way to get accurate results EXCEPT when checking for -o-transform which only works with cs.getPropertyValue()!
} else if (t.currentStyle) {
cs = t.currentStyle;
result = cs[p];
}
return str ? result : parseInt(result, 10) || 0;
},
_isArrayLike = function(e) {
return (e.length && e[0] && ((e[0].nodeType && e[0].style && !e.nodeType) || (e[0].length && e[0][0]))) ? true : false; //could be an array of jQuery objects too, so accommodate that.
},
_flattenArray = function(a) {
var result = [],
l = a.length,
i, e, j;
for (i = 0; i < l; i++) {
e = a[i];
if (_isArrayLike(e)) {
j = e.length;
for (j = 0; j < e.length; j++) {
result.push(e[j]);
}
} else {
result.push(e);
}
}
return result;
},
//some characters are combining marks (think diacritics/accents in European languages) which involve 2 or 4 characters that combine in the browser to form a single character. Pass in the remaining text and an array of the special characters to search for and if the text starts with one of those special characters, it'll spit back the number of characters to retain (often 2 or 4). Used in the specialChars features that was introduced in 0.6.0.
_findSpecialChars = function(text, chars) {
var i = chars.length,
s;
while (--i > -1) {
s = chars[i];
if (text.substr(0, s.length) === s) {
return s.length;
}
}
},
_stripExp = /(?:\r|\n|\t\t)/g, //find carriage returns, new line feeds and double-tabs.
_multipleSpacesExp = /(?:\s\s+)/g,
_emojiStart = 0xD800,
_emojiEnd = 0xDBFF,
_emojiLowStart = 0xDC00,
_emojiRegionStart = 0x1F1E6,
_emojiRegionEnd = 0x1F1FF,
_emojiModStart = 0x1f3fb,
_emojiModEnd = 0x1f3ff,
_emojiPairCode = function(s) {
return ((s.charCodeAt(0) - _emojiStart) << 10) + (s.charCodeAt(1) - _emojiLowStart) + 0x10000;
},
_isOldIE = (_doc.all && !_doc.addEventListener),
_divStart = " style='position:relative;display:inline-block;" + (_isOldIE ? "*display:inline;*zoom:1;'" : "'"), //note: we must use both display:inline-block and *display:inline for IE8 and earlier, otherwise it won't flow correctly (and if we only use display:inline, IE won't render most of the property tweens - very odd).
_cssClassFunc = function(cssClass, tag) {
cssClass = cssClass || "";
var iterate = (cssClass.indexOf("++") !== -1),
num = 1;
if (iterate) {
cssClass = cssClass.split("++").join("");
}
return function() {
return "<" + tag + _divStart + (cssClass ? " class='" + cssClass + (iterate ? num++ : "") + "'>" : ">");
};
},
SplitText = pkg.SplitText = _globals.SplitText = function(element, vars) {
if (typeof(element) === "string") {
element = SplitText.selector(element);
}
if (!element) {
throw("cannot split a null element.");
}
this.elements = _isArrayLike(element) ? _flattenArray(element) : [element];
this.chars = [];
this.words = [];
this.lines = [];
this._originals = [];
this.vars = vars || {};
this.split(vars);
},
_swapText = function(element, oldText, newText) {
var type = element.nodeType;
if (type === 1 || type === 9 || type === 11) {
for (element = element.firstChild; element; element = element.nextSibling) {
_swapText(element, oldText, newText);
}
} else if (type === 3 || type === 4) {
element.nodeValue = element.nodeValue.split(oldText).join(newText);
}
},
_pushReversed = function(a, merge) {
var i = merge.length;
while (--i > -1) {
a.push(merge[i]);
}
},
_slice = function(a) { //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
var b = [],
l = a.length,
i;
for (i = 0; i !== l; b.push(a[i++])) {}
return b;
},
_isBeforeWordDelimiter = function(e, root, wordDelimiter) {
var next;
while (e && e !== root) {
next = e._next || e.nextSibling;
if (next) {
return next.textContent.charAt(0) === wordDelimiter;
}
e = e.parentNode || e._parent;
}
return false;
},
_deWordify = function(e) {
var children = _slice(e.childNodes),
l = children.length,
i, child;
for (i = 0; i < l; i++) {
child = children[i];
if (child._isSplit) {
_deWordify(child);
} else {
if (i && child.previousSibling.nodeType === 3) {
child.previousSibling.nodeValue += (child.nodeType === 3) ? child.nodeValue : child.firstChild.nodeValue;
} else if (child.nodeType !== 3) {
e.insertBefore(child.firstChild, child);
}
e.removeChild(child);
}
}
},
_setPositionsAfterSplit = function(element, vars, allChars, allWords, allLines, origWidth, origHeight) {
var cs = _getComputedStyle(element),
paddingLeft = _getStyle(element, "paddingLeft", cs),
lineOffsetY = -999,
borderTopAndBottom = _getStyle(element, "borderBottomWidth", cs) + _getStyle(element, "borderTopWidth", cs),
borderLeftAndRight = _getStyle(element, "borderLeftWidth", cs) + _getStyle(element, "borderRightWidth", cs),
padTopAndBottom = _getStyle(element, "paddingTop", cs) + _getStyle(element, "paddingBottom", cs),
padLeftAndRight = _getStyle(element, "paddingLeft", cs) + _getStyle(element, "paddingRight", cs),
lineThreshold = _getStyle(element, "fontSize") * 0.2,
textAlign = _getStyle(element, "textAlign", cs, true),
charArray = [],
wordArray = [],
lineArray = [],
wordDelimiter = vars.wordDelimiter || " ",
tag = vars.tag ? vars.tag : (vars.span ? "span" : "div"),
types = vars.type || vars.split || "chars,words,lines",
lines = (allLines && types.indexOf("lines") !== -1) ? [] : null,
words = (types.indexOf("words") !== -1),
chars = (types.indexOf("chars") !== -1),
absolute = (vars.position === "absolute" || vars.absolute === true),
linesClass = vars.linesClass,
iterateLine = ((linesClass || "").indexOf("++") !== -1),
spaceNodesToRemove = [],
i, j, l, node, nodes, isChild, curLine, addWordSpaces, style, lineNode, lineWidth, offset;
if (iterateLine) {
linesClass = linesClass.split("++").join("");
}
//copy all the descendant nodes into an array (we can't use a regular nodeList because it's live and we may need to renest things)
j = element.getElementsByTagName("*");
l = j.length;
nodes = [];
for (i = 0; i < l; i++) {
nodes[i] = j[i];
}
//for absolute positioning, we need to record the x/y offsets and width/height for every <div>. And even if we're not positioning things absolutely, in order to accommodate lines, we must figure out where the y offset changes so that we can sense where the lines break, and we populate the lines array.
if (lines || absolute) {
for (i = 0; i < l; i++) {
node = nodes[i];
isChild = (node.parentNode === element);
if (isChild || absolute || (chars && !words)) {
offset = node.offsetTop;
if (lines && isChild && Math.abs(offset - lineOffsetY) > lineThreshold && (node.nodeName !== "BR" || i === 0)) { //we found some rare occasions where a certain character like &#8209; could cause the offsetTop to be off by 1 pixel, so we build in a threshold.
curLine = [];
lines.push(curLine);
lineOffsetY = offset;
}
if (absolute) { //record offset x and y, as well as width and height so that we can access them later for positioning. Grabbing them at once ensures we don't trigger a browser paint & we maximize performance.
node._x = node.offsetLeft;
node._y = offset;
node._w = node.offsetWidth;
node._h = node.offsetHeight;
}
if (lines) {
if ((node._isSplit && isChild) || (!chars && isChild) || (words && isChild) || (!words && node.parentNode.parentNode === element && !node.parentNode._isSplit)) {
curLine.push(node);
node._x -= paddingLeft;
if (_isBeforeWordDelimiter(node, element, wordDelimiter)) {
node._wordEnd = true;
}
}
if (node.nodeName === "BR" && ((node.nextSibling && node.nextSibling.nodeName === "BR") || i === 0)) { //two consecutive <br> tags signify a new [empty] line. Also, if the entire block of content STARTS with a <br>, add a line.
lines.push([]);
}
}
}
}
}
for (i = 0; i < l; i++) {
node = nodes[i];
isChild = (node.parentNode === element);
if (node.nodeName === "BR") {
if (lines || absolute) {
if (node.parentNode) {
node.parentNode.removeChild(node);
}
nodes.splice(i--, 1);
l--;
} else if (!words) {
element.appendChild(node);
}
continue;
}
if (absolute) {
style = node.style;
if (!words && !isChild) {
node._x += node.parentNode._x;
node._y += node.parentNode._y;
}
style.left = node._x + "px";
style.top = node._y + "px";
style.position = "absolute";
style.display = "block";
//if we don't set the width/height, things collapse in older versions of IE and the origin for transforms is thrown off in all browsers.
style.width = (node._w + 1) + "px"; //IE is 1px short sometimes. Avoid wrapping
style.height = node._h + "px";
}
if (!words && chars) {
//we always start out wrapping words in their own <div> so that line breaks happen correctly, but here we'll remove those <div> tags if necessary and renest the characters directly into the element rather than inside the word <div>
if (node._isSplit) {
node._next = node.nextSibling;
node.parentNode.appendChild(node); //put it at the end to keep the order correct.
} else if (node.parentNode._isSplit) {
node._parent = node.parentNode;
if (!node.previousSibling && node.firstChild) {
node.firstChild._isFirst = true;
}
if (node.nextSibling && node.nextSibling.textContent === " " && !node.nextSibling.nextSibling) { //if the last node inside a nested element is just a space (like T<span>nested </span>), remove it otherwise it'll get placed in the wrong order. Don't remove it right away, though, because we need to sense when words/characters are before a space like _isBeforeWordDelimiter(). Removing it now would make that a false negative.
spaceNodesToRemove.push(node.nextSibling);
}
node._next = (node.nextSibling && node.nextSibling._isFirst) ? null : node.nextSibling;
node.parentNode.removeChild(node);
nodes.splice(i--, 1);
l--;
} else if (!isChild) {
offset = (!node.nextSibling && _isBeforeWordDelimiter(node.parentNode, element, wordDelimiter)); //if this is the last letter in the word (and we're not breaking by lines and not positioning things absolutely), we need to add a space afterwards so that the characters don't just mash together
if (node.parentNode._parent) {
node.parentNode._parent.appendChild(node);
}
if (offset) {
node.parentNode.appendChild(_doc.createTextNode(" "));
}
if (tag === "span") {
node.style.display = "inline"; //so that word breaks are honored properly.
}
charArray.push(node);
}
} else if (node.parentNode._isSplit && !node._isSplit && node.innerHTML !== "") {
wordArray.push(node);
} else if (chars && !node._isSplit) {
if (tag === "span") {
node.style.display = "inline";
}
charArray.push(node);
}
}
i = spaceNodesToRemove.length;
while (--i > -1) {
spaceNodesToRemove[i].parentNode.removeChild(spaceNodesToRemove[i]);
}
if (lines) {
//the next 7 lines just give us the line width in the most reliable way and figure out the left offset (if position isn't relative or absolute). We must set the width along with text-align to ensure everything works properly for various alignments.
if (absolute) {
lineNode = _doc.createElement(tag);
element.appendChild(lineNode);
lineWidth = lineNode.offsetWidth + "px";
offset = (lineNode.offsetParent === element) ? 0 : element.offsetLeft;
element.removeChild(lineNode);
}
style = element.style.cssText;
element.style.cssText = "display:none;"; //to improve performance, set display:none on the element so that the browser doesn't have to worry about reflowing or rendering while we're renesting things. We'll revert the cssText later.
//we can't use element.innerHTML = "" because that causes IE to literally delete all the nodes and their content even though we've stored them in an array! So we must loop through the children and remove them.
while (element.firstChild) {
element.removeChild(element.firstChild);
}
addWordSpaces = (wordDelimiter === " " && (!absolute || (!words && !chars)));
for (i = 0; i < lines.length; i++) {
curLine = lines[i];
lineNode = _doc.createElement(tag);
lineNode.style.cssText = "display:block;text-align:" + textAlign + ";position:" + (absolute ? "absolute;" : "relative;");
if (linesClass) {
lineNode.className = linesClass + (iterateLine ? i+1 : "");
}
lineArray.push(lineNode);
l = curLine.length;
for (j = 0; j < l; j++) {
if (curLine[j].nodeName !== "BR") {
node = curLine[j];
lineNode.appendChild(node);
if (addWordSpaces && node._wordEnd) {
lineNode.appendChild(_doc.createTextNode(" "));
}
if (absolute) {
if (j === 0) {
lineNode.style.top = (node._y) + "px";
lineNode.style.left = (paddingLeft + offset) + "px";
}
node.style.top = "0px";
if (offset) {
node.style.left = (node._x - offset) + "px";
}
}
}
}
if (l === 0) { //if there are no nodes in the line (typically meaning there were two consecutive <br> tags, just add a non-breaking space so that things display properly.
lineNode.innerHTML = "&nbsp;";
} else if (!words && !chars) {
_deWordify(lineNode);
_swapText(lineNode, String.fromCharCode(160), " ");
}
if (absolute) {
lineNode.style.width = lineWidth;
lineNode.style.height = node._h + "px";
}
element.appendChild(lineNode);
}
element.style.cssText = style;
}
//if everything shifts to being position:absolute, the container can collapse in terms of height or width, so fix that here.
if (absolute) {
if (origHeight > element.clientHeight) {
element.style.height = (origHeight - padTopAndBottom) + "px";
if (element.clientHeight < origHeight) { //IE8 and earlier use a different box model - we must include padding and borders
element.style.height = (origHeight + borderTopAndBottom)+ "px";
}
}
if (origWidth > element.clientWidth) {
element.style.width = (origWidth - padLeftAndRight) + "px";
if (element.clientWidth < origWidth) { //IE8 and earlier use a different box model - we must include padding and borders
element.style.width = (origWidth + borderLeftAndRight)+ "px";
}
}
}
_pushReversed(allChars, charArray);
if (words) {
_pushReversed(allWords, wordArray);
}
_pushReversed(allLines, lineArray);
},
_splitRawText = function(element, vars, wordStart, charStart) {
var tag = vars.tag ? vars.tag : (vars.span ? "span" : "div"),
types = vars.type || vars.split || "chars,words,lines",
//words = (types.indexOf("words") !== -1),
chars = (types.indexOf("chars") !== -1),
absolute = (vars.position === "absolute" || vars.absolute === true),
wordDelimiter = vars.wordDelimiter || " ",
space = wordDelimiter !== " " ? "" : (absolute ? "&#173; " : " "),
wordEnd = "</" + tag + ">",
wordIsOpen = true,
specialChars = vars.specialChars ? (typeof(vars.specialChars) === "function" ? vars.specialChars : _findSpecialChars) : null, //specialChars can be an array or a function. For performance reasons, we always set this local "specialChars" to a function to which we pass the remaining text and whatever the original vars.specialChars was so that if it's an array, it works with the _findSpecialChars() function.
text, splitText, i, j, l, character, hasTagStart, emojiPair1, emojiPair2, testResult,
container = _doc.createElement("div"),
parent = element.parentNode;
parent.insertBefore(container, element);
container.textContent = element.nodeValue;
parent.removeChild(element);
element = container;
text = _getText(element);
hasTagStart = text.indexOf("<") !== -1;
if (vars.reduceWhiteSpace !== false) {
text = text.replace(_multipleSpacesExp, " ").replace(_stripExp, "");
}
if (hasTagStart) {
text = text.split("<").join("{{LT}}"); //we can't leave "<" in the string, or when we set the innerHTML, it can be interpreted as a node
}
l = text.length;
splitText = ((text.charAt(0) === " ") ? space : "") + wordStart();
for (i = 0; i < l; i++) {
character = text.charAt(i);
if (specialChars && (testResult = specialChars(text.substr(i), vars.specialChars))) { // look for any specialChars that were declared. Remember, they can be passed in like {specialChars:["मी", "पा", "है"]} or a function could be defined instead. Either way, the function should return the number of characters that should be grouped together for this "character".
character = text.substr(i, testResult || 1);
splitText += (chars && character !== " ") ? charStart() + character + "</" + tag + ">" : character;
i += testResult - 1;
} else if (character === wordDelimiter && text.charAt(i-1) !== wordDelimiter && i) {
splitText += wordIsOpen ? wordEnd : "";
wordIsOpen = false;
while (text.charAt(i + 1) === wordDelimiter) { //skip over empty spaces (to avoid making them words)
splitText += space;
i++;
}
if (i === l-1) {
splitText += space;
} else if (text.charAt(i + 1) !== ")") {
splitText += space + wordStart();
wordIsOpen = true;
}
} else if (character === "{" && text.substr(i, 6) === "{{LT}}") {
splitText += chars ? charStart() + "{{LT}}" + "</" + tag + ">" : "{{LT}}";
i += 5;
} else if ((character.charCodeAt(0) >= _emojiStart && character.charCodeAt(0) <= _emojiEnd) || (text.charCodeAt(i+1) >= 0xFE00 && text.charCodeAt(i+1) <= 0xFE0F)) { //special emoji characters use 2 or 4 unicode characters that we must keep together.
emojiPair1 = _emojiPairCode(text.substr(i, 2));
emojiPair2 = _emojiPairCode(text.substr(i + 2, 2));
j = ((emojiPair1 >= _emojiRegionStart && emojiPair1 <= _emojiRegionEnd && emojiPair2 >= _emojiRegionStart && emojiPair2 <= _emojiRegionEnd) || (emojiPair2 >= _emojiModStart && emojiPair2 <= _emojiModEnd)) ? 4 : 2;
splitText += (chars && character !== " ") ? charStart() + text.substr(i, j) + "</" + tag + ">" : text.substr(i, j);
i += j - 1;
} else {
splitText += (chars && character !== " ") ? charStart() + character + "</" + tag + ">" : character;
}
}
element.outerHTML = splitText + (wordIsOpen ? wordEnd : "");
if (hasTagStart) {
_swapText(parent, "{{LT}}", "<"); //note: don't perform this on "element" because that gets replaced with all new elements when we set element.outerHTML.
}
},
_split = function(element, vars, wordStart, charStart) {
var children = _slice(element.childNodes),
l = children.length,
absolute = (vars.position === "absolute" || vars.absolute === true),
i, child;
if (element.nodeType !== 3 || l > 1) {
vars.absolute = false;
for (i = 0; i < l; i++) {
child = children[i];
if (child.nodeType !== 3 || /\S+/.test(child.nodeValue)) {
if (absolute && child.nodeType !== 3 && _getStyle(child, "display", null, true) === "inline") { //if there's a child node that's display:inline, switch it to inline-block so that absolute positioning works properly (most browsers don't report offsetTop/offsetLeft properly inside a <span> for example)
child.style.display = "inline-block";
child.style.position = "relative";
}
child._isSplit = true;
_split(child, vars, wordStart, charStart); //don't split lines on child elements
}
}
vars.absolute = absolute;
element._isSplit = true;
return;
}
_splitRawText(element, vars, wordStart, charStart);
},
p = SplitText.prototype;
p.split = function(vars) {
if (this.isSplit) {
this.revert();
}
this.vars = vars = vars || this.vars;
this._originals.length = this.chars.length = this.words.length = this.lines.length = 0;
var i = this.elements.length,
tag = vars.tag ? vars.tag : (vars.span ? "span" : "div"),
wordStart = _cssClassFunc(vars.wordsClass, tag),
charStart = _cssClassFunc(vars.charsClass, tag),
origHeight, origWidth, e;
//we split in reversed order so that if/when we position:absolute elements, they don't affect the position of the ones after them in the document flow (shifting them up as they're taken out of the document flow).
while (--i > -1) {
e = this.elements[i];
this._originals[i] = e.innerHTML;
origHeight = e.clientHeight;
origWidth = e.clientWidth;
_split(e, vars, wordStart, charStart);
_setPositionsAfterSplit(e, vars, this.chars, this.words, this.lines, origWidth, origHeight);
}
this.chars.reverse();
this.words.reverse();
this.lines.reverse();
this.isSplit = true;
return this;
};
p.revert = function() {
if (!this._originals) {
throw("revert() call wasn't scoped properly.");
}
var i = this._originals.length;
while (--i > -1) {
this.elements[i].innerHTML = this._originals[i];
}
this.chars = [];
this.words = [];
this.lines = [];
this.isSplit = false;
return this;
};
SplitText.selector = window.$ || window.jQuery || function(e) {
var selector = window.$ || window.jQuery;
if (selector) {
SplitText.selector = selector;
return selector(e);
}
return (typeof(document) === "undefined") ? e : (document.querySelectorAll ? document.querySelectorAll(e) : document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e));
};
SplitText.version = "0.7.0";
})(_gsScope);
export var SplitText = globals.SplitText;
export { SplitText as default };
@@ -0,0 +1,726 @@
/*!
* VERSION: 0.11.2
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* ThrowPropsPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
import { TweenLite, _gsScope, globals, TweenPlugin, Ease } from "gsap/TweenLite.js";
_gsScope._gsDefine("plugins.ThrowPropsPlugin", ["utils.VelocityTracker", "plugins.TweenPlugin", "TweenLite", "easing.Ease"], function(VelocityTracker) {
var ThrowPropsPlugin = function(props, priority) {
TweenPlugin.call(this, "throwProps");
this._overwriteProps.length = 0;
},
_max = 999999999999999,
_min = 0.0000000001,
_globals = _gsScope._gsDefine.globals,
_recordEndMode = false,//in a typical throwProps css tween that has an "end" defined as a function, it grabs that value initially when the tween is rendered, then again when we calculate the necessary duration, and then a 3rd time after we invalidate() the tween, so we toggle _recordEndMode to true when we're about to begin such a tween which tells the engine to grab the end value(s) once and record them as "max" and "min" on the throwProps object, thus we can skip those extra calls. Then we set it back to false when we're done with our fancy initialization routine.
_transforms = {x:1,y:1,z:2,scale:1,scaleX:1,scaleY:1,rotation:1,rotationZ:1,rotationX:2,rotationY:2,skewX:1,skewY:1,xPercent:1,yPercent:1},
_getClosest = function(n, values, max, min, radius) {
var i = values.length,
closest = 0,
absDif = _max,
val, dif, p, dist;
if (typeof(n) === "object") {
while (--i > -1) {
val = values[i];
dif = 0;
for (p in n) {
dist = val[p] - n[p];
dif += dist * dist;
}
if (dif < absDif) {
closest = i;
absDif = dif;
}
}
if ((radius || _max) < _max && radius < Math.sqrt(absDif)) {
return n;
}
} else {
while (--i > -1) {
val = values[i];
dif = val - n;
if (dif < 0) {
dif = -dif;
}
if (dif < absDif && val >= min && val <= max) {
closest = i;
absDif = dif;
}
}
}
return values[closest];
},
_parseEnd = function(curProp, end, max, min, name, radius) {
if (curProp.end === "auto") {
return curProp;
}
var endVar = curProp.end,
adjustedEnd, p;
max = isNaN(max) ? _max : max;
min = isNaN(min) ? -_max : min;
if (typeof(end) === "object") { //for objects, like {x, y} where they're linked and we must pass an object to the function or find the closest value in an array.
adjustedEnd = end.calculated ? end : ((typeof(endVar) === "function") ? endVar(end) : _getClosest(end, endVar, max, min, radius)) || end;
if (!end.calculated) {
for (p in adjustedEnd) {
end[p] = adjustedEnd[p];
}
end.calculated = true;
}
adjustedEnd = adjustedEnd[name];
} else {
adjustedEnd = (typeof(endVar) === "function") ? endVar(end) : (endVar instanceof Array) ? _getClosest(end, endVar, max, min, radius) : Number(endVar);
}
if (adjustedEnd > max) {
adjustedEnd = max;
} else if (adjustedEnd < min) {
adjustedEnd = min;
}
return {max:adjustedEnd, min:adjustedEnd, unitFactor:curProp.unitFactor};
},
_extend = function(decoratee, extras, exclude) {
for (var p in extras) {
if (decoratee[p] === undefined && p !== exclude) {
decoratee[p] = extras[p];
}
}
return decoratee;
},
_calculateChange = ThrowPropsPlugin.calculateChange = function(velocity, ease, duration, checkpoint) {
if (checkpoint == null) {
checkpoint = 0.05;
}
var e = (ease instanceof Ease) ? ease : (!ease) ? TweenLite.defaultEase : new Ease(ease);
return (duration * checkpoint * velocity) / e.getRatio(checkpoint);
},
_calculateDuration = ThrowPropsPlugin.calculateDuration = function(start, end, velocity, ease, checkpoint) {
checkpoint = checkpoint || 0.05;
var e = (ease instanceof Ease) ? ease : (!ease) ? TweenLite.defaultEase : new Ease(ease);
return Math.abs( (end - start) * e.getRatio(checkpoint) / velocity / checkpoint );
},
_calculateTweenDuration = ThrowPropsPlugin.calculateTweenDuration = function(target, vars, maxDuration, minDuration, overshootTolerance, recordEnd) {
if (typeof(target) === "string") {
target = TweenLite.selector(target);
}
if (!target) {
return 0;
}
if (maxDuration == null) {
maxDuration = 10;
}
if (minDuration == null) {
minDuration = 0.2;
}
if (overshootTolerance == null) {
overshootTolerance = 1;
}
if (target.length) {
target = target[0] || target;
}
var duration = 0,
clippedDuration = 9999999999,
throwPropsVars = vars.throwProps || vars,
ease = (vars.ease instanceof Ease) ? vars.ease : (!vars.ease) ? TweenLite.defaultEase : new Ease(vars.ease),
checkpoint = isNaN(throwPropsVars.checkpoint) ? 0.05 : Number(throwPropsVars.checkpoint),
resistance = isNaN(throwPropsVars.resistance) ? ThrowPropsPlugin.defaultResistance : Number(throwPropsVars.resistance),
p, curProp, curDuration, curVelocity, curResistance, curVal, end, curClippedDuration, tracker, unitFactor,
linkedProps, linkedPropNames, i;
if (throwPropsVars.linkedProps) { //when there are linkedProps (typically "x,y" where snapping has to factor in multiple properties, we must first populate an object with all of those end values, then feed it to the function that make any necessary alterations. So the point of this first loop is to simply build an object (like {x:100, y:204.5}) for feeding into that function which we'll do later in the "real" loop.
linkedPropNames = throwPropsVars.linkedProps.split(",");
linkedProps = {};
for (i = 0; i < linkedPropNames.length; i++) {
p = linkedPropNames[i];
curProp = throwPropsVars[p];
if (curProp) {
if (curProp.velocity !== undefined && typeof(curProp.velocity) === "number") {
curVelocity = Number(curProp.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
curVelocity = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0;
}
curResistance = isNaN(curProp.resistance) ? resistance : Number(curProp.resistance);
curDuration = (curVelocity * curResistance > 0) ? curVelocity / curResistance : curVelocity / -curResistance;
curVal = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p] || 0;
linkedProps[p] = curVal + _calculateChange(curVelocity, ease, curDuration, checkpoint);
}
}
}
for (p in throwPropsVars) {
if (p !== "resistance" && p !== "checkpoint" && p !== "preventOvershoot" && p !== "linkedProps" && p !== "radius") {
curProp = throwPropsVars[p];
if (typeof(curProp) !== "object") {
tracker = tracker || VelocityTracker.getByTarget(target);
if (tracker && tracker.isTrackingProp(p)) {
curProp = (typeof(curProp) === "number") ? {velocity:curProp} : {velocity:tracker.getVelocity(p)}; //if we're tracking this property, we should use the tracking velocity and then use the numeric value that was passed in as the min and max so that it tweens exactly there.
} else {
curVelocity = Number(curProp) || 0;
curDuration = (curVelocity * resistance > 0) ? curVelocity / resistance : curVelocity / -resistance;
}
}
if (typeof(curProp) === "object") {
if (curProp.velocity !== undefined && typeof(curProp.velocity) === "number") {
curVelocity = Number(curProp.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
curVelocity = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0;
}
curResistance = isNaN(curProp.resistance) ? resistance : Number(curProp.resistance);
curDuration = (curVelocity * curResistance > 0) ? curVelocity / curResistance : curVelocity / -curResistance;
curVal = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p] || 0;
end = curVal + _calculateChange(curVelocity, ease, curDuration, checkpoint);
if (curProp.end !== undefined) {
curProp = _parseEnd(curProp, (linkedProps && p in linkedProps) ? linkedProps : end, curProp.max, curProp.min, p, throwPropsVars.radius);
if (recordEnd || _recordEndMode) {
throwPropsVars[p] = _extend(curProp, throwPropsVars[p], "end");
}
}
if (curProp.max !== undefined && end > Number(curProp.max) + _min) {
unitFactor = curProp.unitFactor || ThrowPropsPlugin.defaultUnitFactors[p] || 1; //some values are measured in special units like radians in which case our thresholds need to be adjusted accordingly.
//if the value is already exceeding the max or the velocity is too low, the duration can end up being uncomfortably long but in most situations, users want the snapping to occur relatively quickly (0.75 seconds), so we implement a cap here to make things more intuitive. If the max and min match, it means we're animating to a particular value and we don't want to shorten the time unless the velocity is really slow. Example: a rotation where the start and natural end value are less than the snapping spot, but the natural end is pretty close to the snap.
curClippedDuration = ((curVal > curProp.max && curProp.min !== curProp.max) || (curVelocity * unitFactor > -15 && curVelocity * unitFactor < 45)) ? (minDuration + (maxDuration - minDuration) * 0.1) : _calculateDuration(curVal, curProp.max, curVelocity, ease, checkpoint);
if (curClippedDuration + overshootTolerance < clippedDuration) {
clippedDuration = curClippedDuration + overshootTolerance;
}
} else if (curProp.min !== undefined && end < Number(curProp.min) - _min) {
unitFactor = curProp.unitFactor || ThrowPropsPlugin.defaultUnitFactors[p] || 1; //some values are measured in special units like radians in which case our thresholds need to be adjusted accordingly.
//if the value is already exceeding the min or if the velocity is too low, the duration can end up being uncomfortably long but in most situations, users want the snapping to occur relatively quickly (0.75 seconds), so we implement a cap here to make things more intuitive.
curClippedDuration = ((curVal < curProp.min && curProp.min !== curProp.max) || (curVelocity * unitFactor > -45 && curVelocity * unitFactor < 15)) ? (minDuration + (maxDuration - minDuration) * 0.1) : _calculateDuration(curVal, curProp.min, curVelocity, ease, checkpoint);
if (curClippedDuration + overshootTolerance < clippedDuration) {
clippedDuration = curClippedDuration + overshootTolerance;
}
}
if (curClippedDuration > duration) {
duration = curClippedDuration;
}
}
if (curDuration > duration) {
duration = curDuration;
}
}
}
if (duration > clippedDuration) {
duration = clippedDuration;
}
if (duration > maxDuration) {
return maxDuration;
} else if (duration < minDuration) {
return minDuration;
}
return duration;
},
p = ThrowPropsPlugin.prototype = new TweenPlugin("throwProps"),
_cssProxy, _cssVars, _last, _lastValue; //these serve as a cache of sorts, recording the last css-related proxy and the throwProps vars that get calculated in the _cssRegister() method. This allows us to grab them in the ThrowPropsPlugin.to() function and calculate the duration. Of course we could have structured things in a more "clean" fashion, but performance is of paramount importance.
p.constructor = ThrowPropsPlugin;
ThrowPropsPlugin.version = "0.11.2";
ThrowPropsPlugin.API = 2;
ThrowPropsPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
ThrowPropsPlugin.defaultResistance = 100;
ThrowPropsPlugin.defaultUnitFactors = {time:1000, totalTime:1000}; //setting the unitFactor to a higher value (default is 1) reduces the chance of the auto-accelerating behavior kicking in when determining durations when the initial velocity is adequately low - imagine dragging something past a boundary and then letting go - snapping back relatively quickly should be prioritized over matching the initial velocity (at least that's the behavior most people consider intuitive). But in some situations when the units are very low (like "time" of a timeline or rotation when using radians), it can kick in too frequently so this allows tweaking.
ThrowPropsPlugin.track = function(target, props, types) {
return VelocityTracker.track(target, props, types);
};
ThrowPropsPlugin.untrack = function(target, props) {
VelocityTracker.untrack(target, props);
};
ThrowPropsPlugin.isTracking = function(target, prop) {
return VelocityTracker.isTracking(target, prop);
};
ThrowPropsPlugin.getVelocity = function(target, prop) {
var vt = VelocityTracker.getByTarget(target);
return vt ? vt.getVelocity(prop) : NaN;
};
ThrowPropsPlugin._cssRegister = function() {
var CSSPlugin = _globals.com.greensock.plugins.CSSPlugin;
if (!CSSPlugin) {
return;
}
var _internals = CSSPlugin._internals,
_parseToProxy = _internals._parseToProxy,
_setPluginRatio = _internals._setPluginRatio,
CSSPropTween = _internals.CSSPropTween;
_internals._registerComplexSpecialProp("throwProps", {parser:function(t, e, prop, cssp, pt, plugin) {
plugin = new ThrowPropsPlugin();
var velocities = {},
min = {},
max = {},
end = {},
res = {},
preventOvershoot = {},
hasResistance, val, p, data, tracker;
_cssVars = {};
for (p in e) {
if (p !== "resistance" && p !== "preventOvershoot" && p !== "linkedProps" && p !== "radius") {
val = e[p];
if (typeof(val) === "object") {
if (val.velocity !== undefined && typeof(val.velocity) === "number") {
velocities[p] = Number(val.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(t);
velocities[p] = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0; //rotational values are actually converted to radians in CSSPlugin, but our tracking velocity is in radians already, so make it into degrees to avoid a funky conversion
}
if (val.end !== undefined) {
end[p] = val.end;
}
if (val.min !== undefined) {
min[p] = val.min;
}
if (val.max !== undefined) {
max[p] = val.max;
}
if (val.preventOvershoot) {
preventOvershoot[p] = true;
}
if (val.resistance !== undefined) {
hasResistance = true;
res[p] = val.resistance;
}
} else if (typeof(val) === "number") {
velocities[p] = val;
} else {
tracker = tracker || VelocityTracker.getByTarget(t);
if (tracker && tracker.isTrackingProp(p)) {
velocities[p] = tracker.getVelocity(p);
} else {
velocities[p] = val || 0;
}
}
if (_transforms[p]) {
cssp._enableTransforms((_transforms[p] === 2));
}
}
}
data = _parseToProxy(t, velocities, cssp, pt, plugin);
_cssProxy = data.proxy;
velocities = data.end;
for (p in _cssProxy) {
_cssVars[p] = {velocity:velocities[p], min:min[p], max:max[p], end:end[p], resistance:res[p], preventOvershoot:preventOvershoot[p]};
}
if (e.resistance != null) {
_cssVars.resistance = e.resistance;
}
if (e.linkedProps != null) {
_cssVars.linkedProps = e.linkedProps;
}
if (e.radius != null) {
_cssVars.radius = e.radius;
}
if (e.preventOvershoot) {
_cssVars.preventOvershoot = true;
}
pt = new CSSPropTween(t, "throwProps", 0, 0, data.pt, 2);
cssp._overwriteProps.pop(); //don't overwrite all other throwProps tweens. In the CSSPropTween constructor, we add the property to the _overwriteProps, so remove it here.
pt.plugin = plugin;
pt.setRatio = _setPluginRatio;
pt.data = data;
plugin._onInitTween(_cssProxy, _cssVars, cssp._tween);
return pt;
}});
};
ThrowPropsPlugin.to = function(target, vars, maxDuration, minDuration, overshootTolerance) {
if (!vars.throwProps) {
vars = {throwProps:vars};
}
if (overshootTolerance === 0) {
vars.throwProps.preventOvershoot = true;
}
_recordEndMode = true; //if we encounter a function-based "end" value, ThrowPropsPlugin will record it as "max" and "min" properties, replacing "end" (this is an optimization so that the function only gets called once)
var tween = new TweenLite(target, minDuration || 1, vars);
tween.render(0, true, true); //we force a render so that the CSSPlugin instantiates and populates the _cssProxy and _cssVars which we need in order to calculate the tween duration. Remember, we can't use the regular target for calculating the duration because the current values wouldn't be able to be grabbed like target["propertyName"], as css properties can be complex like boxShadow:"10px 10px 20px 30px red" or backgroundPosition:"25px 50px". The proxy is the result of breaking all that complex data down and finding just the numeric values and assigning them to a generic proxy object with unique names. THAT is what the _calculateTweenDuration() can look at. We also needed to do the same break down of any min or max or velocity data
if (tween.vars.css) {
tween.duration(_calculateTweenDuration(_cssProxy, {throwProps:_cssVars, ease:vars.ease}, maxDuration, minDuration, overshootTolerance));
if (tween._delay && !tween.vars.immediateRender) {
tween.invalidate(); //if there's a delay, the starting values could be off, so invalidate() to force reinstantiation when the tween actually starts.
} else {
_last._onInitTween(_cssProxy, _lastValue, tween);
}
_recordEndMode = false;
return tween;
} else {
tween.kill();
tween = new TweenLite(target, _calculateTweenDuration(target, vars, maxDuration, minDuration, overshootTolerance), vars);
_recordEndMode = false;
return tween;
}
};
p._onInitTween = function(target, value, tween, index) {
this.target = target;
this._props = [];
_last = this;
_lastValue = value;
var ease = tween._ease,
checkpoint = isNaN(value.checkpoint) ? 0.05 : Number(value.checkpoint),
duration = tween._duration,
preventOvershoot = value.preventOvershoot,
cnt = 0,
p, curProp, curVal, isFunc, velocity, change1, end, change2, tracker,
linkedProps, linkedPropNames, i;
if (value.linkedProps) { //when there are linkedProps (typically "x,y" where snapping has to factor in multiple properties, we must first populate an object with all of those end values, then feed it to the function that make any necessary alterations. So the point of this first loop is to simply build an object (like {x:100, y:204.5}) for feeding into that function which we'll do later in the "real" loop.
linkedPropNames = value.linkedProps.split(",");
linkedProps = {};
for (i = 0; i < linkedPropNames.length; i++) {
p = linkedPropNames[i];
curProp = value[p];
if (curProp) {
if (curProp.velocity !== undefined && typeof(curProp.velocity) === "number") {
velocity = Number(curProp.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
velocity = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0;
}
curVal = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p] || 0;
linkedProps[p] = curVal + _calculateChange(velocity, ease, duration, checkpoint);
}
}
}
for (p in value) {
if (p !== "resistance" && p !== "checkpoint" && p !== "preventOvershoot" && p !== "linkedProps" && p !== "radius") {
curProp = value[p];
if (typeof(curProp) === "function") {
curProp = curProp(index, target);
}
if (typeof(curProp) === "number") {
velocity = Number(curProp) || 0;
} else if (typeof(curProp) === "object" && !isNaN(curProp.velocity)) {
velocity = Number(curProp.velocity);
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
if (tracker && tracker.isTrackingProp(p)) {
velocity = tracker.getVelocity(p);
} else {
throw("ERROR: No velocity was defined in the throwProps tween of " + target + " property: " + p);
}
}
change1 = _calculateChange(velocity, ease, duration, checkpoint);
change2 = 0;
isFunc = (typeof(target[p]) === "function");
curVal = (isFunc) ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p];
if (typeof(curProp) === "object") {
end = curVal + change1;
if (curProp.end !== undefined) {
curProp = _parseEnd(curProp, (linkedProps && p in linkedProps) ? linkedProps : end, curProp.max, curProp.min, p, value.radius);
if (_recordEndMode) {
value[p] = _extend(curProp, value[p], "end");
}
}
if (curProp.max !== undefined && Number(curProp.max) < end) {
if (preventOvershoot || curProp.preventOvershoot) {
change1 = curProp.max - curVal;
} else {
change2 = (curProp.max - curVal) - change1;
}
} else if (curProp.min !== undefined && Number(curProp.min) > end) {
if (preventOvershoot || curProp.preventOvershoot) {
change1 = curProp.min - curVal;
} else {
change2 = (curProp.min - curVal) - change1;
}
}
}
this._overwriteProps[cnt] = p;
this._props[cnt++] = {p:p, s:curVal, c1:change1, c2:change2, f:isFunc, r:false};
}
}
return true;
};
p._kill = function(lookup) {
var i = this._props.length;
while (--i > -1) {
if (lookup[this._props[i].p] != null) {
this._props.splice(i, 1);
}
}
return TweenPlugin.prototype._kill.call(this, lookup);
};
p._mod = function(lookup) {
var p = this._props,
i = p.length,
val;
while (--i > -1) {
val = lookup[p[i].p] || lookup.throwProps;
if (typeof(val) === "function") {
p[i].m = val;
}
}
};
p.setRatio = function(v) {
var i = this._props.length,
cp, val;
while (--i > -1) {
cp = this._props[i];
val = cp.s + cp.c1 * v + cp.c2 * v * v;
if (cp.m) {
val = cp.m(val, this.target);
} else if (v === 1) {
val = ((val * 10000 + (val < 0 ? -0.5 : 0.5)) | 0) / 10000; //if we don't round things at the very end, binary math issues can creep in and cause snapping not to be exact (like landing on 20.000000000001 instead of 20).
}
if (cp.f) {
this.target[cp.p](val);
} else {
this.target[cp.p] = val;
}
}
};
TweenPlugin.activate([ThrowPropsPlugin]);
return ThrowPropsPlugin;
}, true);
/*
* ----------------------------------------------------------------
* VelocityTracker
* ----------------------------------------------------------------
*/
_gsScope._gsDefine("utils.VelocityTracker", ["TweenLite"], function() {
var _first, _initted, _time1, _time2,
_capsExp = /([A-Z])/g,
_empty = {},
_doc = _gsScope.document,
_transforms = {x:1,y:1,z:2,scale:1,scaleX:1,scaleY:1,rotation:1,rotationZ:1,rotationX:2,rotationY:2,skewX:1,skewY:1,xPercent:1,yPercent:1},
_computedStyleScope = (typeof(window) !== "undefined" ? window : _doc.defaultView || {getComputedStyle:function() {}}),
_getComputedStyle = function(e) {
return _computedStyleScope.getComputedStyle(e); //to avoid errors in Microsoft Edge, we need to call getComputedStyle() from a specific scope, typically window.
},
_getStyle = function(t, p, cs) {
var rv = (t._gsTransform || _empty)[p];
if (rv || rv === 0) {
return rv;
} else if (t.style[p]) {
rv = t.style[p];
} else if ((cs = cs || _getComputedStyle(t, null))) {
rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
} else if (t.currentStyle) {
rv = t.currentStyle[p];
}
return parseFloat(rv) || 0;
},
_ticker = TweenLite.ticker,
VelocityProp = function(p, isFunc, next) {
this.p = p;
this.f = isFunc;
this.v1 = this.v2 = 0;
this.t1 = this.t2 = _ticker.time;
this.css = false;
this.type = "";
this._prev = null;
if (next) {
this._next = next;
next._prev = this;
}
},
_update = function() {
var vt = _first,
t = _ticker.time,
val, vp;
//if the frame rate is too high, we won't be able to track the velocity as well, so only update the values about 33 times per second
if (t - _time1 >= 0.03) {
_time2 = _time1;
_time1 = t;
while (vt) {
vp = vt._firstVP;
while (vp) {
val = vp.css ? _getStyle(vt.target, vp.p) : vp.f ? vt.target[vp.p]() : vt.target[vp.p];
if (val !== vp.v1 || t - vp.t1 > 0.15) { //use a threshold of 0.15 seconds for zeroing-out velocity. If we only use 0.03 and things update slightly slower, like some Android devices dispatch "touchmove" events sluggishly so 2 or 3 ticks of the TweenLite.ticker may elapse inbetween, thus it may appear like the object is not moving but it actually is but it's not updating as frequently. A threshold of 0.15 seconds seems to be a good balance. We want to update things frequently (0.03 seconds) when they're moving so that we can respond to fast motions accurately, but we want to be more resistant to go back to a zero velocity.
vp.v2 = vp.v1;
vp.v1 = val;
vp.t2 = vp.t1;
vp.t1 = t;
}
vp = vp._next;
}
vt = vt._next;
}
}
},
VelocityTracker = function(target) {
this._lookup = {};
this.target = target;
this.elem = (target.style && target.nodeType) ? true : false;
if (!_initted) {
_ticker.addEventListener("tick", _update, null, false, -100);
_time1 = _time2 = _ticker.time;
_initted = true;
}
if (_first) {
this._next = _first;
_first._prev = this;
}
_first = this;
},
getByTarget = VelocityTracker.getByTarget = function(target) {
var vt = _first;
while (vt) {
if (vt.target === target) {
return vt;
}
vt = vt._next;
}
},
p = VelocityTracker.prototype;
p.addProp = function(prop, type) {
if (!this._lookup[prop]) {
var t = this.target,
isFunc = (typeof(t[prop]) === "function"),
alt = isFunc ? this._altProp(prop) : prop,
vp = this._firstVP;
this._firstVP = this._lookup[prop] = this._lookup[alt] = vp = new VelocityProp((alt !== prop && prop.indexOf("set") === 0) ? alt : prop, isFunc, vp);
vp.css = (this.elem && (this.target.style[vp.p] !== undefined || _transforms[vp.p]));
if (vp.css && _transforms[vp.p] && !t._gsTransform) {
TweenLite.set(t, {x:"+=0", overwrite:false}); //just forces CSSPlugin to create a _gsTransform for the element if it doesn't exist
}
vp.type = type || (vp.css && prop.indexOf("rotation") === 0) ? "deg" : "";
vp.v1 = vp.v2 = vp.css ? _getStyle(t, vp.p) : isFunc ? t[vp.p]() : t[vp.p];
}
};
p.removeProp = function(prop) {
var vp = this._lookup[prop];
if (vp) {
if (vp._prev) {
vp._prev._next = vp._next;
} else if (vp === this._firstVP) {
this._firstVP = vp._next;
}
if (vp._next) {
vp._next._prev = vp._prev;
}
this._lookup[prop] = 0;
if (vp.f) {
this._lookup[this._altProp(prop)] = 0; //if it's a getter/setter, we should remove the matching counterpart (if one exists)
}
}
};
p.isTrackingProp = function(prop) {
return (this._lookup[prop] instanceof VelocityProp);
};
p.getVelocity = function(prop) {
var vp = this._lookup[prop],
target = this.target,
val, dif, rotationCap;
if (!vp) {
throw "The velocity of " + prop + " is not being tracked.";
}
val = vp.css ? _getStyle(target, vp.p) : vp.f ? target[vp.p]() : target[vp.p];
dif = (val - vp.v2);
if (vp.type === "rad" || vp.type === "deg") { //rotational values need special interpretation so that if, for example, they go from 179 to -178 degrees it is interpreted as a change of 3 instead of -357.
rotationCap = (vp.type === "rad") ? Math.PI * 2 : 360;
dif = dif % rotationCap;
if (dif !== dif % (rotationCap / 2)) {
dif = (dif < 0) ? dif + rotationCap : dif - rotationCap;
}
}
return dif / (_ticker.time - vp.t2);
};
p._altProp = function(p) { //for getters/setters like getCustomProp() and setCustomProp() - we should accommodate both
var pre = p.substr(0, 3),
alt = ((pre === "get") ? "set" : (pre === "set") ? "get" : pre) + p.substr(3);
return (typeof(this.target[alt]) === "function") ? alt : p;
};
VelocityTracker.getByTarget = function(target) {
var vt = _first;
if (typeof(target) === "string") {
target = TweenLite.selector(target);
}
if (target.length && target !== window && target[0] && target[0].style && !target.nodeType) {
target = target[0];
}
while (vt) {
if (vt.target === target) {
return vt;
}
vt = vt._next;
}
};
VelocityTracker.track = function(target, props, types) {
var vt = getByTarget(target),
a = props.split(","),
i = a.length;
types = (types || "").split(",");
if (!vt) {
vt = new VelocityTracker(target);
}
while (--i > -1) {
vt.addProp(a[i], types[i] || types[0]);
}
return vt;
};
VelocityTracker.untrack = function(target, props) {
var vt = getByTarget(target),
a = (props || "").split(","),
i = a.length;
if (!vt) {
return;
}
while (--i > -1) {
vt.removeProp(a[i]);
}
if (!vt._firstVP || !props) {
if (vt._prev) {
vt._prev._next = vt._next;
} else if (vt === _first) {
_first = vt._next;
}
if (vt._next) {
vt._next._prev = vt._prev;
}
}
};
VelocityTracker.isTracking = function(target, prop) {
var vt = getByTarget(target);
return (!vt) ? false : (!prop && vt._firstVP) ? true : vt.isTrackingProp(prop);
};
return VelocityTracker;
}, true);
export var ThrowPropsPlugin = globals.ThrowPropsPlugin;
export { ThrowPropsPlugin as default };
export var VelocityTracker = globals.com.greensock.utils.VelocityTracker;
@@ -0,0 +1,167 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-02-15
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, 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
**/
/* eslint-disable */
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("easing.CustomBounce", ["easing.CustomEase"], function(CustomEase) {
var _normalizeX = function (a) { //scales all the x values in an array [x, y, x, y...] AND rounds them to the closest hundredth (decimal)
var l = a.length,
s = 1 / a[l - 2],
rnd = 1000,
i;
for (i = 2; i < l; i += 2) {
a[i] = ((a[i] * s * rnd) | 0) / rnd;
}
a[l - 2] = 1; //in case there are any rounding errors. x should always end at 1.
},
CustomBounce = function(id, vars) {
this.vars = vars = vars || {};
if (vars.squash) {
this.squash = new CustomEase(vars.squashID || (id + "-squash"));
}
CustomEase.call(this, id);
this.bounce = this;
this.update(vars);
},
p;
CustomBounce.prototype = p = new CustomEase();
p.constructor = CustomBounce;
p.update = function(vars) {
vars = vars || this.vars;
var max = 0.999,
decay = Math.min(max, vars.strength || 0.7), // Math.min(0.999, 1 - 0.3 / (vars.strength || 1)),
decayX = decay,
gap = (vars.squash || 0) / 100,
originalGap = gap,
slope = 1 / 0.03,
w = 0.2,
h = 1,
prevX = 0.1,
path = [0, 0, 0.07, 0, 0.1, 1, 0.1, 1],
squashPath = [0, 0, 0, 0, 0.1, 0, 0.1, 0],
cp1, cp2, x, y, i, nextX, squishMagnitude;
for (i = 0; i < 200; i++) {
w *= decayX * ((decayX + 1) / 2);
h *= decay * decay;
nextX = prevX + w;
x = prevX + w * 0.49;
y = 1 - h;
cp1 = prevX + h / slope;
cp2 = x + (x - cp1) * 0.8;
if (gap) {
prevX += gap;
cp1 += gap;
x += gap;
cp2 += gap;
nextX += gap;
squishMagnitude = gap / originalGap;
squashPath.push(
prevX - gap, 0,
prevX - gap, squishMagnitude,
prevX - gap / 2, squishMagnitude, //center peak anchor
prevX, squishMagnitude,
prevX, 0,
prevX, 0, //base anchor
prevX, squishMagnitude * -0.6,
prevX + (nextX - prevX) / 6, 0,
nextX, 0
);
path.push(prevX - gap, 1,
prevX, 1,
prevX, 1);
gap *= decay * decay;
}
path.push(prevX, 1,
cp1, y,
x, y,
cp2, y,
nextX, 1,
nextX, 1);
decay *= 0.95;
slope = h / (nextX - cp2);
prevX = nextX;
if (y > max) {
break;
}
}
if (vars.endAtStart) {
x = -0.1;
path.unshift(x, 1, x, 1, -0.07, 0);
if (originalGap) {
gap = originalGap * 2.5; //make the initial anticipation squash longer (more realistic)
x -= gap;
path.unshift(x, 1, x, 1, x, 1);
squashPath.splice(0, 6);
squashPath.unshift(x, 0, x, 0, x, 1, x + gap / 2, 1, x + gap, 1, x + gap, 0, x + gap, 0, x + gap, -0.6, x + gap + 0.033, 0);
for (i = 0; i < squashPath.length; i+=2) {
squashPath[i] -= x;
}
}
for (i = 0; i < path.length; i+=2) {
path[i] -= x;
path[i+1] = 1 - path[i+1];
}
}
if (gap) {
_normalizeX(squashPath);
squashPath[2] = "C" + squashPath[2];
if (!this.squash) {
this.squash = new CustomEase(vars.squashID || (this.id + "-squash"));
}
this.squash.setData("M" + squashPath.join(","));
}
_normalizeX(path);
path[2] = "C" + path[2];
return this.setData("M" + path.join(","));
};
CustomBounce.create = function(id, vars) {
return new CustomBounce(id, vars);
};
CustomBounce.version = "0.2.1";
return CustomBounce;
}, true);
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("./CustomEase");
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite", "./CustomEase"], getGlobal);
}
}("CustomBounce"));
@@ -0,0 +1,394 @@
/*!
* VERSION: 0.2.2
* DATE: 2018-02-15
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, 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
**/
/* eslint-disable */
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("easing.CustomEase", ["easing.Ease"], function(Ease) {
var _numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_svgPathExp = /[achlmqstvz]|(-?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_scientific = /[\+\-]?\d*\.?\d+e[\+\-]?\d+/ig,
_needsParsingExp = /[cLlsS]/g,
_bezierError = "CustomEase only accepts Cubic Bezier data.",
_bezierToPoints = function (x1, y1, x2, y2, x3, y3, x4, y4, threshold, points, index) {
var x12 = (x1 + x2) / 2,
y12 = (y1 + y2) / 2,
x23 = (x2 + x3) / 2,
y23 = (y2 + y3) / 2,
x34 = (x3 + x4) / 2,
y34 = (y3 + y4) / 2,
x123 = (x12 + x23) / 2,
y123 = (y12 + y23) / 2,
x234 = (x23 + x34) / 2,
y234 = (y23 + y34) / 2,
x1234 = (x123 + x234) / 2,
y1234 = (y123 + y234) / 2,
dx = x4 - x1,
dy = y4 - y1,
d2 = Math.abs((x2 - x4) * dy - (y2 - y4) * dx),
d3 = Math.abs((x3 - x4) * dy - (y3 - y4) * dx),
length;
if (!points) {
points = [{x: x1, y: y1}, {x: x4, y: y4}];
index = 1;
}
points.splice(index || points.length - 1, 0, {x: x1234, y: y1234});
if ((d2 + d3) * (d2 + d3) > threshold * (dx * dx + dy * dy)) {
length = points.length;
_bezierToPoints(x1, y1, x12, y12, x123, y123, x1234, y1234, threshold, points, index);
_bezierToPoints(x1234, y1234, x234, y234, x34, y34, x4, y4, threshold, points, index + 1 + (points.length - length));
}
return points;
},
_pathDataToBezier = function (d) {
var a = (d + "").replace(_scientific, function (m) {
var n = +m;
return (n < 0.0001 && n > -0.0001) ? 0 : n;
}).match(_svgPathExp) || [], //some authoring programs spit out very small numbers in scientific notation like "1e-5", so make sure we round that down to 0 first.
path = [],
relativeX = 0,
relativeY = 0,
elements = a.length,
l = 2,
i, x, y, command, isRelative, segment, startX, startY, prevCommand, difX, difY;
for (i = 0; i < elements; i++) {
prevCommand = command;
if (isNaN(a[i])) {
command = a[i].toUpperCase();
isRelative = (command !== a[i]); //lower case means relative
} else { //commands like "C" can be strung together without any new command characters between.
i--;
}
x = +a[i + 1];
y = +a[i + 2];
if (isRelative) {
x += relativeX;
y += relativeY;
}
if (!i) {
startX = x;
startY = y;
}
if (command === "M") {
if (segment && segment.length < 8) { //if the path data was funky and just had a M with no actual drawing anywhere, skip it.
path.length -= 1;
l = 0;
}
relativeX = startX = x;
relativeY = startY = y;
segment = [x, y];
l = 2;
path.push(segment);
i += 2;
command = "L"; //an "M" with more than 2 values gets interpreted as "lineTo" commands ("L").
} else if (command === "C") {
if (!segment) {
segment = [0, 0];
}
segment[l++] = x;
segment[l++] = y;
if (!isRelative) {
relativeX = relativeY = 0;
}
segment[l++] = relativeX + a[i + 3] * 1; //note: "*1" is just a fast/short way to cast the value as a Number. WAAAY faster in Chrome, slightly slower in Firefox.
segment[l++] = relativeY + a[i + 4] * 1;
segment[l++] = relativeX = relativeX + a[i + 5] * 1;
segment[l++] = relativeY = relativeY + a[i + 6] * 1;
i += 6;
} else if (command === "S") {
if (prevCommand === "C" || prevCommand === "S") {
difX = relativeX - segment[l - 4];
difY = relativeY - segment[l - 3];
segment[l++] = relativeX + difX;
segment[l++] = relativeY + difY;
} else {
segment[l++] = relativeX;
segment[l++] = relativeY;
}
segment[l++] = x;
segment[l++] = y;
if (!isRelative) {
relativeX = relativeY = 0;
}
segment[l++] = relativeX = relativeX + a[i + 3] * 1;
segment[l++] = relativeY = relativeY + a[i + 4] * 1;
i += 4;
} else if (command === "L" || command === "Z") {
if (command === "Z") {
x = startX;
y = startY;
segment.closed = true;
}
if (command === "L" || Math.abs(relativeX - x) > 0.5 || Math.abs(relativeY - y) > 0.5) {
segment[l++] = relativeX + (x - relativeX) / 3;
segment[l++] = relativeY + (y - relativeY) / 3;
segment[l++] = relativeX + (x - relativeX) * 2 / 3;
segment[l++] = relativeY + (y - relativeY) * 2 / 3;
segment[l++] = x;
segment[l++] = y;
if (command === "L") {
i += 2;
}
}
relativeX = x;
relativeY = y;
} else {
throw _bezierError;
}
}
return path[0];
},
_findMinimum = function (values) {
var l = values.length,
min = 999999999999,
i;
for (i = 1; i < l; i += 6) {
if (+values[i] < min) {
min = +values[i];
}
}
return min;
},
_normalize = function (values, height, originY) { //takes all the points and translates/scales them so that the x starts at 0 and ends at 1.
if (!originY && originY !== 0) {
originY = Math.max(+values[values.length-1], +values[1]);
}
var tx = +values[0] * -1,
ty = -originY,
l = values.length,
sx = 1 / (+values[l - 2] + tx),
sy = -height || ((Math.abs(+values[l - 1] - +values[1]) < 0.01 * (+values[l - 2] - +values[0])) ? _findMinimum(values) + ty : +values[l - 1] + ty),
i;
if (sy) { //typically y ends at 1 (so that the end values are reached)
sy = 1 / sy;
} else { //in case the ease returns to its beginning value, scale everything proportionally
sy = -sx;
}
for (i = 0; i < l; i += 2) {
values[i] = (+values[i] + tx) * sx;
values[i + 1] = (+values[i + 1] + ty) * sy;
}
},
_getRatio = function (p) {
var point = this.lookup[(p * this.l) | 0] || this.lookup[this.l - 1];
if (point.nx < p) {
point = point.n;
}
return point.y + ((p - point.x) / point.cx) * point.cy;
},
CustomEase = function (id, data, config) {
this._calcEnd = true;
this.id = id;
if (id) {
Ease.map[id] = this;
}
this.getRatio = _getRatio; //speed optimization, faster lookups.
this.setData(data, config);
},
p = CustomEase.prototype = new Ease();
p.constructor = CustomEase;
p.setData = function(data, config) {
data = data || "0,0,1,1";
var values = data.match(_numbersExp),
closest = 1,
points = [],
l, a1, a2, i, inc, j, point, prevPoint, p, precision;
config = config || {};
precision = config.precision || 1;
this.data = data;
this.lookup = [];
this.points = points;
this.fast = (precision <= 1);
if (_needsParsingExp.test(data) || (data.indexOf("M") !== -1 && data.indexOf("C") === -1)) {
values = _pathDataToBezier(data);
}
l = values.length;
if (l === 4) {
values.unshift(0, 0);
values.push(1, 1);
l = 8;
} else if ((l - 2) % 6) {
throw _bezierError;
}
if (+values[0] !== 0 || +values[l - 2] !== 1) {
_normalize(values, config.height, config.originY);
}
this.rawBezier = values;
for (i = 2; i < l; i += 6) {
a1 = {x: +values[i - 2], y: +values[i - 1]};
a2 = {x: +values[i + 4], y: +values[i + 5]};
points.push(a1, a2);
_bezierToPoints(a1.x, a1.y, +values[i], +values[i + 1], +values[i + 2], +values[i + 3], a2.x, a2.y, 1 / (precision * 200000), points, points.length - 1);
}
l = points.length;
for (i = 0; i < l; i++) {
point = points[i];
prevPoint = points[i - 1] || point;
if (point.x > prevPoint.x || (prevPoint.y !== point.y && prevPoint.x === point.x) || point === prevPoint) { //if a point goes BACKWARD in time or is a duplicate, just drop it.
prevPoint.cx = point.x - prevPoint.x; //change in x between this point and the next point (performance optimization)
prevPoint.cy = point.y - prevPoint.y;
prevPoint.n = point;
prevPoint.nx = point.x; //next point's x value (performance optimization, making lookups faster in getRatio()). Remember, the lookup will always land on a spot where it's either this point or the very next one (never beyond that)
if (this.fast && i > 1 && Math.abs(prevPoint.cy / prevPoint.cx - points[i - 2].cy / points[i - 2].cx) > 2) { //if there's a sudden change in direction, prioritize accuracy over speed. Like a bounce ease - you don't want to risk the sampling chunks landing on each side of the bounce anchor and having it clipped off.
this.fast = false;
}
if (prevPoint.cx < closest) {
if (!prevPoint.cx) {
prevPoint.cx = 0.001; //avoids math problems in getRatio() (dividing by zero)
if (i === l - 1) { //in case the final segment goes vertical RIGHT at the end, make sure we end at the end.
prevPoint.x -= 0.001;
closest = Math.min(closest, 0.001);
this.fast = false;
}
} else {
closest = prevPoint.cx;
}
}
} else {
points.splice(i--, 1);
l--;
}
}
l = (1 / closest + 1) | 0;
this.l = l; //record for speed optimization
inc = 1 / l;
j = 0;
point = points[0];
if (this.fast) {
for (i = 0; i < l; i++) { //for fastest lookups, we just sample along the path at equal x (time) distance. Uses more memory and is slightly less accurate for anchors that don't land on the sampling points, but for the vast majority of eases it's excellent (and fast).
p = i * inc;
if (point.nx < p) {
point = points[++j];
}
a1 = point.y + ((p - point.x) / point.cx) * point.cy;
this.lookup[i] = {x: p, cx: inc, y: a1, cy: 0, nx: 9};
if (i) {
this.lookup[i - 1].cy = a1 - this.lookup[i - 1].y;
}
}
this.lookup[l - 1].cy = points[points.length - 1].y - a1;
} else { //this option is more accurate, ensuring that EVERY anchor is hit perfectly. Clipping across a bounce, for example, would never happen.
for (i = 0; i < l; i++) { //build a lookup table based on the smallest distance so that we can instantly find the appropriate point (well, it'll either be that point or the very next one). We'll look up based on the linear progress. So it's it's 0.5 and the lookup table has 100 elements, it'd be like lookup[Math.floor(0.5 * 100)]
if (point.nx < i * inc) {
point = points[++j];
}
this.lookup[i] = point;
}
if (j < points.length - 1) {
this.lookup[i-1] = points[points.length-2];
}
}
this._calcEnd = (points[points.length-1].y !== 1 || points[0].y !== 0); //ensures that we don't run into floating point errors. As long as we're starting at 0 and ending at 1, tell GSAP to skip the final calculation and use 0/1 as the factor.
return this;
};
p.getRatio = _getRatio;
p.getSVGData = function(config) {
return CustomEase.getSVGData(this, config);
};
CustomEase.create = function (id, data, config) {
return new CustomEase(id, data, config);
};
CustomEase.version = "0.2.2";
CustomEase.bezierToPoints = _bezierToPoints;
CustomEase.get = function (id) {
return Ease.map[id];
};
CustomEase.getSVGData = function(ease, config) {
config = config || {};
var rnd = 1000,
width = config.width || 100,
height = config.height || 100,
x = config.x || 0,
y = (config.y || 0) + height,
e = config.path,
a, slope, i, inc, tx, ty, precision, threshold, prevX, prevY;
if (config.invert) {
height = -height;
y = 0;
}
ease = ease.getRatio ? ease : Ease.map[ease] || console.log("No ease found: ", ease);
if (!ease.rawBezier) {
a = ["M" + x + "," + y];
precision = Math.max(5, (config.precision || 1) * 200);
inc = 1 / precision;
precision += 2;
threshold = 5 / precision;
prevX = (((x + inc * width) * rnd) | 0) / rnd;
prevY = (((y + ease.getRatio(inc) * -height) * rnd) | 0) / rnd;
slope = (prevY - y) / (prevX - x);
for (i = 2; i < precision; i++) {
tx = (((x + i * inc * width) * rnd) | 0) / rnd;
ty = (((y + ease.getRatio(i * inc) * -height) * rnd) | 0) / rnd;
if (Math.abs((ty - prevY) / (tx - prevX) - slope) > threshold || i === precision - 1) { //only add points when the slope changes beyond the threshold
a.push(prevX + "," + prevY);
slope = (ty - prevY) / (tx - prevX);
}
prevX = tx;
prevY = ty;
}
} else {
a = [];
precision = ease.rawBezier.length;
for (i = 0; i < precision; i += 2) {
a.push((((x + ease.rawBezier[i] * width) * rnd) | 0) / rnd + "," + (((y + ease.rawBezier[i + 1] * -height) * rnd) | 0) / rnd);
}
a[0] = "M" + a[0];
a[1] = "C" + a[1];
}
if (e) {
(typeof(e) === "string" ? document.querySelector(e) : e).setAttribute("d", a.join(" "));
}
return a.join(" ");
};
return CustomEase;
}, true);
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite"], getGlobal);
}
}("CustomEase"));
@@ -0,0 +1,128 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-02-15
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, 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
**/
/* eslint-disable */
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("easing.CustomWiggle", ["easing.CustomEase", "easing.Ease"], function(CustomEase, Ease) {
var eases = {
easeOut: new CustomEase("", "M0,1,C0.7,1,0.6,0,1,0"),
easeInOut: new CustomEase("", "M0,0,C0.104,0,0.242,1,0.444,1,0.644,1,0.608,0,1,0"),
anticipate: new CustomEase("", "M0,0,C0,0.222,0.024,0.386,0.06,0.402,0.181,0.455,0.647,0.646,0.7,0.67,0.9,0.76,1,0.846,1,1"),
uniform: new CustomEase("", "M0,0,C0,0.95,0.01,1,0.01,1,0.01,1,1,1,1,1,1,1,1,0.01,1,0")
},
_linearEase = new CustomEase(), //linear
_parseEase = function(ease, invertNonCustomEases) {
ease = ease.getRatio ? ease : Ease.map[ease] || new CustomEase("", ease);
return (ease.rawBezier || !invertNonCustomEases) ? ease : {getRatio:function(n) { return 1 - ease.getRatio(n); }};
},
CustomWiggle = function(id, vars) {
this.vars = vars || {};
CustomEase.call(this, id);
this.update(this.vars);
},
p;
CustomWiggle.prototype = p = new CustomEase();
p.constructor = CustomWiggle;
p.update = function(vars) {
vars = vars || this.vars;
var wiggles = (vars.wiggles || 10) | 0,
inc = 1 / wiggles,
x = inc / 2,
anticipate = (vars.type === "anticipate"),
yEase = eases[vars.type] || eases.easeOut,
xEase = _linearEase,
rnd = 1000,
nextX, nextY, angle, handleX, handleY, easedX, y, path, i;
if (anticipate) { //the anticipate ease is actually applied on the x-axis (timing) and uses easeOut for amplitude.
xEase = yEase;
yEase = eases.easeOut;
}
if (vars.timingEase) {
xEase = _parseEase(vars.timingEase);
}
if (vars.amplitudeEase) {
yEase = _parseEase(vars.amplitudeEase, true);
}
easedX = xEase.getRatio(x);
y = anticipate ? -yEase.getRatio(x) : yEase.getRatio(x);
path = [0, 0, easedX / 4, 0, easedX / 2, y, easedX, y];
if (vars.type === "random") { //if we just select random values on the y-axis and plug them into the "normal" algorithm, since the control points are always straight horizontal, it creates a bit of a slowdown at each anchor which just didn't seem as desirable, so we switched to an algorithm that bends the control points to be more in line with their context.
path.length = 4;
nextX = xEase.getRatio(inc);
nextY = Math.random() * 2 - 1;
for (i = 2; i < wiggles; i++) {
x = nextX;
y = nextY;
nextX = xEase.getRatio(inc * i);
nextY = Math.random() * 2 - 1;
angle = Math.atan2(nextY - path[path.length - 3], nextX - path[path.length - 4]);
handleX = Math.cos(angle) * inc;
handleY = Math.sin(angle) * inc;
path.push(x - handleX, y - handleY, x, y, x + handleX, y + handleY);
}
path.push(nextX, 0, 1, 0);
} else {
for (i = 1; i < wiggles; i++) {
path.push(xEase.getRatio(x + inc / 2), y);
x += inc;
y = ((y > 0) ? -1 : 1) * (yEase.getRatio(i * inc));
easedX = xEase.getRatio(x);
path.push(xEase.getRatio(x - inc / 2), y, easedX, y);
}
path.push(xEase.getRatio(x + inc / 4), y, xEase.getRatio(x + inc / 4), 0, 1, 0);
}
i = path.length;
while (--i > -1) {
path[i] = ((path[i] * rnd) | 0) / rnd; //round values to avoid odd strings for super tiny values
}
path[2] = "C" + path[2];
this.setData("M" + path.join(","));
};
CustomWiggle.create = function (id, vars) {
return new CustomWiggle(id, vars);
};
CustomWiggle.version = "0.2.1";
CustomWiggle.eases = eases;
return CustomWiggle;
}, true);
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("./CustomEase");
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite", "./CustomEase"], getGlobal);
}
}("CustomWiggle"));
@@ -0,0 +1,245 @@
/*!
* VERSION: 0.2.1
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* DrawSVGPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
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";
var _doc = _gsScope.document,
_computedStyleScope = (typeof(window) !== "undefined" ? window : _doc.defaultView || {getComputedStyle:function() {}}),
_getComputedStyle = function(e) {
return _computedStyleScope.getComputedStyle(e); //to avoid errors in Microsoft Edge, we need to call getComputedStyle() from a specific scope, typically window.
},
_numbersExp = /(?:(-|-=|\+=)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_isEdge = (((_gsScope.navigator || {}).userAgent || "").indexOf("Edge") !== -1), //Microsoft Edge has a bug that causes it not to redraw the path correctly if the stroke-linecap is anything other than "butt" (like "round") and it doesn't match the stroke-linejoin. A way to trigger it is to change the stroke-miterlimit, so we'll only do that if/when we have to (to maximize performance)
_types = {rect:["width","height"], circle:["r","r"], ellipse:["rx","ry"], line:["x2","y2"]},
DrawSVGPlugin;
function getDistance(x1, y1, x2, y2, scaleX, scaleY) {
x2 = (parseFloat(x2 || 0) - parseFloat(x1 || 0)) * scaleX;
y2 = (parseFloat(y2 || 0) - parseFloat(y1 || 0)) * scaleY;
return Math.sqrt(x2 * x2 + y2 * y2);
}
function unwrap(element) {
if (typeof(element) === "string" || !element.nodeType) {
element = _gsScope.TweenLite.selector(element);
if (element.length) {
element = element[0];
}
}
return element;
}
//accepts values like "100%" or "20% 80%" or "20 50" and parses it into an absolute start and end position on the line/stroke based on its length. Returns an an array with the start and end values, like [0, 243]
function parse(value, length, defaultStart) {
var i = value.indexOf(" "),
s, e;
if (i === -1) {
s = defaultStart !== undefined ? defaultStart + "" : value;
e = value;
} else {
s = value.substr(0, i);
e = value.substr(i+1);
}
s = (s.indexOf("%") !== -1) ? (parseFloat(s) / 100) * length : parseFloat(s);
e = (e.indexOf("%") !== -1) ? (parseFloat(e) / 100) * length : parseFloat(e);
return (s > e) ? [e, s] : [s, e];
}
function getLength(element) {
if (!element) {
return 0;
}
element = unwrap(element);
var type = element.tagName.toLowerCase(),
scaleX = 1,
scaleY = 1,
length, bbox, points, prevPoint, i, rx, ry;
if (element.getAttribute("vector-effect") === "non-scaling-stroke") { //non-scaling-stroke basically scales the shape and then strokes it at the screen-level (after transforms), thus we need to adjust the length accordingly.
scaleY = element.getScreenCTM();
scaleX = Math.sqrt(scaleY.a * scaleY.a + scaleY.b * scaleY.b);
scaleY = Math.sqrt(scaleY.d * scaleY.d + scaleY.c * scaleY.c);
}
try { //IE bug: calling <path>.getTotalLength() locks the repaint area of the stroke to whatever its current dimensions are on that frame/tick. To work around that, we must call getBBox() to force IE to recalculate things.
bbox = element.getBBox(); //solely for fixing bug in IE - we don't actually use the bbox.
} catch (e) {
//firefox has a bug that throws an error if the element isn't visible.
console.log("Error: Some browsers like Firefox won't report measurements of invisible elements (like display:none or masks inside defs).");
}
if ((!bbox || (!bbox.width && !bbox.height)) && _types[type]) { //if the element isn't visible, try to discern width/height using its attributes.
bbox = {
width: parseFloat( element.getAttribute(_types[type][0]) ),
height: parseFloat( element.getAttribute(_types[type][1]) )
};
if (type !== "rect" && type !== "line") { //double the radius for circles and ellipses
bbox.width *= 2;
bbox.height *= 2;
}
if (type === "line") {
bbox.x = parseFloat( element.getAttribute("x1") );
bbox.y = parseFloat( element.getAttribute("y1") );
bbox.width = Math.abs(bbox.width - bbox.x);
bbox.height = Math.abs(bbox.height - bbox.y);
}
}
if (type === "path") {
prevPoint = element.style.strokeDasharray;
element.style.strokeDasharray = "none";
length = element.getTotalLength() || 0;
if (scaleX !== scaleY) {
console.log("Warning: <path> length cannot be measured accurately when vector-effect is non-scaling-stroke and the element isn't proportionally scaled.");
}
length *= (scaleX + scaleY) / 2;
element.style.strokeDasharray = prevPoint;
} else if (type === "rect") {
length = bbox.width * 2 * scaleX + bbox.height * 2 * scaleY;
} else if (type === "line") {
length = getDistance(bbox.x, bbox.y, bbox.x + bbox.width, bbox.y + bbox.height, scaleX, scaleY);
} else if (type === "polyline" || type === "polygon") {
points = element.getAttribute("points").match(_numbersExp) || [];
if (type === "polygon") {
points.push(points[0], points[1]);
}
length = 0;
for (i = 2; i < points.length; i+=2) {
length += getDistance(points[i-2], points[i-1], points[i], points[i+1], scaleX, scaleY) || 0;
}
} else if (type === "circle" || type === "ellipse") {
rx = (bbox.width / 2) * scaleX;
ry = (bbox.height / 2) * scaleY;
length = Math.PI * ( 3 * (rx + ry) - Math.sqrt((3 * rx + ry) * (rx + 3 * ry)) );
}
return length || 0;
}
function getPosition(element, length) {
if (!element) {
return [0, 0];
}
element = unwrap(element);
length = length || (getLength(element) + 1);
var cs = _getComputedStyle(element),
dash = cs.strokeDasharray || "",
offset = parseFloat(cs.strokeDashoffset),
i = dash.indexOf(",");
if (i < 0) {
i = dash.indexOf(" ");
}
dash = (i < 0) ? length : parseFloat(dash.substr(0, i)) || 0.00001;
if (dash > length) {
dash = length;
}
return [Math.max(0, -offset), Math.max(0, dash - offset)];
}
DrawSVGPlugin = _gsScope._gsDefine.plugin({
propName: "drawSVG",
API: 2,
version: "0.2.1",
global: true,
overwriteProps: ["drawSVG"],
init: function(target, value, tween, index) {
if (!target.getBBox) {
return false;
}
var length = getLength(target) + 1,
start, end, overage, cs;
this._style = target.style;
this._target = target;
if (typeof(value) === "function") {
value = value(index, target);
}
if (value === true || value === "true") {
value = "0 100%";
} else if (!value) {
value = "0 0";
} else if ((value + "").indexOf(" ") === -1) {
value = "0 " + value;
}
start = getPosition(target, length);
end = parse(value, length, start[0]);
this._length = length + 10;
if (start[0] === 0 && end[0] === 0) {
overage = Math.max(0.00001, end[1] - length); //allow people to go past the end, like values of 105% because for some paths, Firefox doesn't return an accurate getTotalLength(), so it could end up coming up short.
this._dash = length + overage;
this._offset = length - start[1] + overage;
this._offsetPT = this._addTween(this, "_offset", this._offset, length - end[1] + overage, "drawSVG");
} else {
this._dash = (start[1] - start[0]) || 0.000001; //some browsers render artifacts if dash is 0, so we use a very small number in that case.
this._offset = -start[0];
this._dashPT = this._addTween(this, "_dash", this._dash, (end[1] - end[0]) || 0.00001, "drawSVG");
this._offsetPT = this._addTween(this, "_offset", this._offset, -end[0], "drawSVG");
}
if (_isEdge) { //to work around a bug in Microsoft Edge, animate the stroke-miterlimit by 0.0001 just to trigger the repaint (unnecessary if it's "round" and stroke-linejoin is also "round"). Imperceptible, relatively high-performance, and effective. Another option was to set the "d" <path> attribute to its current value on every tick, but that seems like it'd be much less performant.
cs = _getComputedStyle(target);
if (cs.strokeLinecap !== cs.strokeLinejoin) {
end = parseFloat(cs.strokeMiterlimit);
this._addTween(target.style, "strokeMiterlimit", end, end + 0.0001, "strokeMiterlimit");
}
}
this._live = (target.getAttribute("vector-effect") === "non-scaling-stroke" || (value + "").indexOf("live") !== -1);
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
if (this._firstPT) {
//when the element has vector-effect="non-scaling-stroke" and the SVG is resized (like on a window resize), it actually changes the length of the stroke! So we must sense that and make the proper adjustments.
if (this._live) {
var length = getLength(this._target) + 11,
lengthRatio;
if (length !== this._length) {
lengthRatio = length / this._length;
this._length = length;
this._offsetPT.s *= lengthRatio;
this._offsetPT.c *= lengthRatio;
if (this._dashPT) {
this._dashPT.s *= lengthRatio;
this._dashPT.c *= lengthRatio;
} else {
this._dash *= lengthRatio;
}
}
}
this._super.setRatio.call(this, ratio);
this._style.strokeDashoffset = this._offset;
if (ratio === 1 || ratio === 0) {
this._style.strokeDasharray = (this._offset < 0.001 && this._length - this._dash <= 10) ? "none" : (this._offset === this._dash) ? "0px, 999999px" : this._dash + "px," + this._length + "px";
} else {
this._style.strokeDasharray = this._dash + "px," + this._length + "px";
}
}
}
});
DrawSVGPlugin.getLength = getLength;
DrawSVGPlugin.getPosition = getPosition;
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite"], getGlobal);
}
}("DrawSVGPlugin"));
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,207 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-02-15
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* Physics2DPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
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";
var _DEG2RAD = Math.PI / 180,
Physics2DProp = function(target, p, velocity, acceleration, stepsPerTimeUnit) {
this.p = p;
this.f = (typeof(target[p]) === "function");
this.start = this.value = (!this.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
this.velocity = velocity || 0;
this.v = this.velocity / stepsPerTimeUnit;
if (acceleration || acceleration === 0) {
this.acceleration = acceleration;
this.a = this.acceleration / (stepsPerTimeUnit * stepsPerTimeUnit);
} else {
this.acceleration = this.a = 0;
}
},
_random = Math.random(),
_globals = _gsScope._gsDefine.globals,
_rootFramesTimeline = _globals.com.greensock.core.Animation._rootFramesTimeline,
Physics2DPlugin = _gsScope._gsDefine.plugin({
propName: "physics2D",
version: "0.2.1",
API: 2,
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
if (typeof(value) === "function") {
value = value(index, target);
}
this._target = target;
this._tween = tween;
this._runBackwards = (tween.vars.runBackwards === true);
this._step = 0;
var tl = tween._timeline,
angle = Number(value.angle) || 0,
velocity = Number(value.velocity) || 0,
acceleration = Number(value.acceleration) || 0,
xProp = value.xProp || "x",
yProp = value.yProp || "y",
aAngle = (value.accelerationAngle || value.accelerationAngle === 0) ? Number(value.accelerationAngle) : angle,
stepsPerTimeUnit;
while (tl._timeline) {
tl = tl._timeline;
}
this._stepsPerTimeUnit = stepsPerTimeUnit = (tl === _rootFramesTimeline) ? 1 : 30;
if (value.gravity) {
acceleration = Number(value.gravity);
aAngle = 90;
}
angle *= _DEG2RAD;
aAngle *= _DEG2RAD;
this._friction = 1 - Number(value.friction || 0);
this._overwriteProps.push(xProp);
this._overwriteProps.push(yProp);
this._x = new Physics2DProp(target, xProp, Math.cos(angle) * velocity, Math.cos(aAngle) * acceleration, stepsPerTimeUnit);
this._y = new Physics2DProp(target, yProp, Math.sin(angle) * velocity, Math.sin(aAngle) * acceleration, stepsPerTimeUnit);
this._skipX = this._skipY = false;
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
var time = this._tween._time,
xp = this._x,
yp = this._y,
x, y, tt, steps, remainder, i;
if (this._runBackwards === true) {
time = this._tween._duration - time;
}
if (this._friction === 1) {
tt = time * time * 0.5;
x = xp.start + ((xp.velocity * time) + (xp.acceleration * tt));
y = yp.start + ((yp.velocity * time) + (yp.acceleration * tt));
} else {
time *= this._stepsPerTimeUnit;
steps = i = (time | 0) - this._step;
remainder = (time % 1);
if (i >= 0) { //going forward
while (--i > -1) {
xp.v += xp.a;
yp.v += yp.a;
xp.v *= this._friction;
yp.v *= this._friction;
xp.value += xp.v;
yp.value += yp.v;
}
} else { //going backwards
i = -i;
while (--i > -1) {
xp.value -= xp.v;
yp.value -= yp.v;
xp.v /= this._friction;
yp.v /= this._friction;
xp.v -= xp.a;
yp.v -= yp.a;
}
}
x = xp.value + (xp.v * remainder);
y = yp.value + (yp.v * remainder);
this._step += steps;
}
if (!this._skipX) {
if (xp.m) {
x = xp.m(x, this._target);
}
if (xp.f) {
this._target[xp.p](x);
} else {
this._target[xp.p] = x;
}
}
if (!this._skipY) {
if (yp.m) {
y = yp.m(y, this._target);
}
if (yp.f) {
this._target[yp.p](y);
} else {
this._target[yp.p] = y;
}
}
}
}),
p = Physics2DPlugin.prototype;
p._kill = function(lookup) {
if (lookup[this._x.p] != null) {
this._skipX = true;
}
if (lookup[this._y.p] != null) {
this._skipY = true;
}
return this._super._kill.call(this, lookup);
};
p._mod = function(lookup) {
var val = lookup[this._x.p] || lookup.physics2D;
if (val && typeof(val) === "function") {
this._x.m = val;
}
val = lookup[this._y.p] || lookup.physics2D;
if (val && typeof(val) === "function") {
this._y.m = val;
}
};
Physics2DPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
Physics2DPlugin._cssRegister = function() {
var CSSPlugin = _globals.CSSPlugin;
if (!CSSPlugin) {
return;
}
var _internals = CSSPlugin._internals,
_parseToProxy = _internals._parseToProxy,
_setPluginRatio = _internals._setPluginRatio,
CSSPropTween = _internals.CSSPropTween;
_internals._registerComplexSpecialProp("physics2D", {parser:function(t, e, prop, cssp, pt, plugin) {
plugin = new Physics2DPlugin();
var xProp = e.xProp || "x",
yProp = e.yProp || "y",
vars = {},
data;
vars[xProp] = vars[yProp] = _random++; //doesn't really matter what values we put here because the plugin will determine end values, but it'd be best of the values don't match the current ones so that CSSPlugin doesn't skip creating a CSSPropTween.
data = _parseToProxy(t, vars, cssp, pt, plugin);
pt = new CSSPropTween(t, "physics2D", 0, 0, data.pt, 2);
pt.data = data;
pt.plugin = plugin;
pt.setRatio = _setPluginRatio;
plugin._onInitTween(data.proxy, e, cssp._tween);
return pt;
}});
};
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite"], getGlobal);
}
}("Physics2DPlugin"));
@@ -0,0 +1,215 @@
/*!
* VERSION: 0.2.1
* DATE: 2018-02-15
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* PhysicsPropsPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
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";
var PhysicsProp = function(target, p, velocity, acceleration, friction, stepsPerTimeUnit) {
this.p = p;
this.f = (typeof(target[p]) === "function");
this.start = this.value = (!this.f) ? parseFloat(target[p]) : target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]();
this.velocity = velocity || 0;
this.v = this.velocity / stepsPerTimeUnit;
if (acceleration || acceleration == 0) {
this.acceleration = acceleration;
this.a = this.acceleration / (stepsPerTimeUnit * stepsPerTimeUnit);
} else {
this.acceleration = this.a = 0;
}
this.friction = 1 - (friction || 0) ;
},
_random = Math.random(),
_globals = _gsScope._gsDefine.globals,
_rootFramesTimeline = _globals.com.greensock.core.Animation._rootFramesTimeline,
PhysicsPropsPlugin = _gsScope._gsDefine.plugin({
propName: "physicsProps",
version: "0.2.1",
API: 2,
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
if (typeof(value) === "function") {
value = value(target);
}
this._target = target;
this._tween = tween;
this._runBackwards = (tween.vars.runBackwards === true);
this._step = 0;
var tl = tween._timeline,
cnt = 0,
p, curProp;
while (tl._timeline) {
tl = tl._timeline;
}
this._stepsPerTimeUnit = (tl === _rootFramesTimeline) ? 1 : 30;
this._props = [];
for (p in value) {
curProp = value[p];
if (typeof(curProp) === "function") {
curProp = curProp(index, target);
}
if (curProp.velocity || curProp.acceleration) {
this._props[cnt++] = new PhysicsProp(target, p, curProp.velocity, curProp.acceleration, curProp.friction, this._stepsPerTimeUnit);
this._overwriteProps[cnt] = p;
if (curProp.friction) {
this._hasFriction = true;
}
}
}
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
var i = this._props.length,
time = this._tween._time,
target = this._target,
curProp, val, steps, remainder, j, tt;
if (this._runBackwards) {
time = this._tween._duration - time;
}
if (this._hasFriction) {
time *= this._stepsPerTimeUnit;
steps = (time | 0) - this._step;
remainder = time % 1;
if (steps >= 0) { //going forward
while (--i > -1) {
curProp = this._props[i];
j = steps;
while (--j > -1) {
curProp.v += curProp.a;
curProp.v *= curProp.friction;
curProp.value += curProp.v;
}
val = curProp.value + (curProp.v * remainder);
if (curProp.m) {
val = curProp.m(val, target);
}
if (curProp.f) {
target[curProp.p](val);
} else {
target[curProp.p] = val;
}
}
} else { //going backwards
while (--i > -1) {
curProp = this._props[i];
j = -steps;
while (--j > -1) {
curProp.value -= curProp.v;
curProp.v /= curProp.friction;
curProp.v -= curProp.a;
}
val = curProp.value + (curProp.v * remainder);
if (curProp.m) {
val = curProp.m(val, target);
}
if (curProp.f) {
target[curProp.p](val);
} else {
target[curProp.p] = val;
}
}
}
this._step += steps;
} else {
tt = time * time * 0.5;
while (--i > -1) {
curProp = this._props[i];
val = curProp.start + ((curProp.velocity * time) + (curProp.acceleration * tt));
if (curProp.m) {
val = curProp.m(val, target);
}
if (curProp.f) {
target[curProp.p](val);
} else {
target[curProp.p] = val;
}
}
}
}
}),
p = PhysicsPropsPlugin.prototype;
p._kill = function(lookup) {
var i = this._props.length;
while (--i > -1) {
if (this._props[i].p in lookup) {
this._props.splice(i, 1);
}
}
return this._super._kill.call(this, lookup);
};
p._mod = function(lookup) {
var i = this._props.length,
val;
while (--i > -1) {
val = lookup[this._props[i].p] || lookup.physicsProps;
if (typeof(val) === "function") {
this._props[i].m = val;
}
}
};
PhysicsPropsPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
PhysicsPropsPlugin._cssRegister = function() {
var CSSPlugin = _globals.CSSPlugin;
if (!CSSPlugin) {
return;
}
var _internals = CSSPlugin._internals,
_parseToProxy = _internals._parseToProxy,
_setPluginRatio = _internals._setPluginRatio,
CSSPropTween = _internals.CSSPropTween;
_internals._registerComplexSpecialProp("physicsProps", {parser:function(t, e, prop, cssp, pt, plugin) {
plugin = new PhysicsPropsPlugin();
var vars = {},
p, data;
if (e.scale) {
e.scaleX = e.scaleY = e.scale;
delete e.scale;
}
for (p in e) {
vars[p] = _random++; //doesn't really matter what values we put here because the plugin will determine end values, but it'd be best of the values don't match the current ones so that CSSPlugin doesn't skip creating a CSSPropTween.
}
data = _parseToProxy(t, vars, cssp, pt, plugin);
pt = new CSSPropTween(t, "physicsProps", 0, 0, data.pt, 2);
pt.data = data;
pt.plugin = plugin;
pt.setRatio = _setPluginRatio;
plugin._onInitTween(data.proxy, e, cssp._tween);
return pt;
}});
};
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite"], getGlobal);
}
}("PhysicsPropsPlugin"));
@@ -0,0 +1,231 @@
/*!
* VERSION: 0.5.2
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* ScrambleTextPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
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";
var _trimExp = /(^\s+|\s+$)/g,
_spacesExp = /\s+/g,
_getText = function(e) {
var type = e.nodeType,
result = "";
if (type === 1 || type === 9 || type === 11) {
if (typeof(e.textContent) === "string") {
return e.textContent;
} else {
for (e = e.firstChild; e; e = e.nextSibling ) {
result += _getText(e);
}
}
} else if (type === 3 || type === 4) {
return e.nodeValue;
}
return result;
},
_scrambleText = function(length, chars) {
var l = chars.length,
s = "";
while (--length > -1) {
s += chars[ ((Math.random() * l) | 0) ];
}
return s;
},
CharSet = function(chars) {
this.chars = _emojiSafeSplit(chars);
this.sets = [];
this.length = 50;
var i;
for (i = 0; i < 20; i++) {
this.sets[i] = _scrambleText(80, this.chars); //we create 20 strings that are 80 characters long, randomly chosen and pack them into an array. We then randomly choose the scrambled text from this array in order to greatly improve efficiency compared to creating new randomized text from scratch each and every time it's needed. This is a simple lookup whereas the other technique requires looping through as many times as there are characters needed, and calling Math.random() each time through the loop, building the string, etc.
}
this.grow = function(newLength) { //if we encounter a tween that has more than 80 characters, we'll need to add to the character sets accordingly. Once it's cached, it'll only need to grow again if we exceed that new length. Again, this is an efficiency tactic.
for (i = 0; i < 20; i++) {
this.sets[i] += _scrambleText(newLength - this.length, this.chars);
}
this.length = newLength;
};
},
_emoji = "[\uE000-\uF8FF]|\uD83C[\uDC00-\uDFFF]|\uD83D[\uDC00-\uDFFF]|[\u2694-\u2697]|\uD83E[\uDD10-\uDD5D]|[\uD800-\uDBFF][\uDC00-\uDFFF]",
_emojiExp = new RegExp(_emoji),
_emojiAndCharsExp = new RegExp(_emoji + "|.", "g"),
_emojiSafeSplit = function(text, delimiter, trim) {
if (trim) {
text = text.replace(_trimExp, "");
}
return ((delimiter === "" || !delimiter) && _emojiExp.test(text)) ? text.match(_emojiAndCharsExp) : text.split(delimiter || "");
},
_upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
_lower = _upper.toLowerCase(),
_charsLookup = {
upperCase: new CharSet(_upper),
lowerCase: new CharSet(_lower),
upperAndLowerCase: new CharSet(_upper + _lower)
},
ScrambleTextPlugin = _gsScope._gsDefine.plugin({
propName: "scrambleText",
version: "0.5.2",
API: 2,
overwriteProps:["scrambleText","text"],
//called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
init: function(target, value, tween, index) {
this._prop = ("innerHTML" in target) ? "innerHTML" : ("textContent" in target) ? "textContent" : 0; // SVG text in IE doesn't have innerHTML, but it does have textContent.
if (!this._prop) {
return false;
}
if (typeof(value) === "function") {
value = value(index, target);
}
this._target = target;
if (typeof(value) !== "object") {
value = {text:value};
}
var text = value.text || value.value,
trim = (value.trim !== false),
delim, maxLength, charset, splitByChars;
this._delimiter = delim = value.delimiter || "";
this._original = _emojiSafeSplit(_getText(target).replace(_spacesExp, " ").split("&nbsp;").join(""), delim, trim);
if (text === "{original}" || text === true || text == null) {
text = this._original.join(delim);
}
this._text = _emojiSafeSplit((text || "").replace(_spacesExp, " "), delim, trim);
this._hasClass = false;
if (typeof(value.newClass) === "string") {
this._newClass = value.newClass;
this._hasClass = true;
}
if (typeof(value.oldClass) === "string") {
this._oldClass = value.oldClass;
this._hasClass = true;
}
splitByChars = (delim === "");
this._textHasEmoji = (_emojiExp.test(this._text.join(delim)) && splitByChars);
this._charsHaveEmoji = !!value.chars && _emojiExp.test(value.chars);
this._length = splitByChars ? this._original.length : this._original.join(delim).length;
this._lengthDif = (splitByChars ? this._text.length : this._text.join(delim).length) - this._length;
this._fillChar = value.fillChar || (value.chars && value.chars.indexOf(" ") !== -1) ? "&nbsp;" : "";
this._charSet = charset = _charsLookup[(value.chars || "upperCase")] || new CharSet(value.chars);
this._speed = 0.016 / (value.speed || 1);
this._prevScrambleTime = 0;
this._setIndex = (Math.random() * 20) | 0;
maxLength = this._length + Math.max(this._lengthDif, 0);
if (maxLength > charset.length) {
charset.grow(maxLength);
}
this._chars = charset.sets[this._setIndex];
this._revealDelay = value.revealDelay || 0;
this._tweenLength = (value.tweenLength !== false);
this._tween = tween;
this._rightToLeft = !!value.rightToLeft;
return true;
},
//called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
set: function(ratio) {
var l = this._text.length,
delim = this._delimiter,
time = this._tween._time,
timeDif = time - this._prevScrambleTime,
i, i2, startText, endText, applyNew, applyOld, str, startClass, endClass;
if (this._revealDelay) {
if (this._tween.vars.runBackwards) {
time = this._tween._duration - time; //invert the time for from() tweens
}
ratio = (time === 0) ? 0 : (time < this._revealDelay) ? 0.000001 : (time === this._tween._duration) ? 1 : this._tween._ease.getRatio((time - this._revealDelay) / (this._tween._duration - this._revealDelay));
}
if (ratio < 0) {
ratio = 0;
} else if (ratio > 1) {
ratio = 1;
}
if (this._rightToLeft) {
ratio = 1 - ratio;
}
i = (ratio * l + 0.5) | 0;
if (ratio) {
if (timeDif > this._speed || timeDif < -this._speed) {
this._setIndex = (this._setIndex + ((Math.random() * 19) | 0)) % 20;
this._chars = this._charSet.sets[this._setIndex];
this._prevScrambleTime += timeDif;
}
endText = this._chars;
} else {
endText = this._original.join(delim);
}
if (this._rightToLeft) {
if (ratio === 1 && (this._tween.vars.runBackwards || this._tween.data === "isFromStart")) { //special case for from() tweens
startText = "";
endText = this._original.join(delim);
} else {
str = this._text.slice(i).join(delim);
if (this._charsHaveEmoji) {
startText = _emojiSafeSplit(endText).slice(0, ((this._length + (this._tweenLength ? 1 - (ratio * ratio * ratio) : 1) * this._lengthDif) - ((this._textHasEmoji ? _emojiSafeSplit(str) : str).length) + 0.5) | 0).join("");
} else {
startText = endText.substr(0, ((this._length + (this._tweenLength ? 1 - (ratio * ratio * ratio) : 1) * this._lengthDif) - ((this._textHasEmoji ? _emojiSafeSplit(str) : str).length) + 0.5) | 0);
}
endText = str;
}
} else {
startText = this._text.slice(0, i).join(delim);
i2 = (this._textHasEmoji ? _emojiSafeSplit(startText) : startText).length;
if (this._charsHaveEmoji) {
endText = _emojiSafeSplit(endText).slice(i2, ((this._length + (this._tweenLength ? 1 - ((ratio = 1 - ratio) * ratio * ratio * ratio) : 1) * this._lengthDif) + 0.5) | 0).join("");
} else {
endText = endText.substr(i2, ((this._length + (this._tweenLength ? 1 - ((ratio = 1 - ratio) * ratio * ratio * ratio) : 1) * this._lengthDif) - i2 + 0.5) | 0);
}
}
if (this._hasClass) {
startClass = this._rightToLeft ? this._oldClass : this._newClass;
endClass = this._rightToLeft ? this._newClass : this._oldClass;
applyNew = (startClass && i !== 0);
applyOld = (endClass && i !== l);
str = (applyNew ? "<span class='" + startClass + "'>" : "") + startText + (applyNew ? "</span>" : "") + (applyOld ? "<span class='" + endClass + "'>" : "") + delim + endText + (applyOld ? "</span>" : "");
} else {
str = startText + delim + endText;
}
this._target[this._prop] = (this._fillChar === "&nbsp;" && str.indexOf(" ") !== -1) ? str.split(" ").join("&nbsp;&nbsp;") : str;
}
}),
p = ScrambleTextPlugin.prototype;
p._newClass = p._oldClass = "";
for (p in _charsLookup) {
_charsLookup[p.toLowerCase()] = _charsLookup[p];
_charsLookup[p.toUpperCase()] = _charsLookup[p];
}
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite"], getGlobal);
}
}("ScrambleTextPlugin"));
@@ -0,0 +1,573 @@
/*!
* VERSION: 0.7.0
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* SplitText is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node
(function(window) {
"use strict";
var _globals = window.GreenSockGlobals || window,
_namespace = function(ns) {
var a = ns.split("."),
p = _globals, i;
for (i = 0; i < a.length; i++) {
p[a[i]] = p = p[a[i]] || {};
}
return p;
},
pkg = _namespace("com.greensock.utils"),
_getText = function(e) {
var type = e.nodeType,
result = "";
if (type === 1 || type === 9 || type === 11) {
if (typeof(e.textContent) === "string") {
return e.textContent;
} else {
for ( e = e.firstChild; e; e = e.nextSibling ) {
result += _getText(e);
}
}
} else if (type === 3 || type === 4) {
return e.nodeValue;
}
return result;
},
_doc = _gsScope.document || {},
_computedStyleScope = (typeof(window) !== "undefined" ? window : _doc.defaultView || {getComputedStyle:function() {}}),
_getComputedStyle = function(e) {
return _computedStyleScope.getComputedStyle(e); //to avoid errors in Microsoft Edge, we need to call getComputedStyle() from a specific scope, typically window.
},
_capsExp = /([A-Z])/g,
_getStyle = function(t, p, cs, str) {
var result;
if ((cs = cs || _getComputedStyle(t, null))) {
t = cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
result = (t || cs.length) ? t : cs[p]; //Opera behaves VERY strangely - length is usually 0 and cs[p] is the only way to get accurate results EXCEPT when checking for -o-transform which only works with cs.getPropertyValue()!
} else if (t.currentStyle) {
cs = t.currentStyle;
result = cs[p];
}
return str ? result : parseInt(result, 10) || 0;
},
_isArrayLike = function(e) {
return (e.length && e[0] && ((e[0].nodeType && e[0].style && !e.nodeType) || (e[0].length && e[0][0]))) ? true : false; //could be an array of jQuery objects too, so accommodate that.
},
_flattenArray = function(a) {
var result = [],
l = a.length,
i, e, j;
for (i = 0; i < l; i++) {
e = a[i];
if (_isArrayLike(e)) {
j = e.length;
for (j = 0; j < e.length; j++) {
result.push(e[j]);
}
} else {
result.push(e);
}
}
return result;
},
//some characters are combining marks (think diacritics/accents in European languages) which involve 2 or 4 characters that combine in the browser to form a single character. Pass in the remaining text and an array of the special characters to search for and if the text starts with one of those special characters, it'll spit back the number of characters to retain (often 2 or 4). Used in the specialChars features that was introduced in 0.6.0.
_findSpecialChars = function(text, chars) {
var i = chars.length,
s;
while (--i > -1) {
s = chars[i];
if (text.substr(0, s.length) === s) {
return s.length;
}
}
},
_stripExp = /(?:\r|\n|\t\t)/g, //find carriage returns, new line feeds and double-tabs.
_multipleSpacesExp = /(?:\s\s+)/g,
_emojiStart = 0xD800,
_emojiEnd = 0xDBFF,
_emojiLowStart = 0xDC00,
_emojiRegionStart = 0x1F1E6,
_emojiRegionEnd = 0x1F1FF,
_emojiModStart = 0x1f3fb,
_emojiModEnd = 0x1f3ff,
_emojiPairCode = function(s) {
return ((s.charCodeAt(0) - _emojiStart) << 10) + (s.charCodeAt(1) - _emojiLowStart) + 0x10000;
},
_isOldIE = (_doc.all && !_doc.addEventListener),
_divStart = " style='position:relative;display:inline-block;" + (_isOldIE ? "*display:inline;*zoom:1;'" : "'"), //note: we must use both display:inline-block and *display:inline for IE8 and earlier, otherwise it won't flow correctly (and if we only use display:inline, IE won't render most of the property tweens - very odd).
_cssClassFunc = function(cssClass, tag) {
cssClass = cssClass || "";
var iterate = (cssClass.indexOf("++") !== -1),
num = 1;
if (iterate) {
cssClass = cssClass.split("++").join("");
}
return function() {
return "<" + tag + _divStart + (cssClass ? " class='" + cssClass + (iterate ? num++ : "") + "'>" : ">");
};
},
SplitText = pkg.SplitText = _globals.SplitText = function(element, vars) {
if (typeof(element) === "string") {
element = SplitText.selector(element);
}
if (!element) {
throw("cannot split a null element.");
}
this.elements = _isArrayLike(element) ? _flattenArray(element) : [element];
this.chars = [];
this.words = [];
this.lines = [];
this._originals = [];
this.vars = vars || {};
this.split(vars);
},
_swapText = function(element, oldText, newText) {
var type = element.nodeType;
if (type === 1 || type === 9 || type === 11) {
for (element = element.firstChild; element; element = element.nextSibling) {
_swapText(element, oldText, newText);
}
} else if (type === 3 || type === 4) {
element.nodeValue = element.nodeValue.split(oldText).join(newText);
}
},
_pushReversed = function(a, merge) {
var i = merge.length;
while (--i > -1) {
a.push(merge[i]);
}
},
_slice = function(a) { //don't use Array.prototype.slice.call(target, 0) because that doesn't work in IE8 with a NodeList that's returned by querySelectorAll()
var b = [],
l = a.length,
i;
for (i = 0; i !== l; b.push(a[i++])) {}
return b;
},
_isBeforeWordDelimiter = function(e, root, wordDelimiter) {
var next;
while (e && e !== root) {
next = e._next || e.nextSibling;
if (next) {
return next.textContent.charAt(0) === wordDelimiter;
}
e = e.parentNode || e._parent;
}
return false;
},
_deWordify = function(e) {
var children = _slice(e.childNodes),
l = children.length,
i, child;
for (i = 0; i < l; i++) {
child = children[i];
if (child._isSplit) {
_deWordify(child);
} else {
if (i && child.previousSibling.nodeType === 3) {
child.previousSibling.nodeValue += (child.nodeType === 3) ? child.nodeValue : child.firstChild.nodeValue;
} else if (child.nodeType !== 3) {
e.insertBefore(child.firstChild, child);
}
e.removeChild(child);
}
}
},
_setPositionsAfterSplit = function(element, vars, allChars, allWords, allLines, origWidth, origHeight) {
var cs = _getComputedStyle(element),
paddingLeft = _getStyle(element, "paddingLeft", cs),
lineOffsetY = -999,
borderTopAndBottom = _getStyle(element, "borderBottomWidth", cs) + _getStyle(element, "borderTopWidth", cs),
borderLeftAndRight = _getStyle(element, "borderLeftWidth", cs) + _getStyle(element, "borderRightWidth", cs),
padTopAndBottom = _getStyle(element, "paddingTop", cs) + _getStyle(element, "paddingBottom", cs),
padLeftAndRight = _getStyle(element, "paddingLeft", cs) + _getStyle(element, "paddingRight", cs),
lineThreshold = _getStyle(element, "fontSize") * 0.2,
textAlign = _getStyle(element, "textAlign", cs, true),
charArray = [],
wordArray = [],
lineArray = [],
wordDelimiter = vars.wordDelimiter || " ",
tag = vars.tag ? vars.tag : (vars.span ? "span" : "div"),
types = vars.type || vars.split || "chars,words,lines",
lines = (allLines && types.indexOf("lines") !== -1) ? [] : null,
words = (types.indexOf("words") !== -1),
chars = (types.indexOf("chars") !== -1),
absolute = (vars.position === "absolute" || vars.absolute === true),
linesClass = vars.linesClass,
iterateLine = ((linesClass || "").indexOf("++") !== -1),
spaceNodesToRemove = [],
i, j, l, node, nodes, isChild, curLine, addWordSpaces, style, lineNode, lineWidth, offset;
if (iterateLine) {
linesClass = linesClass.split("++").join("");
}
//copy all the descendant nodes into an array (we can't use a regular nodeList because it's live and we may need to renest things)
j = element.getElementsByTagName("*");
l = j.length;
nodes = [];
for (i = 0; i < l; i++) {
nodes[i] = j[i];
}
//for absolute positioning, we need to record the x/y offsets and width/height for every <div>. And even if we're not positioning things absolutely, in order to accommodate lines, we must figure out where the y offset changes so that we can sense where the lines break, and we populate the lines array.
if (lines || absolute) {
for (i = 0; i < l; i++) {
node = nodes[i];
isChild = (node.parentNode === element);
if (isChild || absolute || (chars && !words)) {
offset = node.offsetTop;
if (lines && isChild && Math.abs(offset - lineOffsetY) > lineThreshold && (node.nodeName !== "BR" || i === 0)) { //we found some rare occasions where a certain character like &#8209; could cause the offsetTop to be off by 1 pixel, so we build in a threshold.
curLine = [];
lines.push(curLine);
lineOffsetY = offset;
}
if (absolute) { //record offset x and y, as well as width and height so that we can access them later for positioning. Grabbing them at once ensures we don't trigger a browser paint & we maximize performance.
node._x = node.offsetLeft;
node._y = offset;
node._w = node.offsetWidth;
node._h = node.offsetHeight;
}
if (lines) {
if ((node._isSplit && isChild) || (!chars && isChild) || (words && isChild) || (!words && node.parentNode.parentNode === element && !node.parentNode._isSplit)) {
curLine.push(node);
node._x -= paddingLeft;
if (_isBeforeWordDelimiter(node, element, wordDelimiter)) {
node._wordEnd = true;
}
}
if (node.nodeName === "BR" && ((node.nextSibling && node.nextSibling.nodeName === "BR") || i === 0)) { //two consecutive <br> tags signify a new [empty] line. Also, if the entire block of content STARTS with a <br>, add a line.
lines.push([]);
}
}
}
}
}
for (i = 0; i < l; i++) {
node = nodes[i];
isChild = (node.parentNode === element);
if (node.nodeName === "BR") {
if (lines || absolute) {
if (node.parentNode) {
node.parentNode.removeChild(node);
}
nodes.splice(i--, 1);
l--;
} else if (!words) {
element.appendChild(node);
}
continue;
}
if (absolute) {
style = node.style;
if (!words && !isChild) {
node._x += node.parentNode._x;
node._y += node.parentNode._y;
}
style.left = node._x + "px";
style.top = node._y + "px";
style.position = "absolute";
style.display = "block";
//if we don't set the width/height, things collapse in older versions of IE and the origin for transforms is thrown off in all browsers.
style.width = (node._w + 1) + "px"; //IE is 1px short sometimes. Avoid wrapping
style.height = node._h + "px";
}
if (!words && chars) {
//we always start out wrapping words in their own <div> so that line breaks happen correctly, but here we'll remove those <div> tags if necessary and renest the characters directly into the element rather than inside the word <div>
if (node._isSplit) {
node._next = node.nextSibling;
node.parentNode.appendChild(node); //put it at the end to keep the order correct.
} else if (node.parentNode._isSplit) {
node._parent = node.parentNode;
if (!node.previousSibling && node.firstChild) {
node.firstChild._isFirst = true;
}
if (node.nextSibling && node.nextSibling.textContent === " " && !node.nextSibling.nextSibling) { //if the last node inside a nested element is just a space (like T<span>nested </span>), remove it otherwise it'll get placed in the wrong order. Don't remove it right away, though, because we need to sense when words/characters are before a space like _isBeforeWordDelimiter(). Removing it now would make that a false negative.
spaceNodesToRemove.push(node.nextSibling);
}
node._next = (node.nextSibling && node.nextSibling._isFirst) ? null : node.nextSibling;
node.parentNode.removeChild(node);
nodes.splice(i--, 1);
l--;
} else if (!isChild) {
offset = (!node.nextSibling && _isBeforeWordDelimiter(node.parentNode, element, wordDelimiter)); //if this is the last letter in the word (and we're not breaking by lines and not positioning things absolutely), we need to add a space afterwards so that the characters don't just mash together
if (node.parentNode._parent) {
node.parentNode._parent.appendChild(node);
}
if (offset) {
node.parentNode.appendChild(_doc.createTextNode(" "));
}
if (tag === "span") {
node.style.display = "inline"; //so that word breaks are honored properly.
}
charArray.push(node);
}
} else if (node.parentNode._isSplit && !node._isSplit && node.innerHTML !== "") {
wordArray.push(node);
} else if (chars && !node._isSplit) {
if (tag === "span") {
node.style.display = "inline";
}
charArray.push(node);
}
}
i = spaceNodesToRemove.length;
while (--i > -1) {
spaceNodesToRemove[i].parentNode.removeChild(spaceNodesToRemove[i]);
}
if (lines) {
//the next 7 lines just give us the line width in the most reliable way and figure out the left offset (if position isn't relative or absolute). We must set the width along with text-align to ensure everything works properly for various alignments.
if (absolute) {
lineNode = _doc.createElement(tag);
element.appendChild(lineNode);
lineWidth = lineNode.offsetWidth + "px";
offset = (lineNode.offsetParent === element) ? 0 : element.offsetLeft;
element.removeChild(lineNode);
}
style = element.style.cssText;
element.style.cssText = "display:none;"; //to improve performance, set display:none on the element so that the browser doesn't have to worry about reflowing or rendering while we're renesting things. We'll revert the cssText later.
//we can't use element.innerHTML = "" because that causes IE to literally delete all the nodes and their content even though we've stored them in an array! So we must loop through the children and remove them.
while (element.firstChild) {
element.removeChild(element.firstChild);
}
addWordSpaces = (wordDelimiter === " " && (!absolute || (!words && !chars)));
for (i = 0; i < lines.length; i++) {
curLine = lines[i];
lineNode = _doc.createElement(tag);
lineNode.style.cssText = "display:block;text-align:" + textAlign + ";position:" + (absolute ? "absolute;" : "relative;");
if (linesClass) {
lineNode.className = linesClass + (iterateLine ? i+1 : "");
}
lineArray.push(lineNode);
l = curLine.length;
for (j = 0; j < l; j++) {
if (curLine[j].nodeName !== "BR") {
node = curLine[j];
lineNode.appendChild(node);
if (addWordSpaces && node._wordEnd) {
lineNode.appendChild(_doc.createTextNode(" "));
}
if (absolute) {
if (j === 0) {
lineNode.style.top = (node._y) + "px";
lineNode.style.left = (paddingLeft + offset) + "px";
}
node.style.top = "0px";
if (offset) {
node.style.left = (node._x - offset) + "px";
}
}
}
}
if (l === 0) { //if there are no nodes in the line (typically meaning there were two consecutive <br> tags, just add a non-breaking space so that things display properly.
lineNode.innerHTML = "&nbsp;";
} else if (!words && !chars) {
_deWordify(lineNode);
_swapText(lineNode, String.fromCharCode(160), " ");
}
if (absolute) {
lineNode.style.width = lineWidth;
lineNode.style.height = node._h + "px";
}
element.appendChild(lineNode);
}
element.style.cssText = style;
}
//if everything shifts to being position:absolute, the container can collapse in terms of height or width, so fix that here.
if (absolute) {
if (origHeight > element.clientHeight) {
element.style.height = (origHeight - padTopAndBottom) + "px";
if (element.clientHeight < origHeight) { //IE8 and earlier use a different box model - we must include padding and borders
element.style.height = (origHeight + borderTopAndBottom)+ "px";
}
}
if (origWidth > element.clientWidth) {
element.style.width = (origWidth - padLeftAndRight) + "px";
if (element.clientWidth < origWidth) { //IE8 and earlier use a different box model - we must include padding and borders
element.style.width = (origWidth + borderLeftAndRight)+ "px";
}
}
}
_pushReversed(allChars, charArray);
if (words) {
_pushReversed(allWords, wordArray);
}
_pushReversed(allLines, lineArray);
},
_splitRawText = function(element, vars, wordStart, charStart) {
var tag = vars.tag ? vars.tag : (vars.span ? "span" : "div"),
types = vars.type || vars.split || "chars,words,lines",
//words = (types.indexOf("words") !== -1),
chars = (types.indexOf("chars") !== -1),
absolute = (vars.position === "absolute" || vars.absolute === true),
wordDelimiter = vars.wordDelimiter || " ",
space = wordDelimiter !== " " ? "" : (absolute ? "&#173; " : " "),
wordEnd = "</" + tag + ">",
wordIsOpen = true,
specialChars = vars.specialChars ? (typeof(vars.specialChars) === "function" ? vars.specialChars : _findSpecialChars) : null, //specialChars can be an array or a function. For performance reasons, we always set this local "specialChars" to a function to which we pass the remaining text and whatever the original vars.specialChars was so that if it's an array, it works with the _findSpecialChars() function.
text, splitText, i, j, l, character, hasTagStart, emojiPair1, emojiPair2, testResult,
container = _doc.createElement("div"),
parent = element.parentNode;
parent.insertBefore(container, element);
container.textContent = element.nodeValue;
parent.removeChild(element);
element = container;
text = _getText(element);
hasTagStart = text.indexOf("<") !== -1;
if (vars.reduceWhiteSpace !== false) {
text = text.replace(_multipleSpacesExp, " ").replace(_stripExp, "");
}
if (hasTagStart) {
text = text.split("<").join("{{LT}}"); //we can't leave "<" in the string, or when we set the innerHTML, it can be interpreted as a node
}
l = text.length;
splitText = ((text.charAt(0) === " ") ? space : "") + wordStart();
for (i = 0; i < l; i++) {
character = text.charAt(i);
if (specialChars && (testResult = specialChars(text.substr(i), vars.specialChars))) { // look for any specialChars that were declared. Remember, they can be passed in like {specialChars:["मी", "पा", "है"]} or a function could be defined instead. Either way, the function should return the number of characters that should be grouped together for this "character".
character = text.substr(i, testResult || 1);
splitText += (chars && character !== " ") ? charStart() + character + "</" + tag + ">" : character;
i += testResult - 1;
} else if (character === wordDelimiter && text.charAt(i-1) !== wordDelimiter && i) {
splitText += wordIsOpen ? wordEnd : "";
wordIsOpen = false;
while (text.charAt(i + 1) === wordDelimiter) { //skip over empty spaces (to avoid making them words)
splitText += space;
i++;
}
if (i === l-1) {
splitText += space;
} else if (text.charAt(i + 1) !== ")") {
splitText += space + wordStart();
wordIsOpen = true;
}
} else if (character === "{" && text.substr(i, 6) === "{{LT}}") {
splitText += chars ? charStart() + "{{LT}}" + "</" + tag + ">" : "{{LT}}";
i += 5;
} else if ((character.charCodeAt(0) >= _emojiStart && character.charCodeAt(0) <= _emojiEnd) || (text.charCodeAt(i+1) >= 0xFE00 && text.charCodeAt(i+1) <= 0xFE0F)) { //special emoji characters use 2 or 4 unicode characters that we must keep together.
emojiPair1 = _emojiPairCode(text.substr(i, 2));
emojiPair2 = _emojiPairCode(text.substr(i + 2, 2));
j = ((emojiPair1 >= _emojiRegionStart && emojiPair1 <= _emojiRegionEnd && emojiPair2 >= _emojiRegionStart && emojiPair2 <= _emojiRegionEnd) || (emojiPair2 >= _emojiModStart && emojiPair2 <= _emojiModEnd)) ? 4 : 2;
splitText += (chars && character !== " ") ? charStart() + text.substr(i, j) + "</" + tag + ">" : text.substr(i, j);
i += j - 1;
} else {
splitText += (chars && character !== " ") ? charStart() + character + "</" + tag + ">" : character;
}
}
element.outerHTML = splitText + (wordIsOpen ? wordEnd : "");
if (hasTagStart) {
_swapText(parent, "{{LT}}", "<"); //note: don't perform this on "element" because that gets replaced with all new elements when we set element.outerHTML.
}
},
_split = function(element, vars, wordStart, charStart) {
var children = _slice(element.childNodes),
l = children.length,
absolute = (vars.position === "absolute" || vars.absolute === true),
i, child;
if (element.nodeType !== 3 || l > 1) {
vars.absolute = false;
for (i = 0; i < l; i++) {
child = children[i];
if (child.nodeType !== 3 || /\S+/.test(child.nodeValue)) {
if (absolute && child.nodeType !== 3 && _getStyle(child, "display", null, true) === "inline") { //if there's a child node that's display:inline, switch it to inline-block so that absolute positioning works properly (most browsers don't report offsetTop/offsetLeft properly inside a <span> for example)
child.style.display = "inline-block";
child.style.position = "relative";
}
child._isSplit = true;
_split(child, vars, wordStart, charStart); //don't split lines on child elements
}
}
vars.absolute = absolute;
element._isSplit = true;
return;
}
_splitRawText(element, vars, wordStart, charStart);
},
p = SplitText.prototype;
p.split = function(vars) {
if (this.isSplit) {
this.revert();
}
this.vars = vars = vars || this.vars;
this._originals.length = this.chars.length = this.words.length = this.lines.length = 0;
var i = this.elements.length,
tag = vars.tag ? vars.tag : (vars.span ? "span" : "div"),
wordStart = _cssClassFunc(vars.wordsClass, tag),
charStart = _cssClassFunc(vars.charsClass, tag),
origHeight, origWidth, e;
//we split in reversed order so that if/when we position:absolute elements, they don't affect the position of the ones after them in the document flow (shifting them up as they're taken out of the document flow).
while (--i > -1) {
e = this.elements[i];
this._originals[i] = e.innerHTML;
origHeight = e.clientHeight;
origWidth = e.clientWidth;
_split(e, vars, wordStart, charStart);
_setPositionsAfterSplit(e, vars, this.chars, this.words, this.lines, origWidth, origHeight);
}
this.chars.reverse();
this.words.reverse();
this.lines.reverse();
this.isSplit = true;
return this;
};
p.revert = function() {
if (!this._originals) {
throw("revert() call wasn't scoped properly.");
}
var i = this._originals.length;
while (--i > -1) {
this.elements[i].innerHTML = this._originals[i];
}
this.chars = [];
this.words = [];
this.lines = [];
this.isSplit = false;
return this;
};
SplitText.selector = window.$ || window.jQuery || function(e) {
var selector = window.$ || window.jQuery;
if (selector) {
SplitText.selector = selector;
return selector(e);
}
return (typeof(document) === "undefined") ? e : (document.querySelectorAll ? document.querySelectorAll(e) : document.getElementById((e.charAt(0) === "#") ? e.substr(1) : e));
};
SplitText.version = "0.7.0";
})(_gsScope);
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define([], getGlobal);
}
}("SplitText"));
@@ -0,0 +1,740 @@
/*!
* VERSION: 0.11.2
* DATE: 2019-02-07
* UPDATES AND DOCS AT: http://greensock.com
*
* @license Copyright (c) 2008-2019, GreenSock. All rights reserved.
* ThrowPropsPlugin is a Club GreenSock membership benefit; You must have a valid membership to use
* this code without violating the terms of use. Visit http://greensock.com/club/ to sign up or get more details.
* This work is subject to the software agreement that was issued with your membership.
*
* @author: Jack Doyle, jack@greensock.com
*/
/* eslint-disable */
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("plugins.ThrowPropsPlugin", ["plugins.TweenPlugin", "TweenLite", "easing.Ease", "utils.VelocityTracker"], function(TweenPlugin, TweenLite, Ease, VelocityTracker) {
var ThrowPropsPlugin = function(props, priority) {
TweenPlugin.call(this, "throwProps");
this._overwriteProps.length = 0;
},
_max = 999999999999999,
_min = 0.0000000001,
_globals = _gsScope._gsDefine.globals,
_recordEndMode = false,//in a typical throwProps css tween that has an "end" defined as a function, it grabs that value initially when the tween is rendered, then again when we calculate the necessary duration, and then a 3rd time after we invalidate() the tween, so we toggle _recordEndMode to true when we're about to begin such a tween which tells the engine to grab the end value(s) once and record them as "max" and "min" on the throwProps object, thus we can skip those extra calls. Then we set it back to false when we're done with our fancy initialization routine.
_transforms = {x:1,y:1,z:2,scale:1,scaleX:1,scaleY:1,rotation:1,rotationZ:1,rotationX:2,rotationY:2,skewX:1,skewY:1,xPercent:1,yPercent:1},
_getClosest = function(n, values, max, min, radius) {
var i = values.length,
closest = 0,
absDif = _max,
val, dif, p, dist;
if (typeof(n) === "object") {
while (--i > -1) {
val = values[i];
dif = 0;
for (p in n) {
dist = val[p] - n[p];
dif += dist * dist;
}
if (dif < absDif) {
closest = i;
absDif = dif;
}
}
if ((radius || _max) < _max && radius < Math.sqrt(absDif)) {
return n;
}
} else {
while (--i > -1) {
val = values[i];
dif = val - n;
if (dif < 0) {
dif = -dif;
}
if (dif < absDif && val >= min && val <= max) {
closest = i;
absDif = dif;
}
}
}
return values[closest];
},
_parseEnd = function(curProp, end, max, min, name, radius) {
if (curProp.end === "auto") {
return curProp;
}
var endVar = curProp.end,
adjustedEnd, p;
max = isNaN(max) ? _max : max;
min = isNaN(min) ? -_max : min;
if (typeof(end) === "object") { //for objects, like {x, y} where they're linked and we must pass an object to the function or find the closest value in an array.
adjustedEnd = end.calculated ? end : ((typeof(endVar) === "function") ? endVar(end) : _getClosest(end, endVar, max, min, radius)) || end;
if (!end.calculated) {
for (p in adjustedEnd) {
end[p] = adjustedEnd[p];
}
end.calculated = true;
}
adjustedEnd = adjustedEnd[name];
} else {
adjustedEnd = (typeof(endVar) === "function") ? endVar(end) : (endVar instanceof Array) ? _getClosest(end, endVar, max, min, radius) : Number(endVar);
}
if (adjustedEnd > max) {
adjustedEnd = max;
} else if (adjustedEnd < min) {
adjustedEnd = min;
}
return {max:adjustedEnd, min:adjustedEnd, unitFactor:curProp.unitFactor};
},
_extend = function(decoratee, extras, exclude) {
for (var p in extras) {
if (decoratee[p] === undefined && p !== exclude) {
decoratee[p] = extras[p];
}
}
return decoratee;
},
_calculateChange = ThrowPropsPlugin.calculateChange = function(velocity, ease, duration, checkpoint) {
if (checkpoint == null) {
checkpoint = 0.05;
}
var e = (ease instanceof Ease) ? ease : (!ease) ? TweenLite.defaultEase : new Ease(ease);
return (duration * checkpoint * velocity) / e.getRatio(checkpoint);
},
_calculateDuration = ThrowPropsPlugin.calculateDuration = function(start, end, velocity, ease, checkpoint) {
checkpoint = checkpoint || 0.05;
var e = (ease instanceof Ease) ? ease : (!ease) ? TweenLite.defaultEase : new Ease(ease);
return Math.abs( (end - start) * e.getRatio(checkpoint) / velocity / checkpoint );
},
_calculateTweenDuration = ThrowPropsPlugin.calculateTweenDuration = function(target, vars, maxDuration, minDuration, overshootTolerance, recordEnd) {
if (typeof(target) === "string") {
target = TweenLite.selector(target);
}
if (!target) {
return 0;
}
if (maxDuration == null) {
maxDuration = 10;
}
if (minDuration == null) {
minDuration = 0.2;
}
if (overshootTolerance == null) {
overshootTolerance = 1;
}
if (target.length) {
target = target[0] || target;
}
var duration = 0,
clippedDuration = 9999999999,
throwPropsVars = vars.throwProps || vars,
ease = (vars.ease instanceof Ease) ? vars.ease : (!vars.ease) ? TweenLite.defaultEase : new Ease(vars.ease),
checkpoint = isNaN(throwPropsVars.checkpoint) ? 0.05 : Number(throwPropsVars.checkpoint),
resistance = isNaN(throwPropsVars.resistance) ? ThrowPropsPlugin.defaultResistance : Number(throwPropsVars.resistance),
p, curProp, curDuration, curVelocity, curResistance, curVal, end, curClippedDuration, tracker, unitFactor,
linkedProps, linkedPropNames, i;
if (throwPropsVars.linkedProps) { //when there are linkedProps (typically "x,y" where snapping has to factor in multiple properties, we must first populate an object with all of those end values, then feed it to the function that make any necessary alterations. So the point of this first loop is to simply build an object (like {x:100, y:204.5}) for feeding into that function which we'll do later in the "real" loop.
linkedPropNames = throwPropsVars.linkedProps.split(",");
linkedProps = {};
for (i = 0; i < linkedPropNames.length; i++) {
p = linkedPropNames[i];
curProp = throwPropsVars[p];
if (curProp) {
if (curProp.velocity !== undefined && typeof(curProp.velocity) === "number") {
curVelocity = Number(curProp.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
curVelocity = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0;
}
curResistance = isNaN(curProp.resistance) ? resistance : Number(curProp.resistance);
curDuration = (curVelocity * curResistance > 0) ? curVelocity / curResistance : curVelocity / -curResistance;
curVal = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p] || 0;
linkedProps[p] = curVal + _calculateChange(curVelocity, ease, curDuration, checkpoint);
}
}
}
for (p in throwPropsVars) {
if (p !== "resistance" && p !== "checkpoint" && p !== "preventOvershoot" && p !== "linkedProps" && p !== "radius") {
curProp = throwPropsVars[p];
if (typeof(curProp) !== "object") {
tracker = tracker || VelocityTracker.getByTarget(target);
if (tracker && tracker.isTrackingProp(p)) {
curProp = (typeof(curProp) === "number") ? {velocity:curProp} : {velocity:tracker.getVelocity(p)}; //if we're tracking this property, we should use the tracking velocity and then use the numeric value that was passed in as the min and max so that it tweens exactly there.
} else {
curVelocity = Number(curProp) || 0;
curDuration = (curVelocity * resistance > 0) ? curVelocity / resistance : curVelocity / -resistance;
}
}
if (typeof(curProp) === "object") {
if (curProp.velocity !== undefined && typeof(curProp.velocity) === "number") {
curVelocity = Number(curProp.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
curVelocity = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0;
}
curResistance = isNaN(curProp.resistance) ? resistance : Number(curProp.resistance);
curDuration = (curVelocity * curResistance > 0) ? curVelocity / curResistance : curVelocity / -curResistance;
curVal = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p] || 0;
end = curVal + _calculateChange(curVelocity, ease, curDuration, checkpoint);
if (curProp.end !== undefined) {
curProp = _parseEnd(curProp, (linkedProps && p in linkedProps) ? linkedProps : end, curProp.max, curProp.min, p, throwPropsVars.radius);
if (recordEnd || _recordEndMode) {
throwPropsVars[p] = _extend(curProp, throwPropsVars[p], "end");
}
}
if (curProp.max !== undefined && end > Number(curProp.max) + _min) {
unitFactor = curProp.unitFactor || ThrowPropsPlugin.defaultUnitFactors[p] || 1; //some values are measured in special units like radians in which case our thresholds need to be adjusted accordingly.
//if the value is already exceeding the max or the velocity is too low, the duration can end up being uncomfortably long but in most situations, users want the snapping to occur relatively quickly (0.75 seconds), so we implement a cap here to make things more intuitive. If the max and min match, it means we're animating to a particular value and we don't want to shorten the time unless the velocity is really slow. Example: a rotation where the start and natural end value are less than the snapping spot, but the natural end is pretty close to the snap.
curClippedDuration = ((curVal > curProp.max && curProp.min !== curProp.max) || (curVelocity * unitFactor > -15 && curVelocity * unitFactor < 45)) ? (minDuration + (maxDuration - minDuration) * 0.1) : _calculateDuration(curVal, curProp.max, curVelocity, ease, checkpoint);
if (curClippedDuration + overshootTolerance < clippedDuration) {
clippedDuration = curClippedDuration + overshootTolerance;
}
} else if (curProp.min !== undefined && end < Number(curProp.min) - _min) {
unitFactor = curProp.unitFactor || ThrowPropsPlugin.defaultUnitFactors[p] || 1; //some values are measured in special units like radians in which case our thresholds need to be adjusted accordingly.
//if the value is already exceeding the min or if the velocity is too low, the duration can end up being uncomfortably long but in most situations, users want the snapping to occur relatively quickly (0.75 seconds), so we implement a cap here to make things more intuitive.
curClippedDuration = ((curVal < curProp.min && curProp.min !== curProp.max) || (curVelocity * unitFactor > -45 && curVelocity * unitFactor < 15)) ? (minDuration + (maxDuration - minDuration) * 0.1) : _calculateDuration(curVal, curProp.min, curVelocity, ease, checkpoint);
if (curClippedDuration + overshootTolerance < clippedDuration) {
clippedDuration = curClippedDuration + overshootTolerance;
}
}
if (curClippedDuration > duration) {
duration = curClippedDuration;
}
}
if (curDuration > duration) {
duration = curDuration;
}
}
}
if (duration > clippedDuration) {
duration = clippedDuration;
}
if (duration > maxDuration) {
return maxDuration;
} else if (duration < minDuration) {
return minDuration;
}
return duration;
},
p = ThrowPropsPlugin.prototype = new TweenPlugin("throwProps"),
_cssProxy, _cssVars, _last, _lastValue; //these serve as a cache of sorts, recording the last css-related proxy and the throwProps vars that get calculated in the _cssRegister() method. This allows us to grab them in the ThrowPropsPlugin.to() function and calculate the duration. Of course we could have structured things in a more "clean" fashion, but performance is of paramount importance.
p.constructor = ThrowPropsPlugin;
ThrowPropsPlugin.version = "0.11.2";
ThrowPropsPlugin.API = 2;
ThrowPropsPlugin._autoCSS = true; //indicates that this plugin can be inserted into the "css" object using the autoCSS feature of TweenLite
ThrowPropsPlugin.defaultResistance = 100;
ThrowPropsPlugin.defaultUnitFactors = {time:1000, totalTime:1000}; //setting the unitFactor to a higher value (default is 1) reduces the chance of the auto-accelerating behavior kicking in when determining durations when the initial velocity is adequately low - imagine dragging something past a boundary and then letting go - snapping back relatively quickly should be prioritized over matching the initial velocity (at least that's the behavior most people consider intuitive). But in some situations when the units are very low (like "time" of a timeline or rotation when using radians), it can kick in too frequently so this allows tweaking.
ThrowPropsPlugin.track = function(target, props, types) {
return VelocityTracker.track(target, props, types);
};
ThrowPropsPlugin.untrack = function(target, props) {
VelocityTracker.untrack(target, props);
};
ThrowPropsPlugin.isTracking = function(target, prop) {
return VelocityTracker.isTracking(target, prop);
};
ThrowPropsPlugin.getVelocity = function(target, prop) {
var vt = VelocityTracker.getByTarget(target);
return vt ? vt.getVelocity(prop) : NaN;
};
ThrowPropsPlugin._cssRegister = function() {
var CSSPlugin = _globals.com.greensock.plugins.CSSPlugin;
if (!CSSPlugin) {
return;
}
var _internals = CSSPlugin._internals,
_parseToProxy = _internals._parseToProxy,
_setPluginRatio = _internals._setPluginRatio,
CSSPropTween = _internals.CSSPropTween;
_internals._registerComplexSpecialProp("throwProps", {parser:function(t, e, prop, cssp, pt, plugin) {
plugin = new ThrowPropsPlugin();
var velocities = {},
min = {},
max = {},
end = {},
res = {},
preventOvershoot = {},
hasResistance, val, p, data, tracker;
_cssVars = {};
for (p in e) {
if (p !== "resistance" && p !== "preventOvershoot" && p !== "linkedProps" && p !== "radius") {
val = e[p];
if (typeof(val) === "object") {
if (val.velocity !== undefined && typeof(val.velocity) === "number") {
velocities[p] = Number(val.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(t);
velocities[p] = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0; //rotational values are actually converted to radians in CSSPlugin, but our tracking velocity is in radians already, so make it into degrees to avoid a funky conversion
}
if (val.end !== undefined) {
end[p] = val.end;
}
if (val.min !== undefined) {
min[p] = val.min;
}
if (val.max !== undefined) {
max[p] = val.max;
}
if (val.preventOvershoot) {
preventOvershoot[p] = true;
}
if (val.resistance !== undefined) {
hasResistance = true;
res[p] = val.resistance;
}
} else if (typeof(val) === "number") {
velocities[p] = val;
} else {
tracker = tracker || VelocityTracker.getByTarget(t);
if (tracker && tracker.isTrackingProp(p)) {
velocities[p] = tracker.getVelocity(p);
} else {
velocities[p] = val || 0;
}
}
if (_transforms[p]) {
cssp._enableTransforms((_transforms[p] === 2));
}
}
}
data = _parseToProxy(t, velocities, cssp, pt, plugin);
_cssProxy = data.proxy;
velocities = data.end;
for (p in _cssProxy) {
_cssVars[p] = {velocity:velocities[p], min:min[p], max:max[p], end:end[p], resistance:res[p], preventOvershoot:preventOvershoot[p]};
}
if (e.resistance != null) {
_cssVars.resistance = e.resistance;
}
if (e.linkedProps != null) {
_cssVars.linkedProps = e.linkedProps;
}
if (e.radius != null) {
_cssVars.radius = e.radius;
}
if (e.preventOvershoot) {
_cssVars.preventOvershoot = true;
}
pt = new CSSPropTween(t, "throwProps", 0, 0, data.pt, 2);
cssp._overwriteProps.pop(); //don't overwrite all other throwProps tweens. In the CSSPropTween constructor, we add the property to the _overwriteProps, so remove it here.
pt.plugin = plugin;
pt.setRatio = _setPluginRatio;
pt.data = data;
plugin._onInitTween(_cssProxy, _cssVars, cssp._tween);
return pt;
}});
};
ThrowPropsPlugin.to = function(target, vars, maxDuration, minDuration, overshootTolerance) {
if (!vars.throwProps) {
vars = {throwProps:vars};
}
if (overshootTolerance === 0) {
vars.throwProps.preventOvershoot = true;
}
_recordEndMode = true; //if we encounter a function-based "end" value, ThrowPropsPlugin will record it as "max" and "min" properties, replacing "end" (this is an optimization so that the function only gets called once)
var tween = new TweenLite(target, minDuration || 1, vars);
tween.render(0, true, true); //we force a render so that the CSSPlugin instantiates and populates the _cssProxy and _cssVars which we need in order to calculate the tween duration. Remember, we can't use the regular target for calculating the duration because the current values wouldn't be able to be grabbed like target["propertyName"], as css properties can be complex like boxShadow:"10px 10px 20px 30px red" or backgroundPosition:"25px 50px". The proxy is the result of breaking all that complex data down and finding just the numeric values and assigning them to a generic proxy object with unique names. THAT is what the _calculateTweenDuration() can look at. We also needed to do the same break down of any min or max or velocity data
if (tween.vars.css) {
tween.duration(_calculateTweenDuration(_cssProxy, {throwProps:_cssVars, ease:vars.ease}, maxDuration, minDuration, overshootTolerance));
if (tween._delay && !tween.vars.immediateRender) {
tween.invalidate(); //if there's a delay, the starting values could be off, so invalidate() to force reinstantiation when the tween actually starts.
} else {
_last._onInitTween(_cssProxy, _lastValue, tween);
}
_recordEndMode = false;
return tween;
} else {
tween.kill();
tween = new TweenLite(target, _calculateTweenDuration(target, vars, maxDuration, minDuration, overshootTolerance), vars);
_recordEndMode = false;
return tween;
}
};
p._onInitTween = function(target, value, tween, index) {
this.target = target;
this._props = [];
_last = this;
_lastValue = value;
var ease = tween._ease,
checkpoint = isNaN(value.checkpoint) ? 0.05 : Number(value.checkpoint),
duration = tween._duration,
preventOvershoot = value.preventOvershoot,
cnt = 0,
p, curProp, curVal, isFunc, velocity, change1, end, change2, tracker,
linkedProps, linkedPropNames, i;
if (value.linkedProps) { //when there are linkedProps (typically "x,y" where snapping has to factor in multiple properties, we must first populate an object with all of those end values, then feed it to the function that make any necessary alterations. So the point of this first loop is to simply build an object (like {x:100, y:204.5}) for feeding into that function which we'll do later in the "real" loop.
linkedPropNames = value.linkedProps.split(",");
linkedProps = {};
for (i = 0; i < linkedPropNames.length; i++) {
p = linkedPropNames[i];
curProp = value[p];
if (curProp) {
if (curProp.velocity !== undefined && typeof(curProp.velocity) === "number") {
velocity = Number(curProp.velocity) || 0;
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
velocity = (tracker && tracker.isTrackingProp(p)) ? tracker.getVelocity(p) : 0;
}
curVal = (typeof(target[p]) === "function") ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p] || 0;
linkedProps[p] = curVal + _calculateChange(velocity, ease, duration, checkpoint);
}
}
}
for (p in value) {
if (p !== "resistance" && p !== "checkpoint" && p !== "preventOvershoot" && p !== "linkedProps" && p !== "radius") {
curProp = value[p];
if (typeof(curProp) === "function") {
curProp = curProp(index, target);
}
if (typeof(curProp) === "number") {
velocity = Number(curProp) || 0;
} else if (typeof(curProp) === "object" && !isNaN(curProp.velocity)) {
velocity = Number(curProp.velocity);
} else {
tracker = tracker || VelocityTracker.getByTarget(target);
if (tracker && tracker.isTrackingProp(p)) {
velocity = tracker.getVelocity(p);
} else {
throw("ERROR: No velocity was defined in the throwProps tween of " + target + " property: " + p);
}
}
change1 = _calculateChange(velocity, ease, duration, checkpoint);
change2 = 0;
isFunc = (typeof(target[p]) === "function");
curVal = (isFunc) ? target[ ((p.indexOf("set") || typeof(target["get" + p.substr(3)]) !== "function") ? p : "get" + p.substr(3)) ]() : target[p];
if (typeof(curProp) === "object") {
end = curVal + change1;
if (curProp.end !== undefined) {
curProp = _parseEnd(curProp, (linkedProps && p in linkedProps) ? linkedProps : end, curProp.max, curProp.min, p, value.radius);
if (_recordEndMode) {
value[p] = _extend(curProp, value[p], "end");
}
}
if (curProp.max !== undefined && Number(curProp.max) < end) {
if (preventOvershoot || curProp.preventOvershoot) {
change1 = curProp.max - curVal;
} else {
change2 = (curProp.max - curVal) - change1;
}
} else if (curProp.min !== undefined && Number(curProp.min) > end) {
if (preventOvershoot || curProp.preventOvershoot) {
change1 = curProp.min - curVal;
} else {
change2 = (curProp.min - curVal) - change1;
}
}
}
this._overwriteProps[cnt] = p;
this._props[cnt++] = {p:p, s:curVal, c1:change1, c2:change2, f:isFunc, r:false};
}
}
return true;
};
p._kill = function(lookup) {
var i = this._props.length;
while (--i > -1) {
if (lookup[this._props[i].p] != null) {
this._props.splice(i, 1);
}
}
return TweenPlugin.prototype._kill.call(this, lookup);
};
p._mod = function(lookup) {
var p = this._props,
i = p.length,
val;
while (--i > -1) {
val = lookup[p[i].p] || lookup.throwProps;
if (typeof(val) === "function") {
p[i].m = val;
}
}
};
p.setRatio = function(v) {
var i = this._props.length,
cp, val;
while (--i > -1) {
cp = this._props[i];
val = cp.s + cp.c1 * v + cp.c2 * v * v;
if (cp.m) {
val = cp.m(val, this.target);
} else if (v === 1) {
val = ((val * 10000 + (val < 0 ? -0.5 : 0.5)) | 0) / 10000; //if we don't round things at the very end, binary math issues can creep in and cause snapping not to be exact (like landing on 20.000000000001 instead of 20).
}
if (cp.f) {
this.target[cp.p](val);
} else {
this.target[cp.p] = val;
}
}
};
TweenPlugin.activate([ThrowPropsPlugin]);
return ThrowPropsPlugin;
}, true);
/*
* ----------------------------------------------------------------
* VelocityTracker
* ----------------------------------------------------------------
*/
_gsScope._gsDefine("utils.VelocityTracker", ["TweenLite"], function(TweenLite) {
var _first, _initted, _time1, _time2,
_capsExp = /([A-Z])/g,
_empty = {},
_doc = _gsScope.document,
_transforms = {x:1,y:1,z:2,scale:1,scaleX:1,scaleY:1,rotation:1,rotationZ:1,rotationX:2,rotationY:2,skewX:1,skewY:1,xPercent:1,yPercent:1},
_computedStyleScope = (typeof(window) !== "undefined" ? window : _doc.defaultView || {getComputedStyle:function() {}}),
_getComputedStyle = function(e) {
return _computedStyleScope.getComputedStyle(e); //to avoid errors in Microsoft Edge, we need to call getComputedStyle() from a specific scope, typically window.
},
_getStyle = function(t, p, cs) {
var rv = (t._gsTransform || _empty)[p];
if (rv || rv === 0) {
return rv;
} else if (t.style[p]) {
rv = t.style[p];
} else if ((cs = cs || _getComputedStyle(t, null))) {
rv = cs[p] || cs.getPropertyValue(p) || cs.getPropertyValue(p.replace(_capsExp, "-$1").toLowerCase());
} else if (t.currentStyle) {
rv = t.currentStyle[p];
}
return parseFloat(rv) || 0;
},
_ticker = TweenLite.ticker,
VelocityProp = function(p, isFunc, next) {
this.p = p;
this.f = isFunc;
this.v1 = this.v2 = 0;
this.t1 = this.t2 = _ticker.time;
this.css = false;
this.type = "";
this._prev = null;
if (next) {
this._next = next;
next._prev = this;
}
},
_update = function() {
var vt = _first,
t = _ticker.time,
val, vp;
//if the frame rate is too high, we won't be able to track the velocity as well, so only update the values about 33 times per second
if (t - _time1 >= 0.03) {
_time2 = _time1;
_time1 = t;
while (vt) {
vp = vt._firstVP;
while (vp) {
val = vp.css ? _getStyle(vt.target, vp.p) : vp.f ? vt.target[vp.p]() : vt.target[vp.p];
if (val !== vp.v1 || t - vp.t1 > 0.15) { //use a threshold of 0.15 seconds for zeroing-out velocity. If we only use 0.03 and things update slightly slower, like some Android devices dispatch "touchmove" events sluggishly so 2 or 3 ticks of the TweenLite.ticker may elapse inbetween, thus it may appear like the object is not moving but it actually is but it's not updating as frequently. A threshold of 0.15 seconds seems to be a good balance. We want to update things frequently (0.03 seconds) when they're moving so that we can respond to fast motions accurately, but we want to be more resistant to go back to a zero velocity.
vp.v2 = vp.v1;
vp.v1 = val;
vp.t2 = vp.t1;
vp.t1 = t;
}
vp = vp._next;
}
vt = vt._next;
}
}
},
VelocityTracker = function(target) {
this._lookup = {};
this.target = target;
this.elem = (target.style && target.nodeType) ? true : false;
if (!_initted) {
_ticker.addEventListener("tick", _update, null, false, -100);
_time1 = _time2 = _ticker.time;
_initted = true;
}
if (_first) {
this._next = _first;
_first._prev = this;
}
_first = this;
},
getByTarget = VelocityTracker.getByTarget = function(target) {
var vt = _first;
while (vt) {
if (vt.target === target) {
return vt;
}
vt = vt._next;
}
},
p = VelocityTracker.prototype;
p.addProp = function(prop, type) {
if (!this._lookup[prop]) {
var t = this.target,
isFunc = (typeof(t[prop]) === "function"),
alt = isFunc ? this._altProp(prop) : prop,
vp = this._firstVP;
this._firstVP = this._lookup[prop] = this._lookup[alt] = vp = new VelocityProp((alt !== prop && prop.indexOf("set") === 0) ? alt : prop, isFunc, vp);
vp.css = (this.elem && (this.target.style[vp.p] !== undefined || _transforms[vp.p]));
if (vp.css && _transforms[vp.p] && !t._gsTransform) {
TweenLite.set(t, {x:"+=0", overwrite:false}); //just forces CSSPlugin to create a _gsTransform for the element if it doesn't exist
}
vp.type = type || (vp.css && prop.indexOf("rotation") === 0) ? "deg" : "";
vp.v1 = vp.v2 = vp.css ? _getStyle(t, vp.p) : isFunc ? t[vp.p]() : t[vp.p];
}
};
p.removeProp = function(prop) {
var vp = this._lookup[prop];
if (vp) {
if (vp._prev) {
vp._prev._next = vp._next;
} else if (vp === this._firstVP) {
this._firstVP = vp._next;
}
if (vp._next) {
vp._next._prev = vp._prev;
}
this._lookup[prop] = 0;
if (vp.f) {
this._lookup[this._altProp(prop)] = 0; //if it's a getter/setter, we should remove the matching counterpart (if one exists)
}
}
};
p.isTrackingProp = function(prop) {
return (this._lookup[prop] instanceof VelocityProp);
};
p.getVelocity = function(prop) {
var vp = this._lookup[prop],
target = this.target,
val, dif, rotationCap;
if (!vp) {
throw "The velocity of " + prop + " is not being tracked.";
}
val = vp.css ? _getStyle(target, vp.p) : vp.f ? target[vp.p]() : target[vp.p];
dif = (val - vp.v2);
if (vp.type === "rad" || vp.type === "deg") { //rotational values need special interpretation so that if, for example, they go from 179 to -178 degrees it is interpreted as a change of 3 instead of -357.
rotationCap = (vp.type === "rad") ? Math.PI * 2 : 360;
dif = dif % rotationCap;
if (dif !== dif % (rotationCap / 2)) {
dif = (dif < 0) ? dif + rotationCap : dif - rotationCap;
}
}
return dif / (_ticker.time - vp.t2);
};
p._altProp = function(p) { //for getters/setters like getCustomProp() and setCustomProp() - we should accommodate both
var pre = p.substr(0, 3),
alt = ((pre === "get") ? "set" : (pre === "set") ? "get" : pre) + p.substr(3);
return (typeof(this.target[alt]) === "function") ? alt : p;
};
VelocityTracker.getByTarget = function(target) {
var vt = _first;
if (typeof(target) === "string") {
target = TweenLite.selector(target);
}
if (target.length && target !== window && target[0] && target[0].style && !target.nodeType) {
target = target[0];
}
while (vt) {
if (vt.target === target) {
return vt;
}
vt = vt._next;
}
};
VelocityTracker.track = function(target, props, types) {
var vt = getByTarget(target),
a = props.split(","),
i = a.length;
types = (types || "").split(",");
if (!vt) {
vt = new VelocityTracker(target);
}
while (--i > -1) {
vt.addProp(a[i], types[i] || types[0]);
}
return vt;
};
VelocityTracker.untrack = function(target, props) {
var vt = getByTarget(target),
a = (props || "").split(","),
i = a.length;
if (!vt) {
return;
}
while (--i > -1) {
vt.removeProp(a[i]);
}
if (!vt._firstVP || !props) {
if (vt._prev) {
vt._prev._next = vt._next;
} else if (vt === _first) {
_first = vt._next;
}
if (vt._next) {
vt._next._prev = vt._prev;
}
}
};
VelocityTracker.isTracking = function(target, prop) {
var vt = getByTarget(target);
return (!vt) ? false : (!prop && vt._firstVP) ? true : vt.isTrackingProp(prop);
};
return VelocityTracker;
}, true);
}); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
//export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
(function(name) {
"use strict";
var getGlobal = function() {
return (_gsScope.GreenSockGlobals || _gsScope)[name];
};
if (typeof(module) !== "undefined" && module.exports) { //node
require("gsap/umd/TweenLite");
module.exports = getGlobal();
} else if (typeof(define) === "function" && define.amd) { //AMD
define(["gsap/umd/TweenLite"], getGlobal);
}
}("ThrowPropsPlugin"));