mirror of
https://github.com/mum4k/termdash.git
synced 2025-04-25 13:48:50 +08:00
Implementation of the SparkLine widget.
And completing the demo.
This commit is contained in:
parent
2ce014d35a
commit
a9813c4c76
@ -28,7 +28,9 @@ type options struct {
|
||||
|
||||
// newOptions returns options with the default values set.
|
||||
func newOptions() *options {
|
||||
return &options{}
|
||||
return &options{
|
||||
color: DefaultColor,
|
||||
}
|
||||
}
|
||||
|
||||
// Label adds a label above the SparkLine.
|
||||
|
@ -8,6 +8,8 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/mum4k/termdash/canvas"
|
||||
"github.com/mum4k/termdash/cell"
|
||||
"github.com/mum4k/termdash/draw"
|
||||
"github.com/mum4k/termdash/terminalapi"
|
||||
"github.com/mum4k/termdash/widgetapi"
|
||||
)
|
||||
@ -45,6 +47,62 @@ func New(opts ...Option) *SparkLine {
|
||||
func (sl *SparkLine) Draw(cvs *canvas.Canvas) error {
|
||||
sl.mu.Lock()
|
||||
defer sl.mu.Unlock()
|
||||
|
||||
ar := sl.area(cvs)
|
||||
visible, max := visibleMax(sl.data, ar.Dx())
|
||||
var curX int
|
||||
if len(visible) < ar.Dx() {
|
||||
curX = ar.Max.X - len(visible)
|
||||
} else {
|
||||
curX = ar.Min.X
|
||||
}
|
||||
|
||||
for _, v := range visible {
|
||||
blocks := toBlocks(v, max, ar.Dy())
|
||||
curY := ar.Max.Y - 1
|
||||
for i := 0; i < blocks.full; i++ {
|
||||
cells, err := cvs.SetCell(
|
||||
image.Point{curX, curY},
|
||||
sparks[len(sparks)-1],
|
||||
cell.FgColor(sl.opts.color),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cells != 1 {
|
||||
panic(fmt.Sprintf("set an unexpected number of cells %d while filling a full block, expected one", cells))
|
||||
}
|
||||
curY--
|
||||
}
|
||||
|
||||
if blocks.partSpark != 0 {
|
||||
cells, err := cvs.SetCell(
|
||||
image.Point{curX, curY},
|
||||
blocks.partSpark,
|
||||
cell.FgColor(sl.opts.color),
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cells != 1 {
|
||||
panic(fmt.Sprintf("set an unexpected number of cells %d while filling a partial block, expected one", cells))
|
||||
}
|
||||
}
|
||||
|
||||
curX++
|
||||
}
|
||||
|
||||
if sl.opts.label != "" {
|
||||
lStart := image.Point{ar.Min.X, ar.Min.Y - 1}
|
||||
if err := draw.Text(cvs, sl.opts.label, lStart,
|
||||
draw.TextCellOpts(sl.opts.labelCellOpts...),
|
||||
draw.TextOverrunMode(draw.OverrunModeThreeDot),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -84,6 +142,29 @@ func (*SparkLine) Mouse(m *terminalapi.Mouse) error {
|
||||
return errors.New("the SparkLine widget doesn't support mouse events")
|
||||
}
|
||||
|
||||
// area returns the area of the canvas available to the SparkLine.
|
||||
func (sl *SparkLine) area(cvs *canvas.Canvas) image.Rectangle {
|
||||
cvsAr := cvs.Area()
|
||||
|
||||
maxY := cvsAr.Max.Y
|
||||
var minY int
|
||||
if sl.opts.height > 0 {
|
||||
minY = maxY - sl.opts.height
|
||||
} else {
|
||||
minY = cvsAr.Min.Y
|
||||
|
||||
if sl.opts.label != "" {
|
||||
minY++ // Reserve one line for the label.
|
||||
}
|
||||
}
|
||||
return image.Rect(
|
||||
cvsAr.Min.X,
|
||||
minY,
|
||||
cvsAr.Max.X,
|
||||
maxY,
|
||||
)
|
||||
}
|
||||
|
||||
// minSize returns the minimum canvas size for the sparkline based on the options.
|
||||
func (sl *SparkLine) minSize() image.Point {
|
||||
// At least one data point.
|
||||
|
@ -45,19 +45,20 @@ func TestSparkLine(t *testing.T) {
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
return faketerm.MustNew(size)
|
||||
},
|
||||
wantUpdateErr: true,
|
||||
},
|
||||
{
|
||||
desc: "single height sparkline",
|
||||
sparkLine: New(),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(0, 1, 2, 3, 4, 5, 6, 7)
|
||||
return sl.Add(0, 1, 2, 3, 4, 5, 6, 7, 8)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 8, 1),
|
||||
canvas: image.Rect(0, 0, 9, 1),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, " ▁▂▃▄▅▆▇", image.Point{0, 0}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "▁▂▃▄▅▆▇█", image.Point{1, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustApply(c, ft)
|
||||
@ -70,72 +71,32 @@ func TestSparkLine(t *testing.T) {
|
||||
Color(cell.ColorMagenta),
|
||||
),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(0, 1, 2, 3, 4, 5, 6, 7)
|
||||
return sl.Add(0, 1, 2, 3, 4, 5, 6, 7, 8)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 8, 1),
|
||||
canvas: image.Rect(0, 0, 9, 1),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, " ▁▂▃▄▅▆▇", image.Point{0, 0}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "▁▂▃▄▅▆▇█", image.Point{1, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(cell.ColorMagenta),
|
||||
))
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "full cell has background set",
|
||||
sparkLine: New(),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(8)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 1, 1),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, "█", image.Point{0, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "full cell has background set to custom color",
|
||||
sparkLine: New(
|
||||
Color(cell.ColorMagenta),
|
||||
),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(8)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 1, 1),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, "█", image.Point{0, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(cell.ColorMagenta),
|
||||
cell.BgColor(cell.ColorMagenta),
|
||||
))
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
},
|
||||
},
|
||||
{
|
||||
desc: "draws data points from the right",
|
||||
sparkLine: New(),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(6, 7)
|
||||
return sl.Add(7, 8)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 9, 1),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, " ▆▇", image.Point{0, 0}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "▇█", image.Point{7, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
|
||||
@ -149,7 +110,7 @@ func TestSparkLine(t *testing.T) {
|
||||
Label("Hello"),
|
||||
),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(0, 1, 2, 3, 7, 3, 2, 0, 1)
|
||||
return sl.Add(0, 1, 2, 3, 8, 3, 2, 1, 1)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 9, 2),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
@ -157,7 +118,7 @@ func TestSparkLine(t *testing.T) {
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, "Hello", image.Point{0, 0})
|
||||
testdraw.MustText(c, " ▁▂▃▇▃▂ ▁", image.Point{0, 1}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "▁▂▃█▃▂▁▁", image.Point{1, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
|
||||
@ -171,7 +132,7 @@ func TestSparkLine(t *testing.T) {
|
||||
Label("Hello world"),
|
||||
),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(7)
|
||||
return sl.Add(8)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 9, 2),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
@ -179,7 +140,7 @@ func TestSparkLine(t *testing.T) {
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, "Hello wo…", image.Point{0, 0})
|
||||
testdraw.MustText(c, " ▇", image.Point{0, 1}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "█", image.Point{8, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
|
||||
@ -198,46 +159,24 @@ func TestSparkLine(t *testing.T) {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, " █ ▃", image.Point{0, 0}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "█", image.Point{1, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{1, 0}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testdraw.MustText(c, " █ █", image.Point{0, 1}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "▃", image.Point{3, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{1, 1}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
testcanvas.MustSetCell(c, image.Point{3, 1}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testdraw.MustText(c, " ███", image.Point{0, 2}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "█", image.Point{1, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustRectangle(c, image.Rect(1, 2, 4, 3),
|
||||
draw.RectChar('█'),
|
||||
draw.RectCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
),
|
||||
)
|
||||
testdraw.MustText(c, " ███", image.Point{0, 3}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "█", image.Point{3, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustText(c, "███", image.Point{1, 2}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustText(c, "███", image.Point{1, 3}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustRectangle(c, image.Rect(1, 3, 4, 4),
|
||||
draw.RectChar('█'),
|
||||
draw.RectCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
),
|
||||
)
|
||||
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
@ -246,47 +185,32 @@ func TestSparkLine(t *testing.T) {
|
||||
{
|
||||
desc: "stretches up to the height of the container with label",
|
||||
sparkLine: New(
|
||||
Label("Hello"),
|
||||
Label("zoo"),
|
||||
),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(0, 90, 30, 85)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 9, 4),
|
||||
canvas: image.Rect(0, 0, 4, 4),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, "Hello", image.Point{0, 0})
|
||||
testdraw.MustText(c, " █ ▇", image.Point{0, 1}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "zoo", image.Point{0, 0})
|
||||
testdraw.MustText(c, "█", image.Point{1, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{1, 1}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testdraw.MustText(c, " █ █", image.Point{0, 2}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "▇", image.Point{3, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{1, 2}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
testcanvas.MustSetCell(c, image.Point{3, 2}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testdraw.MustText(c, " ███", image.Point{0, 3}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "█", image.Point{1, 2}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustText(c, "█", image.Point{3, 2}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustText(c, "███", image.Point{1, 3}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustRectangle(c, image.Rect(1, 3, 4, 4),
|
||||
draw.RectChar('█'),
|
||||
draw.RectCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
),
|
||||
)
|
||||
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
@ -300,29 +224,20 @@ func TestSparkLine(t *testing.T) {
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(0, 100, 50, 85)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 9, 4),
|
||||
canvas: image.Rect(0, 0, 4, 4),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, " █ ▆", image.Point{0, 2}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "█", image.Point{1, 2}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{1, 2}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testdraw.MustText(c, " ███", image.Point{0, 3}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "▆", image.Point{3, 2}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustText(c, "███", image.Point{1, 3}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustRectangle(c, image.Rect(1, 3, 4, 4),
|
||||
draw.RectChar('█'),
|
||||
draw.RectCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
),
|
||||
)
|
||||
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
@ -335,34 +250,22 @@ func TestSparkLine(t *testing.T) {
|
||||
Height(2),
|
||||
),
|
||||
update: func(sl *SparkLine) error {
|
||||
return sl.Add(0, 100, 50, 85)
|
||||
return sl.Add(0, 100, 50, 0)
|
||||
},
|
||||
canvas: image.Rect(0, 0, 9, 4),
|
||||
canvas: image.Rect(0, 0, 4, 4),
|
||||
want: func(size image.Point) *faketerm.Terminal {
|
||||
ft := faketerm.MustNew(size)
|
||||
c := testcanvas.MustNew(ft.Area())
|
||||
|
||||
testdraw.MustText(c, "zoo", image.Point{0, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(cell.ColorDefault),
|
||||
))
|
||||
testdraw.MustText(c, "█", image.Point{1, 2}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustText(c, " █ ▆", image.Point{0, 2}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "██", image.Point{1, 3}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{1, 2}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testdraw.MustText(c, " ███", image.Point{0, 3}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testdraw.MustRectangle(c, image.Rect(1, 3, 4, 4),
|
||||
draw.RectChar('█'),
|
||||
draw.RectCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
),
|
||||
)
|
||||
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
@ -389,7 +292,7 @@ func TestSparkLine(t *testing.T) {
|
||||
cell.FgColor(cell.ColorBlue),
|
||||
cell.BgColor(cell.ColorYellow),
|
||||
))
|
||||
testdraw.MustText(c, " ▁", image.Point{0, 1}, draw.TextCellOpts(
|
||||
testdraw.MustText(c, "█", image.Point{8, 1}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
|
||||
@ -411,10 +314,6 @@ func TestSparkLine(t *testing.T) {
|
||||
testdraw.MustText(c, "▆▇█", image.Point{0, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{2, 0}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
@ -434,10 +333,6 @@ func TestSparkLine(t *testing.T) {
|
||||
testdraw.MustText(c, "▄█", image.Point{0, 0}, draw.TextCellOpts(
|
||||
cell.FgColor(DefaultColor),
|
||||
))
|
||||
testcanvas.MustSetCell(c, image.Point{1, 0}, '█',
|
||||
cell.FgColor(DefaultColor),
|
||||
cell.BgColor(DefaultColor),
|
||||
)
|
||||
|
||||
testcanvas.MustApply(c, ft)
|
||||
return ft
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/mum4k/termdash"
|
||||
"github.com/mum4k/termdash/cell"
|
||||
"github.com/mum4k/termdash/container"
|
||||
"github.com/mum4k/termdash/draw"
|
||||
"github.com/mum4k/termdash/terminal/termbox"
|
||||
@ -44,14 +45,48 @@ func main() {
|
||||
defer t.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
bc := sparkline.New()
|
||||
go playSparkLine(ctx, bc, 1*time.Second)
|
||||
green := sparkline.New(
|
||||
sparkline.Label("Green SparkLine", cell.FgColor(cell.ColorBlue)),
|
||||
)
|
||||
go playSparkLine(ctx, green, 250*time.Millisecond)
|
||||
red := sparkline.New(
|
||||
sparkline.Label("Red SparkLine", cell.FgColor(cell.ColorBlue)),
|
||||
sparkline.Color(cell.ColorRed),
|
||||
)
|
||||
go playSparkLine(ctx, red, 500*time.Millisecond)
|
||||
yellow := sparkline.New(
|
||||
sparkline.Label("Yellow SparkLine", cell.FgColor(cell.ColorGreen)),
|
||||
sparkline.Color(cell.ColorYellow),
|
||||
)
|
||||
go playSparkLine(ctx, yellow, 1*time.Second)
|
||||
|
||||
c := container.New(
|
||||
t,
|
||||
container.Border(draw.LineStyleLight),
|
||||
container.BorderTitle("PRESS Q TO QUIT"),
|
||||
container.PlaceWidget(bc),
|
||||
container.SplitVertical(
|
||||
container.Left(
|
||||
container.SplitHorizontal(
|
||||
container.Top(),
|
||||
container.Bottom(
|
||||
container.Border(draw.LineStyleLight),
|
||||
container.BorderTitle("SparkLine group"),
|
||||
container.SplitHorizontal(
|
||||
container.Top(
|
||||
container.PlaceWidget(green),
|
||||
),
|
||||
container.Bottom(
|
||||
container.PlaceWidget(red),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
container.Right(
|
||||
container.Border(draw.LineStyleLight),
|
||||
container.PlaceWidget(yellow),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
quitter := func(k *terminalapi.Keyboard) {
|
||||
|
@ -12,9 +12,11 @@ import "math"
|
||||
var sparks = []rune{'▁', '▂', '▃', '▄', '▅', '▆', '▇', '█'}
|
||||
|
||||
// visibleMax determines the maximum visible data point given the canvas width.
|
||||
func visibleMax(data []int, width int) int {
|
||||
// Returns a slice that contains only visible data points and the maximum value
|
||||
// among them.
|
||||
func visibleMax(data []int, width int) ([]int, int) {
|
||||
if width <= 0 || len(data) == 0 {
|
||||
return 0
|
||||
return nil, 0
|
||||
}
|
||||
|
||||
if width < len(data) {
|
||||
@ -27,7 +29,7 @@ func visibleMax(data []int, width int) int {
|
||||
max = v
|
||||
}
|
||||
}
|
||||
return max
|
||||
return data, max
|
||||
}
|
||||
|
||||
// blocks represents blocks that display one value on a SparkLine.
|
||||
|
@ -8,65 +8,77 @@ import (
|
||||
|
||||
func TestVisibleMax(t *testing.T) {
|
||||
tests := []struct {
|
||||
desc string
|
||||
data []int
|
||||
width int
|
||||
want int
|
||||
desc string
|
||||
data []int
|
||||
width int
|
||||
wantData []int
|
||||
wantMax int
|
||||
}{
|
||||
{
|
||||
desc: "zero for no data",
|
||||
width: 3,
|
||||
want: 0,
|
||||
desc: "zero for no data",
|
||||
width: 3,
|
||||
wantData: nil,
|
||||
wantMax: 0,
|
||||
},
|
||||
{
|
||||
desc: "zero for zero width",
|
||||
data: []int{0, 1},
|
||||
width: 0,
|
||||
want: 0,
|
||||
desc: "zero for zero width",
|
||||
data: []int{0, 1},
|
||||
width: 0,
|
||||
wantData: nil,
|
||||
wantMax: 0,
|
||||
},
|
||||
{
|
||||
desc: "zero for negative width",
|
||||
data: []int{0, 1},
|
||||
width: -1,
|
||||
want: 0,
|
||||
desc: "zero for negative width",
|
||||
data: []int{0, 1},
|
||||
width: -1,
|
||||
wantData: nil,
|
||||
wantMax: 0,
|
||||
},
|
||||
{
|
||||
desc: "all values are zero",
|
||||
data: []int{0, 0, 0},
|
||||
width: 3,
|
||||
want: 0,
|
||||
desc: "all values are zero",
|
||||
data: []int{0, 0, 0},
|
||||
width: 3,
|
||||
wantData: []int{0, 0, 0},
|
||||
wantMax: 0,
|
||||
},
|
||||
{
|
||||
desc: "all values are visible",
|
||||
data: []int{8, 0, 1},
|
||||
width: 3,
|
||||
want: 8,
|
||||
desc: "all values are visible",
|
||||
data: []int{8, 0, 1},
|
||||
width: 3,
|
||||
wantData: []int{8, 0, 1},
|
||||
wantMax: 8,
|
||||
},
|
||||
{
|
||||
desc: "width greater than number of values",
|
||||
data: []int{8, 0, 1},
|
||||
width: 10,
|
||||
want: 8,
|
||||
desc: "width greater than number of values",
|
||||
data: []int{8, 0, 1},
|
||||
width: 10,
|
||||
wantData: []int{8, 0, 1},
|
||||
wantMax: 8,
|
||||
},
|
||||
{
|
||||
desc: "only some values are visible",
|
||||
data: []int{8, 2, 1},
|
||||
width: 2,
|
||||
want: 2,
|
||||
desc: "only some values are visible",
|
||||
data: []int{8, 2, 1},
|
||||
width: 2,
|
||||
wantData: []int{2, 1},
|
||||
wantMax: 2,
|
||||
},
|
||||
{
|
||||
desc: "only one value is visible",
|
||||
data: []int{8, 2, 1},
|
||||
width: 1,
|
||||
want: 1,
|
||||
desc: "only one value is visible",
|
||||
data: []int{8, 2, 1},
|
||||
width: 1,
|
||||
wantData: []int{1},
|
||||
wantMax: 1,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
got := visibleMax(tc.data, tc.width)
|
||||
if got != tc.want {
|
||||
t.Errorf("visibleMax => got %v, want %v", got, tc.want)
|
||||
gotData, gotMax := visibleMax(tc.data, tc.width)
|
||||
if diff := pretty.Compare(tc.wantData, gotData); diff != "" {
|
||||
t.Errorf("visibleMax => unexpected visible data, diff (-want, +got):\n%s", diff)
|
||||
}
|
||||
if gotMax != tc.wantMax {
|
||||
t.Errorf("visibleMax => gotMax %v, wantMax %v", gotMax, tc.wantMax)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user