Files
MikrotikManager/components/reui-kit/traffic-mini-chart.tsx
T

38 lines
2.0 KiB
TypeScript

import { Fragment } from "react"
/** Compact RX/TX history shared by traffic cards. Gaps remain gaps. */
export function TrafficMiniChart({ rx, tx, height = 44 }: { rx: (number|null)[]; tx: (number|null)[]; height?: number }) {
const valid = (value: number|null): value is number => value !== null && Number.isFinite(value) && value >= 0
const values = [...rx, ...tx].filter(valid)
if (!values.length) return <p className="text-xs text-muted-foreground">Нет истории трафика</p>
const width = 300
const count = Math.max(rx.length, tx.length)
const max = Math.max(...values, 1) * 1.1
const segments = (series: (number|null)[]) => {
const result: Array<Array<{ x: number; y: number }>> = []
let current: Array<{ x: number; y: number }> = []
series.forEach((value, index) => {
if (!valid(value)) { current = []; return }
if (!current.length) result.push(current)
current.push({ x: count <= 1 ? width / 2 : index / (count - 1) * width, y: height - value / max * height })
})
return result
}
return (
<svg role="img" aria-label="Мини-график истории RX/TX" viewBox={`0 0 ${width} ${height}`} style={{ width: "100%", height, display: "block" }} preserveAspectRatio="none">
{([[rx, "var(--chart-rx)"], [tx, "var(--chart-tx)"]] as const).map(([series, color], direction) => (
<g key={color} data-direction={direction === 0 ? "rx" : "tx"}>
{segments(series).map((points, index) => {
if (points.length === 1) return <circle key={index} cx={points[0].x} cy={points[0].y} r="1.5" fill={color} />
const line = points.map(p => `${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(" ")
return <Fragment key={index}>
<path d={`M ${points[0].x},${height} L ${line} L ${points[points.length - 1].x},${height} Z`} fill={color} fillOpacity={0.12} />
<polyline points={line} fill="none" stroke={color} strokeWidth="1.4" strokeLinejoin="round" />
</Fragment>
})}
</g>
))}
</svg>
)
}