gotop/vendor/github.com/cjbassi/termui/linegraph.go

126 lines
3.3 KiB
Go
Raw Permalink Normal View History

2018-02-19 15:25:02 +08:00
package termui
import (
"sort"
drawille "github.com/cjbassi/drawille-go"
)
2018-03-04 09:05:52 +08:00
// LineGraph implements a line graph of data points.
2018-02-19 15:25:02 +08:00
type LineGraph struct {
*Block
Data map[string][]float64
2018-02-21 16:46:11 +08:00
LineColor map[string]Color
2018-03-10 08:29:05 +08:00
Zoom int
Labels map[string]string
2018-02-19 15:25:02 +08:00
2018-02-21 16:46:11 +08:00
DefaultLineColor Color
2018-02-19 15:25:02 +08:00
}
// NewLineGraph returns a new LineGraph with current theme.
func NewLineGraph() *LineGraph {
return &LineGraph{
Block: NewBlock(),
Data: make(map[string][]float64),
2018-02-21 16:46:11 +08:00
LineColor: make(map[string]Color),
Labels: make(map[string]string),
2018-03-10 08:29:05 +08:00
Zoom: 5,
2018-02-19 15:25:02 +08:00
DefaultLineColor: Theme.LineGraph,
}
}
2018-03-04 09:05:52 +08:00
// Buffer implements Bufferer interface.
2018-03-28 05:27:23 +08:00
func (self *LineGraph) Buffer() *Buffer {
buf := self.Block.Buffer()
2018-03-04 09:05:52 +08:00
// we render each data point on to the canvas then copy over the braille to the buffer at the end
// fyi braille characters have 2x4 dots for each character
2018-02-19 15:25:02 +08:00
c := drawille.NewCanvas()
2018-03-04 09:05:52 +08:00
// used to keep track of the braille colors until the end when we render the braille to the buffer
2018-03-28 05:27:23 +08:00
colors := make([][]Color, self.X+2)
2018-02-19 15:25:02 +08:00
for i := range colors {
2018-03-28 05:27:23 +08:00
colors[i] = make([]Color, self.Y+2)
2018-02-19 15:25:02 +08:00
}
2018-03-04 09:05:52 +08:00
// sort the series so that overlapping data will overlap the same way each time
2018-03-28 05:27:23 +08:00
seriesList := make([]string, len(self.Data))
2018-02-19 15:25:02 +08:00
i := 0
2018-03-28 05:27:23 +08:00
for seriesName := range self.Data {
2018-02-19 15:25:02 +08:00
seriesList[i] = seriesName
i++
}
sort.Strings(seriesList)
2018-03-04 09:05:52 +08:00
// draw lines in reverse order so that the first color defined in the colorscheme is on top
for i := len(seriesList) - 1; i >= 0; i-- {
seriesName := seriesList[i]
2018-03-28 05:27:23 +08:00
seriesData := self.Data[seriesName]
seriesLineColor, ok := self.LineColor[seriesName]
2018-02-19 15:25:02 +08:00
if !ok {
2018-03-28 05:27:23 +08:00
seriesLineColor = self.DefaultLineColor
2018-02-19 15:25:02 +08:00
}
2018-02-24 13:15:38 +08:00
// coordinates of last point
2018-02-19 15:25:02 +08:00
lastY, lastX := -1, -1
// assign colors to `colors` and lines/points to the canvas
for i := len(seriesData) - 1; i >= 0; i-- {
2018-03-28 05:27:23 +08:00
x := ((self.X + 1) * 2) - 1 - (((len(seriesData) - 1) - i) * self.Zoom)
y := ((self.Y + 1) * 4) - 1 - int((float64((self.Y)*4)-1)*(seriesData[i]/100))
2018-03-10 08:29:05 +08:00
if x < 0 {
// render the line to the last point up to the wall
2018-03-28 05:27:23 +08:00
if x > 0-self.Zoom {
2018-03-10 08:29:05 +08:00
for _, p := range drawille.Line(lastX, lastY, x, y) {
if p.X > 0 {
c.Set(p.X, p.Y)
colors[p.X/2][p.Y/4] = seriesLineColor
}
}
}
2018-02-19 15:25:02 +08:00
break
}
if lastY == -1 { // if this is the first point
c.Set(x, y)
2018-03-04 09:05:52 +08:00
colors[x/2][y/4] = seriesLineColor
2018-02-19 15:25:02 +08:00
} else {
c.DrawLine(lastX, lastY, x, y)
for _, p := range drawille.Line(lastX, lastY, x, y) {
colors[p.X/2][p.Y/4] = seriesLineColor
}
}
lastX, lastY = x, y
}
2018-02-24 13:15:38 +08:00
// copy braille and colors to buffer
2018-02-19 15:25:02 +08:00
for y, line := range c.Rows(c.MinX(), c.MinY(), c.MaxX(), c.MaxY()) {
for x, char := range line {
2018-02-24 13:15:38 +08:00
x /= 3 // idk why but it works
2018-02-19 15:25:02 +08:00
if x == 0 {
continue
}
2018-02-24 13:15:38 +08:00
if char != 10240 { // empty braille character
2018-03-28 05:27:23 +08:00
buf.SetCell(x, y, Cell{char, colors[x][y], self.Bg})
2018-02-19 15:25:02 +08:00
}
}
}
}
// renders key/label ontop
for j, seriesName := range seriesList {
2018-03-28 05:27:23 +08:00
seriesLineColor, ok := self.LineColor[seriesName]
if !ok {
2018-03-28 05:27:23 +08:00
seriesLineColor = self.DefaultLineColor
}
2018-02-19 15:25:02 +08:00
2018-03-04 09:05:52 +08:00
// render key ontop, but let braille be drawn over space characters
str := seriesName + " " + self.Labels[seriesName]
2018-02-19 15:25:02 +08:00
for k, char := range str {
if char != ' ' {
2018-03-28 05:27:23 +08:00
buf.SetCell(3+k, j+2, Cell{char, seriesLineColor, self.Bg})
2018-02-19 15:25:02 +08:00
}
}
}
return buf
}