diff --git a/web/src/components/graph/CameraGraph.tsx b/web/src/components/graph/LineGraph.tsx similarity index 59% rename from web/src/components/graph/CameraGraph.tsx rename to web/src/components/graph/LineGraph.tsx index a347c2d37..ef55c9343 100644 --- a/web/src/components/graph/CameraGraph.tsx +++ b/web/src/components/graph/LineGraph.tsx @@ -143,3 +143,118 @@ export function CameraLineGraph({ ); } + +type EventsPerSecondLineGraphProps = { + graphId: string; + unit: string; + name: string; + updateTimes: number[]; + data: ApexAxisChartSeries; +}; +export function EventsPerSecondsLineGraph({ + graphId, + unit, + name, + updateTimes, + data, +}: EventsPerSecondLineGraphProps) { + const { data: config } = useSWR("config", { + revalidateOnFocus: false, + }); + + const { theme, systemTheme } = useTheme(); + + const lastValue = useMemo( + // @ts-expect-error y is valid + () => data[0].data[data[0].data.length - 1]?.y ?? 0, + [data], + ); + + const formatTime = useCallback( + (val: unknown) => { + return formatUnixTimestampToDateTime( + updateTimes[Math.round(val as number) - 1], + { + timezone: config?.ui.timezone, + strftime_fmt: + config?.ui.time_format == "24hour" ? "%H:%M" : "%I:%M %p", + }, + ); + }, + [config, updateTimes], + ); + + const options = useMemo(() => { + return { + chart: { + id: graphId, + selection: { + enabled: false, + }, + toolbar: { + show: false, + }, + zoom: { + enabled: false, + }, + }, + colors: GRAPH_COLORS, + grid: { + show: false, + }, + legend: { + show: false, + }, + dataLabels: { + enabled: false, + }, + stroke: { + width: 1, + }, + tooltip: { + theme: systemTheme || theme, + }, + markers: { + size: 0, + }, + xaxis: { + tickAmount: isMobileOnly ? 2 : 3, + tickPlacement: "on", + labels: { + rotate: 0, + formatter: formatTime, + }, + axisBorder: { + show: false, + }, + axisTicks: { + show: false, + }, + }, + yaxis: { + show: true, + labels: { + formatter: (val: number) => Math.ceil(val).toString(), + }, + min: 0, + }, + } as ApexCharts.ApexOptions; + }, [graphId, systemTheme, theme, formatTime]); + + useEffect(() => { + ApexCharts.exec(graphId, "updateOptions", options, true, true); + }, [graphId, options]); + + return ( +
+
+
{name}
+
+ {lastValue} + {unit} +
+
+ +
+ ); +} diff --git a/web/src/views/system/CameraMetrics.tsx b/web/src/views/system/CameraMetrics.tsx index 497e6f435..b94dc3606 100644 --- a/web/src/views/system/CameraMetrics.tsx +++ b/web/src/views/system/CameraMetrics.tsx @@ -1,5 +1,5 @@ import { useFrigateStats } from "@/api/ws"; -import { CameraLineGraph } from "@/components/graph/CameraGraph"; +import { CameraLineGraph } from "@/components/graph/LineGraph"; import CameraInfoDialog from "@/components/overlay/CameraInfoDialog"; import { Skeleton } from "@/components/ui/skeleton"; import { FrigateConfig } from "@/types/frigateConfig"; diff --git a/web/src/views/system/FeatureMetrics.tsx b/web/src/views/system/FeatureMetrics.tsx index 5ea5b9933..d9688a2c1 100644 --- a/web/src/views/system/FeatureMetrics.tsx +++ b/web/src/views/system/FeatureMetrics.tsx @@ -7,7 +7,10 @@ import { Skeleton } from "@/components/ui/skeleton"; import { ThresholdBarGraph } from "@/components/graph/SystemGraph"; import { cn } from "@/lib/utils"; import { useTranslation } from "react-i18next"; -import { CameraLineGraph } from "@/components/graph/CameraGraph"; +import { + CameraLineGraph, + EventsPerSecondsLineGraph, +} from "@/components/graph/LineGraph"; type FeatureMetricsProps = { lastUpdated: number; @@ -114,11 +117,11 @@ export default function FeatureMetrics({ data={[series]} /> ) : ( -