Newer
Older
My-Portfolio / frontend / src / components / design / FloatingSVG.jsx
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;