// components/AnimatedBackground.tsx

'use client';

import React, { useEffect, useRef } from 'react';

interface AnimatedBackgroundProps {
  gridSpacing?: number;
  effectRadius?: number;
  maxDisplacement?: number;
  dotColor?: string;
  dotSize?: number;
}

const AnimatedBackground: React.FC<AnimatedBackgroundProps> = ({
  gridSpacing = 25,
  effectRadius = 500,
  maxDisplacement = 10,
  dotColor = '#888',
  dotSize = 1.5,
}) => {
  const canvasRef = useRef<HTMLCanvasElement | null>(null);
  const animationFrameId = useRef<number | null>(null);
  const dots = useRef<{ x: number; y: number }[]>([]); // Store positions of dots
  const mousePosition = useRef<{ x: number; y: number }>({ x: -1000, y: -1000 }); // Initialize off-screen

  useEffect(() => {
    const canvas = canvasRef.current;
    const context = canvas?.getContext('2d');

    if (!canvas || !context) return;

    let width = window.innerWidth;
    let height = window.innerHeight;
    canvas.width = width;
    canvas.height = height;

    // Function to initialize dots
    const initializeDots = () => {
      const columns = Math.floor(width / gridSpacing) + 1;
      const rows = Math.floor(height / gridSpacing) + 1;

      // Initialize dots
      const dotArray: { x: number; y: number }[] = [];
      for (let row = 0; row < rows; row++) {
        for (let col = 0; col < columns; col++) {
          dotArray.push({ x: col * gridSpacing, y: row * gridSpacing });
        }
      }
      dots.current = dotArray;
    };

    initializeDots();

    // Handle window resize
    const handleResize = () => {
      width = window.innerWidth;
      height = window.innerHeight;
      canvas.width = width;
      canvas.height = height;

      // Reinitialize dots on resize
      initializeDots();
    };

    window.addEventListener('resize', handleResize);

    // Handle mouse move
    const handleMouseMove = (event: MouseEvent) => {
      mousePosition.current = { x: event.clientX, y: event.clientY };
    };

    window.addEventListener('mousemove', handleMouseMove);

    // Animation loop
    const animate = () => {
      if (!context) return;

      context.clearRect(0, 0, canvas.width, canvas.height);
      context.fillStyle = dotColor; // Color of the dots

      for (let i = 0; i < dots.current.length; i++) {
        const dot = dots.current[i];
        const dx = dot.x - mousePosition.current.x;
        const dy = dot.y - mousePosition.current.y;
        const distance = Math.sqrt(dx * dx + dy * dy);

        let displacementX = 0;
        let displacementY = 0;

        if (distance < effectRadius) {
          const angle = Math.atan2(dy, dx);
          const strength = (effectRadius - distance) / effectRadius;
          displacementX = Math.cos(angle) * strength * maxDisplacement;
          displacementY = Math.sin(angle) * strength * maxDisplacement;
        }

        context.beginPath();
        context.arc(
          dot.x + displacementX,
          dot.y + displacementY,
          dotSize, // Radius of each dot
          0,
          Math.PI * 2
        );
        context.fill();
      }

      animationFrameId.current = requestAnimationFrame(animate);
    };

    animate(); // Start the animation

    // Cleanup on unmount
    return () => {
      window.removeEventListener('resize', handleResize);
      window.removeEventListener('mousemove', handleMouseMove);
      if (animationFrameId.current !== null) {
        cancelAnimationFrame(animationFrameId.current);
      }
    };
  }, [gridSpacing, effectRadius, maxDisplacement, dotColor, dotSize]);

  return (
    <canvas
      ref={canvasRef}
      className="absolute inset-0 pointer-events-none"
      style={{ display: 'block' }}
    />
  );
};

export default AnimatedBackground;

I want this to be like gravity. e.g. the mouse has a certain 'gravity' which will effect teh displacement.