Animation » Example Animations » 26. Tracking the cursor

26. Tracking the cursor

You’re not limited to Framer’s events; you can also use common events (in React: synthetic events) like, for example, onMouseMove().

Code component

export default function CC_26_Tracking_the_cursor(props) {
    const x = useMotionValue(200)
    const y = useMotionValue(200)

    const rotateX = useTransform(y, [0, 400], [45, -45])
    const rotateY = useTransform(x, [0, 400], [-45, 45])

    function handleMouse(event) {
        x.set(event.pageX)
        y.set(event.pageY)
    }

    return (
        <div
            style={{
                width: 400,
                height: 400,
                ...props.style,
                display: "flex",
                placeItems: "center",
                placeContent: "center",
                perspective: 400,
            }}
            onMouseMove={handleMouse}
        >
            <motion.div
                style={{
                    width: 150,
                    height: 150,
                    borderRadius: 30,
                    backgroundColor: "#fff",
                    rotateX: rotateX,
                    rotateY: rotateY,
                }}
            />
        </div>
    )
}

The version in the CodeSandbox is a bit different because it doesn’t have a fixed size background (we get the getBoundingClientRect() of the div being hovered over):

export function Example() {
    const x = useMotionValue(200);
    const y = useMotionValue(200);

    const rotateX = useTransform(y, [0, 400], [45, -45]);
    const rotateY = useTransform(x, [0, 400], [-45, 45]);

    function handleMouse(event) {
        const rect = event.currentTarget.getBoundingClientRect();

        x.set(event.clientX - rect.left);
        y.set(event.clientY - rect.top);
    }

    return (
        <motion.div
            style={{
                width: 400,
                height: 400,
                display: "flex",
                placeItems: "center",
                placeContent: "center",
                borderRadius: 30,
                backgroundColor: "rgba(255, 255, 255, 0.05)",
                perspective: 400
            }}
            onMouseMove={handleMouse}
        >
            <motion.div
                style={{
                    width: 150,
                    height: 150,
                    borderRadius: 30,
                    backgroundColor: "#fff",
                    rotateX: rotateX,
                    rotateY: rotateY
                }}
            />
        </motion.div>
    );
}

Code overrides

const useStore = createStore({ rotateX: 0, rotateY: 0 })

export function Background(Component): ComponentType {
    return (props) => {
        const { style, ...rest } = props

        const [store, setStore] = useStore()

        // this Frame is 402 more points to the right
        const xTransform = transform([402, 802], [-45, 45])
        const yTransform = transform([0, 400], [45, -45])

        return (
            <Component
                {...props}
                style={{ ...style, perspective: 400 }}
                onMouseMove={(event) => {
                    setStore({
                        rotateX: yTransform(event.pageY),
                        rotateY: xTransform(event.pageX),
                    })
                }}
            />
        )
    }
}

export function Tracking_the_cursor(Component): ComponentType {
    return (props) => {
        const { style, ...rest } = props

        const [store, setStore] = useStore()

        return (
            <Component
                {...rest}
                style={{
                    ...style,
                    rotateX: store.rotateX,
                    rotateY: store.rotateY,
                }}
            />
        )
    }
}

Leave a Reply