This repository has been archived by the owner on Aug 29, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 449
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add widget files from cjbassi/termui
- Loading branch information
Showing
3 changed files
with
422 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
package termui | ||
|
||
import ( | ||
"sort" | ||
|
||
drawille "github.com/cjbassi/drawille-go" | ||
) | ||
|
||
// LineGraph implements a line graph of data points. | ||
type LineGraph struct { | ||
*Block | ||
Data map[string][]float64 | ||
LineColor map[string]Color | ||
Zoom int | ||
Labels map[string]string | ||
|
||
DefaultLineColor Color | ||
} | ||
|
||
// NewLineGraph returns a new LineGraph with current theme. | ||
func NewLineGraph() *LineGraph { | ||
return &LineGraph{ | ||
Block: NewBlock(), | ||
Data: make(map[string][]float64), | ||
LineColor: make(map[string]Color), | ||
Labels: make(map[string]string), | ||
Zoom: 5, | ||
|
||
DefaultLineColor: Theme.LineGraph, | ||
} | ||
} | ||
|
||
// Buffer implements Bufferer interface. | ||
func (self *LineGraph) Buffer() *Buffer { | ||
buf := self.Block.Buffer() | ||
// 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 | ||
c := drawille.NewCanvas() | ||
// used to keep track of the braille colors until the end when we render the braille to the buffer | ||
colors := make([][]Color, self.X+2) | ||
for i := range colors { | ||
colors[i] = make([]Color, self.Y+2) | ||
} | ||
|
||
// sort the series so that overlapping data will overlap the same way each time | ||
seriesList := make([]string, len(self.Data)) | ||
i := 0 | ||
for seriesName := range self.Data { | ||
seriesList[i] = seriesName | ||
i++ | ||
} | ||
sort.Strings(seriesList) | ||
|
||
// 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] | ||
seriesData := self.Data[seriesName] | ||
seriesLineColor, ok := self.LineColor[seriesName] | ||
if !ok { | ||
seriesLineColor = self.DefaultLineColor | ||
} | ||
|
||
// coordinates of last point | ||
lastY, lastX := -1, -1 | ||
// assign colors to `colors` and lines/points to the canvas | ||
for i := len(seriesData) - 1; i >= 0; i-- { | ||
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)) | ||
if x < 0 { | ||
// render the line to the last point up to the wall | ||
if x > 0-self.Zoom { | ||
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 | ||
} | ||
} | ||
} | ||
break | ||
} | ||
if lastY == -1 { // if this is the first point | ||
c.Set(x, y) | ||
colors[x/2][y/4] = seriesLineColor | ||
} 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 | ||
} | ||
|
||
// copy braille and colors to buffer | ||
for y, line := range c.Rows(c.MinX(), c.MinY(), c.MaxX(), c.MaxY()) { | ||
for x, char := range line { | ||
x /= 3 // idk why but it works | ||
if x == 0 { | ||
continue | ||
} | ||
if char != 10240 { // empty braille character | ||
buf.SetCell(x, y, Cell{char, colors[x][y], self.Bg}) | ||
} | ||
} | ||
} | ||
} | ||
|
||
// renders key/label ontop | ||
for i, seriesName := range seriesList { | ||
if i+2 > self.Y { | ||
continue | ||
} | ||
seriesLineColor, ok := self.LineColor[seriesName] | ||
if !ok { | ||
seriesLineColor = self.DefaultLineColor | ||
} | ||
|
||
// render key ontop, but let braille be drawn over space characters | ||
str := seriesName + " " + self.Labels[seriesName] | ||
for k, char := range str { | ||
if char != ' ' { | ||
buf.SetCell(3+k, i+2, Cell{char, seriesLineColor, self.Bg}) | ||
} | ||
} | ||
|
||
} | ||
|
||
return buf | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
package termui | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
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 | ||
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 the *Sparklines. | ||
func (self *Sparklines) Add(sl Sparkline) { | ||
self.Lines = append(self.Lines, &sl) | ||
} | ||
|
||
// NewSparkline returns an unrenderable single sparkline that intended to be added into a Sparklines. | ||
func NewSparkline() *Sparkline { | ||
return &Sparkline{ | ||
TitleColor: Theme.Fg, | ||
LineColor: Theme.Sparkline, | ||
} | ||
} | ||
|
||
// NewSparklines return a new *Sparklines with given Sparklines, you can always add a new Sparkline later. | ||
func NewSparklines(ss ...*Sparkline) *Sparklines { | ||
return &Sparklines{ | ||
Block: NewBlock(), | ||
Lines: ss, | ||
} | ||
} | ||
|
||
// Buffer implements Bufferer interface. | ||
func (self *Sparklines) Buffer() *Buffer { | ||
buf := self.Block.Buffer() | ||
|
||
lc := len(self.Lines) // lineCount | ||
|
||
// renders each sparkline and its titles | ||
for i, line := range self.Lines { | ||
|
||
// prints titles | ||
title1Y := 2 + (self.Y/lc)*i | ||
title2Y := (2 + (self.Y/lc)*i) + 1 | ||
title1 := MaxString(line.Title1, self.X) | ||
title2 := MaxString(line.Title2, self.X) | ||
buf.SetString(1, title1Y, title1, line.TitleColor|AttrBold, self.Bg) | ||
buf.SetString(1, title2Y, title2, line.TitleColor|AttrBold, self.Bg) | ||
|
||
sparkY := (self.Y / lc) * (i + 1) | ||
// finds max data in current view used for relative heights | ||
max := 1 | ||
for i := len(line.Data) - 1; i >= 0 && self.X-((len(line.Data)-1)-i) >= 1; i-- { | ||
if line.Data[i] > max { | ||
max = line.Data[i] | ||
} | ||
} | ||
// prints sparkline | ||
for x := self.X; x >= 1; x-- { | ||
char := SPARKS[0] | ||
if (self.X - x) < len(line.Data) { | ||
offset := self.X - x | ||
cur_item := line.Data[(len(line.Data)-1)-offset] | ||
percent := float64(cur_item) / float64(max) | ||
index := int(percent * 7) | ||
if index < 0 || index >= len(SPARKS) { | ||
Error("sparkline", | ||
fmt.Sprint( | ||
"len(line.Data): ", len(line.Data), "\n", | ||
"max: ", max, "\n", | ||
"x: ", x, "\n", | ||
"self.X: ", self.X, "\n", | ||
"offset: ", offset, "\n", | ||
"cur_item: ", cur_item, "\n", | ||
"percent: ", percent, "\n", | ||
"index: ", index, "\n", | ||
"len(SPARKS): ", len(SPARKS), | ||
)) | ||
} | ||
char = SPARKS[index] | ||
} | ||
buf.SetCell(x, sparkY, Cell{char, line.LineColor, self.Bg}) | ||
} | ||
} | ||
|
||
return buf | ||
} |
Oops, something went wrong.