fix: improve chart tooltip and metar refresh
This commit is contained in:
@@ -1,9 +1,14 @@
|
||||
"use client";
|
||||
|
||||
import { validNumber, type EvidenceSeries } from "@/components/dashboard/scan-terminal/temperature-chart-logic";
|
||||
import {
|
||||
validNumber,
|
||||
type EvidenceSeries,
|
||||
type ProbabilityOverlay,
|
||||
} from "@/components/dashboard/scan-terminal/temperature-chart-logic";
|
||||
|
||||
type TooltipSeries = Pick<EvidenceSeries, "key" | "label" | "color">;
|
||||
type TooltipRow = TooltipSeries & { value: number };
|
||||
type TooltipProbabilityRow = { key: string; label: string; value: string; color: string };
|
||||
|
||||
function isRunwayTooltipSeries(seriesKey: string) {
|
||||
return seriesKey.startsWith("runway_");
|
||||
@@ -36,38 +41,66 @@ export function TemperatureTooltipContent({
|
||||
payload,
|
||||
data,
|
||||
series,
|
||||
probabilityOverlay,
|
||||
tempSymbol = "°C",
|
||||
isEn = false,
|
||||
}: {
|
||||
active?: boolean;
|
||||
label?: string | number;
|
||||
payload?: ReadonlyArray<{ payload?: Record<string, any> }>;
|
||||
data: Array<Record<string, any>>;
|
||||
series: TooltipSeries[];
|
||||
probabilityOverlay?: ProbabilityOverlay | null;
|
||||
tempSymbol?: string;
|
||||
isEn?: boolean;
|
||||
}) {
|
||||
if (!active || !payload?.length || !series.length) return null;
|
||||
const activePoint = payload[0]?.payload || {};
|
||||
const rows = buildTooltipRows(activePoint, data, series);
|
||||
if (!rows.length) return null;
|
||||
if (!active) return null;
|
||||
const activePoint = payload?.[0]?.payload || findTooltipPointByLabel(data, label) || {};
|
||||
const rows = series.length ? buildTooltipRows(activePoint, data, series) : [];
|
||||
const probabilityRows = buildTooltipProbabilityRows(probabilityOverlay, tempSymbol, isEn);
|
||||
if (!rows.length && !probabilityRows.length) return null;
|
||||
|
||||
return (
|
||||
<div className="rounded border border-slate-200 bg-white px-2.5 py-2 text-[11px] shadow-lg">
|
||||
<div className="mb-1 font-mono text-slate-500">{label}</div>
|
||||
<div className="grid gap-1">
|
||||
{rows.slice(0, 8).map((item) => (
|
||||
<div key={item.key} className="flex min-w-[140px] items-center justify-between gap-4">
|
||||
<span className="inline-flex items-center gap-1.5 text-slate-700">
|
||||
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: item.color }} />
|
||||
<span className="font-semibold">{item.label}</span>
|
||||
</span>
|
||||
<strong className="font-mono text-slate-900">{item.value.toFixed(2)}{tempSymbol}</strong>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
{rows.length > 0 && (
|
||||
<div className="grid gap-1">
|
||||
{rows.slice(0, 8).map((item) => (
|
||||
<div key={item.key} className="flex min-w-[140px] items-center justify-between gap-4">
|
||||
<span className="inline-flex items-center gap-1.5 text-slate-700">
|
||||
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: item.color }} />
|
||||
<span className="font-semibold">{item.label}</span>
|
||||
</span>
|
||||
<strong className="font-mono text-slate-900">{item.value.toFixed(2)}{tempSymbol}</strong>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{probabilityRows.length > 0 && (
|
||||
<div className={rows.length > 0 ? "mt-1.5 grid gap-1 border-t border-slate-100 pt-1.5" : "grid gap-1"}>
|
||||
{probabilityRows.slice(0, 8).map((item) => (
|
||||
<div key={item.key} className="flex min-w-[160px] items-center justify-between gap-4">
|
||||
<span className="inline-flex items-center gap-1.5 text-violet-700">
|
||||
<span className="h-2 w-2 rounded-full" style={{ backgroundColor: item.color }} />
|
||||
<span className="font-semibold">{item.label}</span>
|
||||
</span>
|
||||
<strong className="font-mono text-violet-900">{item.value}</strong>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function findTooltipPointByLabel(
|
||||
data: Array<Record<string, any>>,
|
||||
label?: string | number,
|
||||
) {
|
||||
if (label === undefined || label === null) return null;
|
||||
return data.find((point) => String(point.label) === String(label)) || null;
|
||||
}
|
||||
|
||||
function buildTooltipRows(
|
||||
activePoint: Record<string, any>,
|
||||
data: Array<Record<string, any>>,
|
||||
@@ -85,4 +118,43 @@ function buildTooltipRows(
|
||||
.filter((item): item is TooltipRow => item !== null);
|
||||
}
|
||||
|
||||
function formatProbabilityTemp(value: number, tempSymbol: string) {
|
||||
return `${value.toFixed(1)}${tempSymbol}`;
|
||||
}
|
||||
|
||||
function buildTooltipProbabilityRows(
|
||||
probabilityOverlay: ProbabilityOverlay | null | undefined,
|
||||
tempSymbol: string,
|
||||
isEn: boolean,
|
||||
): TooltipProbabilityRow[] {
|
||||
if (!probabilityOverlay) return [];
|
||||
|
||||
const rows: TooltipProbabilityRow[] = [];
|
||||
if (probabilityOverlay.muLine) {
|
||||
rows.push({
|
||||
key: "gaussian_mu",
|
||||
label: isEn ? "Gaussian μ" : "高斯 μ",
|
||||
value: formatProbabilityTemp(probabilityOverlay.muLine.value, tempSymbol),
|
||||
color: "#7c3aed",
|
||||
});
|
||||
}
|
||||
|
||||
probabilityOverlay.bands
|
||||
.slice()
|
||||
.sort((left, right) => right.probability - left.probability)
|
||||
.forEach((band) => {
|
||||
const range = `${band.lower.toFixed(1)}-${band.upper.toFixed(1)}${tempSymbol}`;
|
||||
const probability = `${Math.round(band.probability * 100)}%`;
|
||||
rows.push({
|
||||
key: band.key,
|
||||
label: isEn ? "Probability band" : "概率温度带",
|
||||
value: `${range} ${probability}`,
|
||||
color: "#8b5cf6",
|
||||
});
|
||||
});
|
||||
|
||||
return rows;
|
||||
}
|
||||
|
||||
export const __buildTemperatureTooltipRowsForTest = buildTooltipRows;
|
||||
export const __buildTemperatureTooltipProbabilityRowsForTest = buildTooltipProbabilityRows;
|
||||
|
||||
Reference in New Issue
Block a user