Files
sound-analyze/services/frontend/src/widgets/audioLive/ui/FrequencyHistoryChart.tsx

110 lines
2.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// src/widgets/audioLive/ui/FrequencyHistoryChart.tsx
import { memo, useMemo } from "react";
import {
Line,
LineChart,
ResponsiveContainer,
Tooltip,
XAxis,
YAxis,
} from "recharts";
import {
Card,
CardContent,
CardHeader,
CardTitle,
} from "../../../shared/ui/card";
import type { AudioSample } from "../../../entities/audioSample/model/types";
import { formatTimeHHMMSS } from "../../../shared/lib/time";
type Props = {
history?: AudioSample[];
};
type ChartPoint = {
timeMs: number;
freq_hz: number;
};
const Y_MIN = 129;
const Y_MAX = 5500;
const Y_TICKS = [139, 200, 500, 1000, 2000, 5000, 5500];
function formatHzTick(v: number): string {
const n = Number(v);
if (!Number.isFinite(n)) return "";
if (n >= 1000) return `${(n / 1000).toFixed(n % 1000 === 0 ? 0 : 1)}k`;
return `${Math.round(n)}`;
}
export const FrequencyHistoryChart = memo(function FrequencyHistoryChart({
history = [],
}: Props) {
const data: ChartPoint[] = useMemo(() => {
if (!history?.length) return [];
return history.map((s) => ({ timeMs: s.timeMs, freq_hz: s.freq_hz }));
}, [history]);
const hasData = data.length > 0;
return (
<Card>
<CardHeader className="pb-2">
<CardTitle className="text-base">Доминантная частота</CardTitle>
</CardHeader>
<CardContent>
<div className="relative h-56 min-h-[14rem] w-full">
{!hasData && (
<div className="absolute inset-0 grid place-items-center text-sm text-muted-foreground">
Пока нет данных
</div>
)}
<ResponsiveContainer width="100%" height="100%">
<LineChart
data={data}
margin={{ top: 10, right: 12, left: 0, bottom: 0 }}
>
<XAxis
dataKey="timeMs"
type="number"
domain={["dataMin", "dataMax"]}
tickFormatter={(v) => formatTimeHHMMSS(Number(v))}
tick={{ fontSize: 12 }}
interval="preserveStartEnd"
/>
<YAxis
type="number"
scale="log"
domain={[Y_MIN, Y_MAX]}
ticks={Y_TICKS}
allowDataOverflow
tick={{ fontSize: 12 }}
width={52}
tickFormatter={(v) => formatHzTick(Number(v))}
/>
<Tooltip
labelFormatter={(v) => formatTimeHHMMSS(Number(v))}
formatter={(v) => [`${Number(v).toFixed(0)} Гц`, "част."]}
/>
<Line
type="monotone"
dataKey="freq_hz"
stroke="oklch(0.208 0.042 265.755)"
strokeWidth={2}
dot={false}
isAnimationActive={false}
/>
</LineChart>
</ResponsiveContainer>
</div>
</CardContent>
</Card>
);
});