Init commit
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
"use client"
|
||||
|
||||
interface BandwidthChartProps {
|
||||
rx: number[]
|
||||
tx: number[]
|
||||
}
|
||||
|
||||
export function BandwidthChart({ rx, tx }: BandwidthChartProps) {
|
||||
const W = 600, H = 200
|
||||
const pad = { l: 44, r: 12, t: 12, b: 28 }
|
||||
const iw = W - pad.l - pad.r
|
||||
const ih = H - pad.t - pad.b
|
||||
|
||||
const maxVal = Math.max(...rx, ...tx) * 1.15
|
||||
const xAt = (i: number, n: number) => pad.l + (i / (n - 1)) * iw
|
||||
const yAt = (v: number) => pad.t + (1 - v / maxVal) * ih
|
||||
|
||||
const areaPath = (arr: number[]) => {
|
||||
const top = arr.map((v, i) => `${xAt(i, arr.length).toFixed(1)},${yAt(v).toFixed(1)}`).join(" L ")
|
||||
return `M ${pad.l},${pad.t + ih} L ${top} L ${pad.l + iw},${pad.t + ih} Z`
|
||||
}
|
||||
const linePath = (arr: number[]) =>
|
||||
arr.map((v, i) => `${xAt(i, arr.length).toFixed(1)},${yAt(v).toFixed(1)}`).join(" ")
|
||||
|
||||
return (
|
||||
<div>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: 200, display: "block" }}>
|
||||
<defs>
|
||||
<linearGradient id="rx-grad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" style={{ stopColor: "var(--chart-rx)", stopOpacity: 0.25 }} />
|
||||
<stop offset="100%" style={{ stopColor: "var(--chart-rx)", stopOpacity: 0 }} />
|
||||
</linearGradient>
|
||||
<linearGradient id="tx-grad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" style={{ stopColor: "var(--chart-tx)", stopOpacity: 0.20 }} />
|
||||
<stop offset="100%" style={{ stopColor: "var(--chart-tx)", stopOpacity: 0 }} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
{[0, 0.25, 0.5, 0.75, 1].map((p, i) => (
|
||||
<g key={i}>
|
||||
<line
|
||||
x1={pad.l} x2={W - pad.r}
|
||||
y1={pad.t + ih * p} y2={pad.t + ih * p}
|
||||
style={{ stroke: "var(--border)" }}
|
||||
strokeDasharray={p === 1 ? "0" : "2 4"}
|
||||
/>
|
||||
<text
|
||||
x={pad.l - 8} y={pad.t + ih * p + 4}
|
||||
textAnchor="end" fontSize="10"
|
||||
style={{ fill: "var(--muted-foreground)" }}
|
||||
fontFamily="var(--font-mono, monospace)"
|
||||
>
|
||||
{Math.round(maxVal * (1 - p))}
|
||||
</text>
|
||||
</g>
|
||||
))}
|
||||
|
||||
<path d={areaPath(rx)} fill="url(#rx-grad)" />
|
||||
<polyline points={linePath(rx)} fill="none"
|
||||
style={{ stroke: "var(--chart-rx)" }}
|
||||
strokeWidth="1.6" strokeLinejoin="round" />
|
||||
|
||||
<path d={areaPath(tx)} fill="url(#tx-grad)" />
|
||||
<polyline points={linePath(tx)} fill="none"
|
||||
style={{ stroke: "var(--chart-tx)" }}
|
||||
strokeWidth="1.6" strokeLinejoin="round" />
|
||||
|
||||
{[0, 15, 30, 45, 59].map((i) => (
|
||||
<text
|
||||
key={i} x={xAt(i, 60)} y={H - 6}
|
||||
textAnchor="middle" fontSize="10"
|
||||
style={{ fill: "var(--muted-foreground)" }}
|
||||
fontFamily="var(--font-mono, monospace)"
|
||||
>
|
||||
-{60 - i}м
|
||||
</text>
|
||||
))}
|
||||
</svg>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="flex gap-4 pt-2 pl-11">
|
||||
{[
|
||||
{ key: "rx", label: "RX ↓", color: "var(--chart-rx)" },
|
||||
{ key: "tx", label: "TX ↑", color: "var(--chart-tx)" },
|
||||
].map(({ key, label, color }) => (
|
||||
<div key={key} className="flex items-center gap-1.5 text-xs">
|
||||
<span className="w-3 h-0.5 rounded" style={{ background: color }} />
|
||||
<span className="font-mono text-foreground">{label}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
"use client"
|
||||
|
||||
interface LatencyChartProps {
|
||||
series: Record<string, number[]>
|
||||
}
|
||||
|
||||
// Maps to CSS variables defined in globals.css
|
||||
const COLORS: Record<string, string> = {
|
||||
msk: "var(--chart-line-1)",
|
||||
spb: "var(--chart-line-2)",
|
||||
fra: "var(--chart-line-3)",
|
||||
ams: "var(--chart-line-4)",
|
||||
}
|
||||
|
||||
const LABELS: Record<string, string> = {
|
||||
msk: "MSK",
|
||||
spb: "SPB",
|
||||
fra: "FRA",
|
||||
ams: "AMS",
|
||||
}
|
||||
|
||||
export function LatencyChart({ series }: LatencyChartProps) {
|
||||
const W = 800, H = 220
|
||||
const pad = { l: 44, r: 12, t: 12, b: 28 }
|
||||
const iw = W - pad.l - pad.r
|
||||
const ih = H - pad.t - pad.b
|
||||
|
||||
const allVals = Object.values(series).flat()
|
||||
const maxVal = Math.ceil(Math.max(...allVals) / 20) * 20 + 10
|
||||
|
||||
const xAt = (i: number, n: number) => pad.l + (i / (n - 1)) * iw
|
||||
const yAt = (v: number) => pad.t + (1 - v / maxVal) * ih
|
||||
|
||||
const gridLines = [0, 0.25, 0.5, 0.75, 1]
|
||||
|
||||
return (
|
||||
<div>
|
||||
<svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: 220, display: "block" }}>
|
||||
{gridLines.map((p, i) => (
|
||||
<g key={i}>
|
||||
<line
|
||||
x1={pad.l} x2={W - pad.r}
|
||||
y1={pad.t + ih * p} y2={pad.t + ih * p}
|
||||
style={{ stroke: "var(--border)" }}
|
||||
strokeDasharray={p === 1 ? "0" : "2 4"}
|
||||
/>
|
||||
<text
|
||||
x={pad.l - 8} y={pad.t + ih * p + 4}
|
||||
textAnchor="end" fontSize="10"
|
||||
style={{ fill: "var(--muted-foreground)" }}
|
||||
fontFamily="var(--font-mono, monospace)"
|
||||
>
|
||||
{Math.round(maxVal * (1 - p))}мс
|
||||
</text>
|
||||
</g>
|
||||
))}
|
||||
{[0, 15, 30, 45, 59].map((i) => (
|
||||
<text
|
||||
key={i}
|
||||
x={xAt(i, 60)} y={H - 6}
|
||||
textAnchor="middle" fontSize="10"
|
||||
style={{ fill: "var(--muted-foreground)" }}
|
||||
fontFamily="var(--font-mono, monospace)"
|
||||
>
|
||||
-{60 - i}м
|
||||
</text>
|
||||
))}
|
||||
{Object.entries(series).map(([key, arr]) => {
|
||||
const pts = arr.map((v, i) => `${xAt(i, arr.length).toFixed(1)},${yAt(v).toFixed(1)}`).join(" ")
|
||||
const color = COLORS[key] ?? "var(--chart-line-1)"
|
||||
return (
|
||||
<polyline key={key} points={pts} fill="none"
|
||||
style={{ stroke: color }}
|
||||
strokeWidth="1.6" strokeLinejoin="round" />
|
||||
)
|
||||
})}
|
||||
</svg>
|
||||
<div className="flex gap-4 pt-2 pl-11">
|
||||
{Object.keys(series).map((k) => {
|
||||
const color = COLORS[k] ?? "var(--chart-line-1)"
|
||||
return (
|
||||
<div key={k} className="flex items-center gap-1.5 text-xs">
|
||||
<span className="w-3 h-0.5 rounded" style={{ background: color }} />
|
||||
<span className="font-mono text-foreground">{LABELS[k]}</span>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user