reactjsthree.jsreact-three-fiberreact-three-drei

ThreeJS Div follow mouse


I am brand new into the programming world. I am trying to create a circle that follows the mouse around in Three JS. Here is my code. The circle follows the mouse, but visually it is about half screen width and height away from actual cursor position. How can I fix it?

const CircleFollowMouse = () => {
  const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });
  const circleSize = 40; // Define the size of the circle

  useEffect(() => {
    const handleMouseMove = (event) => {
      // Update mouse position state with the current mouse position
      setMousePosition({ x: event.pageX, y: event.pageY });
    };

    // Add mouse move event listener
    document.addEventListener('mousemove', handleMouseMove);

    // Remove event listener on cleanup
    return () => {
      document.removeEventListener('mousemove', handleMouseMove);
    };
  }, []);

  return (
    <Html>
      <div
        className="circle"
        style={{
          left: `${mousePosition.x - circleSize / 2}px`, // Center the circle on the mouse by adjusting for half its size
          top: `${mousePosition.y - circleSize / 2}px`, // Center the circle on the mouse by adjusting for half its size
          width: `${circleSize}px`, // Set the width of the circle
          height: `${circleSize}px`, // Set the height of the circle
          borderRadius: '50%', // Make the div a circle
          backgroundColor: 'white', // Set the circle color
          position: 'fixed', // Ensure the circle follows the mouse correctly
          zIndex: 9999, // Make sure the circle is above other content
        }}
      ></div>
    </Html>
  );
};

Solution

  • By default Html from @react-three/drei is centered on the middle of the screen.

    You have two options here:

    1. Altering Html layout to put it back into top-left corner:
    <Html
      style={{
        transform: `translate3d(-50vw, -50vh, 0)`
      }}
    ></Html>
    
    1. Update positioning of the circle:
    {
        left: `${mousePosition.x - circleSize / 2 - halfScreenWidth}px`,
         top: `${mousePosition.y - circleSize / 2 - halfScreenHeight}px`
    }
    

    Alternatively, IMO, instead of previous implementation, a more "good process" integration would be to use useFrame and state.pointer instead of useEffect and addEventListener.mousemove:

    import { useFrame, useThree } from '@react-three/fiber'
    
      const { size } = useThree()
      useFrame((state) => {
        setMousePosition({
          // state.pointer.xy are values from -1.0 to 1.0 so they match the logic of the anchor of Html being anchored in the middle
          x: state.pointer.x * (size.width * 0.5),
          y: state.pointer.y * (size.height * -0.5)
        })
      })
      // also apply pointerEvents: none to your circle.