Files
frigate/web/src/components/overlay/TimelineDataOverlay.tsx
Nicolas Mowen af3f6dadcb Improve graph using pandas (#9234)
* Ensure viewport is always full screen

* Protect against hour with no cards and ensure data is consistent

* Reduce grouped up image refreshes

* Include current hour and fix scrubbing bugginess

* Scroll initially selected timeline in to view

* Expand timelne class type

* Use poster image for preview on video player instead of using separate image view

* Fix available streaming modes

* Incrase timing for grouping timline items

* Fix audio activity listener

* Fix player not switching views correctly

* Use player time to convert to timeline time

* Update sub labels for previous timeline items

* Show mini timeline bar for non selected items

* Rewrite desktop timeline to use separate dynamic video player component

* Extend improvements to mobile as well

* Improve time formatting

* Fix scroll

* Fix no preview case

* Mobile fixes

* Audio toggle fixes

* More fixes for mobile

* Improve scaling of graph motion activity

* Add keyboard shortcut hook and support shortcuts for playback page

* Fix sizing of dialog

* Improve height scaling of dialog

* simplify and fix layout system for timeline

* Fix timeilne items not working

* Implement basic Frigate+ submitting from timeline
2024-01-31 12:56:11 +00:00

101 lines
2.6 KiB
TypeScript

import { useState } from "react";
type TimelineEventOverlayProps = {
timeline: Timeline;
cameraConfig: {
detect: {
width: number;
height: number;
};
};
};
export default function TimelineEventOverlay({
timeline,
cameraConfig,
}: TimelineEventOverlayProps) {
if (!timeline.data.box) {
return null;
}
const boxLeftEdge = Math.round(timeline.data.box[0] * 100);
const boxTopEdge = Math.round(timeline.data.box[1] * 100);
const boxRightEdge = Math.round(
(1 - timeline.data.box[2] - timeline.data.box[0]) * 100
);
const boxBottomEdge = Math.round(
(1 - timeline.data.box[3] - timeline.data.box[1]) * 100
);
const [isHovering, setIsHovering] = useState<boolean>(false);
const getHoverStyle = () => {
if (!timeline.data.box) {
return {};
}
if (boxLeftEdge < 15) {
// show object stats on right side
return {
left: `${boxLeftEdge + timeline.data.box[2] * 100 + 1}%`,
top: `${boxTopEdge}%`,
};
}
return {
right: `${boxRightEdge + timeline.data.box[2] * 100 + 1}%`,
top: `${boxTopEdge}%`,
};
};
const getObjectArea = () => {
if (!timeline.data.box) {
return 0;
}
const width = timeline.data.box[2] * cameraConfig.detect.width;
const height = timeline.data.box[3] * cameraConfig.detect.height;
return Math.round(width * height);
};
const getObjectRatio = () => {
if (!timeline.data.box) {
return 0.0;
}
const width = timeline.data.box[2] * cameraConfig.detect.width;
const height = timeline.data.box[3] * cameraConfig.detect.height;
return Math.round(100 * (width / height)) / 100;
};
return (
<>
<div
className="absolute border-4 border-red-600"
onMouseEnter={() => setIsHovering(true)}
onMouseLeave={() => setIsHovering(false)}
onTouchStart={() => setIsHovering(true)}
onTouchEnd={() => setIsHovering(false)}
style={{
left: `${boxLeftEdge}%`,
top: `${boxTopEdge}%`,
right: `${boxRightEdge}%`,
bottom: `${boxBottomEdge}%`,
}}
>
{timeline.class_type == "entered_zone" ? (
<div className="absolute w-2 h-2 bg-yellow-500 left-[50%] -translate-x-1/2 translate-y-3/4 bottom-0" />
) : null}
</div>
{isHovering && (
<div
className="absolute bg-white dark:bg-slate-800 p-4 block text-black dark:text-white text-lg"
style={getHoverStyle()}
>
<div>{`Area: ${getObjectArea()} px`}</div>
<div>{`Ratio: ${getObjectRatio()}`}</div>
</div>
)}
</>
);
}