UNPKG

baseframe-js

Version:

Baseframe JS is a comprehensive suite of modular plugins and utilities designed for front-end development

189 lines (188 loc) 6.9 kB
import $be from "base-elem-js"; import Store from "./core/Store"; import { getDataOptions, setParams } from "./util/helpers"; import { debounceResize } from "./fn/debounce"; const VERSION = "2.0.1"; const DATA_NAME = 'Parallax'; const EVENT_NAME = 'parallax'; const DEFAULTS = { speed: 7, zSpeed: 5, cssPrefix: 'parallax', axis: 'y', scrollAxis: 'y', zAxis: false, relativeElem: false, bgFill: false, rootMargin: 0, scrollMaxPxStop: 5000, zScrollMaxPxStop: 2000, minWidth: null, maxWidth: null }; export default class Parallax { params; zInitOffset; index; instanceEvent; $window; $element; element; elementOffset; $relElem; winHeight; winWidth; elemHeight; elemWidth; speed; zSpeed; fillAmount; bgFill; bgFillProp; axis; zAxis; scrollMaxPxStop; zScrollMaxPxStop; rootMargin; lastZSpeed; lastCssInProps; minWidthIfSet; maxWidthIfSet; effectCleared; cssPrevDir; static defaults = DEFAULTS; static version = VERSION; static pluginName = DATA_NAME; constructor(element, options, index) { const s = this; const dataOptions = getDataOptions(element, EVENT_NAME); s.$window = $be(window); s.$element = $be(element); s.element = element; s.params = setParams(Parallax.defaults, options, dataOptions); s.zInitOffset = 0; s.index = index; s.instanceEvent = EVENT_NAME + index; s.$relElem = s.#relElem; s.cssPrevDir = []; //props to get updated on resize s.#updatableProps(); s.#handleEvents(); return s; } #handleEvents() { const s = this; debounceResize(() => { s.#updatableProps(); s.parallax(s); }, `[${s.instanceEvent}_resize]`, true); $be(window).on([`scroll.${s.instanceEvent}`, `[${s.instanceEvent}]`], () => { window.requestAnimationFrame(() => { s.parallax(s); }); }).trigger(s.instanceEvent); } #updatableProps() { const s = this; const speed = s.#speed, zSpeed = s.#zSpeed, { cssPrefix } = s.params, speedCss = `${cssPrefix}--${s.params.axis}-${zSpeed > 0 ? 'pos' : 'neg'}`, zSpeedCss = s.params.zAxis ? `${cssPrefix}--z-${zSpeed > 0 ? 'pos' : 'neg'}` : '', newCssDir = zSpeedCss ? [speedCss, zSpeedCss] : speedCss, rm = s.params.rootMargin; //reset to get new measurements s.$element.css({ transform: null, height: null, width: null }); if (s.cssPrevDir) s.$element.rmClass(s.cssPrevDir); s.$element.addClass(newCssDir); const relElem = s.$relElem.elem[0]; // const windowRects = s.$window.elemRects(); s.cssPrevDir = newCssDir; s.winHeight = window.innerHeight; s.winWidth = window.innerHeight; s.elemHeight = relElem.scrollHeight; s.elemWidth = relElem.scrollWidth; s.speed = speed; s.zSpeed = zSpeed; s.fillAmount = s.#fillAmount; s.bgFill = s.params.bgFill; s.axis = s.params.axis; s.bgFillProp = s.axis === 'y' ? 'height' : 'width'; s.zAxis = s.params.zAxis; s.$relElem = s.#relElem; s.scrollMaxPxStop = s.params.scrollMaxPxStop; s.zScrollMaxPxStop = s.params.zScrollMaxPxStop; s.lastZSpeed = 0; s.rootMargin = typeof s.params.rootMargin === 'number' ? [rm, rm] : rm; s.minWidthIfSet = s.params.minWidth ? s.winWidth > s.params.minWidth : true; s.maxWidthIfSet = s.params.maxWidth ? s.winWidth < s.params.maxWidth : true; s.elementOffset = s.getElementRects(); if (s.lastCssInProps) { s.$element.css(s.lastCssInProps); } } getElementRects() { const s = this; const elPos = s.$element.elemRects(), top = elPos.top + window.scrollY, left = elPos.left + window.scrollX, bottom = top + s.elemHeight, right = left + s.elemWidth; return { top, left, bottom, right }; } parallax(s) { const { scrollAxis } = s.params, [rootMStart, rootMEnd] = s.rootMargin, withinMinAndMaxIfSet = (s.minWidthIfSet && s.maxWidthIfSet), scrollVertical = scrollAxis === 'y', offset = (scrollVertical ? s.elementOffset.top : s.elementOffset.left), winSide = (scrollVertical ? s.winHeight : s.winWidth) - rootMStart, scrollDir = (scrollVertical ? window.scrollY : window.scrollX), pixelStart = (offset > winSide ? (winSide - offset) + scrollDir : offset + (scrollDir - offset)); if (s.isInView(scrollVertical, pixelStart, scrollDir, rootMEnd) && withinMinAndMaxIfSet) { const speed = (pixelStart * s.speed), zSpeed = (pixelStart * s.zSpeed), speedPx = (speed < s.zScrollMaxPxStop) ? speed : s.zScrollMaxPxStop, zSpeedPx = s.params.zAxis ? ((s.lastZSpeed < s.zScrollMaxPxStop) ? zSpeed : s.lastZSpeed) : 0, translateParams = s.axis === 'y' ? `0, ${speedPx}px, ${zSpeedPx}px` : `${speedPx}px, 0, ${zSpeedPx}px`; const cssProps = { transform: `translate3d(${translateParams})`, [s.bgFillProp]: s.bgFill ? `calc(100% + ${s.fillAmount}px)` : null }; s.lastZSpeed = zSpeedPx; s.lastCssInProps = cssProps; s.$element.css(cssProps); } } isInView(scrollVertical, pixelStart, scrollDir, rootMargin) { const s = this; const elemOffsetEnd = scrollVertical ? s.elementOffset.bottom : s.elementOffset.right; return scrollDir + rootMargin <= elemOffsetEnd && pixelStart >= 0; } //getters get #fillAmount() { const s = this; const saY = s.params.scrollAxis === 'y'; const winSide = s.params.axis === 'y' ? s.winHeight : (s.winWidth + (saY ? 0 : s.elemWidth)); return (winSide * Math.abs(s.speed)); } get #speed() { const s = this; return s.params.speed / 100; } get #zSpeed() { const s = this; return s.params.zSpeed / 100; } get #relElem() { const s = this; const { relativeElem } = s.params; return relativeElem ? relativeElem : s.$element; } static remove(element, plugin) { $be(element).each((elem) => { const s = plugin || Store(elem, DATA_NAME); $be(window).off([ `scroll.${s.instanceEvent}`, `resize.${s.instanceEvent}`, `[${s.instanceEvent}_resize]`, `[${s.instanceEvent}` ]); s.$element.css({ 'transform': null, height: null, width: null }).rmClass(s.cssPrevDir); Store(elem, DATA_NAME, null); }); } }