1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
package dashboard
import "math"
import "strings"
var sparkRowChars = []rune(" ▁▂▃▄▅▆▇█")
func renderSparkline(data []float64, width int) string {
if len(data) == 0 || width <= 0 {
return ""
}
samples := sampleForWidth(data, width)
leftPad := 0
if len(samples) < width {
leftPad = width - len(samples)
}
min, max := minMax(samples)
if min == max {
top := repeatRune(' ', width)
bottom := repeatRune(' ', leftPad) + repeatRune('█', len(samples))
return top + "\n" + bottom
}
top := make([]rune, width)
bottom := make([]rune, width)
for i := 0; i < leftPad; i++ {
top[i] = ' '
bottom[i] = ' '
}
scale := 16.0
denom := max - min
for i, value := range samples {
level := int(math.Round((value - min) / denom * scale))
if level < 0 {
level = 0
}
if level > 16 {
level = 16
}
topLevel := level - 8
if topLevel < 0 {
topLevel = 0
}
bottomLevel := level
if bottomLevel > 8 {
bottomLevel = 8
}
if bottomLevel == 0 {
bottomLevel = 1
}
col := leftPad + i
top[col] = sparkRowChars[topLevel]
bottom[col] = sparkRowChars[bottomLevel]
}
return string(top) + "\n" + string(bottom)
}
func renderLabeledSparkline(label string, data []float64, width int) string {
spark := renderSparkline(data, width)
if spark == "" {
return label
}
lines := strings.Split(spark, "\n")
if len(lines) == 1 {
return label + " " + lines[0]
}
pad := repeatRune(' ', len([]rune(label))+1)
return label + " " + lines[0] + "\n" + pad + lines[1]
}
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)
}
|