include tolerance for displaying of path and zone

some browsers (firefox and probably brave) intentionally reduce precision of seeking with currentTime for privacy reasons
This commit is contained in:
Josh Hawkins 2025-11-01 07:26:09 -05:00
parent af765af0d2
commit b9ca9e49dd

View File

@ -13,6 +13,9 @@ import { cn } from "@/lib/utils";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Event } from "@/types/event"; import { Event } from "@/types/event";
// Use a small tolerance (10ms) for browsers with seek precision by-design issues
const TOLERANCE = 0.01;
type ObjectTrackOverlayProps = { type ObjectTrackOverlayProps = {
camera: string; camera: string;
showBoundingBoxes?: boolean; showBoundingBoxes?: boolean;
@ -166,41 +169,45 @@ export default function ObjectTrackOverlay({
}) || []; }) || [];
// show full path once current time has reached the object's start time // show full path once current time has reached the object's start time
const combinedPoints = [...savedPathPoints, ...eventSequencePoints] // event.start_time is in DETECT stream time, so convert it to record stream time for comparison
.sort((a, b) => a.timestamp - b.timestamp) const eventStartTimeRecord =
.filter( (eventData?.start_time ?? 0) + annotationOffset / 1000;
(point) =>
currentTime >= (eventData?.start_time ?? 0) && const allPoints = [...savedPathPoints, ...eventSequencePoints].sort(
point.timestamp >= (eventData?.start_time ?? 0) && (a, b) => a.timestamp - b.timestamp,
point.timestamp <= (eventData?.end_time ?? Infinity), );
); const combinedPoints = allPoints.filter(
(point) =>
currentTime >= eventStartTimeRecord - TOLERANCE &&
point.timestamp <= effectiveCurrentTime + TOLERANCE,
);
// Get color for this object // Get color for this object
const label = eventData?.label || "unknown"; const label = eventData?.label || "unknown";
const color = getObjectColor(label, objectId); const color = getObjectColor(label, objectId);
// Get current zones // zones (with tolerance for browsers with seek precision by-design issues)
const currentZones = const currentZones =
timelineData timelineData
?.filter( ?.filter(
(event: TrackingDetailsSequence) => (event: TrackingDetailsSequence) =>
event.timestamp <= effectiveCurrentTime, event.timestamp <= effectiveCurrentTime + TOLERANCE,
) )
.sort( .sort(
(a: TrackingDetailsSequence, b: TrackingDetailsSequence) => (a: TrackingDetailsSequence, b: TrackingDetailsSequence) =>
b.timestamp - a.timestamp, b.timestamp - a.timestamp,
)[0]?.data?.zones || []; )[0]?.data?.zones || [];
// Get current bounding box // bounding box (with tolerance for browsers with seek precision by-design issues)
const currentBox = timelineData const boxCandidates = timelineData?.filter(
?.filter( (event: TrackingDetailsSequence) =>
(event: TrackingDetailsSequence) => event.timestamp <= effectiveCurrentTime + TOLERANCE &&
event.timestamp <= effectiveCurrentTime && event.data.box, event.data.box,
) );
.sort( const currentBox = boxCandidates?.sort(
(a: TrackingDetailsSequence, b: TrackingDetailsSequence) => (a: TrackingDetailsSequence, b: TrackingDetailsSequence) =>
b.timestamp - a.timestamp, b.timestamp - a.timestamp,
)[0]?.data?.box; )[0]?.data?.box;
return { return {
objectId, objectId,
@ -221,6 +228,7 @@ export default function ObjectTrackOverlay({
getObjectColor, getObjectColor,
config, config,
camera, camera,
annotationOffset,
]); ]);
// Collect all zones across all objects // Collect all zones across all objects
@ -274,9 +282,10 @@ export default function ObjectTrackOverlay({
const handlePointClick = useCallback( const handlePointClick = useCallback(
(timestamp: number) => { (timestamp: number) => {
onSeekToTime?.(timestamp, false); // Convert detect stream timestamp to record stream timestamp before seeking
onSeekToTime?.(timestamp + annotationOffset / 1000, false);
}, },
[onSeekToTime], [onSeekToTime, annotationOffset],
); );
const zonePolygons = useMemo(() => { const zonePolygons = useMemo(() => {