import React, { useEffect, useRef, useState } from "react"; import useIsMobile from "../../constants/useIsMobile"; // Ensure this hook is correctly implemented const easeInOutSine = (t) => -(Math.cos(Math.PI * t) - 1) / 2; const FloatingSVG = ({ svg, position, speed = 0.5, amplitude = 20, rotationRange = 10, resetTrigger, // Prop to trigger reset }) => { const svgRef = useRef(null); const animationRef = useRef(null); const startTimeRef = useRef(null); const [isExploding, setIsExploding] = useState(true); const isMobile = useIsMobile(); // Detect if the screen is mobile // Reset the explosion animation when resetTrigger changes useEffect(() => { if (!resetTrigger) { // Section is not visible, reset to center const svgElement = svgRef.current; const centerX = window.innerWidth / 2 - (isMobile ? 7.5 : 15); // Adjust center based on size const centerY = window.innerHeight / 2 - (isMobile ? 7.5 : 15); // Adjust center based on size svgElement.style.transition = "left 1s ease-out, top 1s ease-out, opacity 1s ease-out"; svgElement.style.left = `${centerX}px`; svgElement.style.top = `${centerY}px`; svgElement.style.opacity = "0"; // Fade out setIsExploding(true); // Prepare for next explosion } else { // Section is visible, start explosion animation setIsExploding(true); } }, [resetTrigger, isMobile]); // Explosion and floating animation useEffect(() => { const svgElement = svgRef.current; if (isExploding && resetTrigger) { // Set initial position to the center of the screen const centerX = window.innerWidth / 2 - (isMobile ? 7.5 : 15); // Adjust center based on size const centerY = window.innerHeight / 2 - (isMobile ? 7.5 : 15); // Adjust center based on size svgElement.style.left = `${centerX}px`; svgElement.style.top = `${centerY}px`; // Move to the target position with a smooth transition svgElement.style.transition = "left 1s ease-out, top 1s ease-out, opacity 1s ease-out"; svgElement.style.opacity = "0"; // Start invisible setTimeout(() => { svgElement.style.left = position.x; svgElement.style.top = position.y; svgElement.style.opacity = "1"; setIsExploding(false); }, Math.random() * 500); // Random delay between 0 and 500ms } // Floating animation const animate = (timestamp) => { if (!startTimeRef.current) startTimeRef.current = timestamp; const elapsed = (timestamp - startTimeRef.current) / 1000; // Convert to seconds // Simulate floating with multiple sine waves const offsetY = Math.sin(elapsed * speed * 1.8) * amplitude * 0.6 + // Primary wave Math.sin(elapsed * speed * 1.2) * amplitude * 0.4; // Secondary wave const offsetX = Math.cos(elapsed * speed * 1.3) * amplitude * 0.3 + // Horizontal drift Math.sin(elapsed * speed * 0.8) * amplitude * 0.2; // Subtle side drift // Eased Y motion for more natural feel const t = (Math.sin(elapsed * speed) + 1) / 2; // Normalize to 0-1 const easedOffsetY = easeInOutSine(t) * amplitude * 2 - amplitude; // Add smooth rotation const rotation = Math.sin(elapsed * speed * 0.6) * rotationRange; // Apply transformation svgElement.style.transform = `translate(${offsetX}px, ${easedOffsetY}px) rotate(${rotation}deg)`; animationRef.current = requestAnimationFrame(animate); }; // Start floating animation after explosion is complete if (!isExploding && resetTrigger) { animationRef.current = requestAnimationFrame(animate); } return () => cancelAnimationFrame(animationRef.current); }, [ position, speed, amplitude, rotationRange, isExploding, resetTrigger, isMobile, ]); // Set size based on screen type (mobile or desktop) const size = isMobile ? "20px" : "30px"; return ( <div ref={svgRef} style={{ position: "absolute", width: size, height: size, zIndex: 0, }} > <img src={svg} alt="floating-svg" style={{ width: "100%", height: "100%" }} /> </div> ); }; export default FloatingSVG;