Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

useMousePosition does not consider onscroll #177

Open
tommedema opened this issue Sep 27, 2019 · 1 comment
Open

useMousePosition does not consider onscroll #177

tommedema opened this issue Sep 27, 2019 · 1 comment

Comments

@tommedema
Copy link

Since useMousePosition returns the mouse position in the document (and not the window), the position changes as the user scrolls. Yet this is not recognized by the hook. See this video:

https://www.loom.com/share/7009214d57ba44d8b6bc2e0bbdbf04e1

useMousePosition should therefore update the X,Y when onscroll is fired. I also think it would be good to include an option to only look at the mouse position in the window, and not the document, as that is often more useful.

@tommedema
Copy link
Author

I've come up with this solution for now. Can you think of a case where this logic would fail?

useMousePosition.ts

/**
 * Inspired by: https://github.com/sandiiarov/use-events/blob/master/src/useMousePosition/index.tsx
 * 
 * Enhanced to take scrolling into consideration.
 * @see https://github.com/sandiiarov/use-events/issues/177
 */

import React, { useEffect, useState } from 'react'

const useMousePosition = (): [
  number,
  number,
  { onMouseMove: (e: React.MouseEvent) => void }
] => {
  const [lastScrollX, setLastScrollX] = useState(
    (window.document.scrollingElement && window.document.scrollingElement.scrollLeft) || 0
  )
  const [lastScrollY, setLastScrollY] = useState(
    (window.document.scrollingElement && window.document.scrollingElement.scrollTop) || 0
  )
  const [x, setX] = useState(0)
  const [y, setY] = useState(0)

  useEffect(() => {
    const onScroll = () => {
      const scrollElement = window.document.scrollingElement

      if (scrollElement) {
        const {
          scrollTop,
          scrollLeft
        } = scrollElement

        setX(x + scrollLeft - lastScrollX)
        setY(y + scrollTop - lastScrollY)

        setLastScrollX(scrollLeft)
        setLastScrollY(scrollTop)
      }
    }

    window.document.addEventListener('scroll', onScroll, true)

    return () => {
      window.document.removeEventListener('scroll', onScroll, true)
    }
  })

  const bindings = {
    onMouseMove: ({ nativeEvent: { offsetX, offsetY } }: React.MouseEvent) => {
      setX(offsetX)
      setY(offsetY)
    }
  }

  return [x, y, bindings]
}

export default useMousePosition

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant