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 = {
className?: string;
items?: TimelineItem[];
timeBars?: { time: DateType; id?: IdType | undefined }[];
timeBars?: { time: DateType; id: IdType }[];
groups?: TimelineGroup[];
options?: TimelineOptions;
} & TimelineEventsHandlers;
@ -94,6 +94,9 @@ function ActivityScrubber({
timeline: null,
});
const [currentTime, setCurrentTime] = useState(Date.now());
const [customTimes, setCustomTimes] = useState<
{ id: IdType; time: DateType }[]
>([]);
const defaultOptions: TimelineOptions = {
width: "100%",
@ -161,6 +164,41 @@ function ActivityScrubber({
};
}, [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 (
<div className={className || ""}>
<div ref={containerRef} />

View File

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

View File

@ -42,6 +42,11 @@ export default function DesktopTimelineView({
const [seeking, setSeeking] = useState(false);
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(() => {
if (!config) {
@ -54,14 +59,6 @@ export default function DesktopTimelineView({
);
}, [config]);
const timelineTime = useMemo(() => {
if (!selectedPlayback || selectedPlayback.timelineItems.length == 0) {
return selectedPlayback.range.start;
}
return selectedPlayback.timelineItems.at(0)!!.timestamp;
}, [selectedPlayback]);
const recordingParams = useMemo(() => {
return {
before: selectedPlayback.range.end,
@ -121,36 +118,6 @@ export default function DesktopTimelineView({
[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
useEffect(() => {
if (seeking) {
@ -165,15 +132,33 @@ export default function DesktopTimelineView({
// handle loading main playback when selected hour changes
useEffect(() => {
if (!playerRef.current) {
if (!playerRef.current || !previewRef.current) {
return;
}
setTimelineTime(
selectedPlayback.timelineItems.length > 0
? selectedPlayback.timelineItems[0].timestamp
: selectedPlayback.range.start
);
playerRef.current.src({
src: playbackUri,
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(
() =>
@ -181,7 +166,7 @@ export default function DesktopTimelineView({
selectedPlayback.camera,
timelineData,
allPreviews,
timelineTime
selectedPlayback.range.start + 60
),
[]
);
@ -216,9 +201,15 @@ export default function DesktopTimelineView({
seekOptions={{ forward: 10, backward: 5 }}
onReady={(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", () => {
onSelectItem(undefined);
});
@ -285,13 +276,18 @@ export default function DesktopTimelineView({
return (
<div
key={timeline.range.start}
className={`${isSelected ? "border border-primary" : ""}`}
className={`p-1 ${isSelected ? "border border-primary" : ""}`}
>
<ActivityScrubber
items={[]}
timeBars={
isSelected && selectedPlayback.relevantPreview
? [{ time: new Date(timelineTime * 1000), id: "playback" }]
? [
{
time: new Date(timelineTime * 1000),
id: "playback",
},
]
: []
}
options={{
@ -300,8 +296,30 @@ export default function DesktopTimelineView({
max: new Date(timeline.range.end * 1000),
zoomable: false,
}}
timechangeHandler={onScrubTime}
timechangedHandler={onStopScrubbing}
timechangeHandler={(data) => {
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={() => {
setSelectedPlayback(timeline);
}}