ui: chart polish — rotated y-axis labels, wider viewBox, single-day fallback
- Add rotated 'Size' (left) and 'Snapshots' (right) axis titles in the chart's outer margins so the two y-axes are self-describing. - Bump the chart viewBox from 600x220 to 640x220 and lift padL from 56 to 72 so the rotated labels and byte tick numbers don't crowd. - Dedupe the X-axis labels for short windows (1 or 2 days collapsed the start/mid/end indices onto each other, stacking 'May 7' three times); the 1-day case now centres a single label, 2-day uses start+end only. - Pin a lone data dot to the chart centre instead of the left edge when len(days)==1, so it sits under the centred date label. Goldens regenerated.
This commit is contained in:
@@ -156,7 +156,7 @@ func RenderChart(series []Series, days []time.Time, opts ChartOpts) template.HTM
|
||||
if opts.EmptyLabel == "" {
|
||||
opts.EmptyLabel = "no data yet"
|
||||
}
|
||||
const padL, padR, padT, padB = 56, 56, 16, 28
|
||||
const padL, padR, padT, padB = 72, 56, 16, 28
|
||||
w, h := opts.Width, opts.Height
|
||||
innerW := w - padL - padR
|
||||
innerH := h - padT - padB
|
||||
@@ -255,6 +255,11 @@ func RenderChart(series []Series, days []time.Time, opts ChartOpts) template.HTM
|
||||
continue
|
||||
}
|
||||
x := float64(padL) + stepX*float64(i)
|
||||
if len(days) == 1 {
|
||||
// Single-day: pin the lone dot to the chart centre so it
|
||||
// sits under the centred date label.
|
||||
x = float64(padL) + float64(innerW)/2
|
||||
}
|
||||
y := float64(padT) + float64(innerH) - (v-a.min)/(a.max-a.min)*float64(innerH)
|
||||
fmt.Fprintf(&seg, "%.2f,%.2f ", x, y)
|
||||
d := days[i]
|
||||
@@ -267,18 +272,48 @@ func RenderChart(series []Series, days []time.Time, opts ChartOpts) template.HTM
|
||||
|
||||
if axArr[AxisLeft].has {
|
||||
writeAxisLabels(&b, padL-6, padT, innerH, axArr[AxisLeft].min, axArr[AxisLeft].max, FormatBytes, "end")
|
||||
// Rotated axis title in the left margin. Position inset from
|
||||
// the viewBox edge by ≈ font-size so the rotated glyph extents
|
||||
// don't clip against the SVG boundary.
|
||||
cy := padT + innerH/2
|
||||
fmt.Fprintf(&b,
|
||||
`<text x="14" y="%d" text-anchor="middle" font-size="11" fill="currentColor" fill-opacity="0.55" transform="rotate(-90, 14, %d)">Size</text>`,
|
||||
cy, cy)
|
||||
}
|
||||
if axArr[AxisRight].has {
|
||||
writeAxisLabels(&b, w-padR+6, padT, innerH, axArr[AxisRight].min, axArr[AxisRight].max, FormatCount, "start")
|
||||
cy := padT + innerH/2
|
||||
fmt.Fprintf(&b,
|
||||
`<text x="%d" y="%d" text-anchor="middle" font-size="11" fill="currentColor" fill-opacity="0.55" transform="rotate(90, %d, %d)">Snapshots</text>`,
|
||||
w-14, cy, w-14, cy)
|
||||
}
|
||||
|
||||
xLabels := []int{0, len(days) / 2, len(days) - 1}
|
||||
anchors := []string{"start", "middle", "end"}
|
||||
for i, idx := range xLabels {
|
||||
x := float64(padL) + stepX*float64(idx)
|
||||
// X-axis labels at start / mid / end. With 1-2 days the indices
|
||||
// collapse onto each other — dedupe so we don't stack overlapping
|
||||
// "Jan 2" labels at the same x coordinate.
|
||||
type xLabel struct {
|
||||
idx int
|
||||
anchor string
|
||||
}
|
||||
var xLabels []xLabel
|
||||
switch {
|
||||
case len(days) == 1:
|
||||
xLabels = []xLabel{{0, "middle"}}
|
||||
case len(days) == 2:
|
||||
xLabels = []xLabel{{0, "start"}, {1, "end"}}
|
||||
default:
|
||||
xLabels = []xLabel{{0, "start"}, {len(days) / 2, "middle"}, {len(days) - 1, "end"}}
|
||||
}
|
||||
for _, l := range xLabels {
|
||||
x := float64(padL) + stepX*float64(l.idx)
|
||||
// With a single point, anchor "middle" centres on padL — push to
|
||||
// the chart's centre line so the lone label sits over the dot.
|
||||
if len(days) == 1 {
|
||||
x = float64(padL) + float64(innerW)/2
|
||||
}
|
||||
fmt.Fprintf(&b,
|
||||
`<text x="%.2f" y="%d" text-anchor="%s" font-size="10" fill="currentColor" fill-opacity="0.55">%s</text>`,
|
||||
x, h-padB+16, anchors[i], days[idx].Format("Jan 2"))
|
||||
x, h-padB+16, l.anchor, days[l.idx].Format("Jan 2"))
|
||||
}
|
||||
|
||||
b.WriteString(`</svg>`)
|
||||
|
||||
Reference in New Issue
Block a user