keep handlebar centered when zooming

This commit is contained in:
Josh Hawkins 2024-12-03 10:54:02 -06:00
parent a9a8db784c
commit 63e21763ec
4 changed files with 67 additions and 11 deletions

View File

@ -116,14 +116,31 @@ export function EventReviewTimeline({
]);
const scrollToSegment = useCallback(
(segmentTime: number, ifNeeded?: boolean) => {
(segmentTime: number, ifNeeded?: boolean, behavior?: ScrollBehavior) => {
if (virtualizedSegmentsRef.current) {
virtualizedSegmentsRef.current.scrollToSegment(segmentTime, ifNeeded);
virtualizedSegmentsRef.current.scrollToSegment(
segmentTime,
ifNeeded,
behavior,
);
}
},
[],
);
// keep handlebar centered when zooming
useEffect(() => {
setTimeout(() => {
scrollToSegment(
alignStartDateToTimeline(handlebarTime ?? timelineStart),
true,
"auto",
);
}, 0);
// we only want to scroll when zooming level changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [segmentDuration]);
return (
<ReviewTimeline
timelineRef={selectedTimelineRef}

View File

@ -1,4 +1,10 @@
import React, { useCallback, useMemo, useRef, RefObject } from "react";
import React, {
useCallback,
useMemo,
useRef,
RefObject,
useEffect,
} from "react";
import { useTimelineUtils } from "@/hooks/use-timeline-utils";
import { MotionData, ReviewSegment } from "@/types/review";
import ReviewTimeline from "./ReviewTimeline";
@ -120,14 +126,31 @@ export function MotionReviewTimeline({
]);
const scrollToSegment = useCallback(
(segmentTime: number, ifNeeded?: boolean) => {
(segmentTime: number, ifNeeded?: boolean, behavior?: ScrollBehavior) => {
if (virtualizedSegmentsRef.current) {
virtualizedSegmentsRef.current.scrollToSegment(segmentTime, ifNeeded);
virtualizedSegmentsRef.current.scrollToSegment(
segmentTime,
ifNeeded,
behavior,
);
}
},
[],
);
// keep handlebar centered when zooming
useEffect(() => {
setTimeout(() => {
scrollToSegment(
alignStartDateToTimeline(handlebarTime ?? timelineStart),
true,
"auto",
);
}, 0);
// we only want to scroll when zooming level changes
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [segmentDuration]);
return (
<ReviewTimeline
timelineRef={selectedTimelineRef}

View File

@ -26,7 +26,11 @@ interface VirtualizedEventSegmentsProps {
}
export interface VirtualizedEventSegmentsRef {
scrollToSegment: (segmentTime: number, ifNeeded?: boolean) => void;
scrollToSegment: (
segmentTime: number,
ifNeeded?: boolean,
behavior?: ScrollBehavior,
) => void;
}
const SEGMENT_HEIGHT = 8;
@ -93,7 +97,11 @@ export const VirtualizedEventSegments = forwardRef<
}, [updateVisibleRange, timelineRef]);
const scrollToSegment = useCallback(
(segmentTime: number, ifNeeded: boolean = true) => {
(
segmentTime: number,
ifNeeded: boolean = true,
behavior: ScrollBehavior = "smooth",
) => {
const alignedSegmentTime = alignStartDateToTimeline(segmentTime);
const segmentIndex = segments.findIndex(
(time) => time === alignedSegmentTime,
@ -115,7 +123,7 @@ export const VirtualizedEventSegments = forwardRef<
if (!ifNeeded || !isVisible) {
timelineRef.current.scrollTo({
top: Math.max(0, centeredScrollTop),
behavior: "smooth",
behavior: behavior,
});
}
updateVisibleRange();

View File

@ -27,7 +27,11 @@ type VirtualizedMotionSegmentsProps = {
};
export interface VirtualizedMotionSegmentsRef {
scrollToSegment: (segmentTime: number, ifNeeded?: boolean) => void;
scrollToSegment: (
segmentTime: number,
ifNeeded?: boolean,
behavior?: ScrollBehavior,
) => void;
}
const SEGMENT_HEIGHT = 8;
@ -93,7 +97,11 @@ export const VirtualizedMotionSegments = forwardRef<
}, [updateVisibleRange, timelineRef]);
const scrollToSegment = useCallback(
(segmentTime: number, ifNeeded: boolean = true) => {
(
segmentTime: number,
ifNeeded: boolean = true,
behavior: ScrollBehavior = "smooth",
) => {
const segmentIndex = segments.findIndex((time) => time === segmentTime);
if (
segmentIndex !== -1 &&
@ -112,7 +120,7 @@ export const VirtualizedMotionSegments = forwardRef<
if (!ifNeeded || !isVisible) {
timelineRef.current.scrollTo({
top: Math.max(0, centeredScrollTop),
behavior: "smooth",
behavior: behavior,
});
}
updateVisibleRange();