fix: preserve lidar review scroll
This commit is contained in:
parent
796b9306f9
commit
4c83e8a4e7
|
|
@ -2825,6 +2825,7 @@
|
|||
display: grid;
|
||||
gap: 0.72rem;
|
||||
margin-top: 1.2rem;
|
||||
overflow-anchor: none;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,11 @@
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import {
|
||||
useCallback,
|
||||
useEffect,
|
||||
useLayoutEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import { StatusBadge } from "@nodedc/ui-react";
|
||||
|
||||
import {
|
||||
|
|
@ -35,6 +42,8 @@ export function LidarLocalSurfacePanel({
|
|||
selectedWindowKey: string | null;
|
||||
reloadGeneration: number;
|
||||
}) {
|
||||
const panelRef = useRef<HTMLElement | null>(null);
|
||||
const pendingScrollTopRef = useRef<number | null>(null);
|
||||
const [model, setModel] = useState<LidarLocalSurfaceModel | null>(null);
|
||||
const [frame, setFrame] = useState<LidarLocalSurfaceFrame | null>(null);
|
||||
const [timeline, setTimeline] = useState<Timeline | null>(null);
|
||||
|
|
@ -47,6 +56,27 @@ export function LidarLocalSurfacePanel({
|
|||
>("local-surface");
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const captureFrameSelectionScroll = useCallback(() => {
|
||||
const scrollContainer = panelRef.current?.closest<HTMLElement>(
|
||||
".nodedc-application-panel__body",
|
||||
);
|
||||
pendingScrollTopRef.current = scrollContainer?.scrollTop ?? null;
|
||||
}, []);
|
||||
const selectFrame = useCallback((frameIndex: number) => {
|
||||
if (pendingScrollTopRef.current === null) {
|
||||
captureFrameSelectionScroll();
|
||||
}
|
||||
setSelectedFrameIndex(frameIndex);
|
||||
}, [captureFrameSelectionScroll]);
|
||||
useLayoutEffect(() => {
|
||||
const scrollTop = pendingScrollTopRef.current;
|
||||
if (scrollTop === null) return;
|
||||
const scrollContainer = panelRef.current?.closest<HTMLElement>(
|
||||
".nodedc-application-panel__body",
|
||||
);
|
||||
scrollContainer?.scrollTo({ top: scrollTop, behavior: "auto" });
|
||||
pendingScrollTopRef.current = null;
|
||||
}, [selectedFrameIndex]);
|
||||
|
||||
const anchor = useMemo(() => {
|
||||
if (!model) return null;
|
||||
|
|
@ -205,6 +235,7 @@ export function LidarLocalSurfacePanel({
|
|||
|
||||
return (
|
||||
<section
|
||||
ref={panelRef}
|
||||
className="lidar-local-surface"
|
||||
aria-label="Динамическая локальная поверхность LiDAR"
|
||||
>
|
||||
|
|
@ -289,12 +320,14 @@ export function LidarLocalSurfacePanel({
|
|||
timeline={timeline}
|
||||
review={review}
|
||||
selectedFrameIndex={selectedFrameIndex}
|
||||
onSelectFrame={setSelectedFrameIndex}
|
||||
onSelectionStart={captureFrameSelectionScroll}
|
||||
onSelectFrame={selectFrame}
|
||||
/>
|
||||
<LidarLocalSurfaceReviewQueue
|
||||
review={review}
|
||||
selectedFrameIndex={selectedFrameIndex}
|
||||
onSelectFrame={setSelectedFrameIndex}
|
||||
onSelectionStart={captureFrameSelectionScroll}
|
||||
onSelectFrame={selectFrame}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
|
|
|||
|
|
@ -42,11 +42,13 @@ export function LidarLocalSurfaceTimeline({
|
|||
timeline,
|
||||
review,
|
||||
selectedFrameIndex,
|
||||
onSelectionStart,
|
||||
onSelectFrame,
|
||||
}: {
|
||||
timeline: Timeline;
|
||||
review: LidarLocalSurfaceReview;
|
||||
selectedFrameIndex: number;
|
||||
onSelectionStart: () => void;
|
||||
onSelectFrame: (frameIndex: number) => void;
|
||||
}) {
|
||||
const plot = useMemo(() => {
|
||||
|
|
@ -131,6 +133,10 @@ export function LidarLocalSurfaceTimeline({
|
|||
role="img"
|
||||
tabIndex={0}
|
||||
aria-label="Ошибка предсказания локальной поверхности по всей записи"
|
||||
onMouseDown={(event) => {
|
||||
onSelectionStart();
|
||||
event.preventDefault();
|
||||
}}
|
||||
onClick={(event) => selectAtPointer(event.clientX, event.currentTarget)}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "ArrowLeft") {
|
||||
|
|
@ -221,10 +227,12 @@ function hasReasonKind(
|
|||
export function LidarLocalSurfaceReviewQueue({
|
||||
review,
|
||||
selectedFrameIndex,
|
||||
onSelectionStart,
|
||||
onSelectFrame,
|
||||
}: {
|
||||
review: LidarLocalSurfaceReview;
|
||||
selectedFrameIndex: number;
|
||||
onSelectionStart: () => void;
|
||||
onSelectFrame: (frameIndex: number) => void;
|
||||
}) {
|
||||
const [filter, setFilter] = useState<ReviewFilter>("high");
|
||||
|
|
@ -281,6 +289,7 @@ export function LidarLocalSurfaceReviewQueue({
|
|||
type="button"
|
||||
key={item.key}
|
||||
data-active={filter === item.key ? "true" : undefined}
|
||||
onMouseDown={(event) => event.preventDefault()}
|
||||
onClick={() => setFilter(item.key)}
|
||||
>
|
||||
{item.label} <span>{item.count}</span>
|
||||
|
|
@ -297,6 +306,10 @@ export function LidarLocalSurfaceReviewQueue({
|
|||
item.frameIndex === selectedFrameIndex ? "true" : undefined
|
||||
}
|
||||
data-attention={item.attention}
|
||||
onMouseDown={(event) => {
|
||||
onSelectionStart();
|
||||
event.preventDefault();
|
||||
}}
|
||||
onClick={() => onSelectFrame(item.frameIndex)}
|
||||
>
|
||||
<span>
|
||||
|
|
|
|||
Loading…
Reference in New Issue