Skip to content

Instantly share code, notes, and snippets.

@rektdeckard
Created April 25, 2022 02:34
Show Gist options
  • Save rektdeckard/501b701540adb27c058540edcde85f94 to your computer and use it in GitHub Desktop.
Save rektdeckard/501b701540adb27c058540edcde85f94 to your computer and use it in GitHub Desktop.
A pan and scroll helper hook for React
import React, { useRef, useEffect, useCallback } from "react";
const useDragScroll = <E extends HTMLElement = HTMLElement>() => {
const ref = useRef<E | null>(null);
const startX = useRef<number>(0);
const startY = useRef<number>(0);
const scrollLeft = useRef<number>(0);
const scrollTop = useRef<number>(0);
const onMouseMove = useCallback((e: MouseEvent) => {
if (!ref.current) return;
const x = e.pageX - ref.current.offsetLeft;
const y = e.pageY - ref.current.offsetTop;
ref.current.scrollLeft = scrollLeft.current - (x - startX.current);
ref.current.scrollTop = scrollTop.current - (y - startY.current);
}, []);
const onMouseDown: React.MouseEventHandler = useCallback((e) => {
if (!ref.current) return;
startX.current = e.pageX - ref.current.offsetLeft;
startY.current = e.pageY - ref.current.offsetTop;
scrollLeft.current = ref.current.scrollLeft;
scrollTop.current = ref.current.scrollTop;
ref.current.addEventListener("mousemove", onMouseMove, { passive: true });
}, [onMouseMove]);
const onMouseUp: React.MouseEventHandler = useCallback(() => {
if (!ref.current) return;
ref.current.removeEventListener("mousemove", onMouseMove);
}, [onMouseMove]);
const onMouseLeave: React.MouseEventHandler = useCallback(() => {
if (!ref.current) return;
ref.current.removeEventListener("mousemove", onMouseMove);
}, [onMouseMove]);
useEffect(() => () => ref.current?.removeEventListener("mousemove", onMouseMove), [onMouseMove]);
return { ref, onMouseDown, onMouseUp, onMouseLeave };
};
export default useDragScroll;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment