UNPKG

reeller

Version:

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

145 lines (127 loc) 4.33 kB
export default class ScrollerPlugin { /** * @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} */ static pluginName = 'scroller'; /** * Default options. * * @type {ScrollerPluginOptions} */ static defaultOptions = { speed: 1, multiplier: 0.5, threshold: 1, ease: 'expo.out', overwrite: true, bothDirection: true, reversed: false, stopOnEnd: false, scrollProxy: null, }; /** * Reeller ScrollerPlugin. * * @param {Reeller} reeller Reeller instance. * @param {object} options Options */ constructor(reeller, options) { /** @type {ScrollerPluginOptions} **/ this.options = {...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. */ getScrollPos() { if (this.options.scrollProxy) return this.options.scrollProxy(); return window.scrollY; } /** * Initialize plugin. */ init() { let lastScrollPos = this.getScrollPos(); let lastDirection = 1; let reachedEnd = true; let isScrolled = false; this.tickerFn = () => { const scrollPos = this.getScrollPos(); let 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) { const delta = velocity * this.options.multiplier; const 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) { const 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. */ destroy() { if (this.tickerFn) { this.gsap.ticker.remove(this.tickerFn); this.tickerFn = null; } if (this.tween) this.tween.kill(); } }