diff options
| author | Paul Buetow <paul@buetow.org> | 2026-02-24 08:34:00 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-02-24 08:34:00 +0200 |
| commit | 89ba8287d490a0fef15a80a34ea4efe0c5ecf2e8 (patch) | |
| tree | d164744464c7997a23be60200eebf710015d8fed /internal/tui/dashboard/sparkline.go | |
| parent | 9c400937d9e32f3ce85c668d9ca52c351f8b5d13 (diff) | |
tui: add dashboard sparkline renderer
Diffstat (limited to 'internal/tui/dashboard/sparkline.go')
| -rw-r--r-- | internal/tui/dashboard/sparkline.go | 74 |
1 files changed, 74 insertions, 0 deletions
diff --git a/internal/tui/dashboard/sparkline.go b/internal/tui/dashboard/sparkline.go new file mode 100644 index 0000000..1531ca6 --- /dev/null +++ b/internal/tui/dashboard/sparkline.go @@ -0,0 +1,74 @@ +package dashboard + +import "math" + +var sparkChars = []rune("▁▂▃▄▅▆▇█") + +func renderSparkline(data []float64, width int) string { + if len(data) == 0 || width <= 0 { + return "" + } + + samples := sampleForWidth(data, width) + min, max := minMax(samples) + if min == max { + return repeatRune('▄', len(samples)) + } + + out := make([]rune, len(samples)) + scale := float64(len(sparkChars) - 1) + denom := max - min + for i, value := range samples { + idx := int(math.Round((value - min) / denom * scale)) + if idx < 0 { + idx = 0 + } + if idx >= len(sparkChars) { + idx = len(sparkChars) - 1 + } + out[i] = sparkChars[idx] + } + return string(out) +} + +func sampleForWidth(data []float64, width int) []float64 { + if width >= len(data) { + return append([]float64(nil), data...) + } + if width == 1 { + return []float64{data[len(data)-1]} + } + + last := len(data) - 1 + samples := make([]float64, width) + for i := 0; i < width; i++ { + idx := int(math.Round(float64(i) * float64(last) / float64(width-1))) + samples[i] = data[idx] + } + return samples +} + +func minMax(values []float64) (float64, float64) { + min := values[0] + max := values[0] + for _, v := range values[1:] { + if v < min { + min = v + } + if v > max { + max = v + } + } + return min, max +} + +func repeatRune(r rune, count int) string { + if count <= 0 { + return "" + } + out := make([]rune, count) + for i := range out { + out[i] = r + } + return string(out) +} |
