UNPKG

vevet

Version:

Vevet is a JavaScript library for creative development that simplifies crafting rich interactions like split text animations, carousels, marquees, preloading, and more.

241 lines 8.45 kB
import { isFiniteNumber } from '../../../internal/isFiniteNumber'; import { isNumber } from '../../../internal/isNumber'; import { isString } from '../../../internal/isString'; import { addEventListener, clamp, lerp, toPixels } from '../../../utils'; import { LERP_APPROXIMATION } from '../constants'; export class CursorHoverElement { constructor(_data, _onEnter, _onLeave) { this._data = _data; this._onEnter = _onEnter; this._onLeave = _onLeave; this._debounce = null; this._isHovered = false; this._parallaxX = { current: 0, target: 0, prevTarget: null, }; this._parallaxY = { current: 0, target: 0, prevTarget: null, }; const { emitter } = this; if (emitter.matches(':hover')) { this._handleElementEnter(); } this._mouseEnter = addEventListener(emitter, 'mouseenter', () => { var _a; this._debounce = setTimeout(() => this._handleElementEnter(), (_a = _data.hoverDebounce) !== null && _a !== void 0 ? _a : 16); }); this._mouseLeave = addEventListener(emitter, 'mouseleave', () => { if (this._debounce) { clearTimeout(this._debounce); } this._handleElementLeave(); }); this._mouseMove = addEventListener(emitter, 'mousemove', (evt) => { this._handleElementMove(evt); }); } get element() { return this._data.element; } get emitter() { var _a; return (_a = this._data.emitter) !== null && _a !== void 0 ? _a : this._data.element; } get type() { return this._data.type; } get snap() { var _a; return (_a = this._data.snap) !== null && _a !== void 0 ? _a : false; } get width() { if (this._data.width === 'auto') { return 'auto'; } if (this._data.width) { return toPixels(this._data.width); } return null; } get height() { if (this._data.height === 'auto') { return 'auto'; } if (this._data.height) { return toPixels(this._data.height); } return null; } get padding() { return this._data.padding ? toPixels(this._data.padding) : 0; } get sticky() { var _a; return (_a = this._data.sticky) !== null && _a !== void 0 ? _a : false; } get stickyLerp() { var _a; return (_a = this._data.stickyLerp) !== null && _a !== void 0 ? _a : undefined; } get stickyFriction() { var _a; return (_a = this._data.stickyFriction) !== null && _a !== void 0 ? _a : 0; } get hasStickyFriction() { return isFiniteNumber(this.stickyFriction) && this.stickyFriction > 0; } /** Get element dimensions */ getDimensions() { let x; let y; let width; let height; let padding = 0; const bounding = this.element.getBoundingClientRect(); if (this.snap) { x = bounding.left + bounding.width / 2; y = bounding.top + bounding.height / 2; } if (this.width === 'auto') { width = bounding.width; } else if (isNumber(this.width)) { width = this.width; } if (this.height === 'auto') { height = bounding.height; } else if (isNumber(this.height)) { height = this.height; } padding = this.padding; return { x, y, width, height, padding }; } /** Destroy all events */ destroy() { this._mouseEnter(); this._mouseMove(); this._mouseLeave(); if (this._debounce) { clearTimeout(this._debounce); } } /** Handle element enter */ _handleElementEnter() { this._isHovered = true; this._onEnter(this); } /** Handle element leave */ _handleElementLeave() { this._isHovered = false; this._parallaxX.target = 0; this._parallaxX.prevTarget = null; this._parallaxY.target = 0; this._parallaxY.prevTarget = null; this._onLeave(this); } /** Handle element move */ _handleElementMove(evt) { if (!this.sticky || !this._isHovered) { return; } const { element, _parallaxX: parallaxX, _parallaxY: parallaxY } = this; const { clientX, clientY } = evt; const bounding = element.getBoundingClientRect(); const computed = getComputedStyle(element).transform; const matrix = computed === 'none' ? new DOMMatrix() : new DOMMatrix(computed); const { width, height } = bounding; const translateX = matrix.e; const translateY = matrix.f; const basicLeft = bounding.left - translateX; const basicTop = bounding.top - translateY; const basicCenterX = basicLeft + width / 2; const basicCenterY = basicTop + height / 2; const distanceX = clientX - basicCenterX; const distanceY = clientY - basicCenterY; const amp = this._getStickyAmplitude(); const maxX = amp.x === 'auto' ? width : Math.abs(amp.x); const maxY = amp.y === 'auto' ? height : Math.abs(amp.y); const parallaxXTarget = clamp(distanceX, -maxX, maxX); const parallaxYTarget = clamp(distanceY, -maxY, maxY); if (parallaxX.prevTarget === null) { parallaxX.prevTarget = parallaxXTarget; } if (parallaxY.prevTarget === null) { parallaxY.prevTarget = parallaxYTarget; } if (this.hasStickyFriction) { const parallaxXDelta = parallaxXTarget - parallaxX.prevTarget; const parallaxYDelta = parallaxYTarget - parallaxY.prevTarget; parallaxX.target += parallaxXDelta; parallaxY.target += parallaxYDelta; } else { parallaxX.target = parallaxXTarget; parallaxY.target = parallaxYTarget; } parallaxX.prevTarget = parallaxXTarget; parallaxY.prevTarget = parallaxYTarget; } /** Get sticky amplitude for both axis */ _getStickyAmplitude() { const { stickyAmplitude } = this._data; let x = 'auto'; let y = 'auto'; if (!stickyAmplitude) { return { x, y }; } if (isNumber(stickyAmplitude) || isString(stickyAmplitude)) { x = this._getStickyAmplitudeAxis(stickyAmplitude); y = this._getStickyAmplitudeAxis(stickyAmplitude); } else { if ('x' in stickyAmplitude) { x = this._getStickyAmplitudeAxis(stickyAmplitude.x); } if ('y' in stickyAmplitude) { y = this._getStickyAmplitudeAxis(stickyAmplitude.y); } } return { x, y }; } /** Get sticky amplitude for one axis */ _getStickyAmplitudeAxis(value) { if (isNumber(value)) { return value; } if (!value || value === 'auto') { return 'auto'; } return toPixels(value); } /** Check if the element is interpolated */ get isInterpolated() { return (this._parallaxX.current === this._parallaxX.target && this._parallaxY.current === this._parallaxY.target); } /** Render the element */ render(getLerp) { const { _parallaxX: parallaxX, _parallaxY: parallaxY } = this; const element = this.element; if (!this.sticky || this.isInterpolated) { return; } // Friction if (this.hasStickyFriction) { const frictionLerp = getLerp(this.stickyFriction); parallaxX.target = lerp(parallaxX.target, 0, frictionLerp, LERP_APPROXIMATION); parallaxY.target = lerp(parallaxY.target, 0, frictionLerp, LERP_APPROXIMATION); } // Magnet const lerpFactor = getLerp(this.stickyLerp); parallaxX.current = lerp(parallaxX.current, parallaxX.target, lerpFactor, LERP_APPROXIMATION); parallaxY.current = lerp(parallaxY.current, parallaxY.target, lerpFactor, LERP_APPROXIMATION); element.style.transform = `translate3d(${parallaxX.current}px, ${parallaxY.current}px, 0)`; } } //# sourceMappingURL=index.js.map