Timeline minimap and scrolling changes (#10589)

* add function to get visible timeline duration

* Don't show minimap when minimap bounds exceed timeline area

* when minimap is hidden, only scroll timeline when needed

* observe only when not showing minimap

* no need to duplicate observer

* fix out of order param

* timeline utils hook props

---------

Co-authored-by: Nicolas Mowen <nickmowen213@gmail.com>
This commit is contained in:
Josh Hawkins
2024-03-21 12:49:04 -05:00
committed by GitHub
parent 973275e163
commit 0ac7aaabe3
8 changed files with 133 additions and 26 deletions

View File

@@ -11,6 +11,7 @@ import EventSegment from "./EventSegment";
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
import { ReviewSegment, ReviewSeverity } from "@/types/review";
import ReviewTimeline from "./ReviewTimeline";
import scrollIntoView from "scroll-into-view-if-needed";
export type EventReviewTimelineProps = {
segmentDuration: number;
@@ -29,6 +30,7 @@ export type EventReviewTimelineProps = {
setExportStartTime?: React.Dispatch<React.SetStateAction<number>>;
setExportEndTime?: React.Dispatch<React.SetStateAction<number>>;
events: ReviewSegment[];
visibleTimestamps?: number[];
severityType: ReviewSeverity;
timelineRef?: RefObject<HTMLDivElement>;
contentRef: RefObject<HTMLDivElement>;
@@ -52,6 +54,7 @@ export function EventReviewTimeline({
setExportStartTime,
setExportEndTime,
events,
visibleTimestamps,
severityType,
timelineRef,
contentRef,
@@ -68,14 +71,20 @@ export function EventReviewTimeline({
const exportStartTimeRef = useRef<HTMLDivElement>(null);
const exportEndRef = useRef<HTMLDivElement>(null);
const exportEndTimeRef = useRef<HTMLDivElement>(null);
const selectedTimelineRef = timelineRef || internalTimelineRef;
const timelineDuration = useMemo(
() => timelineStart - timelineEnd,
[timelineEnd, timelineStart],
);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useTimelineUtils(
{
segmentDuration,
timelineDuration,
timelineRef: selectedTimelineRef,
},
);
const timelineStartAligned = useMemo(
() => alignStartDateToTimeline(timelineStart),
@@ -100,7 +109,7 @@ export function EventReviewTimeline({
handleMouseMove: handlebarMouseMove,
} = useDraggableElement({
contentRef,
timelineRef: timelineRef || internalTimelineRef,
timelineRef: selectedTimelineRef,
draggableElementRef: handlebarRef,
segmentDuration,
showDraggableElement: showHandlebar,
@@ -119,7 +128,7 @@ export function EventReviewTimeline({
handleMouseMove: exportStartMouseMove,
} = useDraggableElement({
contentRef,
timelineRef: timelineRef || internalTimelineRef,
timelineRef: selectedTimelineRef,
draggableElementRef: exportStartRef,
segmentDuration,
showDraggableElement: showExportHandles,
@@ -140,7 +149,7 @@ export function EventReviewTimeline({
handleMouseMove: exportEndMouseMove,
} = useDraggableElement({
contentRef,
timelineRef: timelineRef || internalTimelineRef,
timelineRef: selectedTimelineRef,
draggableElementRef: exportEndRef,
segmentDuration,
showDraggableElement: showExportHandles,
@@ -213,9 +222,36 @@ export function EventReviewTimeline({
}
}, [isDragging, onHandlebarDraggingChange]);
useEffect(() => {
if (
selectedTimelineRef.current &&
segments &&
visibleTimestamps &&
visibleTimestamps?.length > 0 &&
!showMinimap
) {
const alignedVisibleTimestamps = visibleTimestamps.map(
alignStartDateToTimeline,
);
const element = selectedTimelineRef.current?.querySelector(
`[data-segment-id="${Math.max(...alignedVisibleTimestamps)}"]`,
);
scrollIntoView(element as HTMLDivElement, {
scrollMode: "if-needed",
behavior: "smooth",
});
}
}, [
selectedTimelineRef,
segments,
showMinimap,
alignStartDateToTimeline,
visibleTimestamps,
]);
return (
<ReviewTimeline
timelineRef={timelineRef || internalTimelineRef}
timelineRef={selectedTimelineRef}
handlebarRef={handlebarRef}
handlebarTimeRef={handlebarTimeRef}
handlebarMouseMove={handlebarMouseMove}

View File

@@ -53,8 +53,9 @@ export function EventSegment({
getEventThumbnail,
} = useEventSegmentUtils(segmentDuration, events, severityType);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useTimelineUtils(
{ segmentDuration },
);
const severity = useMemo(
() => getSeverity(segmentTime, displaySeverityType),
@@ -199,6 +200,7 @@ export function EventSegment({
return (
<div
key={segmentKey}
data-segment-id={segmentKey}
className={segmentClasses}
onClick={segmentClick}
onTouchEnd={(event) => handleTouchStart(event, segmentClick)}

View File

@@ -76,8 +76,12 @@ export function MotionReviewTimeline({
[timelineEnd, timelineStart, segmentDuration],
);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useTimelineUtils(
{
segmentDuration,
timelineDuration,
},
);
const timelineStartAligned = useMemo(
() => alignStartDateToTimeline(timelineStart) + 2 * segmentDuration,

View File

@@ -42,8 +42,9 @@ export function MotionSegment({
const { getMotionSegmentValue, interpolateMotionAudioData } =
useMotionSegmentUtils(segmentDuration, motion_events);
const { alignStartDateToTimeline, alignEndDateToTimeline } =
useTimelineUtils(segmentDuration);
const { alignStartDateToTimeline, alignEndDateToTimeline } = useTimelineUtils(
{ segmentDuration },
);
const { handleTouchStart } = useTapUtils();

View File

@@ -39,18 +39,22 @@ export function SummaryTimeline({
const observer = useRef<ResizeObserver | null>(null);
const { alignStartDateToTimeline } = useTimelineUtils(segmentDuration);
const reviewTimelineDuration = useMemo(
() => timelineStart - timelineEnd + 4 * segmentDuration,
[timelineEnd, timelineStart, segmentDuration],
);
const { alignStartDateToTimeline } = useTimelineUtils({
segmentDuration,
timelineDuration: reviewTimelineDuration,
timelineRef: reviewTimelineRef,
});
const timelineStartAligned = useMemo(
() => alignStartDateToTimeline(timelineStart) + 2 * segmentDuration,
[timelineStart, alignStartDateToTimeline, segmentDuration],
);
const reviewTimelineDuration = useMemo(
() => timelineStart - timelineEnd + 4 * segmentDuration,
[timelineEnd, timelineStart, segmentDuration],
);
// Generate segments for the timeline
const generateSegments = useCallback(() => {
const segmentCount = reviewTimelineDuration / segmentDuration;