sampler-fork/component/gauge/gauge.go

125 lines
2.6 KiB
Go

package gauge
import (
"fmt"
ui "github.com/gizak/termui/v3"
"github.com/sqshq/sampler/component"
"github.com/sqshq/sampler/console"
"github.com/sqshq/sampler/data"
"image"
"math"
"strconv"
)
const (
MinValueLabel = "min"
MaxValueLabel = "max"
CurValueLabel = "cur"
)
type Gauge struct {
ui.Block
data.Consumer
*component.Alerter
minValue float64
maxValue float64
curValue float64
scale int
color ui.Color
}
func NewGauge(title string, scale int, color ui.Color) *Gauge {
consumer := data.NewConsumer()
block := *ui.NewBlock()
block.Title = title
gauge := Gauge{
Block: block,
Consumer: consumer,
Alerter: component.NewAlerter(consumer.AlertChannel),
scale: scale,
color: color,
}
go gauge.consume()
return &gauge
}
func (g *Gauge) consume() {
for {
select {
case sample := <-g.SampleChannel:
g.ConsumeSample(sample)
//case alert := <-g.alertChannel:
// TODO base alerting mechanism
}
}
}
func (g *Gauge) ConsumeSample(sample data.Sample) {
float, err := strconv.ParseFloat(sample.Value, 64)
if err != nil {
// TODO visual notification + check sample.Error
}
switch sample.Label {
case MinValueLabel:
g.minValue = float
break
case MaxValueLabel:
g.maxValue = float
break
case CurValueLabel:
g.curValue = float
break
}
}
func (g *Gauge) Draw(buf *ui.Buffer) {
g.Block.Draw(buf)
percent := 0.0
if g.curValue != 0 && g.maxValue != g.minValue {
percent = (100 * g.curValue) / (g.maxValue - g.minValue)
}
label := fmt.Sprintf("%v%% (%v)", formatValue(percent, g.scale), g.curValue)
// plot bar
barWidth := int((percent / 100) * float64(g.Inner.Dx()))
if barWidth == 0 {
barWidth = 1
} else if barWidth > g.Dx()-2 {
barWidth = g.Dx() - 2
}
buf.Fill(
ui.NewCell(console.SymbolVerticalBar, ui.NewStyle(g.color)),
image.Rect(g.Inner.Min.X+1, g.Inner.Min.Y, g.Inner.Min.X+barWidth, g.Inner.Max.Y),
)
// plot label
labelXCoordinate := g.Inner.Min.X + (g.Inner.Dx() / 2) - int(float64(len(label))/2)
labelYCoordinate := g.Inner.Min.Y + ((g.Inner.Dy() - 1) / 2)
if labelYCoordinate < g.Inner.Max.Y {
for i, char := range label {
style := ui.NewStyle(console.ColorWhite)
if labelXCoordinate+i+1 <= g.Inner.Min.X+barWidth {
style = ui.NewStyle(console.ColorWhite, ui.ColorClear)
}
buf.SetCell(ui.NewCell(char, style), image.Pt(labelXCoordinate+i, labelYCoordinate))
}
}
}
// TODO extract to utils
func formatValue(value float64, scale int) string {
if math.Abs(value) == math.MaxFloat64 {
return "Inf"
} else {
format := "%." + strconv.Itoa(scale) + "f"
return fmt.Sprintf(format, value)
}
}