mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-04-11 09:37:37 +03:00
improve annotation offset popver
This commit is contained in:
parent
6a011df427
commit
57f328e9e5
@ -74,7 +74,7 @@
|
|||||||
"label": "Annotation Offset",
|
"label": "Annotation Offset",
|
||||||
"desc": "This data comes from your camera's detect feed but is overlayed on images from the the record feed. It is unlikely that the two streams are perfectly in sync. As a result, the bounding box and the footage will not line up perfectly. You can use this setting to offset the annotations forward or backward in time to better align them with the recorded footage.",
|
"desc": "This data comes from your camera's detect feed but is overlayed on images from the the record feed. It is unlikely that the two streams are perfectly in sync. As a result, the bounding box and the footage will not line up perfectly. You can use this setting to offset the annotations forward or backward in time to better align them with the recorded footage.",
|
||||||
"millisecondsToOffset": "Milliseconds to offset detect annotations by. <em>Default: 0</em>",
|
"millisecondsToOffset": "Milliseconds to offset detect annotations by. <em>Default: 0</em>",
|
||||||
"tips": "TIP: Imagine there is an event clip with a person walking from left to right. If the event timeline bounding box is consistently to the left of the person then the value should be decreased. Similarly, if a person is walking from left to right and the bounding box is consistently ahead of the person then the value should be increased.",
|
"tips": "Lower the value if the video playback is ahead of the boxes and path points, and increase the value if the video playback is behind them. This value can be negative.",
|
||||||
"toast": {
|
"toast": {
|
||||||
"success": "Annotation offset for {{camera}} has been saved to the config file. Restart Frigate to apply your changes."
|
"success": "Annotation offset for {{camera}} has been saved to the config file. Restart Frigate to apply your changes."
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
import Heading from "@/components/ui/heading";
|
import Heading from "@/components/ui/heading";
|
||||||
import { Label } from "@/components/ui/label";
|
|
||||||
import { Switch } from "@/components/ui/switch";
|
|
||||||
import { Event } from "@/types/event";
|
import { Event } from "@/types/event";
|
||||||
import { FrigateConfig } from "@/types/frigateConfig";
|
import { FrigateConfig } from "@/types/frigateConfig";
|
||||||
import { zodResolver } from "@hookform/resolvers/zod";
|
import { zodResolver } from "@hookform/resolvers/zod";
|
||||||
@ -8,7 +6,6 @@ import axios from "axios";
|
|||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
import { LuExternalLink } from "react-icons/lu";
|
import { LuExternalLink } from "react-icons/lu";
|
||||||
import { PiWarningCircle } from "react-icons/pi";
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import useSWR from "swr";
|
import useSWR from "swr";
|
||||||
@ -31,15 +28,11 @@ import { useDocDomain } from "@/hooks/use-doc-domain";
|
|||||||
|
|
||||||
type AnnotationSettingsPaneProps = {
|
type AnnotationSettingsPaneProps = {
|
||||||
event: Event;
|
event: Event;
|
||||||
showZones: boolean;
|
|
||||||
setShowZones: React.Dispatch<React.SetStateAction<boolean>>;
|
|
||||||
annotationOffset: number;
|
annotationOffset: number;
|
||||||
setAnnotationOffset: React.Dispatch<React.SetStateAction<number>>;
|
setAnnotationOffset: React.Dispatch<React.SetStateAction<number>>;
|
||||||
};
|
};
|
||||||
export function AnnotationSettingsPane({
|
export function AnnotationSettingsPane({
|
||||||
event,
|
event,
|
||||||
showZones,
|
|
||||||
setShowZones,
|
|
||||||
annotationOffset,
|
annotationOffset,
|
||||||
setAnnotationOffset,
|
setAnnotationOffset,
|
||||||
}: AnnotationSettingsPaneProps) {
|
}: AnnotationSettingsPaneProps) {
|
||||||
@ -144,21 +137,7 @@ export function AnnotationSettingsPane({
|
|||||||
<Heading as="h4" className="my-2">
|
<Heading as="h4" className="my-2">
|
||||||
{t("trackingDetails.annotationSettings.title")}
|
{t("trackingDetails.annotationSettings.title")}
|
||||||
</Heading>
|
</Heading>
|
||||||
<div className="flex flex-col">
|
|
||||||
<div className="flex flex-row items-center justify-start gap-2 p-3">
|
|
||||||
<Switch
|
|
||||||
id="show-zones"
|
|
||||||
checked={showZones}
|
|
||||||
onCheckedChange={setShowZones}
|
|
||||||
/>
|
|
||||||
<Label className="cursor-pointer" htmlFor="show-zones">
|
|
||||||
{t("trackingDetails.annotationSettings.showAllZones.title")}
|
|
||||||
</Label>
|
|
||||||
</div>
|
|
||||||
<div className="text-sm text-muted-foreground">
|
|
||||||
{t("trackingDetails.annotationSettings.showAllZones.desc")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<Separator className="my-2 flex bg-secondary" />
|
<Separator className="my-2 flex bg-secondary" />
|
||||||
<Form {...form}>
|
<Form {...form}>
|
||||||
<form
|
<form
|
||||||
@ -169,17 +148,17 @@ export function AnnotationSettingsPane({
|
|||||||
control={form.control}
|
control={form.control}
|
||||||
name="annotationOffset"
|
name="annotationOffset"
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<FormItem>
|
<FormItem className="flex flex-row items-start justify-between space-x-2">
|
||||||
<FormLabel>
|
<div className="flex flex-col gap-1">
|
||||||
{t("trackingDetails.annotationSettings.offset.label")}
|
<FormLabel>
|
||||||
</FormLabel>
|
{t("trackingDetails.annotationSettings.offset.label")}
|
||||||
<div className="flex flex-col gap-3 md:flex-row-reverse md:gap-8">
|
</FormLabel>
|
||||||
<div className="flex flex-row items-center gap-3 rounded-lg bg-destructive/50 p-3 text-sm text-primary-variant md:my-5">
|
<FormDescription>
|
||||||
<PiWarningCircle className="size-24" />
|
<Trans ns="views/explore">
|
||||||
<div>
|
trackingDetails.annotationSettings.offset.millisecondsToOffset
|
||||||
<Trans ns="views/explore">
|
</Trans>
|
||||||
trackingDetails.annotationSettings.offset.desc
|
<div className="mt-2">
|
||||||
</Trans>
|
{t("trackingDetails.annotationSettings.offset.tips")}
|
||||||
<div className="mt-2 flex items-center text-primary">
|
<div className="mt-2 flex items-center text-primary">
|
||||||
<Link
|
<Link
|
||||||
to={getLocaleDocUrl("configuration/reference")}
|
to={getLocaleDocUrl("configuration/reference")}
|
||||||
@ -192,23 +171,26 @@ export function AnnotationSettingsPane({
|
|||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</FormDescription>
|
||||||
<div className="flex flex-col">
|
</div>
|
||||||
|
<div className="flex flex-col gap-3">
|
||||||
|
{/* <div className="flex flex-row items-center gap-3 rounded-lg bg-destructive/50 p-3 text-sm text-primary-variant md:my-5">
|
||||||
|
<PiWarningCircle className="size-24" />
|
||||||
|
<div>
|
||||||
|
<Trans ns="views/explore">
|
||||||
|
trackingDetails.annotationSettings.offset.desc
|
||||||
|
</Trans>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
<div className="min-w-24">
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Input
|
<Input
|
||||||
className="text-md w-full border border-input bg-background p-2 hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
className="text-md w-full border border-input bg-background p-2 text-center hover:bg-accent hover:text-accent-foreground dark:[color-scheme:dark]"
|
||||||
placeholder="0"
|
placeholder="0"
|
||||||
{...field}
|
{...field}
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
<FormDescription>
|
|
||||||
<Trans ns="views/explore">
|
|
||||||
trackingDetails.annotationSettings.offset.millisecondsToOffset
|
|
||||||
</Trans>
|
|
||||||
<div className="mt-2">
|
|
||||||
{t("trackingDetails.annotationSettings.offset.tips")}
|
|
||||||
</div>
|
|
||||||
</FormDescription>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<FormMessage />
|
<FormMessage />
|
||||||
|
|||||||
@ -33,7 +33,6 @@ import {
|
|||||||
} from "react-icons/fa";
|
} from "react-icons/fa";
|
||||||
import { TrackingDetails } from "./TrackingDetails";
|
import { TrackingDetails } from "./TrackingDetails";
|
||||||
import { AnnotationSettingsPane } from "./AnnotationSettingsPane";
|
import { AnnotationSettingsPane } from "./AnnotationSettingsPane";
|
||||||
import { LuSettings } from "react-icons/lu";
|
|
||||||
import { DetailStreamProvider } from "@/context/detail-stream-context";
|
import { DetailStreamProvider } from "@/context/detail-stream-context";
|
||||||
import {
|
import {
|
||||||
MobilePage,
|
MobilePage,
|
||||||
@ -76,6 +75,7 @@ import { getTranslatedLabel } from "@/utils/i18n";
|
|||||||
import { CameraNameLabel } from "@/components/camera/CameraNameLabel";
|
import { CameraNameLabel } from "@/components/camera/CameraNameLabel";
|
||||||
import { DialogPortal } from "@radix-ui/react-dialog";
|
import { DialogPortal } from "@radix-ui/react-dialog";
|
||||||
import { useDetailStream } from "@/context/detail-stream-context";
|
import { useDetailStream } from "@/context/detail-stream-context";
|
||||||
|
import { PiSlidersHorizontalBold } from "react-icons/pi";
|
||||||
|
|
||||||
const SEARCH_TABS = ["snapshot", "tracking_details"] as const;
|
const SEARCH_TABS = ["snapshot", "tracking_details"] as const;
|
||||||
export type SearchTab = (typeof SEARCH_TABS)[number];
|
export type SearchTab = (typeof SEARCH_TABS)[number];
|
||||||
@ -108,7 +108,7 @@ function TabsWithActions({
|
|||||||
if (!search) return null;
|
if (!search) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-between gap-2">
|
<div className="flex items-center justify-between gap-1">
|
||||||
<ScrollArea className="flex-1 whitespace-nowrap">
|
<ScrollArea className="flex-1 whitespace-nowrap">
|
||||||
<div className="mb-2 flex flex-row md:mb-0">
|
<div className="mb-2 flex flex-row md:mb-0">
|
||||||
<ToggleGroup
|
<ToggleGroup
|
||||||
@ -173,7 +173,6 @@ function AnnotationSettingsPopover({
|
|||||||
}: AnnotationSettingsPopoverProps) {
|
}: AnnotationSettingsPopoverProps) {
|
||||||
const { t } = useTranslation(["views/explore"]);
|
const { t } = useTranslation(["views/explore"]);
|
||||||
const { annotationOffset, setAnnotationOffset } = useDetailStream();
|
const { annotationOffset, setAnnotationOffset } = useDetailStream();
|
||||||
const [showZones, setShowZones] = useState(true);
|
|
||||||
|
|
||||||
const ignoreNextOpenRef = useRef(false);
|
const ignoreNextOpenRef = useRef(false);
|
||||||
|
|
||||||
@ -218,18 +217,16 @@ function AnnotationSettingsPopover({
|
|||||||
<Button
|
<Button
|
||||||
type="button"
|
type="button"
|
||||||
className="size-7 p-1.5"
|
className="size-7 p-1.5"
|
||||||
variant={open ? "select" : "default"}
|
variant={open ? "select" : "ghost"}
|
||||||
aria-label={t("trackingDetails.adjustAnnotationSettings")}
|
aria-label={t("trackingDetails.adjustAnnotationSettings")}
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
>
|
>
|
||||||
<LuSettings className="size-5" />
|
<PiSlidersHorizontalBold className="size-5" />
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="w-[90vw] max-w-2xl p-0" align="end">
|
<PopoverContent className="w-[90vw] max-w-md p-0" align="end">
|
||||||
<AnnotationSettingsPane
|
<AnnotationSettingsPane
|
||||||
event={search as unknown as Event}
|
event={search as unknown as Event}
|
||||||
showZones={showZones}
|
|
||||||
setShowZones={setShowZones}
|
|
||||||
annotationOffset={annotationOffset}
|
annotationOffset={annotationOffset}
|
||||||
setAnnotationOffset={(value) => {
|
setAnnotationOffset={(value) => {
|
||||||
if (typeof value === "function") {
|
if (typeof value === "function") {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user