Optimizations and improvements

This commit is contained in:
Nick Mowen 2023-12-31 14:45:59 -07:00
parent d1b1c67062
commit 88820613ce
3 changed files with 117 additions and 54 deletions

View File

@ -76,7 +76,7 @@ const domEvents: TimelineEventsWithMissing[] = [
type ActivityScrubberProps = { type ActivityScrubberProps = {
className?: string; className?: string;
items?: TimelineItem[]; items?: TimelineItem[];
timeBars?: { time: DateType; id?: IdType | undefined }[]; timeBars?: { time: DateType; id: IdType }[];
groups?: TimelineGroup[]; groups?: TimelineGroup[];
options?: TimelineOptions; options?: TimelineOptions;
} & TimelineEventsHandlers; } & TimelineEventsHandlers;
@ -94,6 +94,9 @@ function ActivityScrubber({
timeline: null, timeline: null,
}); });
const [currentTime, setCurrentTime] = useState(Date.now()); const [currentTime, setCurrentTime] = useState(Date.now());
const [customTimes, setCustomTimes] = useState<
{ id: IdType; time: DateType }[]
>([]);
const defaultOptions: TimelineOptions = { const defaultOptions: TimelineOptions = {
width: "100%", width: "100%",
@ -161,6 +164,41 @@ function ActivityScrubber({
}; };
}, [containerRef]); }, [containerRef]);
// need to keep custom times in sync
useEffect(() => {
if (!timelineRef.current.timeline || timeBars == undefined) {
return;
}
setCustomTimes((prevTimes) => {
if (prevTimes.length == 0 && timeBars.length == 0) {
return [];
}
prevTimes
.filter((x) => timeBars.find((y) => x.id == y.id) == undefined)
.forEach((time) => {
try {
timelineRef.current.timeline?.removeCustomTime(time.id);
} catch {}
});
timeBars.forEach((time) => {
try {
const existing = timelineRef.current.timeline?.getCustomTime(time.id);
if (existing != time.time) {
timelineRef.current.timeline?.setCustomTime(time.time, time.id);
}
} catch {
timelineRef.current.timeline?.addCustomTime(time.time, time.id);
}
});
return timeBars;
});
}, [timeBars, timelineRef]);
return ( return (
<div className={className || ""}> <div className={className || ""}>
<div ref={containerRef} /> <div ref={containerRef} />

View File

@ -111,10 +111,20 @@ export function getTimelineHoursForDay(
const now = new Date(); const now = new Date();
const data: TimelinePlayback[] = []; const data: TimelinePlayback[] = [];
const startDay = new Date(timestamp * 1000); const startDay = new Date(timestamp * 1000);
startDay.setHours(23, 59, 59, 999);
const dayEnd = startDay.getTime() / 1000;
startDay.setHours(0, 0, 0, 0); startDay.setHours(0, 0, 0, 0);
let start = startDay.getTime() / 1000; let start = startDay.getTime() / 1000;
let end = 0; let end = 0;
const relevantPreviews = allPreviews.filter((preview) => {
return (
preview.camera == camera &&
preview.start >= start &&
Math.floor(preview.end - 1) <= dayEnd
);
});
const dayIdx = Object.keys(cards).find((day) => { const dayIdx = Object.keys(cards).find((day) => {
if (parseInt(day) > start) { if (parseInt(day) > start) {
return false; return false;
@ -156,12 +166,9 @@ export function getTimelineHoursForDay(
return []; return [];
}) })
: []; : [];
const previewCheck = start + 30; // preview can start after the hour const relevantPreview = relevantPreviews.find(
const relevantPreview = Object.values(allPreviews || []).find(
(preview) => (preview) =>
preview.camera == camera && Math.round(preview.start) >= start && Math.floor(preview.end) <= end
preview.start < previewCheck &&
preview.end > previewCheck
); );
data.push({ data.push({
camera, camera,

View File

@ -42,6 +42,11 @@ export default function DesktopTimelineView({
const [seeking, setSeeking] = useState(false); const [seeking, setSeeking] = useState(false);
const [timeToSeek, setTimeToSeek] = useState<number | undefined>(undefined); const [timeToSeek, setTimeToSeek] = useState<number | undefined>(undefined);
const [timelineTime, setTimelineTime] = useState(
initialPlayback.timelineItems.length > 0
? initialPlayback.timelineItems[0].timestamp
: initialPlayback.range.start
);
const annotationOffset = useMemo(() => { const annotationOffset = useMemo(() => {
if (!config) { if (!config) {
@ -54,14 +59,6 @@ export default function DesktopTimelineView({
); );
}, [config]); }, [config]);
const timelineTime = useMemo(() => {
if (!selectedPlayback || selectedPlayback.timelineItems.length == 0) {
return selectedPlayback.range.start;
}
return selectedPlayback.timelineItems.at(0)!!.timestamp;
}, [selectedPlayback]);
const recordingParams = useMemo(() => { const recordingParams = useMemo(() => {
return { return {
before: selectedPlayback.range.end, before: selectedPlayback.range.end,
@ -121,36 +118,6 @@ export default function DesktopTimelineView({
[annotationOffset, recordings, playerRef] [annotationOffset, recordings, playerRef]
); );
const onScrubTime = useCallback(
(data: { time: Date }) => {
if (!selectedPlayback.relevantPreview) {
return;
}
if (playerRef.current?.paused() == false) {
setScrubbing(true);
playerRef.current?.pause();
}
const seekTimestamp = data.time.getTime() / 1000;
const seekTime = seekTimestamp - selectedPlayback.relevantPreview.start;
setTimeToSeek(Math.round(seekTime));
},
[scrubbing, playerRef, selectedPlayback]
);
const onStopScrubbing = useCallback(
(data: { time: Date }) => {
const playbackTime = data.time.getTime() / 1000;
playerRef.current?.currentTime(
playbackTime - selectedPlayback.range.start
);
setScrubbing(false);
playerRef.current?.play();
},
[selectedPlayback, playerRef]
);
// handle seeking to next frame when seek is finished // handle seeking to next frame when seek is finished
useEffect(() => { useEffect(() => {
if (seeking) { if (seeking) {
@ -165,15 +132,33 @@ export default function DesktopTimelineView({
// handle loading main playback when selected hour changes // handle loading main playback when selected hour changes
useEffect(() => { useEffect(() => {
if (!playerRef.current) { if (!playerRef.current || !previewRef.current) {
return; return;
} }
setTimelineTime(
selectedPlayback.timelineItems.length > 0
? selectedPlayback.timelineItems[0].timestamp
: selectedPlayback.range.start
);
playerRef.current.src({ playerRef.current.src({
src: playbackUri, src: playbackUri,
type: "application/vnd.apple.mpegurl", type: "application/vnd.apple.mpegurl",
}); });
}, [playerRef, selectedPlayback]);
if (selectedPlayback.relevantPreview) {
console.log(
`found relevant preview with start ${new Date(
selectedPlayback.relevantPreview.start * 1000
)} for ${new Date(selectedPlayback.range.start * 1000)}`
);
previewRef.current.src({
src: selectedPlayback.relevantPreview.src,
type: selectedPlayback.relevantPreview.type,
});
}
}, [playerRef, previewRef, selectedPlayback]);
const timelineStack = useMemo( const timelineStack = useMemo(
() => () =>
@ -181,7 +166,7 @@ export default function DesktopTimelineView({
selectedPlayback.camera, selectedPlayback.camera,
timelineData, timelineData,
allPreviews, allPreviews,
timelineTime selectedPlayback.range.start + 60
), ),
[] []
); );
@ -216,9 +201,15 @@ export default function DesktopTimelineView({
seekOptions={{ forward: 10, backward: 5 }} seekOptions={{ forward: 10, backward: 5 }}
onReady={(player) => { onReady={(player) => {
playerRef.current = player; playerRef.current = player;
player.currentTime(
timelineTime - selectedPlayback.range.start if (selectedPlayback.timelineItems.length > 0) {
); player.currentTime(
selectedPlayback.timelineItems[0].timestamp -
selectedPlayback.range.start
);
} else {
player.currentTime(0);
}
player.on("playing", () => { player.on("playing", () => {
onSelectItem(undefined); onSelectItem(undefined);
}); });
@ -285,13 +276,18 @@ export default function DesktopTimelineView({
return ( return (
<div <div
key={timeline.range.start} key={timeline.range.start}
className={`${isSelected ? "border border-primary" : ""}`} className={`p-1 ${isSelected ? "border border-primary" : ""}`}
> >
<ActivityScrubber <ActivityScrubber
items={[]} items={[]}
timeBars={ timeBars={
isSelected && selectedPlayback.relevantPreview isSelected && selectedPlayback.relevantPreview
? [{ time: new Date(timelineTime * 1000), id: "playback" }] ? [
{
time: new Date(timelineTime * 1000),
id: "playback",
},
]
: [] : []
} }
options={{ options={{
@ -300,8 +296,30 @@ export default function DesktopTimelineView({
max: new Date(timeline.range.end * 1000), max: new Date(timeline.range.end * 1000),
zoomable: false, zoomable: false,
}} }}
timechangeHandler={onScrubTime} timechangeHandler={(data) => {
timechangedHandler={onStopScrubbing} if (!timeline.relevantPreview) {
return;
}
if (playerRef.current?.paused() == false) {
setScrubbing(true);
playerRef.current?.pause();
}
const seekTimestamp = data.time.getTime() / 1000;
const seekTime =
seekTimestamp - timeline.relevantPreview.start;
setTimelineTime(seekTimestamp);
setTimeToSeek(Math.round(seekTime));
}}
timechangedHandler={(data) => {
const playbackTime = data.time.getTime() / 1000;
playerRef.current?.currentTime(
playbackTime - timeline.range.start
);
setScrubbing(false);
playerRef.current?.play();
}}
doubleClickHandler={() => { doubleClickHandler={() => {
setSelectedPlayback(timeline); setSelectedPlayback(timeline);
}} }}