Merge remote-tracking branch 'refs/remotes/origin/master' into refactoring
This commit is contained in:
commit
746582638b
11
README.md
11
README.md
@ -1,7 +1,9 @@
|
|||||||
# termui [](https://travis-ci.org/gizak/termui) [](https://godoc.org/github.com/gizak/termui)
|
# termui [](https://travis-ci.org/gizak/termui) [](https://godoc.org/github.com/gizak/termui)
|
||||||
|
|
||||||
---
|
## Notice
|
||||||
|
termui comes with ABSOLUTELY NO WARRANTY, and there is a breaking change coming up (see refactoring branch) which will change the `Bufferer` interface and many others. These changes reduce calculation overhead and introduce a new drawing buffer with better capacibilities. We will step into the next stage (call it beta) after merging these changes.
|
||||||
|
|
||||||
|
## Introduction
|
||||||
Go terminal dashboard. Inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go.
|
Go terminal dashboard. Inspired by [blessed-contrib](https://github.com/yaronn/blessed-contrib), but purely in Go.
|
||||||
|
|
||||||
Cross-platform, easy to compile, and fully-customizable.
|
Cross-platform, easy to compile, and fully-customizable.
|
||||||
@ -132,6 +134,11 @@ TODO: Image (let's wait until the implementation is finished).
|
|||||||
|
|
||||||
<img src="./example/barchart.png" alt="barchart" type="image/png" width="150">
|
<img src="./example/barchart.png" alt="barchart" type="image/png" width="150">
|
||||||
|
|
||||||
|
#### Mult-Bar / Stacked-Bar Chart
|
||||||
|
[demo code](https://github.com/gizak/termui/blob/master/example/mbarchart.go)
|
||||||
|
|
||||||
|
<img src="./example/mbarchart.png" alt="barchart" type="image/png" width="150">
|
||||||
|
|
||||||
#### Sparklines
|
#### Sparklines
|
||||||
[demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go)
|
[demo code](https://github.com/gizak/termui/blob/master/example/sparklines.go)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import (
|
|||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
)
|
)
|
||||||
|
|
||||||
var r *row
|
var r *Row
|
||||||
|
|
||||||
func TestRowWidth(t *testing.T) {
|
func TestRowWidth(t *testing.T) {
|
||||||
p0 := NewPar("p0")
|
p0 := NewPar("p0")
|
||||||
|
@ -47,7 +47,7 @@ func main() {
|
|||||||
spark := ui.Sparkline{}
|
spark := ui.Sparkline{}
|
||||||
spark.Height = 1
|
spark.Height = 1
|
||||||
spark.Title = "srv 0:"
|
spark.Title = "srv 0:"
|
||||||
spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
|
spdata := []int{4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6, 4, 2, 1, 6, 3, 9, 1, 4, 2, 15, 14, 9, 8, 6, 10, 13, 15, 12, 10, 5, 3, 6, 1, 7, 10, 10, 14, 13, 6}
|
||||||
spark.Data = spdata
|
spark.Data = spdata
|
||||||
spark.LineColor = ui.ColorCyan
|
spark.LineColor = ui.ColorCyan
|
||||||
spark.TitleColor = ui.ColorWhite
|
spark.TitleColor = ui.ColorWhite
|
||||||
@ -119,8 +119,8 @@ func main() {
|
|||||||
draw := func(t int) {
|
draw := func(t int) {
|
||||||
g.Percent = t % 101
|
g.Percent = t % 101
|
||||||
list.Items = strs[t%9:]
|
list.Items = strs[t%9:]
|
||||||
sp.Lines[0].Data = spdata[t%10:]
|
sp.Lines[0].Data = spdata[:30+t%50]
|
||||||
sp.Lines[1].Data = spdata[t/2%10:]
|
sp.Lines[1].Data = spdata[:35+t%50]
|
||||||
lc.Data = sinps[t/2:]
|
lc.Data = sinps[t/2:]
|
||||||
lc1.Data = sinps[2*t:]
|
lc1.Data = sinps[2*t:]
|
||||||
bc.Data = bcdata[t/2%10:]
|
bc.Data = bcdata[t/2%10:]
|
||||||
|
@ -55,7 +55,15 @@ func main() {
|
|||||||
g1.Border.Fg = termui.ColorWhite
|
g1.Border.Fg = termui.ColorWhite
|
||||||
g1.Border.LabelFgClr = termui.ColorMagenta
|
g1.Border.LabelFgClr = termui.ColorMagenta
|
||||||
|
|
||||||
termui.Render(g0, g1, g2, gg)
|
g3 := termui.NewGauge()
|
||||||
|
g3.Percent = 50
|
||||||
|
g3.Width = 50
|
||||||
|
g3.Height = 3
|
||||||
|
g3.Y = 11
|
||||||
|
g3.Border.Label = "Gauge with custom label"
|
||||||
|
g3.Label = "{{percent}}% (100MBs free)"
|
||||||
|
g3.LabelAlign = termui.AlignRight
|
||||||
|
|
||||||
|
termui.Render(g0, g1, g2, g3)
|
||||||
<-termui.EventCh()
|
<-termui.EventCh()
|
||||||
}
|
}
|
||||||
|
Binary file not shown.
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 32 KiB |
@ -8,7 +8,6 @@ package main
|
|||||||
|
|
||||||
import ui "github.com/gizak/termui"
|
import ui "github.com/gizak/termui"
|
||||||
import "math"
|
import "math"
|
||||||
|
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@ -39,7 +38,7 @@ func main() {
|
|||||||
spark := ui.Sparkline{}
|
spark := ui.Sparkline{}
|
||||||
spark.Height = 8
|
spark.Height = 8
|
||||||
spdata := sinpsint
|
spdata := sinpsint
|
||||||
spark.Data = spdata
|
spark.Data = spdata[:100]
|
||||||
spark.LineColor = ui.ColorCyan
|
spark.LineColor = ui.ColorCyan
|
||||||
spark.TitleColor = ui.ColorWhite
|
spark.TitleColor = ui.ColorWhite
|
||||||
|
|
||||||
@ -92,34 +91,44 @@ func main() {
|
|||||||
// calculate layout
|
// calculate layout
|
||||||
ui.Body.Align()
|
ui.Body.Align()
|
||||||
|
|
||||||
draw := func(t int) {
|
done := make(chan bool)
|
||||||
sp.Lines[0].Data = spdata[t:]
|
redraw := make(chan bool)
|
||||||
lc.Data = sinps[2*t:]
|
|
||||||
ui.Render(ui.Body)
|
update := func() {
|
||||||
|
for i := 0; i < 103; i++ {
|
||||||
|
for _, g := range gs {
|
||||||
|
g.Percent = (g.Percent + 3) % 100
|
||||||
|
}
|
||||||
|
|
||||||
|
sp.Lines[0].Data = spdata[:100+i]
|
||||||
|
lc.Data = sinps[2*i:]
|
||||||
|
|
||||||
|
time.Sleep(time.Second / 2)
|
||||||
|
redraw <- true
|
||||||
|
}
|
||||||
|
done <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
evt := ui.EventCh()
|
evt := ui.EventCh()
|
||||||
|
|
||||||
i := 0
|
ui.Render(ui.Body)
|
||||||
|
go update()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case e := <-evt:
|
case e := <-evt:
|
||||||
if e.Type == ui.EventKey && e.Ch == 'q' {
|
if e.Type == ui.EventKey && e.Ch == 'q' {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
default:
|
if e.Type == ui.EventResize {
|
||||||
for _, g := range gs {
|
ui.Body.Width = ui.TermWidth()
|
||||||
g.Percent = (g.Percent + 3) % 100
|
ui.Body.Align()
|
||||||
|
go func() { redraw <- true }()
|
||||||
}
|
}
|
||||||
ui.Body.Width = ui.TermWidth()
|
case <-done:
|
||||||
ui.Body.Align()
|
return
|
||||||
|
case <-redraw:
|
||||||
draw(i)
|
ui.Render(ui.Body)
|
||||||
i++
|
|
||||||
if i == 102 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
time.Sleep(time.Second / 2)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
50
example/mbarchart.go
Normal file
50
example/mbarchart.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build ignore
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/gizak/termui"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := termui.Init()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
defer termui.Close()
|
||||||
|
|
||||||
|
termui.UseTheme("helloworld")
|
||||||
|
|
||||||
|
bc := termui.NewMBarChart()
|
||||||
|
math := []int{90, 85, 90, 80}
|
||||||
|
english := []int{70, 85, 75, 60}
|
||||||
|
science := []int{75, 60, 80, 85}
|
||||||
|
compsci := []int{100, 100, 100, 100}
|
||||||
|
bc.Data[0] = math
|
||||||
|
bc.Data[1] = english
|
||||||
|
bc.Data[2] = science
|
||||||
|
bc.Data[3] = compsci
|
||||||
|
studentsName := []string{"Ken", "Rob", "Dennis", "Linus"}
|
||||||
|
bc.Border.Label = "Student's Marks X-Axis=Name Y-Axis=Marks[Math,English,Science,ComputerScience] in %"
|
||||||
|
bc.Width = 100
|
||||||
|
bc.Height = 50
|
||||||
|
bc.Y = 10
|
||||||
|
bc.BarWidth = 10
|
||||||
|
bc.DataLabels = studentsName
|
||||||
|
bc.ShowScale = true //Show y_axis scale value (min and max)
|
||||||
|
bc.SetMax(400)
|
||||||
|
|
||||||
|
bc.TextColor = termui.ColorGreen //this is color for label (x-axis)
|
||||||
|
bc.BarColor[3] = termui.ColorGreen //BarColor for computerscience
|
||||||
|
bc.BarColor[1] = termui.ColorYellow //Bar Color for english
|
||||||
|
bc.NumColor[3] = termui.ColorRed // Num color for computerscience
|
||||||
|
bc.NumColor[1] = termui.ColorRed // num color for english
|
||||||
|
|
||||||
|
//Other colors are automatically populated, btw All the students seems do well in computerscience. :p
|
||||||
|
|
||||||
|
termui.Render(bc)
|
||||||
|
|
||||||
|
<-termui.EventCh()
|
||||||
|
}
|
BIN
example/mbarchart.png
Normal file
BIN
example/mbarchart.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
113
gauge.go
Normal file
113
gauge.go
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Gauge is a progress bar like widget.
|
||||||
|
// A simple example:
|
||||||
|
/*
|
||||||
|
g := termui.NewGauge()
|
||||||
|
g.Percent = 40
|
||||||
|
g.Width = 50
|
||||||
|
g.Height = 3
|
||||||
|
g.Border.Label = "Slim Gauge"
|
||||||
|
g.BarColor = termui.ColorRed
|
||||||
|
g.PercentColor = termui.ColorBlue
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Align is the position of the gauge's label.
|
||||||
|
type Align int
|
||||||
|
|
||||||
|
// All supported positions.
|
||||||
|
const (
|
||||||
|
AlignLeft Align = iota
|
||||||
|
AlignCenter
|
||||||
|
AlignRight
|
||||||
|
)
|
||||||
|
|
||||||
|
type Gauge struct {
|
||||||
|
Block
|
||||||
|
Percent int
|
||||||
|
BarColor Attribute
|
||||||
|
PercentColor Attribute
|
||||||
|
Label string
|
||||||
|
LabelAlign Align
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewGauge return a new gauge with current theme.
|
||||||
|
func NewGauge() *Gauge {
|
||||||
|
g := &Gauge{
|
||||||
|
Block: *NewBlock(),
|
||||||
|
PercentColor: theme.GaugePercent,
|
||||||
|
BarColor: theme.GaugeBar,
|
||||||
|
Label: "{{percent}}%",
|
||||||
|
LabelAlign: AlignCenter,
|
||||||
|
}
|
||||||
|
|
||||||
|
g.Width = 12
|
||||||
|
g.Height = 5
|
||||||
|
return g
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (g *Gauge) Buffer() []Point {
|
||||||
|
ps := g.Block.Buffer()
|
||||||
|
|
||||||
|
// plot bar
|
||||||
|
w := g.Percent * g.innerWidth / 100
|
||||||
|
for i := 0; i < g.innerHeight; i++ {
|
||||||
|
for j := 0; j < w; j++ {
|
||||||
|
p := Point{}
|
||||||
|
p.X = g.innerX + j
|
||||||
|
p.Y = g.innerY + i
|
||||||
|
p.Ch = ' '
|
||||||
|
p.Bg = g.BarColor
|
||||||
|
if p.Bg == ColorDefault {
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// plot percentage
|
||||||
|
s := strings.Replace(g.Label, "{{percent}}", strconv.Itoa(g.Percent), -1)
|
||||||
|
pry := g.innerY + g.innerHeight/2
|
||||||
|
rs := str2runes(s)
|
||||||
|
var pos int
|
||||||
|
switch g.LabelAlign {
|
||||||
|
case AlignLeft:
|
||||||
|
pos = 0
|
||||||
|
|
||||||
|
case AlignCenter:
|
||||||
|
pos = (g.innerWidth - strWidth(s)) / 2
|
||||||
|
|
||||||
|
case AlignRight:
|
||||||
|
pos = g.innerWidth - strWidth(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, v := range rs {
|
||||||
|
p := Point{}
|
||||||
|
p.X = 1 + pos + i
|
||||||
|
p.Y = pry
|
||||||
|
p.Ch = v
|
||||||
|
p.Fg = g.PercentColor
|
||||||
|
if w+g.innerX > pos+i {
|
||||||
|
p.Bg = g.BarColor
|
||||||
|
if p.Bg == ColorDefault {
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
p.Bg = g.Block.BgColor
|
||||||
|
}
|
||||||
|
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
return g.Block.chopOverflow(ps)
|
||||||
|
}
|
@ -29,6 +29,7 @@ const (
|
|||||||
ColorWhite
|
ColorWhite
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const NumberofColors = 8 //Have a constant that defines number of colors
|
||||||
const (
|
const (
|
||||||
AttrBold Attribute = 1 << (iota + 9)
|
AttrBold Attribute = 1 << (iota + 9)
|
||||||
AttrUnderline
|
AttrUnderline
|
||||||
|
233
mbar.go
Normal file
233
mbar.go
Normal file
@ -0,0 +1,233 @@
|
|||||||
|
// Copyright 2015 Zack Guo <gizak@icloud.com>. All rights reserved.
|
||||||
|
// Use of this source code is governed by a MIT license that can
|
||||||
|
// be found in the LICENSE file.
|
||||||
|
|
||||||
|
package termui
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is the implemetation of multi-colored or stacked bar graph. This is different from default barGraph which is implemented in bar.go
|
||||||
|
// Multi-Colored-BarChart creates multiple bars in a widget:
|
||||||
|
/*
|
||||||
|
bc := termui.NewMBarChart()
|
||||||
|
data := make([][]int, 2)
|
||||||
|
data[0] := []int{3, 2, 5, 7, 9, 4}
|
||||||
|
data[1] := []int{7, 8, 5, 3, 1, 6}
|
||||||
|
bclabels := []string{"S0", "S1", "S2", "S3", "S4", "S5"}
|
||||||
|
bc.Border.Label = "Bar Chart"
|
||||||
|
bc.Data = data
|
||||||
|
bc.Width = 26
|
||||||
|
bc.Height = 10
|
||||||
|
bc.DataLabels = bclabels
|
||||||
|
bc.TextColor = termui.ColorGreen
|
||||||
|
bc.BarColor = termui.ColorRed
|
||||||
|
bc.NumColor = termui.ColorYellow
|
||||||
|
*/
|
||||||
|
type MBarChart struct {
|
||||||
|
Block
|
||||||
|
BarColor [NumberofColors]Attribute
|
||||||
|
TextColor Attribute
|
||||||
|
NumColor [NumberofColors]Attribute
|
||||||
|
Data [NumberofColors][]int
|
||||||
|
DataLabels []string
|
||||||
|
BarWidth int
|
||||||
|
BarGap int
|
||||||
|
labels [][]rune
|
||||||
|
dataNum [NumberofColors][][]rune
|
||||||
|
numBar int
|
||||||
|
scale float64
|
||||||
|
max int
|
||||||
|
minDataLen int
|
||||||
|
numStack int
|
||||||
|
ShowScale bool
|
||||||
|
maxScale []rune
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewBarChart returns a new *BarChart with current theme.
|
||||||
|
func NewMBarChart() *MBarChart {
|
||||||
|
bc := &MBarChart{Block: *NewBlock()}
|
||||||
|
bc.BarColor[0] = theme.MBarChartBar
|
||||||
|
bc.NumColor[0] = theme.MBarChartNum
|
||||||
|
bc.TextColor = theme.MBarChartText
|
||||||
|
bc.BarGap = 1
|
||||||
|
bc.BarWidth = 3
|
||||||
|
return bc
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *MBarChart) layout() {
|
||||||
|
bc.numBar = bc.innerWidth / (bc.BarGap + bc.BarWidth)
|
||||||
|
bc.labels = make([][]rune, bc.numBar)
|
||||||
|
DataLen := 0
|
||||||
|
LabelLen := len(bc.DataLabels)
|
||||||
|
bc.minDataLen = 9999 //Set this to some very hight value so that we find the minimum one We want to know which array among data[][] has got the least length
|
||||||
|
|
||||||
|
// We need to know how many stack/data array data[0] , data[1] are there
|
||||||
|
for i := 0; i < len(bc.Data); i++ {
|
||||||
|
if bc.Data[i] == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
DataLen++
|
||||||
|
}
|
||||||
|
bc.numStack = DataLen
|
||||||
|
|
||||||
|
//We need to know what is the mimimum size of data array data[0] could have 10 elements data[1] could have only 5, so we plot only 5 bar graphs
|
||||||
|
|
||||||
|
for i := 0; i < DataLen; i++ {
|
||||||
|
if bc.minDataLen > len(bc.Data[i]) {
|
||||||
|
bc.minDataLen = len(bc.Data[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if LabelLen > bc.minDataLen {
|
||||||
|
LabelLen = bc.minDataLen
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < LabelLen && i < bc.numBar; i++ {
|
||||||
|
bc.labels[i] = trimStr2Runes(bc.DataLabels[i], bc.BarWidth)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < bc.numStack; i++ {
|
||||||
|
bc.dataNum[i] = make([][]rune, len(bc.Data[i]))
|
||||||
|
//For each stack of bar calcualte the rune
|
||||||
|
for j := 0; j < LabelLen && i < bc.numBar; j++ {
|
||||||
|
n := bc.Data[i][j]
|
||||||
|
s := fmt.Sprint(n)
|
||||||
|
bc.dataNum[i][j] = trimStr2Runes(s, bc.BarWidth)
|
||||||
|
}
|
||||||
|
//If color is not defined by default then populate a color that is different from the prevous bar
|
||||||
|
if bc.BarColor[i] == ColorDefault && bc.NumColor[i] == ColorDefault {
|
||||||
|
if i == 0 {
|
||||||
|
bc.BarColor[i] = ColorBlack
|
||||||
|
} else {
|
||||||
|
bc.BarColor[i] = bc.BarColor[i-1] + 1
|
||||||
|
if bc.BarColor[i] > NumberofColors {
|
||||||
|
bc.BarColor[i] = ColorBlack
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bc.NumColor[i] = (NumberofColors + 1) - bc.BarColor[i] //Make NumColor opposite of barColor for visibility
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If Max value is not set then we have to populate, this time the max value will be max(sum(d1[0],d2[0],d3[0]) .... sum(d1[n], d2[n], d3[n]))
|
||||||
|
|
||||||
|
if bc.max == 0 {
|
||||||
|
bc.max = -1
|
||||||
|
}
|
||||||
|
for i := 0; i < bc.minDataLen && i < LabelLen; i++ {
|
||||||
|
var dsum int
|
||||||
|
for j := 0; j < bc.numStack; j++ {
|
||||||
|
dsum += bc.Data[j][i]
|
||||||
|
}
|
||||||
|
if dsum > bc.max {
|
||||||
|
bc.max = dsum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Finally Calculate max sale
|
||||||
|
if bc.ShowScale {
|
||||||
|
s := fmt.Sprintf("%d", bc.max)
|
||||||
|
bc.maxScale = trimStr2Runes(s, len(s))
|
||||||
|
bc.scale = float64(bc.max) / float64(bc.innerHeight-2)
|
||||||
|
} else {
|
||||||
|
bc.scale = float64(bc.max) / float64(bc.innerHeight-1)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bc *MBarChart) SetMax(max int) {
|
||||||
|
|
||||||
|
if max > 0 {
|
||||||
|
bc.max = max
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffer implements Bufferer interface.
|
||||||
|
func (bc *MBarChart) Buffer() []Point {
|
||||||
|
ps := bc.Block.Buffer()
|
||||||
|
bc.layout()
|
||||||
|
var oftX int
|
||||||
|
|
||||||
|
for i := 0; i < bc.numBar && i < bc.minDataLen && i < len(bc.DataLabels); i++ {
|
||||||
|
ph := 0 //Previous Height to stack up
|
||||||
|
oftX = i * (bc.BarWidth + bc.BarGap)
|
||||||
|
for i1 := 0; i1 < bc.numStack; i1++ {
|
||||||
|
h := int(float64(bc.Data[i1][i]) / bc.scale)
|
||||||
|
// plot bars
|
||||||
|
for j := 0; j < bc.BarWidth; j++ {
|
||||||
|
for k := 0; k < h; k++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = ' '
|
||||||
|
p.Bg = bc.BarColor[i1]
|
||||||
|
if bc.BarColor[i1] == ColorDefault { // when color is default, space char treated as transparent!
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
p.X = bc.innerX + i*(bc.BarWidth+bc.BarGap) + j
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2 - k - ph
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ph += h
|
||||||
|
}
|
||||||
|
// plot text
|
||||||
|
for j, k := 0, 0; j < len(bc.labels[i]); j++ {
|
||||||
|
w := charWidth(bc.labels[i][j])
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.labels[i][j]
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
p.Fg = bc.TextColor
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 1
|
||||||
|
p.X = bc.innerX + oftX + ((bc.BarWidth - len(bc.labels[i])) / 2) + k
|
||||||
|
ps = append(ps, p)
|
||||||
|
k += w
|
||||||
|
}
|
||||||
|
// plot num
|
||||||
|
ph = 0 //re-initialize previous height
|
||||||
|
for i1 := 0; i1 < bc.numStack; i1++ {
|
||||||
|
h := int(float64(bc.Data[i1][i]) / bc.scale)
|
||||||
|
for j := 0; j < len(bc.dataNum[i1][i]) && h > 0; j++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.dataNum[i1][i][j]
|
||||||
|
p.Fg = bc.NumColor[i1]
|
||||||
|
p.Bg = bc.BarColor[i1]
|
||||||
|
if bc.BarColor[i1] == ColorDefault { // the same as above
|
||||||
|
p.Bg |= AttrReverse
|
||||||
|
}
|
||||||
|
if h == 0 {
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
}
|
||||||
|
p.X = bc.innerX + oftX + (bc.BarWidth-len(bc.dataNum[i1][i]))/2 + j
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2 - ph
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
ph += h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if bc.ShowScale {
|
||||||
|
//Currently bar graph only supprts data range from 0 to MAX
|
||||||
|
//Plot 0
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = '0'
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
p.Fg = bc.TextColor
|
||||||
|
p.Y = bc.innerY + bc.innerHeight - 2
|
||||||
|
p.X = bc.X
|
||||||
|
ps = append(ps, p)
|
||||||
|
|
||||||
|
//Plot the maximum sacle value
|
||||||
|
for i := 0; i < len(bc.maxScale); i++ {
|
||||||
|
p := Point{}
|
||||||
|
p.Ch = bc.maxScale[i]
|
||||||
|
p.Bg = bc.BgColor
|
||||||
|
p.Fg = bc.TextColor
|
||||||
|
p.Y = bc.innerY
|
||||||
|
p.X = bc.X + i
|
||||||
|
ps = append(ps, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return bc.Block.chopOverflow(ps)
|
||||||
|
}
|
@ -35,12 +35,14 @@ func Close() {
|
|||||||
|
|
||||||
// TermWidth returns the current terminal's width.
|
// TermWidth returns the current terminal's width.
|
||||||
func TermWidth() int {
|
func TermWidth() int {
|
||||||
|
tm.Sync()
|
||||||
w, _ := tm.Size()
|
w, _ := tm.Size()
|
||||||
return w
|
return w
|
||||||
}
|
}
|
||||||
|
|
||||||
// TermHeight returns the current terminal's height.
|
// TermHeight returns the current terminal's height.
|
||||||
func TermHeight() int {
|
func TermHeight() int {
|
||||||
|
tm.Sync()
|
||||||
_, h := tm.Size()
|
_, h := tm.Size()
|
||||||
return h
|
return h
|
||||||
}
|
}
|
||||||
|
6
theme.go
6
theme.go
@ -26,6 +26,9 @@ type ColorScheme struct {
|
|||||||
BarChartBar Attribute
|
BarChartBar Attribute
|
||||||
BarChartText Attribute
|
BarChartText Attribute
|
||||||
BarChartNum Attribute
|
BarChartNum Attribute
|
||||||
|
MBarChartBar Attribute
|
||||||
|
MBarChartText Attribute
|
||||||
|
MBarChartNum Attribute
|
||||||
}
|
}
|
||||||
|
|
||||||
// default color scheme depends on the user's terminal setting.
|
// default color scheme depends on the user's terminal setting.
|
||||||
@ -52,6 +55,9 @@ var themeHelloWorld = ColorScheme{
|
|||||||
BarChartBar: ColorRed,
|
BarChartBar: ColorRed,
|
||||||
BarChartNum: ColorWhite,
|
BarChartNum: ColorWhite,
|
||||||
BarChartText: ColorCyan,
|
BarChartText: ColorCyan,
|
||||||
|
MBarChartBar: ColorRed,
|
||||||
|
MBarChartNum: ColorWhite,
|
||||||
|
MBarChartText: ColorCyan,
|
||||||
}
|
}
|
||||||
|
|
||||||
var theme = themeDefault // global dep
|
var theme = themeDefault // global dep
|
||||||
|
@ -108,7 +108,7 @@ func (sl *Sparklines) Buffer() []Point {
|
|||||||
data := l.Data
|
data := l.Data
|
||||||
|
|
||||||
if len(data) > sl.innerWidth {
|
if len(data) > sl.innerWidth {
|
||||||
data = data[:sl.innerWidth]
|
data = data[len(data)-sl.innerWidth:]
|
||||||
}
|
}
|
||||||
|
|
||||||
if l.Title != "" {
|
if l.Title != "" {
|
||||||
|
Loading…
Reference in New Issue
Block a user