Use intersection observer for timeline segments

This commit is contained in:
Josh Hawkins 2024-06-19 17:10:46 -05:00
parent e9cdef9f25
commit 753d05189a

View File

@ -8,6 +8,7 @@ import React, {
useEffect, useEffect,
useMemo, useMemo,
useRef, useRef,
useState,
} from "react"; } from "react";
import { import {
HoverCard, HoverCard,
@ -195,71 +196,100 @@ export function EventSegment({
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [startTimestamp]); }, [startTimestamp]);
const [segmentVisible, setSegmentVisible] = useState(false);
const segmentObserverRef = useRef<IntersectionObserver | null>(null);
const segmentRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const segmentObserver = new IntersectionObserver(
([entry]) => {
setSegmentVisible(entry.isIntersecting);
},
{ threshold: 0 },
);
if (segmentRef.current) {
segmentObserver.observe(segmentRef.current);
}
segmentObserverRef.current = segmentObserver;
return () => {
if (segmentObserverRef.current) {
segmentObserverRef.current.disconnect();
}
};
}, []);
return ( return (
<div <div
key={segmentKey} key={segmentKey}
ref={segmentRef}
data-segment-id={segmentKey} data-segment-id={segmentKey}
className={`segment ${segmentClasses}`} className={`segment ${segmentClasses}`}
onClick={segmentClick} onClick={segmentClick}
onTouchEnd={(event) => handleTouchStart(event, segmentClick)} onTouchEnd={(event) => handleTouchStart(event, segmentClick)}
> >
{showMinimap && ( {segmentVisible && (
<MinimapBounds <>
isFirstSegmentInMinimap={isFirstSegmentInMinimap} {showMinimap && (
isLastSegmentInMinimap={isLastSegmentInMinimap} <MinimapBounds
alignedMinimapStartTime={alignedMinimapStartTime} isFirstSegmentInMinimap={isFirstSegmentInMinimap}
alignedMinimapEndTime={alignedMinimapEndTime} isLastSegmentInMinimap={isLastSegmentInMinimap}
firstMinimapSegmentRef={firstMinimapSegmentRef} alignedMinimapStartTime={alignedMinimapStartTime}
dense={dense} alignedMinimapEndTime={alignedMinimapEndTime}
/> firstMinimapSegmentRef={firstMinimapSegmentRef}
)} dense={dense}
/>
)}
<Tick timestamp={timestamp} timestampSpread={timestampSpread} /> <Tick timestamp={timestamp} timestampSpread={timestampSpread} />
<Timestamp <Timestamp
isFirstSegmentInMinimap={isFirstSegmentInMinimap} isFirstSegmentInMinimap={isFirstSegmentInMinimap}
isLastSegmentInMinimap={isLastSegmentInMinimap} isLastSegmentInMinimap={isLastSegmentInMinimap}
timestamp={timestamp} timestamp={timestamp}
timestampSpread={timestampSpread} timestampSpread={timestampSpread}
segmentKey={segmentKey} segmentKey={segmentKey}
/> />
{severity.map((severityValue: number, index: number) => ( {severity.map((severityValue: number, index: number) => (
<React.Fragment key={index}> <React.Fragment key={index}>
{severityValue === displaySeverityType && ( {severityValue === displaySeverityType && (
<HoverCard openDelay={200} closeDelay={100}> <HoverCard openDelay={200} closeDelay={100}>
<HoverCardTrigger asChild> <HoverCardTrigger asChild>
<div className="absolute left-1/2 z-10 h-[8px] w-[20px] -translate-x-1/2 transform cursor-pointer md:w-[40px]"> <div className="absolute left-1/2 z-10 h-[8px] w-[20px] -translate-x-1/2 transform cursor-pointer md:w-[40px]">
<div className="flex w-[20px] flex-row justify-center md:w-[40px]"> <div className="flex w-[20px] flex-row justify-center md:w-[40px]">
<div className="flex justify-center"> <div className="flex justify-center">
<div <div
className="absolute left-1/2 z-10 ml-[2px] h-[8px] w-[8px] -translate-x-1/2 transform cursor-pointer" className="absolute left-1/2 z-10 ml-[2px] h-[8px] w-[8px] -translate-x-1/2 transform cursor-pointer"
data-severity={severityValue} data-severity={severityValue}
> >
<div <div
key={`${segmentKey}_${index}_primary_data`} key={`${segmentKey}_${index}_primary_data`}
className={`h-[8px] w-full bg-gradient-to-r ${roundBottomPrimary ? "rounded-bl-full rounded-br-full" : ""} ${roundTopPrimary ? "rounded-tl-full rounded-tr-full" : ""} ${severityColors[severityValue]}`} className={`h-[8px] w-full bg-gradient-to-r ${roundBottomPrimary ? "rounded-bl-full rounded-br-full" : ""} ${roundTopPrimary ? "rounded-tl-full rounded-tr-full" : ""} ${severityColors[severityValue]}`}
></div> ></div>
</div>
</div>
</div> </div>
</div> </div>
</div> </HoverCardTrigger>
</div> <HoverCardPortal>
</HoverCardTrigger> <HoverCardContent
<HoverCardPortal> className="w-[250px] rounded-lg p-2 md:rounded-2xl"
<HoverCardContent side="left"
className="w-[250px] rounded-lg p-2 md:rounded-2xl" >
side="left" <img
> className="rounded-lg"
<img src={`${apiHost}${eventThumbnail.replace("/media/frigate/", "")}`}
className="rounded-lg" />
src={`${apiHost}${eventThumbnail.replace("/media/frigate/", "")}`} </HoverCardContent>
/> </HoverCardPortal>
</HoverCardContent> </HoverCard>
</HoverCardPortal> )}
</HoverCard> </React.Fragment>
)} ))}
</React.Fragment> </>
))} )}
</div> </div>
); );
} }