mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-05-31 10:14:15 +00:00
refactor(sparkline): move min/max readout to a corner badge
On-chart extrema labels were colliding with the Y-axis ticks at the top, the X-axis timestamps at the bottom, and the chart line itself when min/max sat near a chart edge. Replace the floating labels with a single rounded pill in the chart's top-right corner that lists "▲ max ▼ min", outside the drawing area. Dots still mark the points on the line. Also nudge Y tick text 4px left, push X timestamps down with tickMargin=14, and widen YAxis to 56px so values like "234 KB/s" don't crowd the chart.
This commit is contained in:
parent
e23599cb18
commit
be5425cbed
2 changed files with 147 additions and 111 deletions
|
|
@ -2,3 +2,33 @@
|
|||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sparkline-container {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.sparkline-extrema {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 8px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 2px 8px;
|
||||
background: color-mix(in srgb, var(--ant-color-bg-elevated) 88%, transparent);
|
||||
border: 1px solid var(--ant-color-border-secondary);
|
||||
border-radius: 999px;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
line-height: 16px;
|
||||
pointer-events: none;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.sparkline-extrema .extrema-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ export default function Sparkline({
|
|||
if (points[i].value > points[maxIdx].value) maxIdx = i;
|
||||
}
|
||||
if (minIdx === maxIdx) return null;
|
||||
return { min: points[minIdx], max: points[maxIdx] };
|
||||
return { min: points[minIdx], max: points[maxIdx], minIdx, maxIdx };
|
||||
}, [points, extrema?.show]);
|
||||
|
||||
const fmtExtrema = extrema?.formatter ?? yFormatter;
|
||||
|
|
@ -145,8 +145,27 @@ export default function Sparkline({
|
|||
const maxColor = extrema?.maxColor ?? DEFAULT_MAX_COLOR;
|
||||
|
||||
return (
|
||||
<div className="sparkline-container">
|
||||
{extremaPoints && (
|
||||
<div className="sparkline-extrema" aria-hidden="true">
|
||||
<span className="extrema-item" style={{ color: maxColor }}>
|
||||
▲ {fmtExtrema(extremaPoints.max.value)}
|
||||
</span>
|
||||
<span className="extrema-item" style={{ color: minColor }}>
|
||||
▼ {fmtExtrema(extremaPoints.min.value)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
<ResponsiveContainer width="100%" height={height} className="sparkline-svg">
|
||||
<AreaChart data={points} margin={{ top: 6, right: 6, bottom: showAxes ? 14 : 4, left: showAxes ? 4 : 4 }}>
|
||||
<AreaChart
|
||||
data={points}
|
||||
margin={{
|
||||
top: showAxes ? 14 : 6,
|
||||
right: showAxes ? 12 : 6,
|
||||
bottom: showAxes ? 26 : 4,
|
||||
left: 4,
|
||||
}}
|
||||
>
|
||||
<defs>
|
||||
<linearGradient id={gradId} x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stopColor={stroke} stopOpacity={fillOpacity} />
|
||||
|
|
@ -162,18 +181,20 @@ export default function Sparkline({
|
|||
tick={{ fontSize: 10, fill: 'var(--ant-color-text-tertiary)' }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tickMargin={14}
|
||||
interval={0}
|
||||
ticks={xTickIndexes?.map((i) => points[i]?.label).filter(Boolean) as string[] | undefined}
|
||||
/>
|
||||
<YAxis
|
||||
domain={yDomain}
|
||||
hide={!showAxes}
|
||||
tick={{ fontSize: 10, fill: 'var(--ant-color-text-tertiary)' }}
|
||||
tick={{ fontSize: 10, fill: 'var(--ant-color-text-tertiary)', dx: -4 }}
|
||||
axisLine={false}
|
||||
tickLine={false}
|
||||
tickMargin={8}
|
||||
tickFormatter={yFormatter}
|
||||
ticks={yTicks}
|
||||
width={48}
|
||||
width={56}
|
||||
/>
|
||||
{showTooltip && (
|
||||
<Tooltip
|
||||
|
|
@ -219,14 +240,6 @@ export default function Sparkline({
|
|||
fill={maxColor}
|
||||
stroke="var(--ant-color-bg-elevated)"
|
||||
strokeWidth={2}
|
||||
label={{
|
||||
value: `▲ ${fmtExtrema(extremaPoints.max.value)}`,
|
||||
position: 'top',
|
||||
fontSize: 10.5,
|
||||
fill: maxColor,
|
||||
fontWeight: 600,
|
||||
offset: 8,
|
||||
}}
|
||||
ifOverflow="extendDomain"
|
||||
/>
|
||||
<ReferenceDot
|
||||
|
|
@ -236,14 +249,6 @@ export default function Sparkline({
|
|||
fill={minColor}
|
||||
stroke="var(--ant-color-bg-elevated)"
|
||||
strokeWidth={2}
|
||||
label={{
|
||||
value: `▼ ${fmtExtrema(extremaPoints.min.value)}`,
|
||||
position: 'bottom',
|
||||
fontSize: 10.5,
|
||||
fill: minColor,
|
||||
fontWeight: 600,
|
||||
offset: 8,
|
||||
}}
|
||||
ifOverflow="extendDomain"
|
||||
/>
|
||||
</>
|
||||
|
|
@ -260,5 +265,6 @@ export default function Sparkline({
|
|||
/>
|
||||
</AreaChart>
|
||||
</ResponsiveContainer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue