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! The ScrollTrigger plug

166 lines (160 loc) 6.29 kB
/*! * ScrollToPlugin 3.4.2 * https://greensock.com * * @license Copyright 2008-2020, 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 gsap, _coreInitted, _window, _docEl, _body, _toArray, _config, _windowExists = () => typeof(window) !== "undefined", _getGSAP = () => gsap || (_windowExists() && (gsap = window.gsap) && gsap.registerPlugin && gsap), _isString = value => typeof(value) === "string", _max = (element, axis) => { let dim = (axis === "x") ? "Width" : "Height", scroll = "scroll" + dim, client = "client" + dim; return (element === _window || element === _docEl || element === _body) ? Math.max(_docEl[scroll], _body[scroll]) - (_window["inner" + dim] || _docEl[client] || _body[client]) : element[scroll] - element["offset" + dim]; }, _buildGetter = (e, axis) => { //pass in an element and an axis ("x" or "y") and it'll return a getter function for the scroll position of that element (like scrollTop or scrollLeft, although if the element is the window, it'll use the pageXOffset/pageYOffset or the documentElement's scrollTop/scrollLeft or document.body's. Basically this streamlines things and makes a very fast getter across browsers. let p = "scroll" + ((axis === "x") ? "Left" : "Top"); if (e === _window) { if (e.pageXOffset != null) { p = "page" + axis.toUpperCase() + "Offset"; } else { e = _docEl[p] != null ? _docEl : _body; } } return () => e[p]; }, _getOffset = (element, container) => { let rect = _toArray(element)[0].getBoundingClientRect(), isRoot = (!container || container === _window || container === _body), cRect = isRoot ? {top:_docEl.clientTop - (_window.pageYOffset || _docEl.scrollTop || _body.scrollTop || 0), left:_docEl.clientLeft - (_window.pageXOffset || _docEl.scrollLeft || _body.scrollLeft || 0)} : container.getBoundingClientRect(), offsets = {x: rect.left - cRect.left, y: rect.top - cRect.top}; if (!isRoot && container) { //only add the current scroll position if it's not the window/body. offsets.x += _buildGetter(container, "x")(); offsets.y += _buildGetter(container, "y")(); } return offsets; }, _parseVal = (value, target, axis, currentVal) => !isNaN(value) && typeof(value) !== "object" ? parseFloat(value) : (_isString(value) && value.charAt(1) === "=") ? parseFloat(value.substr(2)) * (value.charAt(0) === "-" ? -1 : 1) + currentVal : (value === "max") ? _max(target, axis) : Math.min(_max(target, axis), _getOffset(value, target)[axis]), _initCore = () => { gsap = _getGSAP(); if (_windowExists() && gsap && document.body) { _window = window; _body = document.body; _docEl = document.documentElement; _toArray = gsap.utils.toArray; gsap.config({autoKillThreshold:7}); _config = gsap.config(); _coreInitted = 1; } }; export const ScrollToPlugin = { version:"3.4.2", name:"scrollTo", rawVars:1, register(core) { gsap = core; _initCore(); }, init(target, value, tween, index, targets) { if (!_coreInitted) { _initCore(); } let data = this; data.isWin = (target === _window); data.target = target; data.tween = tween; if (typeof(value) !== "object") { value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y". if (_isString(value.y) && value.y !== "max" && value.y.charAt(1) !== "=") { value.x = value.y; } } else if (value.nodeType) { value = {y:value, x:value}; } data.vars = value; data.autoKill = !!value.autoKill; data.getX = _buildGetter(target, "x"); data.getY = _buildGetter(target, "y"); data.x = data.xPrev = data.getX(); data.y = data.yPrev = data.getY(); if (value.x != null) { data.add(data, "x", data.x, _parseVal(value.x, target, "x", data.x) - (value.offsetX || 0), index, targets, Math.round); data._props.push("scrollTo_x"); } else { data.skipX = 1; } if (value.y != null) { data.add(data, "y", data.y, _parseVal(value.y, target, "y", data.y) - (value.offsetY || 0), index, targets, Math.round); data._props.push("scrollTo_y"); } else { data.skipY = 1; } }, render(ratio, data) { let pt = data._pt, { target, tween, autoKill, xPrev, yPrev, isWin } = data, x, y, yDif, xDif, threshold; while (pt) { pt.r(ratio, pt.d); pt = pt._next; } x = (isWin || !data.skipX) ? data.getX() : xPrev; y = (isWin || !data.skipY) ? data.getY() : yPrev; yDif = y - yPrev; xDif = x - xPrev; threshold = _config.autoKillThreshold; if (data.x < 0) { //can't scroll to a position less than 0! Might happen if someone uses a Back.easeOut or Elastic.easeOut when scrolling back to the top of the page (for example) data.x = 0; } if (data.y < 0) { data.y = 0; } if (autoKill) { //note: iOS has a bug that throws off the scroll by several pixels, so we need to check if it's within 7 pixels of the previous one that we set instead of just looking for an exact match. if (!data.skipX && (xDif > threshold || xDif < -threshold) && x < _max(target, "x")) { data.skipX = 1; //if the user scrolls separately, we should stop tweening! } if (!data.skipY && (yDif > threshold || yDif < -threshold) && y < _max(target, "y")) { data.skipY = 1; //if the user scrolls separately, we should stop tweening! } if (data.skipX && data.skipY) { tween.kill(); if (data.vars.onAutoKill) { data.vars.onAutoKill.apply(tween, data.vars.onAutoKillParams || []); } } } if (isWin) { _window.scrollTo((!data.skipX) ? data.x : x, (!data.skipY) ? data.y : y); } else { if (!data.skipY) { target.scrollTop = data.y; } if (!data.skipX) { target.scrollLeft = data.x; } } data.xPrev = data.x; data.yPrev = data.y; }, kill(property) { let both = (property === "scrollTo"); if (both || property === "scrollTo_x") { this.skipX = 1; } if (both || property === "scrollTo_y") { this.skipY = 1; } } }; ScrollToPlugin.max = _max; ScrollToPlugin.getOffset = _getOffset; ScrollToPlugin.buildGetter = _buildGetter; _getGSAP() && gsap.registerPlugin(ScrollToPlugin); export { ScrollToPlugin as default };