44b5d2d6ec
Fixes #128 for Sparkline. Also, the amount of data held is tiny so bumped the buffer to 4x to reduce collections. Minor comment change
107 lines
2.7 KiB
Go
107 lines
2.7 KiB
Go
package termui
|
|
|
|
import (
|
|
"image"
|
|
"log"
|
|
|
|
. "github.com/gizak/termui/v3"
|
|
)
|
|
|
|
// Sparkline is like: ▅▆▂▂▅▇▂▂▃▆▆▆▅▃. The data points should be non-negative integers.
|
|
type Sparkline struct {
|
|
Data []int
|
|
Title1 string
|
|
Title2 string
|
|
TitleColor Color
|
|
LineColor Color
|
|
}
|
|
|
|
// SparklineGroup is a renderable widget which groups together the given sparklines.
|
|
type SparklineGroup struct {
|
|
*Block
|
|
Lines []*Sparkline
|
|
}
|
|
|
|
// Add appends a given Sparkline to the *SparklineGroup.
|
|
func (self *SparklineGroup) Add(sl Sparkline) {
|
|
self.Lines = append(self.Lines, &sl)
|
|
}
|
|
|
|
// NewSparkline returns an unrenderable single sparkline that intended to be added into a SparklineGroup.
|
|
func NewSparkline() *Sparkline {
|
|
return &Sparkline{}
|
|
}
|
|
|
|
// NewSparklineGroup return a new *SparklineGroup with given Sparklines, you can always add a new Sparkline later.
|
|
func NewSparklineGroup(ss ...*Sparkline) *SparklineGroup {
|
|
return &SparklineGroup{
|
|
Block: NewBlock(),
|
|
Lines: ss,
|
|
}
|
|
}
|
|
|
|
func (self *SparklineGroup) Draw(buf *Buffer) {
|
|
self.Block.Draw(buf)
|
|
|
|
lc := len(self.Lines) // lineCount
|
|
|
|
// renders each sparkline and its titles
|
|
for i, line := range self.Lines {
|
|
|
|
// prints titles
|
|
title1Y := self.Inner.Min.Y + 1 + (self.Inner.Dy()/lc)*i
|
|
title2Y := self.Inner.Min.Y + 2 + (self.Inner.Dy()/lc)*i
|
|
title1 := TrimString(line.Title1, self.Inner.Dx())
|
|
title2 := TrimString(line.Title2, self.Inner.Dx())
|
|
if self.Inner.Dy() > 5 {
|
|
buf.SetString(
|
|
title1,
|
|
NewStyle(line.TitleColor, ColorClear, ModifierBold),
|
|
image.Pt(self.Inner.Min.X, title1Y),
|
|
)
|
|
}
|
|
if self.Inner.Dy() > 6 {
|
|
buf.SetString(
|
|
title2,
|
|
NewStyle(line.TitleColor, ColorClear, ModifierBold),
|
|
image.Pt(self.Inner.Min.X, title2Y),
|
|
)
|
|
}
|
|
|
|
sparkY := (self.Inner.Dy() / lc) * (i + 1)
|
|
// finds max data in current view used for relative heights
|
|
max := 1
|
|
for i := len(line.Data) - 1; i >= 0 && self.Inner.Dx()-((len(line.Data)-1)-i) >= 1; i-- {
|
|
if line.Data[i] > max {
|
|
max = line.Data[i]
|
|
}
|
|
}
|
|
// prints sparkline
|
|
for x := self.Inner.Dx(); x >= 1; x-- {
|
|
char := BARS[1]
|
|
if (self.Inner.Dx() - x) < len(line.Data) {
|
|
offset := self.Inner.Dx() - x
|
|
curItem := line.Data[(len(line.Data)-1)-offset]
|
|
percent := float64(curItem) / float64(max)
|
|
index := int(percent*float64(len(BARS)-2)) + 1
|
|
if index < 1 || index >= len(BARS) {
|
|
log.Printf(
|
|
"invalid sparkline data value. index: %v, percent: %v, curItem: %v, offset: %v",
|
|
index, percent, curItem, offset,
|
|
)
|
|
} else {
|
|
char = BARS[index]
|
|
}
|
|
}
|
|
buf.SetCell(
|
|
NewCell(char, NewStyle(line.LineColor)),
|
|
image.Pt(self.Inner.Min.X+x-1, self.Inner.Min.Y+sparkY-1),
|
|
)
|
|
}
|
|
dx := self.Inner.Dx()
|
|
if len(line.Data) > 4*dx {
|
|
line.Data = line.Data[dx-1:]
|
|
}
|
|
}
|
|
}
|