Timeline handlebar changes (#10170)

* auto scrolling handlebar with preview time

* tablets can show 2 columns on the event view grid

* font sizes

* hide minimap when previewing
This commit is contained in:
Josh Hawkins
2024-03-01 09:36:13 -06:00
committed by GitHub
parent 49530dc2e4
commit a49e1bbc64
4 changed files with 86 additions and 113 deletions

View File

@@ -1,6 +1,6 @@
import { useCallback, useEffect } from "react";
interface DragHandlerProps {
type DragHandlerProps = {
contentRef: React.RefObject<HTMLElement>;
timelineRef: React.RefObject<HTMLDivElement>;
scrollTimeRef: React.RefObject<HTMLDivElement>;
@@ -8,15 +8,15 @@ interface DragHandlerProps {
alignEndDateToTimeline: (time: number) => number;
segmentDuration: number;
showHandlebar: boolean;
handlebarTime?: number;
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
handlebarTimeRef: React.MutableRefObject<HTMLDivElement | null>;
timelineDuration: number;
timelineStart: number;
isDragging: boolean;
setIsDragging: React.Dispatch<React.SetStateAction<boolean>>;
currentTimeRef: React.MutableRefObject<HTMLDivElement | null>;
setHandlebarTime?: React.Dispatch<React.SetStateAction<number>>;
}
};
// TODO: handle mobile touch events
function useDraggableHandler({
contentRef,
timelineRef,
@@ -24,12 +24,13 @@ function useDraggableHandler({
alignStartDateToTimeline,
segmentDuration,
showHandlebar,
handlebarTime,
setHandlebarTime,
handlebarTimeRef,
timelineDuration,
timelineStart,
isDragging,
setIsDragging,
currentTimeRef,
setHandlebarTime,
}: DragHandlerProps) {
const handleMouseDown = useCallback(
(e: React.MouseEvent<HTMLDivElement>) => {
@@ -51,6 +52,39 @@ function useDraggableHandler({
[isDragging, setIsDragging],
);
const getCumulativeScrollTop = useCallback((element: HTMLElement | null) => {
let scrollTop = 0;
while (element) {
scrollTop += element.scrollTop;
element = element.parentElement;
}
return scrollTop;
}, []);
const updateHandlebarPosition = useCallback(
(newHandlePosition: number, segmentStartTime: number) => {
const thumb = scrollTimeRef.current;
if (thumb) {
requestAnimationFrame(() => {
thumb.style.top = `${newHandlePosition}px`;
if (handlebarTimeRef.current) {
handlebarTimeRef.current.textContent = new Date(
segmentStartTime * 1000,
).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
...(segmentDuration < 60 && { second: "2-digit" }),
});
}
});
if (setHandlebarTime) {
setHandlebarTime(segmentStartTime);
}
}
},
[segmentDuration, handlebarTimeRef, scrollTimeRef, setHandlebarTime],
);
const handleMouseMove = useCallback(
(e: MouseEvent) => {
if (
@@ -64,7 +98,7 @@ function useDraggableHandler({
e.preventDefault();
e.stopPropagation();
if (isDragging) {
if (showHandlebar && isDragging) {
const {
scrollHeight: timelineHeight,
clientHeight: visibleTimelineHeight,
@@ -75,15 +109,6 @@ function useDraggableHandler({
const segmentHeight =
timelineHeight / (timelineDuration / segmentDuration);
const getCumulativeScrollTop = (element: HTMLElement | null) => {
let scrollTop = 0;
while (element) {
scrollTop += element.scrollTop;
element = element.parentElement;
}
return scrollTop;
};
const parentScrollTop = getCumulativeScrollTop(timelineRef.current);
const newHandlePosition = Math.min(
@@ -99,27 +124,10 @@ function useDraggableHandler({
timelineStart - segmentIndex * segmentDuration,
);
if (showHandlebar) {
const thumb = scrollTimeRef.current;
requestAnimationFrame(() => {
thumb.style.top = `${newHandlePosition - segmentHeight}px`;
if (currentTimeRef.current) {
currentTimeRef.current.textContent = new Date(
segmentStartTime * 1000,
).toLocaleTimeString([], {
hour: "2-digit",
minute: "2-digit",
...(segmentDuration < 60 && { second: "2-digit" }),
});
}
});
if (setHandlebarTime) {
setHandlebarTime(
timelineStart -
(newHandlePosition / segmentHeight) * segmentDuration,
);
}
}
updateHandlebarPosition(
newHandlePosition - segmentHeight,
segmentStartTime,
);
}
},
// we know that these deps are correct
@@ -131,21 +139,43 @@ function useDraggableHandler({
showHandlebar,
timelineDuration,
timelineStart,
updateHandlebarPosition,
alignStartDateToTimeline,
getCumulativeScrollTop,
],
);
useEffect(() => {
// TODO: determine when we want to do this
const handlebar = scrollTimeRef.current;
if (handlebar && showHandlebar) {
handlebar.scrollIntoView({
if (
timelineRef.current &&
scrollTimeRef.current &&
showHandlebar &&
handlebarTime &&
!isDragging
) {
const { scrollHeight: timelineHeight, scrollTop: scrolled } =
timelineRef.current;
const segmentHeight =
timelineHeight / (timelineDuration / segmentDuration);
const parentScrollTop = getCumulativeScrollTop(timelineRef.current);
const newHandlePosition =
((timelineStart - handlebarTime) / segmentDuration) * segmentHeight +
parentScrollTop -
scrolled;
updateHandlebarPosition(newHandlePosition - segmentHeight, handlebarTime);
scrollTimeRef.current.scrollIntoView({
behavior: "smooth",
block: "center",
});
}
// temporary until behavior is decided
// we know that these deps are correct
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [handlebarTime, showHandlebar, scrollTimeRef, timelineStart]);
return { handleMouseDown, handleMouseUp, handleMouseMove };
}