summaryrefslogtreecommitdiffstats
path: root/termui/sparkline.go
blob: 9f3b9ee4c38ebafd7f557a4883dddb0bcde59e4b (plain)
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
package termui

var SPARKS = [8]rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}

// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃. The data points should be non-negative integers.
type Sparkline struct {
	Data       []int
	Title1     string
	Title2     string
	TitleColor Color
	Total      int
	LineColor  Color
}

// Sparklines is a renderable widget which groups together the given sparklines.
type Sparklines struct {
	*Block
	Lines []*Sparkline
}

// Add appends a given Sparkline to s *Sparklines.
func (s *Sparklines) Add(sl Sparkline) {
	s.Lines = append(s.Lines, &sl)
}

// NewSparkline returns a unrenderable single sparkline that intended to be added into Sparklines.
func NewSparkline() *Sparkline {
	return &Sparkline{
		TitleColor: Theme.Fg,
		LineColor:  Theme.Sparkline,
	}
}

// NewSparklines return a new *Sparklines with given Sparkline(s), you can always add a new Sparkline later.
func NewSparklines(ss ...*Sparkline) *Sparklines {
	return &Sparklines{
		Block: NewBlock(),
		Lines: ss,
	}
}

// Buffer implements Bufferer interface.
func (sl *Sparklines) Buffer() *Buffer {
	buf := sl.Block.Buffer()

	lc := len(sl.Lines) // lineCount

	// for each line
	for i, line := range sl.Lines {

		title1Y := 2 + (sl.Y/lc)*i
		title2Y := (2 + (sl.Y/lc)*i) + 1

		title1 := MaxString(line.Title1, sl.X)
		title2 := MaxString(line.Title2, sl.X)
		buf.SetString(1, title1Y, title1, line.TitleColor|AttrBold, sl.Bg)
		buf.SetString(1, title2Y, title2, line.TitleColor|AttrBold, sl.Bg)

		// sparkline
		sparkY := (sl.Y / lc) * (i + 1)
		// finds max used for relative heights
		max := 1
		for i := len(line.Data) - 1; i >= 0 && sl.X-((len(line.Data)-1)-i) >= 1; i-- {
			if line.Data[i] > max {
				max = line.Data[i]
			}
		}
		// prints sparkline
		for x := sl.X; x >= 1; x-- {
			char := SPARKS[0]
			if (sl.X - x) < len(line.Data) {
				char = SPARKS[int((float64(line.Data[(len(line.Data)-1)-(sl.X-x)])/float64(max))*7)]
			}
			buf.SetCell(x, sparkY, Cell{char, line.LineColor, sl.Bg})
		}
	}

	return buf
}