forked from Github/frigate
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:
@@ -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 };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user