69 lines
2.0 KiB
TypeScript
69 lines
2.0 KiB
TypeScript
import React from "react";
|
|
|
|
interface TelemetryGaugeProps {
|
|
label: string;
|
|
value: number;
|
|
unit: string;
|
|
maxValue: number;
|
|
}
|
|
|
|
export function TelemetryGauge({
|
|
label,
|
|
value,
|
|
unit,
|
|
maxValue,
|
|
}: TelemetryGaugeProps) {
|
|
const radius = 32;
|
|
const stroke = 3;
|
|
const normalizedRadius = radius - stroke * 2;
|
|
const circumference = normalizedRadius * 2 * Math.PI;
|
|
const fillRatio = Math.min(Math.max(value / maxValue, 0), 1);
|
|
const strokeDashoffset = circumference - fillRatio * circumference;
|
|
|
|
return (
|
|
<div className="flex flex-col items-center justify-center relative w-20">
|
|
<div className="relative w-16 h-16">
|
|
<svg
|
|
height="100%"
|
|
width="100%"
|
|
className="absolute inset-0 transform -rotate-90"
|
|
>
|
|
<circle
|
|
stroke="rgba(255, 255, 255, 0.15)"
|
|
fill="transparent"
|
|
strokeWidth={stroke}
|
|
r={normalizedRadius}
|
|
cx="50%"
|
|
cy="50%"
|
|
/>
|
|
<circle
|
|
stroke="white"
|
|
fill="transparent"
|
|
strokeWidth={stroke}
|
|
strokeDasharray={circumference + " " + circumference}
|
|
style={{
|
|
strokeDashoffset,
|
|
transition: "stroke-dashoffset 0.1s linear",
|
|
}}
|
|
strokeLinecap="round"
|
|
r={normalizedRadius}
|
|
cx="50%"
|
|
cy="50%"
|
|
/>
|
|
</svg>
|
|
<div className="absolute inset-0 flex flex-col items-center justify-center">
|
|
<span className="text-[1.1rem] font-mono font-bold text-white tracking-tighter drop-shadow-md tabular-nums leading-none">
|
|
{Math.floor(value).toLocaleString()}
|
|
</span>
|
|
<span className="text-[8px] uppercase tracking-widest text-white/50 font-semibold mt-0.5">
|
|
{unit}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<div className="text-white/80 text-[9px] font-bold font-sans tracking-[0.2em] whitespace-nowrap mt-2">
|
|
{label}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|