UNPKG

gsap

Version:

GSAP is a JavaScript library for building high-performance animations that work in **every** major browser. Animate CSS, SVG, canvas, React, Vue, WebGL, colors, strings, motion paths, generic objects...anything JavaScript can touch! No other library deliv

209 lines (199 loc) 6.9 kB
/*! * matrix 3.0.4 * https://greensock.com * * Copyright 2008-2019, GreenSock. All rights reserved. * Subject to the terms at https://greensock.com/standard-license or for * Club GreenSock members, the agreement issued with that membership. * @author: Jack Doyle, jack@greensock.com */ /* eslint-disable */ let _doc, _win, _docElement, _body, _divContainer, _svgContainer, _identityMatrix, _transformProp = "transform", _transformOriginProp = _transformProp + "Origin", _setDoc = element => { let doc = element.ownerDocument || element; if (!(_transformProp in element.style) && "msTransform" in element.style) { //to improve compatibility with old Microsoft browsers _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; } return doc; }, _svgTemps = [], //we create 3 elements for SVG, and 3 for other DOM elements and cache them for performance reasons. They get nested in _divContainer and _svgContainer so that just one element is added to the DOM on each successive attempt. Again, performance is key. _divTemps = [], _getDocScrollTop = () => _win.pageYOffset || _doc.scrollTop || _docElement.scrollTop || _body.scrollTop || 0, _getDocScrollLeft = () => _win.pageXOffset || _doc.scrollLeft || _docElement.scrollLeft || _body.scrollLeft || 0, _svgOwner = element => element.ownerSVGElement || ((element.tagName + "").toLowerCase() === "svg" ? element : null), _isFixed = element => { if (_win.getComputedStyle(element).position === "fixed") { return true; } element = element.parentNode; if (element && element.nodeType === 1) { // avoid document fragments which will throw an error. return _isFixed(element); } }, _createSibling = (element, i) => { if (element.parentNode && (_doc || _setDoc(element))) { let 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;", 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:1px;height:1px;top:" + y + "px;left:" + x + "px"; _divContainer.appendChild(e); } else { if (!_svgContainer) { _svgContainer = _createSibling(element); } e.setAttribute("width", 1); e.setAttribute("height", 1); e.setAttribute("transform", "translate(" + x + "," + y + ")"); _svgContainer.appendChild(e); } } return e; } throw "Need document and parent."; }, _placeSiblings = element => { let svg = _svgOwner(element), isRootSVG = element === svg, siblings = svg ? _svgTemps : _divTemps, container, m, b, x, y; if (element === _win) { return element; } if (!siblings.length) { siblings.push(_createSibling(element, 1), _createSibling(element, 2), _createSibling(element, 3)); } container = svg ? _svgContainer : _divContainer; if (svg) { b = isRootSVG ? {x:0, y:0} : element.getBBox(); m = element.transform ? element.transform.baseVal : []; // IE11 doesn't follow the spec. if (m.length) { m = m.consolidate().matrix; x = m.a * b.x + m.c * b.y; y = m.b * b.x + m.d * b.y; } else { m = _identityMatrix; if (element.tagName.toLowerCase() === "g") { x = y = 0; } else { x = b.x; y = b.y; } } container.setAttribute("transform", "matrix(" + m.a + "," + m.b + "," + m.c + "," + m.d + "," + (m.e + x) + "," + (m.f + y) + ")"); (isRootSVG ? svg : element.parentNode).appendChild(container); } else { container.style.top = element.offsetTop + "px"; container.style.left = element.offsetLeft + "px"; m = _win.getComputedStyle(element); container.style[_transformProp] = m[_transformProp]; container.style[_transformOriginProp] = m[_transformOriginProp]; container.style.position = m.position === "fixed" ? "fixed" : "absolute"; element.parentNode.appendChild(container); } return container; }, _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; }; export class Matrix2D { constructor(a=1, b=0, c=0, d=1, e=0, f=0) { _setMatrix(this, a, b, c, d, e, f); } inverse() { let {a, b, c, d, e, f} = this, determinant = (a * d - b * c); return _setMatrix( this, d / determinant, -b / determinant, -c / determinant, a / determinant, (c * f - d * e) / determinant, -(a * f - b * e) / determinant ); } multiply(matrix) { let {a, b, c, d, e, f} = this, 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); } equals(matrix) { let {a, b, c, d, e, f} = this; return (a === matrix.a && b === matrix.b && c === matrix.c && d === matrix.d && e === matrix.e && f === matrix.f); } apply(point, decoratee={}) { let {x, y} = point, {a, b, c, d, e, f} = this; decoratee.x = x * a + y * c + e; decoratee.y = x * b + y * d + f; return decoratee; } } //feed in an element and it'll return a 2D matrix (optionally inverted) so that you can translate between coordinate spaces. // Inverting lets you translate a global point into a local coordinate space. No inverting lets you go the other way. // We needed this to work around various browser bugs, like Firefox doesn't accurately report getScreenCTM() when there // are transforms applied to ancestor elements. // The matrix math to convert any x/y coordinate is: // tx = m.a * x + m.c * y + m.e // ty = m.b * x + m.d * y + m.f export function getGlobalMatrix(element, inverse) { if (!element || !element.parentNode) { return new Matrix2D(); } let svg = _svgOwner(element), temps = svg ? _svgTemps : _divTemps, container = _placeSiblings(element), b1 = temps[0].getBoundingClientRect(), b2 = temps[1].getBoundingClientRect(), b3 = temps[2].getBoundingClientRect(), parent = container.parentNode, isFixed = _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); return inverse ? m.inverse() : m; }