buzz
buzz

Reputation: 1106

Follow mouse with animation in Framer motion react

I have a custom cursor component in my react app. And for the smooth transition inside viewport I'm using framer motion.
The div under the mouse has some custom styling and it is following the cursor without any issues. But I want that div to animate all the time such as rotate + change border radius or even change bg color also.
From framer motion docs I went through the keyframes section and after applying the same instruction it does animate but stops following the cursor.
It just stays top left corner of the screen and do the animation. But I want it animate while following the cursor.

import React, { useState, useEffect } from "react";
import { motion } from "framer-motion";

const CustomCursor = () => {
  const [mousePosition, setMousePosition] = useState({
    x: 0,
    y: 0,
  });

  useEffect(() => {
    const updateMousePosition = (e) => {
      setMousePosition({
        x: e.clientX,
        y: e.clientY,
      });
    };

    window.addEventListener("mousemove", updateMousePosition);

    return () => {
      window.removeEventListener("mousemove", updateMousePosition);
    };
  }, []);

  const style = {
    transform: "translate(-50%, -50%)",
    width: "400px",
    height: "400px",
    borderRadius: "50% 22% 40% 80%",
    filter: " blur(100px)",
    background: "rgb(255, 67, 75)",
    background: "linear-gradient(#43d9ad, #4d5bce)",
    opacity: 0.4,
    zIndex: 2,
  };

  const variants = {
    default: {
      x: mousePosition.x - 200,
      y: mousePosition.y - 200,
    },
  };

  const animate = {
    scale: [1, 2, 2, 1, 1],
    rotate: [0, 0, 270, 270, 0],
    borderRadius: ["20%", "20%", "50%", "50%", "20%"],
  };

  return (
    <motion.div
      className={`fixed top-0 left-0 sm:hidden`}
      style={style}
      variants={variants}
      //tried setting animate={animate} but didn't work
      animate="default"
      transition={{
        duration: 0.3,
        ease: "linear",
        repeat: 0,
        type: "spring",
        stiffness: 80,
      }}
    ></motion.div>
  );
};

export default CustomCursor;

So how do I achieve the animate + follow cursor action here?

Upvotes: 2

Views: 7506

Answers (1)

John Li
John Li

Reputation: 7447

Assuming that the goal is to have the animated element follow cursor and at the same time show a loop animation, it seems that the animate values could be added to variants, instead of defining another animate property.

Simple demo of below example: stackblitz (the blur is turned lower temporarily in the example for better visibility of motion).

const variants = {
  default: {
    x: mousePosition.x - 200,
    y: mousePosition.y - 200,
    scale: [1, 2, 2, 1, 1],
    rotate: [0, 0, 270, 270, 0],
    borderRadius: ["20%", "20%", "50%", "50%", "20%"],
  },
};

The transition on motion.div could be used to specify the desired properties for each animation. The default key in below example can be edited to control the loop animation of scale, rotate and borderRadius, in this use case.

<motion.div
  className={`fixed top-0 left-0`}
  style={style}
  variants={variants}
  animate="default"
  transition={{
    x: {
      duration: 0.3,
      ease: "linear",
      repeat: 0,
      type: "spring",
      stiffness: 80,
    },
    y: {
      duration: 0.3,
      ease: "linear",
      repeat: 0,
      type: "spring",
      stiffness: 80,
    },
    default: {
      duration: 2.5,
      repeat: Infinity,
    },
  }}
></motion.div>

Upvotes: 3

Related Questions