UNPKG

kinetic-slider

Version:

A WebGL-powered kinetic slider component using PIXI.js

284 lines (279 loc) 9.31 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var react = require('react'); var gsap = require('gsap'); const logError = (context, error) => { }; const useTextTilt = ({ sliderRef, textContainersRef, currentIndex, cursorTextEffect, maxContainerShiftFraction, bgDispFilterRef, cursorDispFilterRef, cursorImgEffect, resourceManager, throttleTime = 50 }) => { const lastMoveTimeRef = react.useRef(0); const tiltTimeoutRef = react.useRef(null); const animationStateRef = react.useRef({ isAnimating: false, lastOffsetX: 0, lastOffsetY: 0 }); const cancellationRef = react.useRef({ isCancelled: false }); const activeTweensRef = react.useRef([]); react.useEffect(() => { if (typeof window === "undefined") return; if (!cursorTextEffect || !sliderRef.current) { return; } cancellationRef.current.isCancelled = false; const sliderElement = sliderRef.current; const cleanupActiveTweens = () => { try { activeTweensRef.current.forEach((tween) => { if (tween && tween.isActive()) { tween.kill(); } }); activeTweensRef.current = []; } catch (error) { } }; const calculateTiltValues = (mouseX, mouseY) => { try { if (!sliderElement) { logError("calculateTiltValues", "Slider element is undefined"); return { containerShiftX: 0, containerShiftY: 0, titleShiftX: 0, subtitleShiftX: 0, centerX: 0, centerY: 0 }; } const containerWidth = sliderElement.clientWidth; const containerHeight = sliderElement.clientHeight; if (containerWidth <= 0 || containerHeight <= 0) { logError("calculateTiltValues", "Invalid container dimensions"); return { containerShiftX: 0, containerShiftY: 0, titleShiftX: 0, subtitleShiftX: 0, centerX: 0, centerY: 0 }; } const centerX = containerWidth / 2; const centerY = containerHeight / 2; const offsetX = centerX - mouseX; const offsetY = centerY - mouseY; animationStateRef.current.lastOffsetX = offsetX; animationStateRef.current.lastOffsetY = offsetY; const rawContainerShiftX = offsetX * 0.05; const rawContainerShiftY = offsetY * 0.1; const maxShiftX = containerWidth * maxContainerShiftFraction; const maxShiftY = containerHeight * maxContainerShiftFraction; const containerShiftX = Math.max(Math.min(rawContainerShiftX, maxShiftX), -maxShiftX); const containerShiftY = Math.max(Math.min(rawContainerShiftY, maxShiftY), -maxShiftY); const maxTitleShift = containerWidth * 0.1; const titleRawShiftX = offsetX * 0.8; const titleShiftX = Math.max(Math.min(titleRawShiftX, maxTitleShift), -maxTitleShift); const maxSubtitleShift = containerWidth * 0.15; const subtitleShiftX = Math.max(Math.min(offsetX, maxSubtitleShift), -maxSubtitleShift); return { containerShiftX, containerShiftY, titleShiftX, subtitleShiftX, centerX, centerY }; } catch (error) { return { containerShiftX: 0, containerShiftY: 0, titleShiftX: 0, subtitleShiftX: 0, centerX: sliderElement?.clientWidth / 2 || 0, centerY: sliderElement?.clientHeight / 2 || 0 }; } }; const applyTiltEffect = (tiltValues) => { try { if (cancellationRef.current.isCancelled) return; const activeTextContainer = textContainersRef.current[currentIndex.current]; if (!activeTextContainer || activeTextContainer.children.length < 2) { return; } cleanupActiveTweens(); const createTrackedTween = (target, props) => { const tween = gsap.gsap.to(target, { ...props, onComplete: () => { if (resourceManager) { resourceManager.trackDisplayObject(target); } } }); if (resourceManager) { resourceManager.trackAnimation(tween); } activeTweensRef.current.push(tween); return tween; }; createTrackedTween(activeTextContainer, { x: tiltValues.centerX + tiltValues.containerShiftX, y: tiltValues.centerY + tiltValues.containerShiftY, duration: 0.5, ease: "expo.out" }); if (activeTextContainer.children[0]) { createTrackedTween(activeTextContainer.children[0], { x: tiltValues.titleShiftX, duration: 0.5, ease: "expo.out" }); } if (activeTextContainer.children[1]) { createTrackedTween(activeTextContainer.children[1], { x: tiltValues.subtitleShiftX, duration: 0.5, ease: "expo.out" }); } animationStateRef.current.isAnimating = true; } catch (error) { animationStateRef.current.isAnimating = false; } }; const resetTiltEffect = () => { try { if (cancellationRef.current.isCancelled) return; const activeContainer = textContainersRef.current[currentIndex.current]; if (!activeContainer) return; cleanupActiveTweens(); const centerX = sliderElement.clientWidth / 2; const centerY = sliderElement.clientHeight / 2; const createResetTween = (target, props) => { const tween = gsap.gsap.to(target, { ...props, duration: 1, ease: "expo.inOut", onComplete: () => { if (resourceManager) { resourceManager.trackDisplayObject(target); } } }); if (resourceManager) { resourceManager.trackAnimation(tween); } activeTweensRef.current.push(tween); return tween; }; createResetTween(activeContainer, { x: centerX, y: centerY, onComplete: () => { animationStateRef.current.isAnimating = false; } }); if (activeContainer.children[0]) { createResetTween(activeContainer.children[0], { x: 0 }); } if (activeContainer.children[1]) { createResetTween(activeContainer.children[1], { x: 0 }); } const resetFilterTween = (filterRef) => { if (filterRef.current) { const tween = gsap.gsap.to(filterRef.current.scale, { x: 0, y: 0, duration: 1, ease: "expo.inOut", onComplete: () => { if (resourceManager && filterRef.current) { resourceManager.trackFilter(filterRef.current); } } }); if (resourceManager) { resourceManager.trackAnimation(tween); } activeTweensRef.current.push(tween); } }; resetFilterTween(bgDispFilterRef); if (cursorImgEffect) { resetFilterTween(cursorDispFilterRef); } } catch (error) { animationStateRef.current.isAnimating = false; } }; const handleTextTilt = (e) => { try { if (cancellationRef.current.isCancelled) return; const now = Date.now(); if (now - lastMoveTimeRef.current < throttleTime) { return; } lastMoveTimeRef.current = now; const tiltValues = calculateTiltValues(e.clientX, e.clientY); applyTiltEffect(tiltValues); if (tiltTimeoutRef.current !== null) { if (resourceManager) { resourceManager.clearTimeout(tiltTimeoutRef.current); } else { clearTimeout(tiltTimeoutRef.current); } tiltTimeoutRef.current = null; } const setTimeoutFn = () => { resetTiltEffect(); tiltTimeoutRef.current = null; }; if (resourceManager) { tiltTimeoutRef.current = resourceManager.setTimeout(setTimeoutFn, 300); } else { tiltTimeoutRef.current = window.setTimeout(setTimeoutFn, 300); } } catch (error) { } }; sliderElement.addEventListener("mousemove", handleTextTilt, { passive: true }); return () => { cancellationRef.current.isCancelled = true; sliderElement.removeEventListener("mousemove", handleTextTilt); cleanupActiveTweens(); if (tiltTimeoutRef.current !== null) { if (resourceManager) { resourceManager.clearTimeout(tiltTimeoutRef.current); } else { clearTimeout(tiltTimeoutRef.current); } tiltTimeoutRef.current = null; } }; }, [ sliderRef, textContainersRef, currentIndex, cursorTextEffect, maxContainerShiftFraction, bgDispFilterRef, cursorDispFilterRef, cursorImgEffect, resourceManager, throttleTime ]); }; exports.default = useTextTilt; //# sourceMappingURL=useTextTilt.cjs.map