gsap
Version:
GSAP is a framework-agnostic JavaScript animation library that turns developers into animation superheroes. Build high-performance animations that work in **every** major browser. Animate CSS, SVG, canvas, React, Vue, WebGL, colors, strings, motion paths,
1,521 lines (1,309 loc) • 42.2 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = global || self, factory(global.window = global.window || {}));
}(this, (function (exports) { 'use strict';
var _svgPathExp = /[achlmqstvz]|(-?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_numbersExp = /(?:(-)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig,
_scientific = /[\+\-]?\d*\.?\d+e[\+\-]?\d+/ig,
_selectorExp = /(^[#\.][a-z]|[a-y][a-z])/i,
_DEG2RAD = Math.PI / 180,
_sin = Math.sin,
_cos = Math.cos,
_abs = Math.abs,
_sqrt = Math.sqrt,
_isString = function _isString(value) {
return typeof value === "string";
},
_isNumber = function _isNumber(value) {
return typeof value === "number";
},
_roundingNum = 1e5,
_round = function _round(value) {
return Math.round(value * _roundingNum) / _roundingNum || 0;
};
function getRawPath(value) {
value = _isString(value) && _selectorExp.test(value) ? document.querySelector(value) || value : value;
var e = value.getAttribute ? value : 0,
rawPath;
if (e && (value = value.getAttribute("d"))) {
if (!e._gsPath) {
e._gsPath = {};
}
rawPath = e._gsPath[value];
return rawPath && !rawPath._dirty ? rawPath : e._gsPath[value] = stringToRawPath(value);
}
return !value ? console.warn("Expecting a <path> element or an SVG path data string") : _isString(value) ? stringToRawPath(value) : _isNumber(value[0]) ? [value] : value;
}
function reverseSegment(segment) {
var i = 0,
y;
segment.reverse();
for (; i < segment.length; i += 2) {
y = segment[i];
segment[i] = segment[i + 1];
segment[i + 1] = y;
}
segment.reversed = !segment.reversed;
}
var _createPath = function _createPath(e, ignore) {
var path = document.createElementNS("http://www.w3.org/2000/svg", "path"),
attr = [].slice.call(e.attributes),
i = attr.length,
name;
ignore = "," + ignore + ",";
while (--i > -1) {
name = attr[i].nodeName.toLowerCase();
if (ignore.indexOf("," + name + ",") < 0) {
path.setAttributeNS(null, name, attr[i].nodeValue);
}
}
return path;
},
_typeAttrs = {
rect: "rx,ry,x,y,width,height",
circle: "r,cx,cy",
ellipse: "rx,ry,cx,cy",
line: "x1,x2,y1,y2"
},
_attrToObj = function _attrToObj(e, attrs) {
var props = attrs ? attrs.split(",") : [],
obj = {},
i = props.length;
while (--i > -1) {
obj[props[i]] = +e.getAttribute(props[i]) || 0;
}
return obj;
};
function convertToPath(element, swap) {
var type = element.tagName.toLowerCase(),
circ = 0.552284749831,
data,
x,
y,
r,
ry,
path,
rcirc,
rycirc,
points,
w,
h,
x2,
x3,
x4,
x5,
x6,
y2,
y3,
y4,
y5,
y6,
attr;
if (type === "path" || !element.getBBox) {
return element;
}
path = _createPath(element, "x,y,width,height,cx,cy,rx,ry,r,x1,x2,y1,y2,points");
attr = _attrToObj(element, _typeAttrs[type]);
if (type === "rect") {
r = attr.rx;
ry = attr.ry || r;
x = attr.x;
y = attr.y;
w = attr.width - r * 2;
h = attr.height - ry * 2;
if (r || ry) {
x2 = x + r * (1 - circ);
x3 = x + r;
x4 = x3 + w;
x5 = x4 + r * circ;
x6 = x4 + r;
y2 = y + ry * (1 - circ);
y3 = y + ry;
y4 = y3 + h;
y5 = y4 + ry * circ;
y6 = y4 + ry;
data = "M" + x6 + "," + y3 + " V" + y4 + " C" + [x6, y5, x5, y6, x4, y6, x4 - (x4 - x3) / 3, y6, x3 + (x4 - x3) / 3, y6, x3, y6, x2, y6, x, y5, x, y4, x, y4 - (y4 - y3) / 3, x, y3 + (y4 - y3) / 3, x, y3, x, y2, x2, y, x3, y, x3 + (x4 - x3) / 3, y, x4 - (x4 - x3) / 3, y, x4, y, x5, y, x6, y2, x6, y3].join(",") + "z";
} else {
data = "M" + (x + w) + "," + y + " v" + h + " h" + -w + " v" + -h + " h" + w + "z";
}
} else if (type === "circle" || type === "ellipse") {
if (type === "circle") {
r = ry = attr.r;
rycirc = r * circ;
} else {
r = attr.rx;
ry = attr.ry;
rycirc = ry * circ;
}
x = attr.cx;
y = attr.cy;
rcirc = r * circ;
data = "M" + (x + r) + "," + y + " C" + [x + r, y + rycirc, x + rcirc, y + ry, x, y + ry, x - rcirc, y + ry, x - r, y + rycirc, x - r, y, x - r, y - rycirc, x - rcirc, y - ry, x, y - ry, x + rcirc, y - ry, x + r, y - rycirc, x + r, y].join(",") + "z";
} else if (type === "line") {
data = "M" + attr.x1 + "," + attr.y1 + " L" + attr.x2 + "," + attr.y2;
} else if (type === "polyline" || type === "polygon") {
points = (element.getAttribute("points") + "").match(_numbersExp) || [];
x = points.shift();
y = points.shift();
data = "M" + x + "," + y + " L" + points.join(",");
if (type === "polygon") {
data += "," + x + "," + y + "z";
}
}
path.setAttribute("d", rawPathToString(path._gsRawPath = stringToRawPath(data)));
if (swap && element.parentNode) {
element.parentNode.insertBefore(path, element);
element.parentNode.removeChild(element);
}
return path;
}
function arcToSegment(lastX, lastY, rx, ry, angle, largeArcFlag, sweepFlag, x, y) {
if (lastX === x && lastY === y) {
return;
}
rx = _abs(rx);
ry = _abs(ry);
var angleRad = angle % 360 * _DEG2RAD,
cosAngle = _cos(angleRad),
sinAngle = _sin(angleRad),
PI = Math.PI,
TWOPI = PI * 2,
dx2 = (lastX - x) / 2,
dy2 = (lastY - y) / 2,
x1 = cosAngle * dx2 + sinAngle * dy2,
y1 = -sinAngle * dx2 + cosAngle * dy2,
x1_sq = x1 * x1,
y1_sq = y1 * y1,
radiiCheck = x1_sq / (rx * rx) + y1_sq / (ry * ry);
if (radiiCheck > 1) {
rx = _sqrt(radiiCheck) * rx;
ry = _sqrt(radiiCheck) * ry;
}
var rx_sq = rx * rx,
ry_sq = ry * ry,
sq = (rx_sq * ry_sq - rx_sq * y1_sq - ry_sq * x1_sq) / (rx_sq * y1_sq + ry_sq * x1_sq);
if (sq < 0) {
sq = 0;
}
var coef = (largeArcFlag === sweepFlag ? -1 : 1) * _sqrt(sq),
cx1 = coef * (rx * y1 / ry),
cy1 = coef * -(ry * x1 / rx),
sx2 = (lastX + x) / 2,
sy2 = (lastY + y) / 2,
cx = sx2 + (cosAngle * cx1 - sinAngle * cy1),
cy = sy2 + (sinAngle * cx1 + cosAngle * cy1),
ux = (x1 - cx1) / rx,
uy = (y1 - cy1) / ry,
vx = (-x1 - cx1) / rx,
vy = (-y1 - cy1) / ry,
temp = ux * ux + uy * uy,
angleStart = (uy < 0 ? -1 : 1) * Math.acos(ux / _sqrt(temp)),
angleExtent = (ux * vy - uy * vx < 0 ? -1 : 1) * Math.acos((ux * vx + uy * vy) / _sqrt(temp * (vx * vx + vy * vy)));
isNaN(angleExtent) && (angleExtent = PI);
if (!sweepFlag && angleExtent > 0) {
angleExtent -= TWOPI;
} else if (sweepFlag && angleExtent < 0) {
angleExtent += TWOPI;
}
angleStart %= TWOPI;
angleExtent %= TWOPI;
var segments = Math.ceil(_abs(angleExtent) / (TWOPI / 4)),
rawPath = [],
angleIncrement = angleExtent / segments,
controlLength = 4 / 3 * _sin(angleIncrement / 2) / (1 + _cos(angleIncrement / 2)),
ma = cosAngle * rx,
mb = sinAngle * rx,
mc = sinAngle * -ry,
md = cosAngle * ry,
i;
for (i = 0; i < segments; i++) {
angle = angleStart + i * angleIncrement;
x1 = _cos(angle);
y1 = _sin(angle);
ux = _cos(angle += angleIncrement);
uy = _sin(angle);
rawPath.push(x1 - controlLength * y1, y1 + controlLength * x1, ux + controlLength * uy, uy - controlLength * ux, ux, uy);
}
for (i = 0; i < rawPath.length; i += 2) {
x1 = rawPath[i];
y1 = rawPath[i + 1];
rawPath[i] = x1 * ma + y1 * mc + cx;
rawPath[i + 1] = x1 * mb + y1 * md + cy;
}
rawPath[i - 2] = x;
rawPath[i - 1] = y;
return rawPath;
}
function stringToRawPath(d) {
var a = (d + "").replace(_scientific, function (m) {
var n = +m;
return n < 0.0001 && n > -0.0001 ? 0 : n;
}).match(_svgPathExp) || [],
path = [],
relativeX = 0,
relativeY = 0,
twoThirds = 2 / 3,
elements = a.length,
points = 0,
errorMessage = "ERROR: malformed path: " + d,
i,
j,
x,
y,
command,
isRelative,
segment,
startX,
startY,
difX,
difY,
beziers,
prevCommand,
flag1,
flag2,
line = function line(sx, sy, ex, ey) {
difX = (ex - sx) / 3;
difY = (ey - sy) / 3;
segment.push(sx + difX, sy + difY, ex - difX, ey - difY, ex, ey);
};
if (!d || !isNaN(a[0]) || isNaN(a[1])) {
console.log(errorMessage);
return path;
}
for (i = 0; i < elements; i++) {
prevCommand = command;
if (isNaN(a[i])) {
command = a[i].toUpperCase();
isRelative = command !== a[i];
} else {
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) {
if (segment.length < 8) {
path.length -= 1;
} else {
points += segment.length;
}
}
relativeX = startX = x;
relativeY = startY = y;
segment = [x, y];
path.push(segment);
i += 2;
command = "L";
} else if (command === "C") {
if (!segment) {
segment = [0, 0];
}
if (!isRelative) {
relativeX = relativeY = 0;
}
segment.push(x, y, relativeX + a[i + 3] * 1, relativeY + a[i + 4] * 1, relativeX += a[i + 5] * 1, relativeY += a[i + 6] * 1);
i += 6;
} else if (command === "S") {
difX = relativeX;
difY = relativeY;
if (prevCommand === "C" || prevCommand === "S") {
difX += relativeX - segment[segment.length - 4];
difY += relativeY - segment[segment.length - 3];
}
if (!isRelative) {
relativeX = relativeY = 0;
}
segment.push(difX, difY, x, y, relativeX += a[i + 3] * 1, relativeY += a[i + 4] * 1);
i += 4;
} else if (command === "Q") {
difX = relativeX + (x - relativeX) * twoThirds;
difY = relativeY + (y - relativeY) * twoThirds;
if (!isRelative) {
relativeX = relativeY = 0;
}
relativeX += a[i + 3] * 1;
relativeY += a[i + 4] * 1;
segment.push(difX, difY, relativeX + (x - relativeX) * twoThirds, relativeY + (y - relativeY) * twoThirds, relativeX, relativeY);
i += 4;
} else if (command === "T") {
difX = relativeX - segment[segment.length - 4];
difY = relativeY - segment[segment.length - 3];
segment.push(relativeX + difX, relativeY + difY, x + (relativeX + difX * 1.5 - x) * twoThirds, y + (relativeY + difY * 1.5 - y) * twoThirds, relativeX = x, relativeY = y);
i += 2;
} else if (command === "H") {
line(relativeX, relativeY, relativeX = x, relativeY);
i += 1;
} else if (command === "V") {
line(relativeX, relativeY, relativeX, relativeY = x + (isRelative ? relativeY - relativeX : 0));
i += 1;
} else if (command === "L" || command === "Z") {
if (command === "Z") {
x = startX;
y = startY;
segment.closed = true;
}
if (command === "L" || _abs(relativeX - x) > 0.5 || _abs(relativeY - y) > 0.5) {
line(relativeX, relativeY, x, y);
if (command === "L") {
i += 2;
}
}
relativeX = x;
relativeY = y;
} else if (command === "A") {
flag1 = a[i + 4];
flag2 = a[i + 5];
difX = a[i + 6];
difY = a[i + 7];
j = 7;
if (flag1.length > 1) {
if (flag1.length < 3) {
difY = difX;
difX = flag2;
j--;
} else {
difY = flag2;
difX = flag1.substr(2);
j -= 2;
}
flag2 = flag1.charAt(1);
flag1 = flag1.charAt(0);
}
beziers = arcToSegment(relativeX, relativeY, +a[i + 1], +a[i + 2], +a[i + 3], +flag1, +flag2, (isRelative ? relativeX : 0) + difX * 1, (isRelative ? relativeY : 0) + difY * 1);
i += j;
if (beziers) {
for (j = 0; j < beziers.length; j++) {
segment.push(beziers[j]);
}
}
relativeX = segment[segment.length - 2];
relativeY = segment[segment.length - 1];
} else {
console.log(errorMessage);
}
}
i = segment.length;
if (i < 6) {
path.pop();
i = 0;
} else if (segment[0] === segment[i - 2] && segment[1] === segment[i - 1]) {
segment.closed = true;
}
path.totalPoints = points + i;
return path;
}
function rawPathToString(rawPath) {
if (_isNumber(rawPath[0])) {
rawPath = [rawPath];
}
var result = "",
l = rawPath.length,
sl,
s,
i,
segment;
for (s = 0; s < l; s++) {
segment = rawPath[s];
result += "M" + _round(segment[0]) + "," + _round(segment[1]) + " C";
sl = segment.length;
for (i = 2; i < sl; i++) {
result += _round(segment[i++]) + "," + _round(segment[i++]) + " " + _round(segment[i++]) + "," + _round(segment[i++]) + " " + _round(segment[i++]) + "," + _round(segment[i]) + " ";
}
if (segment.closed) {
result += "z";
}
}
return result;
}
/*!
* MorphSVGPlugin 3.13.0
* https://gsap.com
*
* @license Copyright 2008-2025, GreenSock. All rights reserved.
* Subject to the terms at https://gsap.com/standard-license
* @author: Jack Doyle, jack@greensock.com
*/
var gsap,
_toArray,
_lastLinkedAnchor,
_coreInitted,
PluginClass,
_getGSAP = function _getGSAP() {
return gsap || typeof window !== "undefined" && (gsap = window.gsap) && gsap.registerPlugin && gsap;
},
_isFunction = function _isFunction(value) {
return typeof value === "function";
},
_atan2 = Math.atan2,
_cos$1 = Math.cos,
_sin$1 = Math.sin,
_sqrt$1 = Math.sqrt,
_PI = Math.PI,
_2PI = _PI * 2,
_angleMin = _PI * 0.3,
_angleMax = _PI * 0.7,
_bigNum = 1e20,
_numExp = /[-+=\.]*\d+[\.e\-\+]*\d*[e\-\+]*\d*/gi,
_selectorExp$1 = /(^[#\.][a-z]|[a-y][a-z])/i,
_commands = /[achlmqstvz]/i,
_log = function _log(message) {
return console && console.warn(message);
},
_bonusValidated = 1,
_getAverageXY = function _getAverageXY(segment) {
var l = segment.length,
x = 0,
y = 0,
i;
for (i = 0; i < l; i++) {
x += segment[i++];
y += segment[i];
}
return [x / (l / 2), y / (l / 2)];
},
_getSize = function _getSize(segment) {
var l = segment.length,
xMax = segment[0],
xMin = xMax,
yMax = segment[1],
yMin = yMax,
x,
y,
i;
for (i = 6; i < l; i += 6) {
x = segment[i];
y = segment[i + 1];
if (x > xMax) {
xMax = x;
} else if (x < xMin) {
xMin = x;
}
if (y > yMax) {
yMax = y;
} else if (y < yMin) {
yMin = y;
}
}
segment.centerX = (xMax + xMin) / 2;
segment.centerY = (yMax + yMin) / 2;
return segment.size = (xMax - xMin) * (yMax - yMin);
},
_getTotalSize = function _getTotalSize(rawPath, samplesPerBezier) {
if (samplesPerBezier === void 0) {
samplesPerBezier = 3;
}
var j = rawPath.length,
xMax = rawPath[0][0],
xMin = xMax,
yMax = rawPath[0][1],
yMin = yMax,
inc = 1 / samplesPerBezier,
l,
x,
y,
i,
segment,
k,
t,
inv,
x1,
y1,
x2,
x3,
x4,
y2,
y3,
y4;
while (--j > -1) {
segment = rawPath[j];
l = segment.length;
for (i = 6; i < l; i += 6) {
x1 = segment[i];
y1 = segment[i + 1];
x2 = segment[i + 2] - x1;
y2 = segment[i + 3] - y1;
x3 = segment[i + 4] - x1;
y3 = segment[i + 5] - y1;
x4 = segment[i + 6] - x1;
y4 = segment[i + 7] - y1;
k = samplesPerBezier;
while (--k > -1) {
t = inc * k;
inv = 1 - t;
x = (t * t * x4 + 3 * inv * (t * x3 + inv * x2)) * t + x1;
y = (t * t * y4 + 3 * inv * (t * y3 + inv * y2)) * t + y1;
if (x > xMax) {
xMax = x;
} else if (x < xMin) {
xMin = x;
}
if (y > yMax) {
yMax = y;
} else if (y < yMin) {
yMin = y;
}
}
}
}
rawPath.centerX = (xMax + xMin) / 2;
rawPath.centerY = (yMax + yMin) / 2;
rawPath.left = xMin;
rawPath.width = xMax - xMin;
rawPath.top = yMin;
rawPath.height = yMax - yMin;
return rawPath.size = (xMax - xMin) * (yMax - yMin);
},
_sortByComplexity = function _sortByComplexity(a, b) {
return b.length - a.length;
},
_sortBySize = function _sortBySize(a, b) {
var sizeA = a.size || _getSize(a),
sizeB = b.size || _getSize(b);
return Math.abs(sizeB - sizeA) < (sizeA + sizeB) / 20 ? b.centerX - a.centerX || b.centerY - a.centerY : sizeB - sizeA;
},
_offsetSegment = function _offsetSegment(segment, shapeIndex) {
var a = segment.slice(0),
l = segment.length,
wrap = l - 2,
i,
index;
shapeIndex = shapeIndex | 0;
for (i = 0; i < l; i++) {
index = (i + shapeIndex) % wrap;
segment[i++] = a[index];
segment[i] = a[index + 1];
}
},
_getTotalMovement = function _getTotalMovement(sb, eb, shapeIndex, offsetX, offsetY) {
var l = sb.length,
d = 0,
wrap = l - 2,
index,
i,
x,
y;
shapeIndex *= 6;
for (i = 0; i < l; i += 6) {
index = (i + shapeIndex) % wrap;
y = sb[index] - (eb[i] - offsetX);
x = sb[index + 1] - (eb[i + 1] - offsetY);
d += _sqrt$1(x * x + y * y);
}
return d;
},
_getClosestShapeIndex = function _getClosestShapeIndex(sb, eb, checkReverse) {
var l = sb.length,
sCenter = _getAverageXY(sb),
eCenter = _getAverageXY(eb),
offsetX = eCenter[0] - sCenter[0],
offsetY = eCenter[1] - sCenter[1],
min = _getTotalMovement(sb, eb, 0, offsetX, offsetY),
minIndex = 0,
copy,
d,
i;
for (i = 6; i < l; i += 6) {
d = _getTotalMovement(sb, eb, i / 6, offsetX, offsetY);
if (d < min) {
min = d;
minIndex = i;
}
}
if (checkReverse) {
copy = sb.slice(0);
reverseSegment(copy);
for (i = 6; i < l; i += 6) {
d = _getTotalMovement(copy, eb, i / 6, offsetX, offsetY);
if (d < min) {
min = d;
minIndex = -i;
}
}
}
return minIndex / 6;
},
_getClosestAnchor = function _getClosestAnchor(rawPath, x, y) {
var j = rawPath.length,
closestDistance = _bigNum,
closestX = 0,
closestY = 0,
segment,
dx,
dy,
d,
i,
l;
while (--j > -1) {
segment = rawPath[j];
l = segment.length;
for (i = 0; i < l; i += 6) {
dx = segment[i] - x;
dy = segment[i + 1] - y;
d = _sqrt$1(dx * dx + dy * dy);
if (d < closestDistance) {
closestDistance = d;
closestX = segment[i];
closestY = segment[i + 1];
}
}
}
return [closestX, closestY];
},
_getClosestSegment = function _getClosestSegment(bezier, pool, startIndex, sortRatio, offsetX, offsetY) {
var l = pool.length,
index = 0,
minSize = Math.min(bezier.size || _getSize(bezier), pool[startIndex].size || _getSize(pool[startIndex])) * sortRatio,
min = _bigNum,
cx = bezier.centerX + offsetX,
cy = bezier.centerY + offsetY,
size,
i,
dx,
dy,
d;
for (i = startIndex; i < l; i++) {
size = pool[i].size || _getSize(pool[i]);
if (size < minSize) {
break;
}
dx = pool[i].centerX - cx;
dy = pool[i].centerY - cy;
d = _sqrt$1(dx * dx + dy * dy);
if (d < min) {
index = i;
min = d;
}
}
d = pool[index];
pool.splice(index, 1);
return d;
},
_subdivideSegmentQty = function _subdivideSegmentQty(segment, quantity) {
var tally = 0,
max = 0.999999,
l = segment.length,
newPointsPerSegment = quantity / ((l - 2) / 6),
ax,
ay,
cp1x,
cp1y,
cp2x,
cp2y,
bx,
by,
x1,
y1,
x2,
y2,
i,
t;
for (i = 2; i < l; i += 6) {
tally += newPointsPerSegment;
while (tally > max) {
ax = segment[i - 2];
ay = segment[i - 1];
cp1x = segment[i];
cp1y = segment[i + 1];
cp2x = segment[i + 2];
cp2y = segment[i + 3];
bx = segment[i + 4];
by = segment[i + 5];
t = 1 / ((Math.floor(tally) || 1) + 1);
x1 = ax + (cp1x - ax) * t;
x2 = cp1x + (cp2x - cp1x) * t;
x1 += (x2 - x1) * t;
x2 += (cp2x + (bx - cp2x) * t - x2) * t;
y1 = ay + (cp1y - ay) * t;
y2 = cp1y + (cp2y - cp1y) * t;
y1 += (y2 - y1) * t;
y2 += (cp2y + (by - cp2y) * t - y2) * t;
segment.splice(i, 4, ax + (cp1x - ax) * t, ay + (cp1y - ay) * t, x1, y1, x1 + (x2 - x1) * t, y1 + (y2 - y1) * t, x2, y2, cp2x + (bx - cp2x) * t, cp2y + (by - cp2y) * t);
i += 6;
l += 6;
tally--;
}
}
return segment;
},
_equalizeSegmentQuantity = function _equalizeSegmentQuantity(start, end, shapeIndex, map, fillSafe) {
var dif = end.length - start.length,
longer = dif > 0 ? end : start,
shorter = dif > 0 ? start : end,
added = 0,
sortMethod = map === "complexity" ? _sortByComplexity : _sortBySize,
sortRatio = map === "position" ? 0 : typeof map === "number" ? map : 0.8,
i = shorter.length,
shapeIndices = typeof shapeIndex === "object" && shapeIndex.push ? shapeIndex.slice(0) : [shapeIndex],
reverse = shapeIndices[0] === "reverse" || shapeIndices[0] < 0,
log = shapeIndex === "log",
eb,
sb,
b,
x,
y,
offsetX,
offsetY;
if (!shorter[0]) {
return;
}
if (longer.length > 1) {
start.sort(sortMethod);
end.sort(sortMethod);
offsetX = longer.size || _getTotalSize(longer);
offsetX = shorter.size || _getTotalSize(shorter);
offsetX = longer.centerX - shorter.centerX;
offsetY = longer.centerY - shorter.centerY;
if (sortMethod === _sortBySize) {
for (i = 0; i < shorter.length; i++) {
longer.splice(i, 0, _getClosestSegment(shorter[i], longer, i, sortRatio, offsetX, offsetY));
}
}
}
if (dif) {
if (dif < 0) {
dif = -dif;
}
if (longer[0].length > shorter[0].length) {
_subdivideSegmentQty(shorter[0], (longer[0].length - shorter[0].length) / 6 | 0);
}
i = shorter.length;
while (added < dif) {
x = longer[i].size || _getSize(longer[i]);
b = _getClosestAnchor(shorter, longer[i].centerX, longer[i].centerY);
x = b[0];
y = b[1];
shorter[i++] = [x, y, x, y, x, y, x, y];
shorter.totalPoints += 8;
added++;
}
}
for (i = 0; i < start.length; i++) {
eb = end[i];
sb = start[i];
dif = eb.length - sb.length;
if (dif < 0) {
_subdivideSegmentQty(eb, -dif / 6 | 0);
} else if (dif > 0) {
_subdivideSegmentQty(sb, dif / 6 | 0);
}
if (reverse && fillSafe !== false && !sb.reversed) {
reverseSegment(sb);
}
shapeIndex = shapeIndices[i] || shapeIndices[i] === 0 ? shapeIndices[i] : "auto";
if (shapeIndex) {
if (sb.closed || Math.abs(sb[0] - sb[sb.length - 2]) < 0.5 && Math.abs(sb[1] - sb[sb.length - 1]) < 0.5) {
if (shapeIndex === "auto" || shapeIndex === "log") {
shapeIndices[i] = shapeIndex = _getClosestShapeIndex(sb, eb, !i || fillSafe === false);
if (shapeIndex < 0) {
reverse = true;
reverseSegment(sb);
shapeIndex = -shapeIndex;
}
_offsetSegment(sb, shapeIndex * 6);
} else if (shapeIndex !== "reverse") {
if (i && shapeIndex < 0) {
reverseSegment(sb);
}
_offsetSegment(sb, (shapeIndex < 0 ? -shapeIndex : shapeIndex) * 6);
}
} else if (!reverse && (shapeIndex === "auto" && Math.abs(eb[0] - sb[0]) + Math.abs(eb[1] - sb[1]) + Math.abs(eb[eb.length - 2] - sb[sb.length - 2]) + Math.abs(eb[eb.length - 1] - sb[sb.length - 1]) > Math.abs(eb[0] - sb[sb.length - 2]) + Math.abs(eb[1] - sb[sb.length - 1]) + Math.abs(eb[eb.length - 2] - sb[0]) + Math.abs(eb[eb.length - 1] - sb[1]) || shapeIndex % 2)) {
reverseSegment(sb);
shapeIndices[i] = -1;
reverse = true;
} else if (shapeIndex === "auto") {
shapeIndices[i] = 0;
} else if (shapeIndex === "reverse") {
shapeIndices[i] = -1;
}
if (sb.closed !== eb.closed) {
sb.closed = eb.closed = false;
}
}
}
log && _log("shapeIndex:[" + shapeIndices.join(",") + "]");
start.shapeIndex = shapeIndices;
return shapeIndices;
},
_pathFilter = function _pathFilter(a, shapeIndex, map, precompile, fillSafe) {
var start = stringToRawPath(a[0]),
end = stringToRawPath(a[1]);
if (!_equalizeSegmentQuantity(start, end, shapeIndex || shapeIndex === 0 ? shapeIndex : "auto", map, fillSafe)) {
return;
}
a[0] = rawPathToString(start);
a[1] = rawPathToString(end);
if (precompile === "log" || precompile === true) {
_log('precompile:["' + a[0] + '","' + a[1] + '"]');
}
},
_offsetPoints = function _offsetPoints(text, offset) {
if (!offset) {
return text;
}
var a = text.match(_numExp) || [],
l = a.length,
s = "",
inc,
i,
j;
if (offset === "reverse") {
i = l - 1;
inc = -2;
} else {
i = ((parseInt(offset, 10) || 0) * 2 + 1 + l * 100) % l;
inc = 2;
}
for (j = 0; j < l; j += 2) {
s += a[i - 1] + "," + a[i] + " ";
i = (i + inc) % l;
}
return s;
},
_equalizePointQuantity = function _equalizePointQuantity(a, quantity) {
var tally = 0,
x = parseFloat(a[0]),
y = parseFloat(a[1]),
s = x + "," + y + " ",
max = 0.999999,
newPointsPerSegment,
i,
l,
j,
factor,
nextX,
nextY;
l = a.length;
newPointsPerSegment = quantity * 0.5 / (l * 0.5 - 1);
for (i = 0; i < l - 2; i += 2) {
tally += newPointsPerSegment;
nextX = parseFloat(a[i + 2]);
nextY = parseFloat(a[i + 3]);
if (tally > max) {
factor = 1 / (Math.floor(tally) + 1);
j = 1;
while (tally > max) {
s += (x + (nextX - x) * factor * j).toFixed(2) + "," + (y + (nextY - y) * factor * j).toFixed(2) + " ";
tally--;
j++;
}
}
s += nextX + "," + nextY + " ";
x = nextX;
y = nextY;
}
return s;
},
_pointsFilter = function _pointsFilter(a) {
var startNums = a[0].match(_numExp) || [],
endNums = a[1].match(_numExp) || [],
dif = endNums.length - startNums.length;
if (dif > 0) {
a[0] = _equalizePointQuantity(startNums, dif);
} else {
a[1] = _equalizePointQuantity(endNums, -dif);
}
},
_buildPointsFilter = function _buildPointsFilter(shapeIndex) {
return !isNaN(shapeIndex) ? function (a) {
_pointsFilter(a);
a[1] = _offsetPoints(a[1], parseInt(shapeIndex, 10));
} : _pointsFilter;
},
_parseShape = function _parseShape(shape, forcePath, target) {
var isString = typeof shape === "string",
e,
type;
if (!isString || _selectorExp$1.test(shape) || (shape.match(_numExp) || []).length < 3) {
e = _toArray(shape)[0];
if (e) {
type = (e.nodeName + "").toUpperCase();
if (forcePath && type !== "PATH") {
e = convertToPath(e, false);
type = "PATH";
}
shape = e.getAttribute(type === "PATH" ? "d" : "points") || "";
if (e === target) {
shape = e.getAttributeNS(null, "data-original") || shape;
}
} else {
_log("WARNING: invalid morph to: " + shape);
shape = false;
}
}
return shape;
},
_populateSmoothData = function _populateSmoothData(rawPath, tolerance) {
var j = rawPath.length,
limit = 0.2 * (tolerance || 1),
smooth,
segment,
x,
y,
x2,
y2,
i,
l,
a,
a2,
isSmooth,
smoothData;
while (--j > -1) {
segment = rawPath[j];
isSmooth = segment.isSmooth = segment.isSmooth || [0, 0, 0, 0];
smoothData = segment.smoothData = segment.smoothData || [0, 0, 0, 0];
isSmooth.length = 4;
l = segment.length - 2;
for (i = 6; i < l; i += 6) {
x = segment[i] - segment[i - 2];
y = segment[i + 1] - segment[i - 1];
x2 = segment[i + 2] - segment[i];
y2 = segment[i + 3] - segment[i + 1];
a = _atan2(y, x);
a2 = _atan2(y2, x2);
smooth = Math.abs(a - a2) < limit;
if (smooth) {
smoothData[i - 2] = a;
smoothData[i + 2] = a2;
smoothData[i - 1] = _sqrt$1(x * x + y * y);
smoothData[i + 3] = _sqrt$1(x2 * x2 + y2 * y2);
}
isSmooth.push(smooth, smooth, 0, 0, smooth, smooth);
}
if (segment[l] === segment[0] && segment[l + 1] === segment[1]) {
x = segment[0] - segment[l - 2];
y = segment[1] - segment[l - 1];
x2 = segment[2] - segment[0];
y2 = segment[3] - segment[1];
a = _atan2(y, x);
a2 = _atan2(y2, x2);
if (Math.abs(a - a2) < limit) {
smoothData[l - 2] = a;
smoothData[2] = a2;
smoothData[l - 1] = _sqrt$1(x * x + y * y);
smoothData[3] = _sqrt$1(x2 * x2 + y2 * y2);
isSmooth[l - 2] = isSmooth[l - 1] = true;
}
}
}
return rawPath;
},
_parseOriginFactors = function _parseOriginFactors(v) {
var a = v.trim().split(" "),
x = ~v.indexOf("left") ? 0 : ~v.indexOf("right") ? 100 : isNaN(parseFloat(a[0])) ? 50 : parseFloat(a[0]),
y = ~v.indexOf("top") ? 0 : ~v.indexOf("bottom") ? 100 : isNaN(parseFloat(a[1])) ? 50 : parseFloat(a[1]);
return {
x: x / 100,
y: y / 100
};
},
_shortAngle = function _shortAngle(dif) {
return dif !== dif % _PI ? dif + (dif < 0 ? _2PI : -_2PI) : dif;
},
_morphMessage = "Use MorphSVGPlugin.convertToPath() to convert to a path before morphing.",
_tweenRotation = function _tweenRotation(start, end, i, linkedPT) {
var so = this._origin,
eo = this._eOrigin,
dx = start[i] - so.x,
dy = start[i + 1] - so.y,
d = _sqrt$1(dx * dx + dy * dy),
sa = _atan2(dy, dx),
angleDif,
_short;
dx = end[i] - eo.x;
dy = end[i + 1] - eo.y;
angleDif = _atan2(dy, dx) - sa;
_short = _shortAngle(angleDif);
if (!linkedPT && _lastLinkedAnchor && Math.abs(_short + _lastLinkedAnchor.ca) < _angleMin) {
linkedPT = _lastLinkedAnchor;
}
return this._anchorPT = _lastLinkedAnchor = {
_next: this._anchorPT,
t: start,
sa: sa,
ca: linkedPT && _short * linkedPT.ca < 0 && Math.abs(_short) > _angleMax ? angleDif : _short,
sl: d,
cl: _sqrt$1(dx * dx + dy * dy) - d,
i: i
};
},
_initCore = function _initCore(required) {
gsap = _getGSAP();
PluginClass = PluginClass || gsap && gsap.plugins.morphSVG;
if (gsap && PluginClass) {
_toArray = gsap.utils.toArray;
PluginClass.prototype._tweenRotation = _tweenRotation;
_coreInitted = 1;
} else if (required) {
_log("Please gsap.registerPlugin(MorphSVGPlugin)");
}
};
var MorphSVGPlugin = {
version: "3.13.0",
name: "morphSVG",
rawVars: 1,
register: function register(core, Plugin) {
gsap = core;
PluginClass = Plugin;
_initCore();
},
init: function init(target, value, tween, index, targets) {
_coreInitted || _initCore(1);
if (!value) {
_log("invalid shape");
return false;
}
_isFunction(value) && (value = value.call(tween, index, target, targets));
var type, p, pt, shape, isPoly, shapeIndex, map, startSmooth, endSmooth, start, end, i, j, l, startSeg, endSeg, precompiled, sData, eData, originFactors, useRotation, offset;
if (typeof value === "string" || value.getBBox || value[0]) {
value = {
shape: value
};
} else if (typeof value === "object") {
type = {};
for (p in value) {
type[p] = _isFunction(value[p]) && p !== "render" ? value[p].call(tween, index, target, targets) : value[p];
}
value = type;
}
var cs = target.nodeType ? window.getComputedStyle(target) : {},
fill = cs.fill + "",
fillSafe = !(fill === "none" || (fill.match(_numExp) || [])[3] === "0" || cs.fillRule === "evenodd"),
origins = (value.origin || "50 50").split(",");
type = (target.nodeName + "").toUpperCase();
isPoly = type === "POLYLINE" || type === "POLYGON";
if (type !== "PATH" && !isPoly && !value.prop) {
_log("Cannot morph a <" + type + "> element. " + _morphMessage);
return false;
}
p = type === "PATH" ? "d" : "points";
if (!value.prop && !_isFunction(target.setAttribute)) {
return false;
}
shape = _parseShape(value.shape || value.d || value.points || "", p === "d", target);
if (isPoly && _commands.test(shape)) {
_log("A <" + type + "> cannot accept path data. " + _morphMessage);
return false;
}
shapeIndex = value.shapeIndex || value.shapeIndex === 0 ? value.shapeIndex : "auto";
map = value.map || MorphSVGPlugin.defaultMap;
this._prop = value.prop;
this._render = value.render || MorphSVGPlugin.defaultRender;
this._apply = "updateTarget" in value ? value.updateTarget : MorphSVGPlugin.defaultUpdateTarget;
this._rnd = Math.pow(10, isNaN(value.precision) ? 2 : +value.precision);
this._tween = tween;
if (shape) {
this._target = target;
precompiled = typeof value.precompile === "object";
start = this._prop ? target[this._prop] : target.getAttribute(p);
if (!this._prop && !target.getAttributeNS(null, "data-original")) {
target.setAttributeNS(null, "data-original", start);
}
if (p === "d" || this._prop) {
start = stringToRawPath(precompiled ? value.precompile[0] : start);
end = stringToRawPath(precompiled ? value.precompile[1] : shape);
if (!precompiled && !_equalizeSegmentQuantity(start, end, shapeIndex, map, fillSafe)) {
return false;
}
if (value.precompile === "log" || value.precompile === true) {
_log('precompile:["' + rawPathToString(start) + '","' + rawPathToString(end) + '"]');
}
useRotation = (value.type || MorphSVGPlugin.defaultType) !== "linear";
if (useRotation) {
start = _populateSmoothData(start, value.smoothTolerance);
end = _populateSmoothData(end, value.smoothTolerance);
if (!start.size) {
_getTotalSize(start);
}
if (!end.size) {
_getTotalSize(end);
}
originFactors = _parseOriginFactors(origins[0]);
this._origin = start.origin = {
x: start.left + originFactors.x * start.width,
y: start.top + originFactors.y * start.height
};
if (origins[1]) {
originFactors = _parseOriginFactors(origins[1]);
}
this._eOrigin = {
x: end.left + originFactors.x * end.width,
y: end.top + originFactors.y * end.height
};
}
this._rawPath = target._gsRawPath = start;
j = start.length;
while (--j > -1) {
startSeg = start[j];
endSeg = end[j];
startSmooth = startSeg.isSmooth || [];
endSmooth = endSeg.isSmooth || [];
l = startSeg.length;
_lastLinkedAnchor = 0;
for (i = 0; i < l; i += 2) {
if (endSeg[i] !== startSeg[i] || endSeg[i + 1] !== startSeg[i + 1]) {
if (useRotation) {
if (startSmooth[i] && endSmooth[i]) {
sData = startSeg.smoothData;
eData = endSeg.smoothData;
offset = i + (i === l - 4 ? 7 - l : 5);
this._controlPT = {
_next: this._controlPT,
i: i,
j: j,
l1s: sData[i + 1],
l1c: eData[i + 1] - sData[i + 1],
l2s: sData[offset],
l2c: eData[offset] - sData[offset]
};
pt = this._tweenRotation(startSeg, endSeg, i + 2);
this._tweenRotation(startSeg, endSeg, i, pt);
this._tweenRotation(startSeg, endSeg, offset - 1, pt);
i += 4;
} else {
this._tweenRotation(startSeg, endSeg, i);
}
} else {
pt = this.add(startSeg, i, startSeg[i], endSeg[i], 0, 0, 0, 0, 0, 1);
pt = this.add(startSeg, i + 1, startSeg[i + 1], endSeg[i + 1], 0, 0, 0, 0, 0, 1) || pt;
}
}
}
}
} else {
pt = this.add(target, "setAttribute", target.getAttribute(p) + "", shape + "", index, targets, 0, _buildPointsFilter(shapeIndex), p);
}
if (useRotation) {
this.add(this._origin, "x", this._origin.x, this._eOrigin.x, 0, 0, 0, 0, 0, 1);
pt = this.add(this._origin, "y", this._origin.y, this._eOrigin.y, 0, 0, 0, 0, 0, 1);
}
if (pt) {
this._props.push("morphSVG");
pt.end = shape;
pt.endProp = p;
}
}
return _bonusValidated;
},
render: function render(ratio, data) {
var rawPath = data._rawPath,
controlPT = data._controlPT,
anchorPT = data._anchorPT,
rnd = data._rnd,
target = data._target,
pt = data._pt,
s,
space,
easeInOut,
segment,
l,
angle,
i,
j,
x,
y,
sin,
cos,
offset;
while (pt) {
pt.r(ratio, pt.d);
pt = pt._next;
}
if (ratio === 1 && data._apply) {
pt = data._pt;
while (pt) {
if (pt.end) {
if (data._prop) {
target[data._prop] = pt.end;
} else {
target.setAttribute(pt.endProp, pt.end);
}
}
pt = pt._next;
}
} else if (rawPath) {
while (anchorPT) {
angle = anchorPT.sa + ratio * anchorPT.ca;
l = anchorPT.sl + ratio * anchorPT.cl;
anchorPT.t[anchorPT.i] = data._origin.x + _cos$1(angle) * l;
anchorPT.t[anchorPT.i + 1] = data._origin.y + _sin$1(angle) * l;
anchorPT = anchorPT._next;
}
easeInOut = ratio < 0.5 ? 2 * ratio * ratio : (4 - 2 * ratio) * ratio - 1;
while (controlPT) {
i = controlPT.i;
segment = rawPath[controlPT.j];
offset = i + (i === segment.length - 4 ? 7 - segment.length : 5);
angle = _atan2(segment[offset] - segment[i + 1], segment[offset - 1] - segment[i]);
sin = _sin$1(angle);
cos = _cos$1(angle);
x = segment[i + 2];
y = segment[i + 3];
l = controlPT.l1s + easeInOut * controlPT.l1c;
segment[i] = x - cos * l;
segment[i + 1] = y - sin * l;
l = controlPT.l2s + easeInOut * controlPT.l2c;
segment[offset - 1] = x + cos * l;
segment[offset] = y + sin * l;
controlPT = controlPT._next;
}
target._gsRawPath = rawPath;
if (data._apply) {
s = "";
space = " ";
for (j = 0; j < rawPath.length; j++) {
segment = rawPath[j];
l = segment.length;
s += "M" + (segment[0] * rnd | 0) / rnd + space + (segment[1] * rnd | 0) / rnd + " C";
for (i = 2; i < l; i++) {
s += (segment[i] * rnd | 0) / rnd + space;
}
}
if (data._prop) {
target[data._prop] = s;
} else {
target.setAttribute("d", s);
}
}
}
data._render && rawPath && data._render.call(data._tween, rawPath, target);
},
kill: function kill(property) {
this._pt = this._rawPath = 0;
},
getRawPath: getRawPath,
stringToRawPath: stringToRawPath,
rawPathToString: rawPathToString,
normalizeStrings: function normalizeStrings(shape1, shape2, _ref) {
var shapeIndex = _ref.shapeIndex,
map = _ref.map;
var result = [shape1, shape2];
_pathFilter(result, shapeIndex, map);
return result;
},
pathFilter: _pathFilter,
pointsFilter: _pointsFilter,
getTotalSize: _getTotalSize,
equalizeSegmentQuantity: _equalizeSegmentQuantity,
convertToPath: function convertToPath$1(targets, swap) {
return _toArray(targets).map(function (target) {
return convertToPath(target, swap !== false);
});
},
defaultType: "linear",
defaultUpdateTarget: true,
defaultMap: "size"
};
_getGSAP() && gsap.registerPlugin(MorphSVGPlugin);
exports.MorphSVGPlugin = MorphSVGPlugin;
exports.default = MorphSVGPlugin;
Object.defineProperty(exports, '__esModule', { value: true });
})));