2024-02-21 02:22:59 +03:00
|
|
|
import { useCallback } from "react";
|
|
|
|
|
|
|
|
|
|
interface DragHandlerProps {
|
|
|
|
|
contentRef: React.RefObject<HTMLElement>;
|
|
|
|
|
timelineRef: React.RefObject<HTMLDivElement>;
|
|
|
|
|
scrollTimeRef: React.RefObject<HTMLDivElement>;
|
|
|
|
|
alignDateToTimeline: (time: number) => number;
|
|
|
|
|
segmentDuration: number;
|
|
|
|
|
showHandlebar: boolean;
|
|
|
|
|
timelineDuration: number;
|
|
|
|
|
timelineStart: number;
|
|
|
|
|
isDragging: boolean;
|
|
|
|
|
setIsDragging: React.Dispatch<React.SetStateAction<boolean>>;
|
|
|
|
|
currentTimeRef: React.MutableRefObject<HTMLDivElement | null>;
|
2024-02-22 17:16:37 +03:00
|
|
|
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
|
2024-02-21 02:22:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO: handle mobile touch events
|
|
|
|
|
function useDraggableHandler({
|
|
|
|
|
contentRef,
|
|
|
|
|
timelineRef,
|
|
|
|
|
scrollTimeRef,
|
|
|
|
|
alignDateToTimeline,
|
|
|
|
|
segmentDuration,
|
|
|
|
|
showHandlebar,
|
|
|
|
|
timelineDuration,
|
|
|
|
|
timelineStart,
|
|
|
|
|
isDragging,
|
|
|
|
|
setIsDragging,
|
|
|
|
|
currentTimeRef,
|
2024-02-22 17:16:37 +03:00
|
|
|
setHandlebarTime,
|
2024-02-21 02:22:59 +03:00
|
|
|
}: DragHandlerProps) {
|
|
|
|
|
const handleMouseDown = useCallback(
|
|
|
|
|
(e: React.MouseEvent<HTMLDivElement>) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
setIsDragging(true);
|
|
|
|
|
},
|
|
|
|
|
[setIsDragging]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleMouseUp = useCallback(
|
|
|
|
|
(e: MouseEvent) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
if (isDragging) {
|
|
|
|
|
setIsDragging(false);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[isDragging, setIsDragging]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const handleMouseMove = useCallback(
|
|
|
|
|
(e: MouseEvent) => {
|
2024-02-21 20:58:41 +03:00
|
|
|
if (
|
|
|
|
|
!contentRef.current ||
|
|
|
|
|
!timelineRef.current ||
|
|
|
|
|
!scrollTimeRef.current
|
|
|
|
|
) {
|
2024-02-21 02:22:59 +03:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
e.stopPropagation();
|
|
|
|
|
|
|
|
|
|
if (isDragging) {
|
|
|
|
|
const {
|
|
|
|
|
scrollHeight: timelineHeight,
|
|
|
|
|
clientHeight: visibleTimelineHeight,
|
|
|
|
|
scrollTop: scrolled,
|
|
|
|
|
offsetTop: timelineTop,
|
|
|
|
|
} = timelineRef.current;
|
|
|
|
|
|
|
|
|
|
const segmentHeight =
|
|
|
|
|
timelineHeight / (timelineDuration / segmentDuration);
|
|
|
|
|
|
2024-02-21 20:58:41 +03:00
|
|
|
const getCumulativeScrollTop = (element: HTMLElement | null) => {
|
2024-02-21 02:22:59 +03:00
|
|
|
let scrollTop = 0;
|
|
|
|
|
while (element) {
|
|
|
|
|
scrollTop += element.scrollTop;
|
|
|
|
|
element = element.parentElement;
|
|
|
|
|
}
|
|
|
|
|
return scrollTop;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const parentScrollTop = getCumulativeScrollTop(timelineRef.current);
|
|
|
|
|
|
|
|
|
|
const newHandlePosition = Math.min(
|
|
|
|
|
visibleTimelineHeight - timelineTop + parentScrollTop,
|
|
|
|
|
Math.max(
|
|
|
|
|
segmentHeight + scrolled,
|
|
|
|
|
e.clientY - timelineTop + parentScrollTop
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const segmentIndex = Math.floor(newHandlePosition / segmentHeight);
|
|
|
|
|
const segmentStartTime = alignDateToTimeline(
|
|
|
|
|
timelineStart - segmentIndex * segmentDuration
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (showHandlebar) {
|
|
|
|
|
const thumb = scrollTimeRef.current;
|
|
|
|
|
requestAnimationFrame(() => {
|
|
|
|
|
thumb.style.top = `${newHandlePosition - segmentHeight}px`;
|
|
|
|
|
if (currentTimeRef.current) {
|
|
|
|
|
currentTimeRef.current.textContent = new Date(
|
2024-02-21 20:58:41 +03:00
|
|
|
segmentStartTime * 1000
|
2024-02-21 02:22:59 +03:00
|
|
|
).toLocaleTimeString([], {
|
|
|
|
|
hour: "2-digit",
|
|
|
|
|
minute: "2-digit",
|
|
|
|
|
...(segmentDuration < 60 && { second: "2-digit" }),
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
2024-02-22 17:16:37 +03:00
|
|
|
if (setHandlebarTime) {
|
|
|
|
|
setHandlebarTime(timelineStart - segmentIndex * segmentDuration);
|
|
|
|
|
}
|
2024-02-21 02:22:59 +03:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
[
|
|
|
|
|
isDragging,
|
|
|
|
|
contentRef,
|
|
|
|
|
segmentDuration,
|
|
|
|
|
showHandlebar,
|
|
|
|
|
timelineDuration,
|
|
|
|
|
timelineStart,
|
|
|
|
|
]
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return { handleMouseDown, handleMouseUp, handleMouseMove };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default useDraggableHandler;
|