UNPKG

gsap

Version:

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

1,787 lines (1,500 loc) 90 kB
(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, _scientific = /[\+\-]?\d*\.?\d+e[\+\-]?\d+/ig, _DEG2RAD = Math.PI / 180, _sin = Math.sin, _cos = Math.cos, _abs = Math.abs, _sqrt = Math.sqrt, _largeNum = 1e8, _isNumber = function _isNumber(value) { return typeof value === "number"; }, _roundingNum = 1e5, _round = function _round(value) { return Math.round(value * _roundingNum) / _roundingNum || 0; }, _copyMetaData = function _copyMetaData(source, copy) { copy.totalLength = source.totalLength; if (source.samples) { copy.samples = source.samples.slice(0); copy.lookup = source.lookup.slice(0); copy.minLength = source.minLength; copy.resolution = source.resolution; } else if (source.totalPoints) { copy.totalPoints = source.totalPoints; } return copy; }, _bestDistance; function copyRawPath(rawPath) { var a = [], i = 0; for (; i < rawPath.length; i++) { a[i] = _copyMetaData(rawPath[i], rawPath[i].slice(0)); } return _copyMetaData(rawPath, a); } function subdivideSegment(segment, i, t) { if (t <= 0 || t >= 1) { return 0; } var ax = segment[i], ay = segment[i + 1], cp1x = segment[i + 2], cp1y = segment[i + 3], cp2x = segment[i + 4], cp2y = segment[i + 5], bx = segment[i + 6], by = segment[i + 7], x1a = ax + (cp1x - ax) * t, x2 = cp1x + (cp2x - cp1x) * t, y1a = ay + (cp1y - ay) * t, y2 = cp1y + (cp2y - cp1y) * t, x1 = x1a + (x2 - x1a) * t, y1 = y1a + (y2 - y1a) * t, x2a = cp2x + (bx - cp2x) * t, y2a = cp2y + (by - cp2y) * t; x2 += (x2a - x2) * t; y2 += (y2a - y2) * t; segment.splice(i + 2, 4, _round(x1a), _round(y1a), _round(x1), _round(y1), _round(x1 + (x2 - x1) * t), _round(y1 + (y2 - y1) * t), _round(x2), _round(y2), _round(x2a), _round(y2a)); segment.samples && segment.samples.splice(i / 6 * segment.resolution | 0, 0, 0, 0, 0, 0, 0, 0); return 6; } function transformRawPath(rawPath, a, b, c, d, tx, ty) { var j = rawPath.length, segment, l, i, x, y; while (--j > -1) { segment = rawPath[j]; l = segment.length; for (i = 0; i < l; i += 2) { x = segment[i]; y = segment[i + 1]; segment[i] = x * a + y * c + tx; segment[i + 1] = x * b + y * d + ty; } } rawPath._dirty = 1; return rawPath; } 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 bezierToPoints(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 = _abs((x2 - x4) * dy - (y2 - y4) * dx), d3 = _abs((x3 - x4) * dy - (y3 - y4) * dx), length; if (!points) { points = [x1, y1, x4, y4]; index = 2; } points.splice(index || points.length - 2, 0, x1234, 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 + 2 + (points.length - length)); } return points; } function pointsToSegment(points, curviness) { _abs(points[0] - points[2]) < 1e-4 && _abs(points[1] - points[3]) < 1e-4 && (points = points.slice(2)); var l = points.length - 2, x = +points[0], y = +points[1], nextX = +points[2], nextY = +points[3], segment = [x, y, x, y], dx2 = nextX - x, dy2 = nextY - y, closed = Math.abs(points[l] - x) < 0.001 && Math.abs(points[l + 1] - y) < 0.001, prevX, prevY, i, dx1, dy1, r1, r2, r3, tl, mx1, mx2, mxm, my1, my2, mym; if (closed) { points.push(nextX, nextY); nextX = x; nextY = y; x = points[l - 2]; y = points[l - 1]; points.unshift(x, y); l += 4; } curviness = curviness || curviness === 0 ? +curviness : 1; for (i = 2; i < l; i += 2) { prevX = x; prevY = y; x = nextX; y = nextY; nextX = +points[i + 2]; nextY = +points[i + 3]; if (x === nextX && y === nextY) { continue; } dx1 = dx2; dy1 = dy2; dx2 = nextX - x; dy2 = nextY - y; r1 = _sqrt(dx1 * dx1 + dy1 * dy1); r2 = _sqrt(dx2 * dx2 + dy2 * dy2); r3 = _sqrt(Math.pow(dx2 / r2 + dx1 / r1, 2) + Math.pow(dy2 / r2 + dy1 / r1, 2)); tl = (r1 + r2) * curviness * 0.25 / r3; mx1 = x - (x - prevX) * (r1 ? tl / r1 : 0); mx2 = x + (nextX - x) * (r2 ? tl / r2 : 0); mxm = x - (mx1 + ((mx2 - mx1) * (r1 * 3 / (r1 + r2) + 0.5) / 4 || 0)); my1 = y - (y - prevY) * (r1 ? tl / r1 : 0); my2 = y + (nextY - y) * (r2 ? tl / r2 : 0); mym = y - (my1 + ((my2 - my1) * (r1 * 3 / (r1 + r2) + 0.5) / 4 || 0)); if (x !== prevX || y !== prevY) { segment.push(_round(mx1 + mxm), _round(my1 + mym), _round(x), _round(y), _round(mx2 + mxm), _round(my2 + mym)); } } x !== nextX || y !== nextY || segment.length < 4 ? segment.push(_round(nextX), _round(nextY), _round(nextX), _round(nextY)) : segment.length -= 2; if (segment.length === 2) { segment.push(x, y, x, y, x, y); } else if (closed) { segment.splice(0, 6); segment.length = segment.length - 6; } return segment; } function pointToSegDist(x, y, x1, y1, x2, y2) { var dx = x2 - x1, dy = y2 - y1, t; if (dx || dy) { t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy); if (t > 1) { x1 = x2; y1 = y2; } else if (t > 0) { x1 += dx * t; y1 += dy * t; } } return Math.pow(x - x1, 2) + Math.pow(y - y1, 2); } function simplifyStep(points, first, last, tolerance, simplified) { var maxSqDist = tolerance, firstX = points[first], firstY = points[first + 1], lastX = points[last], lastY = points[last + 1], index, i, d; for (i = first + 2; i < last; i += 2) { d = pointToSegDist(points[i], points[i + 1], firstX, firstY, lastX, lastY); if (d > maxSqDist) { index = i; maxSqDist = d; } } if (maxSqDist > tolerance) { index - first > 2 && simplifyStep(points, first, index, tolerance, simplified); simplified.push(points[index], points[index + 1]); last - index > 2 && simplifyStep(points, index, last, tolerance, simplified); } } function simplifyPoints(points, tolerance) { var prevX = parseFloat(points[0]), prevY = parseFloat(points[1]), temp = [prevX, prevY], l = points.length - 2, i, x, y, dx, dy, result, last; tolerance = Math.pow(tolerance || 1, 2); for (i = 2; i < l; i += 2) { x = parseFloat(points[i]); y = parseFloat(points[i + 1]); dx = prevX - x; dy = prevY - y; if (dx * dx + dy * dy > tolerance) { temp.push(x, y); prevX = x; prevY = y; } } temp.push(parseFloat(points[l]), parseFloat(points[l + 1])); last = temp.length - 2; result = [temp[0], temp[1]]; simplifyStep(temp, 0, last, tolerance, result); result.push(temp[last], temp[last + 1]); return result; } function getClosestProgressOnBezier(iterations, px, py, start, end, slices, x0, y0, x1, y1, x2, y2, x3, y3) { var inc = (end - start) / slices, best = 0, t = start, x, y, d, dx, dy, inv; _bestDistance = _largeNum; while (t <= end) { inv = 1 - t; x = inv * inv * inv * x0 + 3 * inv * inv * t * x1 + 3 * inv * t * t * x2 + t * t * t * x3; y = inv * inv * inv * y0 + 3 * inv * inv * t * y1 + 3 * inv * t * t * y2 + t * t * t * y3; dx = x - px; dy = y - py; d = dx * dx + dy * dy; if (d < _bestDistance) { _bestDistance = d; best = t; } t += inc; } return iterations > 1 ? getClosestProgressOnBezier(iterations - 1, px, py, Math.max(best - inc, 0), Math.min(best + inc, 1), slices, x0, y0, x1, y1, x2, y2, x3, y3) : best; } function getClosestData(rawPath, x, y, slices) { var closest = { j: 0, i: 0, t: 0 }, bestDistance = _largeNum, i, j, t, segment; for (j = 0; j < rawPath.length; j++) { segment = rawPath[j]; for (i = 0; i < segment.length; i += 6) { t = getClosestProgressOnBezier(1, x, y, 0, 1, slices || 20, segment[i], segment[i + 1], segment[i + 2], segment[i + 3], segment[i + 4], segment[i + 5], segment[i + 6], segment[i + 7]); if (bestDistance > _bestDistance) { bestDistance = _bestDistance; closest.j = j; closest.i = i; closest.t = t; } } } return closest; } 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; } var _doc, _win, _docElement, _body, _divContainer, _svgContainer, _identityMatrix, _gEl, _transformProp = "transform", _transformOriginProp = _transformProp + "Origin", _hasOffsetBug, _setDoc = function _setDoc(element) { var doc = element.ownerDocument || element; if (!(_transformProp in element.style) && "msTransform" in element.style) { _transformProp = "msTransform"; _transformOriginProp = _transformProp + "Origin"; } while (doc.parentNode && (doc = doc.parentNode)) {} _win = window; _identityMatrix = new Matrix2D(); if (doc) { _doc = doc; _docElement = doc.documentElement; _body = doc.body; _gEl = _doc.createElementNS("http://www.w3.org/2000/svg", "g"); _gEl.style.transform = "none"; var d1 = doc.createElement("div"), d2 = doc.createElement("div"), root = doc && (doc.body || doc.firstElementChild); if (root && root.appendChild) { root.appendChild(d1); d1.appendChild(d2); d1.setAttribute("style", "position:static;transform:translate3d(0,0,1px)"); _hasOffsetBug = d2.offsetParent !== d1; root.removeChild(d1); } } return doc; }, _forceNonZeroScale = function _forceNonZeroScale(e) { var a, cache; while (e && e !== _body) { cache = e._gsap; cache && cache.uncache && cache.get(e, "x"); if (cache && !cache.scaleX && !cache.scaleY && cache.renderTransform) { cache.scaleX = cache.scaleY = 1e-4; cache.renderTransform(1, cache); a ? a.push(cache) : a = [cache]; } e = e.parentNode; } return a; }, _svgTemps = [], _divTemps = [], _getDocScrollTop = function _getDocScrollTop() { return _win.pageYOffset || _doc.scrollTop || _docElement.scrollTop || _body.scrollTop || 0; }, _getDocScrollLeft = function _getDocScrollLeft() { return _win.pageXOffset || _doc.scrollLeft || _docElement.scrollLeft || _body.scrollLeft || 0; }, _svgOwner = function _svgOwner(element) { return element.ownerSVGElement || ((element.tagName + "").toLowerCase() === "svg" ? element : null); }, _isFixed = function _isFixed(element) { if (_win.getComputedStyle(element).position === "fixed") { return true; } element = element.parentNode; if (element && element.nodeType === 1) { return _isFixed(element); } }, _createSibling = function _createSibling(element, i) { if (element.parentNode && (_doc || _setDoc(element))) { var svg = _svgOwner(element), ns = svg ? svg.getAttribute("xmlns") || "http://www.w3.org/2000/svg" : "http://www.w3.org/1999/xhtml", type = svg ? i ? "rect" : "g" : "div", x = i !== 2 ? 0 : 100, y = i === 3 ? 100 : 0, css = "position:absolute;display:block;pointer-events:none;margin:0;padding:0;", e = _doc.createElementNS ? _doc.createElementNS(ns.replace(/^https/, "http"), type) : _doc.createElement(type); if (i) { if (!svg) { if (!_divContainer) { _divContainer = _createSibling(element); _divContainer.style.cssText = css; } e.style.cssText = css + "width:0.1px;height:0.1px;top:" + y + "px;left:" + x + "px"; _divContainer.appendChild(e); } else { _svgContainer || (_svgContainer = _createSibling(element)); e.setAttribute("width", 0.01); e.setAttribute("height", 0.01); e.setAttribute("transform", "translate(" + x + "," + y + ")"); _svgContainer.appendChild(e); } } return e; } throw "Need document and parent."; }, _consolidate = function _consolidate(m) { var c = new Matrix2D(), i = 0; for (; i < m.numberOfItems; i++) { c.multiply(m.getItem(i).matrix); } return c; }, _getCTM = function _getCTM(svg) { var m = svg.getCTM(), transform; if (!m) { transform = svg.style[_transformProp]; svg.style[_transformProp] = "none"; svg.appendChild(_gEl); m = _gEl.getCTM(); svg.removeChild(_gEl); transform ? svg.style[_transformProp] = transform : svg.style.removeProperty(_transformProp.replace(/([A-Z])/g, "-$1").toLowerCase()); } return m || _identityMatrix.clone(); }, _placeSiblings = function _placeSiblings(element, adjustGOffset) { var svg = _svgOwner(element), isRootSVG = element === svg, siblings = svg ? _svgTemps : _divTemps, parent = element.parentNode, appendToEl = parent && !svg && parent.shadowRoot && parent.shadowRoot.appendChild ? parent.shadowRoot : parent, container, m, b, x, y, cs; if (element === _win) { return element; } siblings.length || siblings.push(_createSibling(element, 1), _createSibling(element, 2), _createSibling(element, 3)); container = svg ? _svgContainer : _divContainer; if (svg) { if (isRootSVG) { b = _getCTM(element); x = -b.e / b.a; y = -b.f / b.d; m = _identityMatrix; } else if (element.getBBox) { b = element.getBBox(); m = element.transform ? element.transform.baseVal : {}; m = !m.numberOfItems ? _identityMatrix : m.numberOfItems > 1 ? _consolidate(m) : m.getItem(0).matrix; x = m.a * b.x + m.c * b.y; y = m.b * b.x + m.d * b.y; } else { m = new Matrix2D(); x = y = 0; } if (adjustGOffset && element.tagName.toLowerCase() === "g") { x = y = 0; } (isRootSVG ? svg : parent).appendChild(container); container.setAttribute("transform", "matrix(" + m.a + "," + m.b + "," + m.c + "," + m.d + "," + (m.e + x) + "," + (m.f + y) + ")"); } else { x = y = 0; if (_hasOffsetBug) { m = element.offsetParent; b = element; while (b && (b = b.parentNode) && b !== m && b.parentNode) { if ((_win.getComputedStyle(b)[_transformProp] + "").length > 4) { x = b.offsetLeft; y = b.offsetTop; b = 0; } } } cs = _win.getComputedStyle(element); if (cs.position !== "absolute" && cs.position !== "fixed") { m = element.offsetParent; while (parent && parent !== m) { x += parent.scrollLeft || 0; y += parent.scrollTop || 0; parent = parent.parentNode; } } b = container.style; b.top = element.offsetTop - y + "px"; b.left = element.offsetLeft - x + "px"; b[_transformProp] = cs[_transformProp]; b[_transformOriginProp] = cs[_transformOriginProp]; b.position = cs.position === "fixed" ? "fixed" : "absolute"; appendToEl.appendChild(container); } return container; }, _setMatrix = function _setMatrix(m, a, b, c, d, e, f) { m.a = a; m.b = b; m.c = c; m.d = d; m.e = e; m.f = f; return m; }; var Matrix2D = function () { function Matrix2D(a, b, c, d, e, f) { if (a === void 0) { a = 1; } if (b === void 0) { b = 0; } if (c === void 0) { c = 0; } if (d === void 0) { d = 1; } if (e === void 0) { e = 0; } if (f === void 0) { f = 0; } _setMatrix(this, a, b, c, d, e, f); } var _proto = Matrix2D.prototype; _proto.inverse = function inverse() { var a = this.a, b = this.b, c = this.c, d = this.d, e = this.e, f = this.f, determinant = a * d - b * c || 1e-10; return _setMatrix(this, d / determinant, -b / determinant, -c / determinant, a / determinant, (c * f - d * e) / determinant, -(a * f - b * e) / determinant); }; _proto.multiply = function multiply(matrix) { var a = this.a, b = this.b, c = this.c, d = this.d, e = this.e, f = this.f, a2 = matrix.a, b2 = matrix.c, c2 = matrix.b, d2 = matrix.d, e2 = matrix.e, f2 = matrix.f; return _setMatrix(this, a2 * a + c2 * c, a2 * b + c2 * d, b2 * a + d2 * c, b2 * b + d2 * d, e + e2 * a + f2 * c, f + e2 * b + f2 * d); }; _proto.clone = function clone() { return new Matrix2D(this.a, this.b, this.c, this.d, this.e, this.f); }; _proto.equals = function equals(matrix) { var a = this.a, b = this.b, c = this.c, d = this.d, e = this.e, f = this.f; return a === matrix.a && b === matrix.b && c === matrix.c && d === matrix.d && e === matrix.e && f === matrix.f; }; _proto.apply = function apply(point, decoratee) { if (decoratee === void 0) { decoratee = {}; } var x = point.x, y = point.y, a = this.a, b = this.b, c = this.c, d = this.d, e = this.e, f = this.f; decoratee.x = x * a + y * c + e || 0; decoratee.y = x * b + y * d + f || 0; return decoratee; }; return Matrix2D; }(); function getGlobalMatrix(element, inverse, adjustGOffset, includeScrollInFixed) { if (!element || !element.parentNode || (_doc || _setDoc(element)).documentElement === element) { return new Matrix2D(); } var zeroScales = _forceNonZeroScale(element), svg = _svgOwner(element), temps = svg ? _svgTemps : _divTemps, container = _placeSiblings(element, adjustGOffset), b1 = temps[0].getBoundingClientRect(), b2 = temps[1].getBoundingClientRect(), b3 = temps[2].getBoundingClientRect(), parent = container.parentNode, isFixed = !includeScrollInFixed && _isFixed(element), m = new Matrix2D((b2.left - b1.left) / 100, (b2.top - b1.top) / 100, (b3.left - b1.left) / 100, (b3.top - b1.top) / 100, b1.left + (isFixed ? 0 : _getDocScrollLeft()), b1.top + (isFixed ? 0 : _getDocScrollTop())); parent.removeChild(container); if (zeroScales) { b1 = zeroScales.length; while (b1--) { b2 = zeroScales[b1]; b2.scaleX = b2.scaleY = 0; b2.renderTransform(1, b2); } } return inverse ? m.inverse() : m; } var _numbersExp = /(?:(-)?\d*\.?\d*(?:e[\-+]?\d+)?)[0-9]/ig, _doc$1, _supportsPointer, _win$1, _body$1, gsap, _context, _selectionColor = "#4e7fff", _minimumMovement = 1, _DEG2RAD$1 = Math.PI / 180, _getTime = Date.now || function () { return new Date().getTime(); }, _lastInteraction = 0, _isPressed = 0, _emptyFunc = function _emptyFunc() { return false; }, _interacted = function _interacted() { return _lastInteraction = _getTime(); }, _CTRL, _ALT, _SHIFT, _CMD, _recentlyAddedAnchor, _editingAxis = {}, _history = [], _point = {}, _temp = [], _comma = ",", _selectedPaths = [], _preventDefault = function _preventDefault(event) { if (event.preventDefault) { event.preventDefault(); if (event.preventManipulation) { event.preventManipulation(); } } }, _createElement = function _createElement(type) { return _doc$1.createElementNS ? _doc$1.createElementNS("http://www.w3.org/1999/xhtml", type) : _doc$1.createElement(type); }, _createSVG = function _createSVG(type, container, attributes) { var element = _doc$1.createElementNS("http://www.w3.org/2000/svg", type), reg = /([a-z])([A-Z])/g, p; attributes = attributes || {}; attributes["class"] = attributes["class"] || "path-editor"; for (p in attributes) { if (element.style[p] !== undefined) { element.style[p] = attributes[p]; } else { element.setAttributeNS(null, p.replace(reg, "$1-$2").toLowerCase(), attributes[p]); } } container.appendChild(element); return element; }, _identityMatrixObject = { matrix: new Matrix2D() }, _getConsolidatedMatrix = function _getConsolidatedMatrix(target) { return (target.transform && target.transform.baseVal.consolidate() || _identityMatrixObject).matrix; }, _getConcatenatedTransforms = function _getConcatenatedTransforms(target) { var m = _getConsolidatedMatrix(target), owner = target.ownerSVGElement; while ((target = target.parentNode) && target.ownerSVGElement === owner) { m.multiply(_getConsolidatedMatrix(target)); } return "matrix(" + m.a + "," + m.b + "," + m.c + "," + m.d + "," + m.e + "," + m.f + ")"; }, _addHistory = function _addHistory(pathEditor) { var selectedIndexes = [], a = pathEditor._selectedAnchors, i; for (i = 0; i < a.length; i++) { selectedIndexes[i] = a[i].i; } _history.unshift({ path: pathEditor, d: pathEditor.path.getAttribute("d"), transform: pathEditor.path.getAttribute("transform") || "", selectedIndexes: selectedIndexes }); if (_history.length > 30) { _history.length = 30; } }, _round$1 = function _round(value) { return ~~(value * 1000 + (value < 0 ? -.5 : .5)) / 1000; }, _getSquarePathData = function _getSquarePathData(size) { size = _round$1(size); return ["M-" + size, -size, size, -size, size, size, -size, size + "z"].join(_comma); }, _getCirclePathData = function _getCirclePathData(size) { var circ = 0.552284749831, rcirc = _round$1(size * circ); size = _round$1(size); return "M" + size + ",0C" + [size, rcirc, rcirc, size, 0, size, -rcirc, size, -size, rcirc, -size, 0, -size, -rcirc, -rcirc, -size, 0, -size, rcirc, -size, size, -rcirc, size, 0].join(_comma) + "z"; }, _checkDeselect = function _checkDeselect(e) { if (!e.target._gsSelection && !_isPressed && _getTime() - _lastInteraction > 100) { var i = _selectedPaths.length; while (--i > -1) { _selectedPaths[i].deselect(); } _selectedPaths.length = 0; } }, _tempDiv, _touchEventLookup, _isMultiTouching = 0, _addListener = function _addListener(element, type, func, capture) { if (element.addEventListener) { var touchType = _touchEventLookup[type]; capture = capture || { passive: false }; element.addEventListener(touchType || type, func, capture); if (touchType && type !== touchType && touchType.substr(0, 7) !== "pointer") { element.addEventListener(type, func, capture); } } else if (element.attachEvent) { element.attachEvent("on" + type, func); } }, _removeListener = function _removeListener(element, type, func) { if (element.removeEventListener) { var touchType = _touchEventLookup[type]; element.removeEventListener(touchType || type, func); if (touchType && type !== touchType && touchType.substr(0, 7) !== "pointer") { element.removeEventListener(type, func); } } else if (element.detachEvent) { element.detachEvent("on" + type, func); } }, _hasTouchID = function _hasTouchID(list, ID) { var i = list.length; while (--i > -1) { if (list[i].identifier === ID) { return true; } } return false; }, _onMultiTouchDocumentEnd = function _onMultiTouchDocumentEnd(e) { _isMultiTouching = e.touches && _dragCount < e.touches.length; _removeListener(e.target, "touchend", _onMultiTouchDocumentEnd); }, _onMultiTouchDocument = function _onMultiTouchDocument(e) { _isMultiTouching = e.touches && _dragCount < e.touches.length; _addListener(e.target, "touchend", _onMultiTouchDocumentEnd); }, _bind = function _bind(func, scope) { return function (e) { return func.call(scope, e); }; }, _callback = function _callback(type, self, param) { var callback = self.vars[type]; if (callback) { callback.call(self.vars.callbackScope || self, param || self); } return self; }, _copyElement, _resetSelection = function _resetSelection() { _copyElement.style.display = "block"; _copyElement.select(); _copyElement.style.display = "none"; }, _coreInitted, _initCore = function _initCore(core) { _doc$1 = document; _win$1 = window; _body$1 = _doc$1.body; gsap = gsap || core || _win$1.gsap || console.warn("Please gsap.registerPlugin(PathEditor)"); _context = gsap && gsap.core.context || function () {}; _tempDiv = _createElement("div"); _copyElement = _createElement("textarea"); _copyElement.style.display = "none"; _body$1 && _body$1.appendChild(_copyElement); _touchEventLookup = function (types) { var standard = types.split(","), converted = (_tempDiv.onpointerdown !== undefined ? "pointerdown,pointermove,pointerup,pointercancel" : _tempDiv.onmspointerdown !== undefined ? "MSPointerDown,MSPointerMove,MSPointerUp,MSPointerCancel" : types).split(","), obj = {}, i = 4; while (--i > -1) { obj[standard[i]] = converted[i]; obj[converted[i]] = standard[i]; } return obj; }("touchstart,touchmove,touchend,touchcancel"); SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function (e) { return e.getScreenCTM().inverse().multiply(this.getScreenCTM()); }; _doc$1.addEventListener("keydown", function (e) { var key = e.keyCode || e.which, keyString = e.key || key, i, state, a, path; if (keyString === "Shift" || key === 16) { _SHIFT = true; } else if (keyString === "Control" || key === 17) { _CTRL = true; } else if (keyString === "Meta" || key === 91) { _CMD = true; } else if (keyString === "Alt" || key === 18) { _ALT = true; i = _selectedPaths.length; while (--i > -1) { _selectedPaths[i]._onPressAlt(); } } else if ((keyString === "z" || key === 90) && (_CTRL || _CMD) && _history.length > 1) { _history.shift(); state = _history[0]; if (state) { path = state.path; path.path.setAttribute("d", state.d); path.path.setAttribute("transform", state.transform); path.init(); a = path._anchors; for (i = 0; i < a.length; i++) { if (state.selectedIndexes.indexOf(a[i].i) !== -1) { path._selectedAnchors.push(a[i]); } } path._updateAnchors(); path.update(); if (path.vars.onUndo) { path.vars.onUndo.call(path); } } } else if (keyString === "Delete" || keyString === "Backspace" || key === 8 || key === 46 || key === 63272 || key === "d" && (_CTRL || _CMD)) { i = _selectedPaths.length; while (--i > -1) { _selectedPaths[i]._deleteSelectedAnchors(); } } else if ((keyString === "a" || key === 65) && (_CMD || _CTRL)) { i = _selectedPaths.length; while (--i > -1) { _selectedPaths[i].select(true); } } }, true); _doc$1.addEventListener("keyup", function (e) { var key = e.key || e.keyCode || e.which; if (key === "Shift" || key === 16) { _SHIFT = false; } else if (key === "Control" || key === 17) { _CTRL = false; } else if (key === "Meta" || key === 91) { _CMD = false; } else if (key === "Alt" || key === 18) { _ALT = false; var i = _selectedPaths.length; while (--i > -1) { _selectedPaths[i]._onReleaseAlt(); } } }, true); _supportsPointer = !!_win$1.PointerEvent; _addListener(_doc$1, "mouseup", _checkDeselect); _addListener(_doc$1, "touchend", _checkDeselect); _addListener(_doc$1, "touchcancel", _emptyFunc); _addListener(_win$1, "touchmove", _emptyFunc); _body$1 && _body$1.addEventListener("touchstart", _emptyFunc); _coreInitted = 1; }, _onPress = function _onPress(e) { var self = this, ctm = getGlobalMatrix(self.target.parentNode, true), touchEventTarget, temp; this._matrix = this.target.transform.baseVal.getItem(0).matrix; this._ctm = ctm; if (_touchEventLookup[e.type]) { touchEventTarget = e.type.indexOf("touch") !== -1 ? e.currentTarget || e.target : _doc$1; _addListener(touchEventTarget, "touchend", self._onRelease); _addListener(touchEventTarget, "touchmove", self._onMove); _addListener(touchEventTarget, "touchcancel", self._onRelease); _addListener(_doc$1, "touchstart", _onMultiTouchDocument); _addListener(_win$1, "touchforcechange", _preventDefault); } else { touchEventTarget = null; _addListener(_doc$1, "mousemove", self._onMove); } if (!_supportsPointer) { _addListener(_doc$1, "mouseup", self._onRelease); } _preventDefault(e); _resetSelection(); if (e.changedTouches) { e = self.touch = e.changedTouches[0]; self.touchID = e.identifier; } else if (e.pointerId) { self.touchID = e.pointerId; } else { self.touch = self.touchID = null; } self._startPointerY = self.pointerY = e.pageY; self._startPointerX = self.pointerX = e.pageX; self._startElementX = self._matrix.e; self._startElementY = self._matrix.f; if (this._ctm.a === 1 && this._ctm.b === 0 && this._ctm.c === 0 && this._ctm.d === 1) { this._ctm = null; } else { temp = self._startPointerX * this._ctm.a + self._startPointerY * this._ctm.c + this._ctm.e; self._startPointerY = self._startPointerX * this._ctm.b + self._startPointerY * this._ctm.d + this._ctm.f; self._startPointerX = temp; } self.isPressed = _isPressed = true; self.touchEventTarget = touchEventTarget; if (self.vars.onPress) { self.vars.onPress.call(self.vars.callbackScope || self, self.pointerEvent); } }, _onMove = function _onMove(e) { var self = this, originalEvent = e, touches, i; if (!self._enabled || _isMultiTouching || !self.isPressed || !e) { return; } self.pointerEvent = e; touches = e.changedTouches; if (touches) { e = touches[0]; if (e !== self.touch && e.identifier !== self.touchID) { i = touches.length; while (--i > -1 && (e = touches[i]).identifier !== self.touchID) {} if (i < 0) { return; } } } else if (e.pointerId && self.touchID && e.pointerId !== self.touchID) { return; } _preventDefault(originalEvent); self.setPointerPosition(e.pageX, e.pageY); if (self.vars.onDrag) { self.vars.onDrag.call(self.vars.callbackScope || self, self.pointerEvent); } }, _onRelease = function _onRelease(e, force) { var self = this; if (!self._enabled || !self.isPressed || e && self.touchID != null && !force && (e.pointerId && e.pointerId !== self.touchID || e.changedTouches && !_hasTouchID(e.changedTouches, self.touchID))) { return; } _interacted(); self.isPressed = _isPressed = false; var originalEvent = e, wasDragging = self.isDragging, touchEventTarget = self.touchEventTarget, touches, i; if (touchEventTarget) { _removeListener(touchEventTarget, "touchend", self._onRelease); _removeListener(touchEventTarget, "touchmove", self._onMove); _removeListener(touchEventTarget, "touchcancel", self._onRelease); _removeListener(_doc$1, "touchstart", _onMultiTouchDocument); } else { _removeListener(_doc$1, "mousemove", self._onMove); } if (!_supportsPointer) { _removeListener(_doc$1, "mouseup", self._onRelease); if (e && e.target) { _removeListener(e.target, "mouseup", self._onRelease); } } if (wasDragging) { self.isDragging = false; } else if (self.vars.onClick) { self.vars.onClick.call(self.vars.callbackScope || self, originalEvent); } if (e) { touches = e.changedTouches; if (touches) { e = touches[0]; if (e !== self.touch && e.identifier !== self.touchID) { i = touches.length; while (--i > -1 && (e = touches[i]).identifier !== self.touchID) {} if (i < 0) { return; } } } self.pointerEvent = originalEvent; self.pointerX = e.pageX; self.pointerY = e.pageY; } if (originalEvent && !wasDragging && self.vars.onDragRelease) { self.vars.onDragRelease.call(self, self.pointerEvent); } else { if (originalEvent) { _preventDefault(originalEvent); } if (self.vars.onRelease) { self.vars.onRelease.call(self.vars.callbackScope || self, self.pointerEvent); } } if (wasDragging && self.vars.onDragEnd) { self.vars.onDragEnd.call(self.vars.callbackScope || self, self.pointerEvent); } return true; }, _createSegmentAnchors = function _createSegmentAnchors(rawPath, j, editor, vars) { var segment = rawPath[j], l = segment.length - (segment.closed ? 6 : 0), a = [], i; for (i = 0; i < l; i += 6) { a.push(new Anchor(editor, rawPath, j, i, vars)); } segment.closed && (a[0].isClosedStart = true); return a; }, _getLength = function _getLength(segment, i, i2) { var x = segment[i2] - segment[i], y = segment[i2 + 1] - segment[i + 1]; return Math.sqrt(x * x + y * y); }; var DraggableSVG = function () { function DraggableSVG(target, vars) { this.target = typeof target === "string" ? _doc$1.querySelectorAll(target)[0] : target; this.vars = vars || {}; this._onPress = _bind(_onPress, this); this._onMove = _bind(_onMove, this); this._onRelease = _bind(_onRelease, this); this.target.setAttribute("transform", (this.target.getAttribute("transform") || "") + " translate(0,0)"); this._matrix = _getConsolidatedMatrix(this.target); this.x = this._matrix.e; this.y = this._matrix.f; this.snap = vars.snap; if (!isNaN(vars.maxX) || !isNaN(vars.minX)) { this._bounds = 1; this.maxX = +vars.maxX; this.minX = +vars.minX; } else { this._bounds = 0; } this.enabled(true); } var _proto = DraggableSVG.prototype; _proto.setPointerPosition = function setPointerPosition(pointerX, pointerY) { var rnd = 1000, xChange, yChange, x, y, temp; this.pointerX = pointerX; this.pointerY = pointerY; if (this._ctm) { temp = pointerX * this._ctm.a + pointerY * this._ctm.c + this._ctm.e; pointerY = pointerX * this._ctm.b + pointerY * this._ctm.d + this._ctm.f; pointerX = temp; } yChange = pointerY - this._startPointerY; xChange = pointerX - this._startPointerX; if (yChange < _minimumMovement && yChange > -_minimumMovement) { yChange = 0; } if (xChange < _minimumMovement && xChange > -_minimumMovement) { xChange = 0; } x = ((this._startElementX + xChange) * rnd | 0) / rnd; y = ((this._startElementY + yChange) * rnd | 0) / rnd; if (this.snap && !_SHIFT) { _point.x = x; _point.y = y; this.snap.call(this, _point); x = _point.x; y = _point.y; } if (this.x !== x || this.y !== y) { this._matrix.f = this.y = y; this._matrix.e = this.x = x; if (!this.isDragging && this.isPressed) { this.isDragging = true; _callback("onDragStart", this, this.pointerEvent); } } }; _proto.enabled = function enabled(_enabled) { if (!arguments.length) { return this._enabled; } var dragging; this._enabled = _enabled; if (_enabled) { if (!_supportsPointer) { _addListener(this.target, "mousedown", this._onPress); } _addListener(this.target, "touchstart", this._onPress); _addListener(this.target, "click", this._onClick, true); } else { dragging = this.isDragging; _removeListener(this.target, "mousedown", this._onPress); _removeListener(this.target, "touchstart", this._onPress); _removeListener(_win$1, "touchforcechange", _preventDefault); _removeListener(this.target, "click", this._onClick); if (this.touchEventTarget) { _removeListener(this.touchEventTarget, "touchcancel", this._onRelease); _removeListener(this.touchEventTarget, "touchend", this._onRelease); _removeListener(this.touchEventTarget, "touchmove", this._onMove); } _removeListener(_doc$1, "mouseup", this._onRelease); _removeListener(_doc$1, "mousemove", this._onMove); this.isDragging = this.isPressed = false; if (dragging) { _callback("onDragEnd", this, this.pointerEvent); } } return this; }; _proto.endDrag = function endDrag(e) { this._onRelease(e); }; return DraggableSVG; }(); var Anchor = function () { function Anchor(editor, rawPath, j, i, vars) { this.editor = editor; this.element = _createSVG("path", editor._selection, { fill: _selectionColor, stroke: _selectionColor, strokeWidth: 2, vectorEffect: "non-scaling-stroke" }); this.update(rawPath, j, i); this.element._gsSelection = true; this.vars = vars || {}; this._draggable = new DraggableSVG(this.element, { callbackScope: this, onDrag: this.onDrag, snap: this.vars.snap, onPress: this.onPress, onRelease: this.onRelease, onClick: this.onClick, onDragEnd: this.onDragEnd }); } var _proto2 = Anchor.prototype; _proto2.onPress = function onPress() { _callback("onPress", this); }; _proto2.onClick = function onClick() { _callback("onClick", this); }; _proto2.onDrag = function onDrag() { var s = this.segment; this.vars.onDrag.call(this.vars.callbackScope || this, this, this._draggable.x - s[this.i], this._draggable.y - s[this.i + 1]); }; _proto2.onDragEnd = function onDragEnd() { _callback("onDragEnd", this); }; _proto2.onRelease = function onRelease() { _callback("onRelease", this); }; _proto2.update = function update(rawPath, j, i) { if (rawPath) { this.rawPath = rawPath; } if (arguments.length <= 1) { j = this.j; i = this.i; } else { this.j = j; this.i = i; } var prevSmooth = this.smooth, segment = this.rawPath[j], pi = i === 0 && segment.closed ? segment.length - 4 : i - 2; this.segment = segment; this.smooth = i > 0 && i < segment.length - 2 && Math.abs(Math.atan2(segment[i + 1] - segment[pi + 1], segment[i] - segment[pi]) - Math.atan2(segment[i + 3] - segment[i + 1], segment[i + 2] - segment[i])) < 0.09 ? 2 : 0; if (this.smooth !== prevSmooth) { this.element.setAttribute("d", this.smooth ? this.editor._circleHandle : this.editor._squareHandle); } this.element.setAttribute("transform", "translate(" + segment[i] + "," + segment[i + 1] + ")"); }; return Anchor; }(); var PathEditor = function () { function PathEditor(target, vars) { vars = vars || {}; _coreInitted || _initCore(); this.vars = vars; this.path = typeof target === "string" ? _doc$1.querySelectorAll(target)[0] : target; this._g = _createSVG("g", this.path.ownerSVGElement, { "class": "path-editor-g path-editor" }); this._selectionHittest = _createSVG("path", this._g, { stroke: "transparent", strokeWidth: 16, fill: "none", vectorEffect: "non-scaling-stroke" }); this._selection = vars._selection || _createSVG("g", this._g, { "class": "path-editor-selection path-editor" }); this._selectionPath = _createSVG("path", this._selection, { stroke: _selectionColor, strokeWidth: 2, fill: "none", vectorEffect: "non-scaling-stroke" }); this._selectedAnchors = []; this._line1 = _createSVG("polyline", this._selection, { stroke: _selectionColor, strokeWidth: 2, vectorEffect: "n