UNPKG

reeller

Version:

Flexible, powerful and modern library for creating the running horizontal blocks effect, also known as ticker or the «marquee effect».

1,187 lines (1,006 loc) 32.6 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.Reeller = {})); })(this, (function (exports) { function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } var Base = /*#__PURE__*/function () { /** * Base class. */ function Base() { this.events = {}; } /** * Attach an event handler function. * * @param {string} event Event name. * @param {function} callback Callback. */ var _proto = Base.prototype; _proto.on = function on(event, callback) { if (!(this.events[event] instanceof Array)) this.events[event] = []; this.events[event].push(callback); } /** * Remove an event handler. * * @param {string} event Event name. * @param {function} [callback] Callback. */ ; _proto.off = function off(event, callback) { if (callback) { this.events[event] = this.events[event].filter(function (f) { return f !== callback; }); } else { this.events[event] = []; } } /** * Execute all handlers for the given event type. * * @param {string} event Event name. * @param params Extra parameters. */ ; _proto.trigger = function trigger(event) { var _arguments = arguments, _this = this; if (!this.events[event]) return; this.events[event].forEach(function (f) { return f.call.apply(f, [_this, _this].concat([].slice.call(_arguments, 1))); }); }; return Base; }(); var Filler = /*#__PURE__*/function (_Base) { _inheritsLoose(Filler, _Base); /** * @typedef {Object} FillerOptions * @property {string|HTMLElement|null} container Container element or selector. * @property {string|HTMLElement|null} wrapper Inner element or selector. * @property {string|null} itemSelector Items CSS selector. * @property {string} [cloneClassName] Class name of the new clones. * @property {boolean} [autoUpdate] Use ResizeObserver to auto update clones number. * @property {boolean} [clonesOverflow] Create artificial overflow with clones. * @property {boolean} [clonesFinish] Bring the cycle of clones to an end. * @property {boolean} [clonesMin] Minimum number of clones. */ /** * Default options. * * @type {FillerOptions} */ /** * Create Filler instance. * * @param {FillerOptions} [options] Filler options. */ function Filler(options) { var _this; _this = _Base.call(this) || this; /** @type {FillerOptions} **/ _this.options = _extends({}, Filler.defaultOptions, options); _this.container = typeof _this.options.container === 'string' ? document.querySelector(_this.options.container) : _this.options.container; _this.wrapper = typeof _this.options.wrapper === 'string' ? _this.container.querySelector(_this.options.wrapper) : _this.options.wrapper || _this.options.container; /** @type Array.<HTMLElement> **/ _this.item = []; _this.refresh(false); if (_this.options.autoUpdate) { _this.bindResizeObserver(); } else { _this.update(); } return _this; } /** * Bind ResizeObserver to container for auto update. */ var _proto = Filler.prototype; _proto.bindResizeObserver = function bindResizeObserver() { var _this2 = this; this.resizeObserver = new ResizeObserver(function () { _this2.update(); }); this.resizeObserver.observe(this.container); } /** * Creates and adds clones to end in the desired number from given offset. * * @param {number} [count] Number of clones to add. * @param {number} [offset] Offset from start. */ ; _proto.addClones = function addClones(count, offset) { var _this$wrapper; if (offset === void 0) { offset = 0; } var clones = []; for (var i = 0; i < count; i++) { var item = this.item[(offset + i) % this.item.length].cloneNode(true); item.classList.add(this.options.cloneClassName); clones.push(item); } (_this$wrapper = this.wrapper).append.apply(_this$wrapper, clones); } /** * Removes the desired number of clones from the end. * * @param {number} [count] Number of clones to remove. */ ; _proto.removeClones = function removeClones(count) { if (count === void 0) { count = 0; } var clones = Array.from(this.wrapper.getElementsByClassName(this.options.cloneClassName)); clones.slice(-count).forEach(function (el) { return el.remove(); }); } /** * Sets the desired number of clones. * * @param {number} [count] Number of clones. */ ; _proto.setClonesCount = function setClonesCount(count) { if (this.clonesCount === count) return; if (this.clonesCount < count) this.addClones(count - this.clonesCount, this.clonesCount); if (this.clonesCount > count) this.removeClones(this.clonesCount - count); this.clonesCount = count; } /** * Get calculated data object. * * @return {Object} Calculated data. */ ; _proto.getCalcData = function getCalcData() { var data = { clonesCount: 0, clonesWidth: 0, containerWidth: this.container.offsetWidth, fullWidth: 0, itemWidth: [], itemsWidth: 0, lastIndex: 0 }; this.item.map(function (el) { var style = window.getComputedStyle(el); var width = el.offsetWidth + parseInt(style.marginLeft) + parseInt(style.marginRight); data.itemWidth.push(width); data.itemsWidth += width; }); var itemLength = data.itemWidth.length; var width = this.options.clonesOverflow ? data.containerWidth : data.containerWidth - data.itemsWidth; while (width > data.clonesWidth || data.clonesCount < this.options.clonesMin || this.options.clonesFinish && data.clonesCount % itemLength > 0) { data.lastIndex = data.clonesCount % itemLength; data.clonesWidth += data.itemWidth[data.lastIndex]; data.clonesCount++; } data.fullWidth = data.clonesWidth + data.itemsWidth; return data; } /** * Calculates and sets the number of clones. */ ; _proto.update = function update() { this.calcData = this.getCalcData(); this.setClonesCount(this.calcData.clonesCount); this.trigger('update', this.calcData); } /** * Fully refresh and update all clones. * * @param {boolean} [update] Update after refresh. */ ; _proto.refresh = function refresh(update) { if (update === void 0) { update = true; } this.removeClones(); this.item = Array.from(this.container.querySelectorAll(this.options.itemSelector)); this.calcData = {}; this.clonesCount = 0; this.trigger('refresh'); if (update) this.update(); } /** * Destroy Reeller instance. * * @param {boolean} [removeClones] Remove clones from DOM. */ ; _proto.destroy = function destroy(removeClones) { if (removeClones === void 0) { removeClones = false; } if (removeClones) this.removeClones(); if (this.resizeObserver) this.resizeObserver.disconnect(); this.trigger('destroy'); }; return Filler; }(Base); Filler.defaultOptions = { container: null, wrapper: null, itemSelector: null, cloneClassName: '-clone', autoUpdate: true, clonesOverflow: false, clonesFinish: false, clonesMin: 0 }; var Reeller = /*#__PURE__*/function (_Base) { _inheritsLoose(Reeller, _Base); /** * @typedef {Object} ReellerOptions * @property {string|HTMLElement|null} container Container element or selector. * @property {string|HTMLElement|null} wrapper Inner element or selector. * @property {string|null} itemSelector Items CSS selector. * @property {string} [cloneClassName] Class name of the new clones. * @property {number} [speed] Movement speed. * @property {string} [ease] Timing function. * @property {number} [initialSeek] Initial seek of timeline. * @property {boolean} [loop] Loop movement. * @property {boolean} [paused] Initialize in paused mode. * @property {boolean} [reversed] Reverse mode. * @property {boolean} [autoPlay] Use IntersectionObserver to auto play/stop movement. * @property {boolean} [autoUpdate] Use ResizeObserver to auto update clones number. * @property {boolean} [clonesOverflow] Create artificial overflow with clones. * @property {boolean} [clonesFinish] Bring the cycle of clones to an end. * @property {boolean} [clonesMin] Minimum number of clones. * @property {Object|null} [plugins] Options for plugins. */ /** * Default options. * * @type {ReellerOptions} */ /** * Registered plugin storage. * * @type {Object} */ /** * Create Reeller instance. * * @param {ReellerOptions} [options] Reeller options. */ function Reeller(options) { var _this; _this = _Base.call(this) || this; /** @type {ReellerOptions} **/ _this.options = _extends({}, Reeller.defaultOptions, options); _this.gsap = Reeller.gsap || window.gsap; _this.paused = _this.options.paused; _this.createFiller(); _this.createTimeline(); if (_this.options.autoPlay || _this.options.autoStop) _this.bindIntersectionObserver(); if (_this.options.plugins) _this.initPlugins(); return _this; } /** * Register GSAP animation library. * * @param {GSAP} gsap GSAP library. */ Reeller.registerGSAP = function registerGSAP(gsap) { Reeller.gsap = gsap; } /** * Register plugins. */ ; Reeller.use = function use() { [].slice.call(arguments).forEach(function (plugin) { var name = plugin.pluginName; if (typeof name !== 'string') throw new TypeError('Invalid plugin. Name is required.'); Reeller.plugins[name] = plugin; }); } /** * Create filler. */ ; var _proto = Reeller.prototype; _proto.createFiller = function createFiller() { var _this2 = this; this.filler = new Filler(this.options); this.filler.on('update', function (filler, calcData) { _this2.invalidate(); _this2.trigger('update', calcData); }); this.filler.on('refresh', function () { _this2.trigger('refresh'); }); } /** * Create timeline. */ ; _proto.createTimeline = function createTimeline() { var _this3 = this; this.tl = new this.gsap.timeline({ paused: this.options.paused, reversed: this.options.reversed, repeat: -1, yoyo: !this.options.loop, onReverseComplete: function onReverseComplete() { this.progress(1); } }); this.gsap.set(this.filler.container, { overflow: 'hidden' }); this.tl.fromTo(this.filler.wrapper, { x: function x() { if (!_this3.options.clonesOverflow) { return -(_this3.filler.calcData.fullWidth - _this3.filler.calcData.containerWidth); } return -_this3.filler.calcData.itemsWidth; } }, { x: 0, duration: this.options.speed, ease: this.options.ease }); this.tl.seek(this.options.seek); return this.tl; } /** * Bind IntersectionObserver to container for autoplay. */ ; _proto.bindIntersectionObserver = function bindIntersectionObserver() { var _this4 = this; this.intersectionObserver = new IntersectionObserver(function (entries) { if (entries[0].isIntersecting) { _this4.resume(); } else { _this4.pause(); } }); this.intersectionObserver.observe(this.filler.container); } /** * Init plugins from options. */ ; _proto.initPlugins = function initPlugins() { this.plugin = {}; for (var _i = 0, _Object$entries = Object.entries(this.options.plugins); _i < _Object$entries.length; _i++) { var _Object$entries$_i = _Object$entries[_i], name = _Object$entries$_i[0], options = _Object$entries$_i[1]; var factory = Reeller.plugins[name]; if (factory) { this.plugin[name] = new factory(this, options); } else { console.error("Plugin " + name + " not found. Make sure you register it with Reeller.use()"); } } } /** * Destroy initialized plugins. */ ; _proto.destroyPlugins = function destroyPlugins() { for (var _i2 = 0, _Object$values = Object.values(this.plugin); _i2 < _Object$values.length; _i2++) { var instance = _Object$values[_i2]; if (instance.destroy) instance.destroy(); } } /** * Resume moving. */ ; _proto.resume = function resume() { this.gsap.set(this.filler.container, { z: '0' }); this.gsap.set(this.filler.wrapper, { willChange: 'transform' }); this.paused = false; this.tl.resume(); this.trigger('resume'); } /** * Set reversed moving. * * @param {boolean} [reversed] Is movement reversed? */ ; _proto.reverse = function reverse(reversed) { if (reversed === void 0) { reversed = true; } this.tl.reversed(reversed); this.resume(); this.trigger('reverse', reversed); } /** * Pause moving. */ ; _proto.pause = function pause() { this.gsap.set(this.filler.container, { clearProps: 'z' }); this.gsap.set(this.filler.wrapper, { willChange: 'auto' }); this.paused = true; this.tl.pause(); this.trigger('pause'); } /** * Refresh timeline. */ ; _proto.invalidate = function invalidate() { this.tl.invalidate(); this.trigger('invalidate'); } /** * Recalculate data. */ ; _proto.update = function update() { this.filler.update(); } /** * Fully refresh and update all clones and position. * * @param {boolean} [update] Update after refresh. */ ; _proto.refresh = function refresh(update) { if (update === void 0) { update = true; } this.filler.refresh(update); } /** * Destroy Reeller instance. * * @param {boolean} [removeClones] Remove clones from DOM. * @param {boolean} [clearProps] Remove transformations. */ ; _proto.destroy = function destroy(removeClones, clearProps) { if (removeClones === void 0) { removeClones = false; } if (clearProps === void 0) { clearProps = false; } if (this.intersectionObserver) this.intersectionObserver.disconnect(); if (this.options.plugins) this.destroyPlugins(); this.tl.kill(); this.filler.destroy(removeClones); if (clearProps) { this.gsap.set(this.filler.container, { clearProps: 'overflow' }); this.gsap.set(this.filler.wrapper, { clearProps: 'x,willChange' }); } this.trigger('destroy'); }; return Reeller; }(Base); Reeller.defaultOptions = { container: null, wrapper: null, itemSelector: null, cloneClassName: '-clone', speed: 10, ease: 'none', initialSeek: 10, loop: true, paused: true, reversed: false, autoPlay: true, autoUpdate: true, clonesOverflow: true, clonesFinish: false, clonesMin: 0, plugins: null }; Reeller.plugins = {}; var DragPlugin = /*#__PURE__*/function () { /** * @typedef {Object} DragPluginOptions * @property {number} [speed] Inertia duration in seconds. * @property {number} [multiplier] Drag movement multiplier. * @property {number} [threshold] Minimum release velocity in px/s to start inertia. * @property {number} [inertiaMultiplier] Inertia distance multiplier. * @property {number} [activationDistance] Minimum movement in px before drag starts. * @property {number} [maxVelocity] Maximum release velocity in px/s. * @property {string} [ease] Timing function. * @property {boolean} [changeDirection] Change autoplay direction after drag. * @property {'x'|'y'} [axis] Pointer axis used for drag. * @property {boolean} [invertAxis] Invert drag direction on the selected axis. * @property {string|HTMLElement|null} [target] Drag target element or selector. * @property {boolean} [preventDefault] Prevent default pointer behaviour while dragging. */ /** * Plugin name. * * @type {string} */ /** * Default options. * * @type {DragPluginOptions} */ /** * Reeller DragPlugin. * * @param {Reeller} reeller Reeller instance. * @param {object} options Options. */ function DragPlugin(reeller, options) { /** @type {DragPluginOptions} **/ this.options = _extends({}, DragPlugin.defaultOptions, options); this.reeller = reeller; this.gsap = this.reeller.gsap; this.tl = this.reeller.tl; this.pointerId = null; this.dragging = false; this.samples = []; this.basePaused = null; this.dragDirection = 0; this.nextReversed = null; this.init(); } /** * Return current movement width for one cycle. * * @return {number} Movement width in pixels. */ var _proto = DragPlugin.prototype; _proto.getTrackWidth = function getTrackWidth() { var _this$reeller$filler$ = this.reeller.filler.calcData, _this$reeller$filler$2 = _this$reeller$filler$.itemsWidth, itemsWidth = _this$reeller$filler$2 === void 0 ? 0 : _this$reeller$filler$2, _this$reeller$filler$3 = _this$reeller$filler$.fullWidth, fullWidth = _this$reeller$filler$3 === void 0 ? 0 : _this$reeller$filler$3, _this$reeller$filler$4 = _this$reeller$filler$.containerWidth, containerWidth = _this$reeller$filler$4 === void 0 ? 0 : _this$reeller$filler$4; if (this.reeller.options.clonesOverflow) return itemsWidth; return fullWidth - containerWidth; } /** * Move timeline by drag delta. * * @param {number} delta Movement delta in pixels. */ ; _proto.applyDelta = function applyDelta(delta) { var trackWidth = this.getTrackWidth(); if (!trackWidth || !delta) return; var timeDelta = delta * this.options.multiplier * this.reeller.options.speed / trackWidth; this.tl.totalTime(this.tl.totalTime() + timeDelta); } /** * Return pointer position for active drag axis. * * @param {PointerEvent} event Pointer event. * @return {number} Pointer position. */ ; _proto.getPointerPosition = function getPointerPosition(event) { var position = this.options.axis === 'y' ? event.clientY : event.clientX; return this.options.invertAxis ? -position : position; } /** * Save point for release velocity calculation. * * @param {number} position Pointer position. */ ; _proto.pushSample = function pushSample(position) { var time = performance.now(); this.samples.push({ position: position, time: time }); while (this.samples.length > 5 || time - this.samples[0].time > 120) { this.samples.shift(); } } /** * Return release velocity in px/s. * * @return {number} Release velocity in px/s. */ ; _proto.getVelocity = function getVelocity() { if (this.samples.length < 2) return 0; var first = this.samples[0]; var last = this.samples[this.samples.length - 1]; var deltaTime = last.time - first.time; if (!deltaTime) return 0; return (last.position - first.position) / deltaTime * 1000; } /** * Save autoplay direction to apply after drag. * * @param {number} velocity Release velocity in px/s. */ ; _proto.saveDirection = function saveDirection(velocity) { if (!this.options.changeDirection) return; var direction = Math.sign(velocity) || this.dragDirection; if (!direction) return; this.nextReversed = direction < 0; } /** * Start drag interaction and pause autoplay. */ ; _proto.beginDrag = function beginDrag() { this.stopInertia(); this.dragging = true; if (this.basePaused === null) { this.basePaused = this.reeller.paused; } this.tl.pause(); this.samples = []; this.pushSample(this.lastPos); } /** * Restore base playback state. */ ; _proto.restorePlayback = function restorePlayback() { if (this.nextReversed !== null) { this.tl.reversed(this.nextReversed); } if (this.basePaused) { this.tl.pause(); } else { this.tl.resume(); } this.basePaused = null; this.nextReversed = null; } /** * Start inertia tween. * * @param {number} velocity Release velocity in px/s. */ ; _proto.startInertia = function startInertia(velocity) { var _this = this; var maxVelocity = Math.abs(this.options.maxVelocity); var clampedVelocity = Math.max(-maxVelocity, Math.min(maxVelocity, velocity)); var distance = clampedVelocity * this.options.speed * this.options.inertiaMultiplier; this.restorePlayback(); if (Math.abs(clampedVelocity) < this.options.threshold || !distance) { return; } var proxy = { offset: 0 }; var lastOffset = 0; this.inertiaTween = this.gsap.to(proxy, { offset: distance, duration: this.options.speed, ease: this.options.ease, overwrite: true, onUpdate: function onUpdate() { var delta = proxy.offset - lastOffset; lastOffset = proxy.offset; _this.applyDelta(delta); }, onComplete: function onComplete() { _this.inertiaTween = null; } }); } /** * Stop current inertia tween. */ ; _proto.stopInertia = function stopInertia() { if (!this.inertiaTween) return; this.inertiaTween.kill(); this.inertiaTween = null; } /** * Reset pointer bookkeeping. */ ; _proto.resetPointer = function resetPointer() { this.pointerId = null; this.dragging = false; this.startPos = 0; this.lastPos = 0; this.dragDirection = 0; this.samples = []; } /** * Initialize plugin. */ ; _proto.init = function init() { var _this2 = this; var target = this.options.target; if (!target) { this.target = this.reeller.filler.container; } else if (typeof target === 'string') { this.target = this.reeller.filler.container.querySelector(target) || document.querySelector(target); } else { this.target = target; } if (!this.target) { throw new TypeError('DragPlugin target not found.'); } this.onPointerDown = function (event) { if (_this2.pointerId !== null) return; if (event.pointerType === 'mouse' && event.button !== 0) return; var position = _this2.getPointerPosition(event); _this2.stopInertia(); _this2.pointerId = event.pointerId; _this2.startPos = position; _this2.lastPos = position; _this2.samples = []; if (_this2.target.setPointerCapture) { _this2.target.setPointerCapture(event.pointerId); } }; this.onPointerMove = function (event) { if (event.pointerId !== _this2.pointerId) return; var position = _this2.getPointerPosition(event); if (!_this2.dragging) { if (Math.abs(position - _this2.startPos) < _this2.options.activationDistance) return; _this2.beginDrag(); } if (_this2.options.preventDefault) event.preventDefault(); var delta = position - _this2.lastPos; _this2.lastPos = position; if (!delta) return; _this2.dragDirection = Math.sign(delta); _this2.pushSample(position); _this2.applyDelta(delta); }; this.onPointerUp = function (event) { if (event.pointerId !== _this2.pointerId) return; if (_this2.target.releasePointerCapture && (!_this2.target.hasPointerCapture || _this2.target.hasPointerCapture(event.pointerId))) { _this2.target.releasePointerCapture(event.pointerId); } if (!_this2.dragging) { if (_this2.basePaused !== null) { _this2.restorePlayback(); } _this2.resetPointer(); return; } if (_this2.options.preventDefault) event.preventDefault(); _this2.pushSample(_this2.getPointerPosition(event)); var velocity = _this2.getVelocity(); _this2.saveDirection(velocity); _this2.resetPointer(); _this2.startInertia(velocity); }; this.onPointerCancel = function (event) { if (event.pointerId !== _this2.pointerId) return; if (_this2.target.releasePointerCapture && (!_this2.target.hasPointerCapture || _this2.target.hasPointerCapture(event.pointerId))) { _this2.target.releasePointerCapture(event.pointerId); } if (_this2.dragging || _this2.basePaused !== null) { _this2.restorePlayback(); } _this2.resetPointer(); }; this.target.addEventListener('pointerdown', this.onPointerDown); this.target.addEventListener('pointermove', this.onPointerMove); this.target.addEventListener('pointerup', this.onPointerUp); this.target.addEventListener('pointercancel', this.onPointerCancel); } /** * Destroy plugin. */ ; _proto.destroy = function destroy() { this.stopInertia(); if (this.target) { this.target.removeEventListener('pointerdown', this.onPointerDown); this.target.removeEventListener('pointermove', this.onPointerMove); this.target.removeEventListener('pointerup', this.onPointerUp); this.target.removeEventListener('pointercancel', this.onPointerCancel); } this.basePaused = null; this.nextReversed = null; this.resetPointer(); }; return DragPlugin; }(); DragPlugin.pluginName = 'drag'; DragPlugin.defaultOptions = { speed: 1, multiplier: 1, threshold: 50, inertiaMultiplier: 0.2, activationDistance: 3, maxVelocity: 3000, ease: 'expo.out', changeDirection: false, axis: 'x', invertAxis: false, target: null, preventDefault: true }; var ScrollerPlugin = /*#__PURE__*/function () { /** * @typedef {Object} ScrollerPluginOptions * @property {number} [speed] Movement and inertia speed. * @property {number} [multiplier] Movement multiplier. * @property {number} [threshold] Movement threshold. * @property {string} [ease] Timing function. * @property {boolean} [overwrite] GSAP overwrite mode. * @property {boolean} [bothDirection] Allow movement in both directions. * @property {boolean} [reversed] Reverse scroll movement. * @property {boolean} [stopOnEnd] Use IntersectionObserver to auto stop movement. * @property {function} [scrollProxy] Use ResizeObserver to auto update clones number. */ /** * Plugin name. * * @type {string} */ /** * Default options. * * @type {ScrollerPluginOptions} */ /** * Reeller ScrollerPlugin. * * @param {Reeller} reeller Reeller instance. * @param {object} options Options */ function ScrollerPlugin(reeller, options) { /** @type {ScrollerPluginOptions} **/ this.options = _extends({}, ScrollerPlugin.defaultOptions, options); this.reeller = reeller; this.gsap = this.reeller.gsap; this.tl = this.reeller.tl; this.init(); } /** * Return scroll position. * * @return {number} Scroll position. */ var _proto = ScrollerPlugin.prototype; _proto.getScrollPos = function getScrollPos() { if (this.options.scrollProxy) return this.options.scrollProxy(); return window.scrollY; } /** * Initialize plugin. */ ; _proto.init = function init() { var _this = this; var lastScrollPos = this.getScrollPos(); var lastDirection = 1; var reachedEnd = true; var isScrolled = false; this.tickerFn = function () { var scrollPos = _this.getScrollPos(); var velocity = scrollPos - lastScrollPos; if (velocity) isScrolled = true; if (!isScrolled) return; if (!_this.options.bothDirection) { velocity = Math.abs(velocity); } if (_this.options.reversed) { velocity *= -1; } if (_this.reeller.paused) { lastDirection = Math.sign(velocity); lastScrollPos = scrollPos; if (!reachedEnd) { _this.gsap.killTweensOf(_this.tl); reachedEnd = true; } _this.tl.timeScale(lastDirection * _this.options.threshold); return; } if (velocity) { var delta = velocity * _this.options.multiplier; var timeScale = delta > 0 ? Math.max(_this.options.threshold, delta) : Math.min(-_this.options.threshold, delta); _this.tween = _this.gsap.to(_this.tl, { timeScale: timeScale, duration: _this.options.speed, ease: _this.options.ease, overwrite: _this.options.overwrite }); reachedEnd = false; } else { if (!reachedEnd) { var _timeScale = _this.options.stopOnEnd ? 0 : lastDirection * _this.options.threshold; _this.gsap.killTweensOf(_this.tl); _this.tween = _this.gsap.to(_this.tl, { timeScale: _timeScale, duration: _this.options.speed, overwrite: _this.options.overwrite, ease: _this.options.ease }); reachedEnd = true; } } lastDirection = Math.sign(velocity); lastScrollPos = scrollPos; }; this.gsap.ticker.add(this.tickerFn); } /** * Destroy plugin. */ ; _proto.destroy = function destroy() { if (this.tickerFn) { this.gsap.ticker.remove(this.tickerFn); this.tickerFn = null; } if (this.tween) this.tween.kill(); }; return ScrollerPlugin; }(); ScrollerPlugin.pluginName = 'scroller'; ScrollerPlugin.defaultOptions = { speed: 1, multiplier: 0.5, threshold: 1, ease: 'expo.out', overwrite: true, bothDirection: true, reversed: false, stopOnEnd: false, scrollProxy: null }; exports.DragPlugin = DragPlugin; exports.Filler = Filler; exports.Reeller = Reeller; exports.ScrollerPlugin = ScrollerPlugin; exports["default"] = Reeller; }));