poller implementation
This commit is contained in:
parent
34a3c0845d
commit
dd146c72f0
20
config.yml
20
config.yml
|
@ -4,21 +4,27 @@ line-charts:
|
||||||
data:
|
data:
|
||||||
- label: example.com
|
- label: example.com
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' http://example.com
|
script: curl -o /dev/null -s -w '%{time_total}' http://example.com
|
||||||
color: red
|
|
||||||
- label: google.com
|
- label: google.com
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' http://google.com
|
script: curl -o /dev/null -s -w '%{time_total}' http://google.com
|
||||||
color: yellow
|
refresh-rate-ms: 200
|
||||||
refresh-rate-ms: 100
|
|
||||||
time-scale-sec: 1
|
time-scale-sec: 1
|
||||||
style: dots/lines
|
style: dots/lines
|
||||||
position:
|
position:
|
||||||
x: 1
|
x: 0
|
||||||
y: 2
|
y: 0
|
||||||
size:
|
size:
|
||||||
x: 3
|
x: 15
|
||||||
y: 4
|
y: 15
|
||||||
- title: mongo-count
|
- title: mongo-count
|
||||||
data:
|
data:
|
||||||
- label: posts
|
- label: posts
|
||||||
script: mongo --quiet --host=localhost blog --eval "db.getCollection('post').find({}).size()" | grep 2
|
script: mongo --quiet --host=localhost blog --eval "db.getCollection('post').find({}).size()" | grep 2
|
||||||
color: red
|
color: red
|
||||||
|
refresh-rate-ms: 200
|
||||||
|
time-scale-sec: 1
|
||||||
|
position:
|
||||||
|
x: 15
|
||||||
|
y: 0
|
||||||
|
size:
|
||||||
|
x: 15
|
||||||
|
y: 15
|
|
@ -1,13 +1,28 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
. "github.com/sqshq/vcmd/layout"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
LineCharts []LineChartConfig `yaml:"line-charts"`
|
LineChartConfigs []LineChartConfig `yaml:"line-charts"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DataConfig struct {
|
||||||
|
Script string `yaml:"script"`
|
||||||
|
Label string `yaml:"label"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LineChartConfig struct {
|
||||||
|
Title string `yaml:"title"`
|
||||||
|
DataConfig []DataConfig `yaml:"data"`
|
||||||
|
Position Position `yaml:"position"`
|
||||||
|
Size Size `yaml:"size"`
|
||||||
|
RefreshRateMs int `yaml:"refresh-rate-ms"`
|
||||||
|
TimeScaleSec int `yaml:"time-scale-sec"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func Load(location string) *Config {
|
func Load(location string) *Config {
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
"os/exec"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Data struct {
|
|
||||||
Label string `yaml:"label"`
|
|
||||||
Color string `yaml:"color"`
|
|
||||||
Script string `yaml:"script"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *Data) NextValue() (float64, error) {
|
|
||||||
|
|
||||||
output, err := exec.Command("sh", "-c", d.Script).Output()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("%s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
trimmedOutput := strings.TrimSpace(string(output))
|
|
||||||
floatValue, err := strconv.ParseFloat(trimmedOutput, 64)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return 0, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return floatValue, nil
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
type LineChartConfig struct {
|
|
||||||
Title string `yaml:"title"`
|
|
||||||
Data []Data `yaml:"data"`
|
|
||||||
Position Position `yaml:"position"`
|
|
||||||
Size Size `yaml:"size"`
|
|
||||||
RefreshRateMs int `yaml:"refresh-rate-ms"`
|
|
||||||
Scale string `yaml:"scale"`
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
type Position struct {
|
|
||||||
X int `yaml:"x"`
|
|
||||||
Y int `yaml:"y"`
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
package config
|
|
||||||
|
|
||||||
type Size struct {
|
|
||||||
X int `yaml:"x"`
|
|
||||||
Y int `yaml:"y"`
|
|
||||||
}
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
package data
|
||||||
|
|
||||||
|
type Consumer interface {
|
||||||
|
ConsumeValue(value string, label string)
|
||||||
|
ConsumeError(err error)
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package data
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Poller struct {
|
||||||
|
consumer Consumer
|
||||||
|
script string
|
||||||
|
label string
|
||||||
|
pause bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewPoller(consumer Consumer, script string, label string, rateMs int) Poller {
|
||||||
|
|
||||||
|
ticker := time.NewTicker(time.Duration(rateMs * int(time.Millisecond)))
|
||||||
|
poller := Poller{consumer, script, label, false}
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-ticker.C:
|
||||||
|
poller.poll()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return poller
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Poller) TogglePause() {
|
||||||
|
self.pause = !self.pause
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Poller) poll() {
|
||||||
|
|
||||||
|
if self.pause {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
output, err := exec.Command("sh", "-c", self.script).Output()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
self.consumer.ConsumeError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
value := strings.TrimSpace(string(output))
|
||||||
|
self.consumer.ConsumeValue(value, self.label)
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
package layout
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/sqshq/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Item struct {
|
||||||
|
Data Drawable
|
||||||
|
Position Position
|
||||||
|
Size Size
|
||||||
|
}
|
||||||
|
|
||||||
|
type Position struct {
|
||||||
|
X int `yaml:"x"`
|
||||||
|
Y int `yaml:"y"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Size struct {
|
||||||
|
X int `yaml:"x"`
|
||||||
|
Y int `yaml:"y"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Item) MoveItem(x, y int) {
|
||||||
|
self.Position.X += x
|
||||||
|
self.Position.Y += y
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Item) ResizeItem(x, y int) {
|
||||||
|
self.Size.X += x
|
||||||
|
self.Size.Y += y
|
||||||
|
}
|
|
@ -0,0 +1,51 @@
|
||||||
|
package layout
|
||||||
|
|
||||||
|
import (
|
||||||
|
. "github.com/sqshq/termui"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Layout struct {
|
||||||
|
Block
|
||||||
|
items []Item
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
columnsCount = 30
|
||||||
|
rowsCount = 30
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewLayout(width, height int) *Layout {
|
||||||
|
|
||||||
|
block := *NewBlock()
|
||||||
|
block.SetRect(0, 0, width, height)
|
||||||
|
|
||||||
|
return &Layout{
|
||||||
|
Block: block,
|
||||||
|
items: make([]Item, 0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Layout) AddItem(drawable Drawable, position Position, size Size) {
|
||||||
|
self.items = append(self.items, Item{drawable, position, size})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Layout) ChangeDimensions(width, height int) {
|
||||||
|
self.SetRect(0, 0, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *Layout) Draw(buf *Buffer) {
|
||||||
|
|
||||||
|
columnWidth := float64(self.GetRect().Dx()) / columnsCount
|
||||||
|
rowHeight := float64(self.GetRect().Dy()) / rowsCount
|
||||||
|
|
||||||
|
for _, item := range self.items {
|
||||||
|
|
||||||
|
x1 := float64(item.Position.X) * columnWidth
|
||||||
|
y1 := float64(item.Position.Y) * rowHeight
|
||||||
|
x2 := x1 + float64(item.Size.X)*columnWidth
|
||||||
|
y2 := y1 + float64(item.Size.Y)*rowHeight
|
||||||
|
|
||||||
|
item.Data.SetRect(int(x1), int(y1), int(x2), int(y2))
|
||||||
|
item.Data.Draw(buf)
|
||||||
|
}
|
||||||
|
}
|
94
main.go
94
main.go
|
@ -3,100 +3,80 @@ package main
|
||||||
import (
|
import (
|
||||||
ui "github.com/sqshq/termui"
|
ui "github.com/sqshq/termui"
|
||||||
"github.com/sqshq/vcmd/config"
|
"github.com/sqshq/vcmd/config"
|
||||||
|
"github.com/sqshq/vcmd/data"
|
||||||
|
"github.com/sqshq/vcmd/layout"
|
||||||
"github.com/sqshq/vcmd/widgets"
|
"github.com/sqshq/vcmd/widgets"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO validation
|
||||||
|
- title uniquness and mandatory within a single type of widget
|
||||||
|
- label uniqueness and mandatory (if > 1 data bullets)
|
||||||
|
*/
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
// todo error handling + validation
|
||||||
cfg := config.Load("/Users/sqshq/Go/src/github.com/sqshq/vcmd/config.yml")
|
cfg := config.Load("/Users/sqshq/Go/src/github.com/sqshq/vcmd/config.yml")
|
||||||
|
|
||||||
for _, linechart := range cfg.LineCharts {
|
|
||||||
for _, data := range linechart.Data {
|
|
||||||
value, _ := data.NextValue()
|
|
||||||
log.Printf("%s: %s - %v", linechart.Title, data.Label, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p1 := widgets.NewTimePlot()
|
|
||||||
p1.Title = " CURL LATENCY STATISTICS (sec) "
|
|
||||||
p1.LineColors[0] = ui.ColorYellow
|
|
||||||
p1.Marker = widgets.MarkerBraille
|
|
||||||
|
|
||||||
p2 := widgets.NewTimePlot()
|
|
||||||
p2.Title = " CURL LATENCY STATISTICS 2 (sec) "
|
|
||||||
p2.LineColors[0] = ui.ColorYellow
|
|
||||||
p2.Marker = widgets.MarkerBraille
|
|
||||||
|
|
||||||
if err := ui.Init(); err != nil {
|
if err := ui.Init(); err != nil {
|
||||||
//log.Fatalf("failed to initialize termui: %v", err)
|
log.Fatalf("failed to initialize termui: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
defer ui.Close()
|
defer ui.Close()
|
||||||
uiEvents := ui.PollEvents()
|
events := ui.PollEvents()
|
||||||
|
|
||||||
layout := widgets.NewLayout(ui.TerminalDimensions())
|
pollers := make([]data.Poller, 0)
|
||||||
layout.AddItem(p1, 0, 0, 6, 6)
|
lout := layout.NewLayout(ui.TerminalDimensions())
|
||||||
layout.AddItem(p2, 0, 6, 6, 12)
|
|
||||||
|
|
||||||
dataTicker := time.NewTicker(200 * time.Millisecond)
|
for _, chartConfig := range cfg.LineChartConfigs {
|
||||||
uiTicker := time.NewTicker(50 * time.Millisecond)
|
|
||||||
|
|
||||||
pause := false
|
chart := widgets.NewTimePlot(chartConfig.Title)
|
||||||
|
lout.AddItem(chart, chartConfig.Position, chartConfig.Size)
|
||||||
|
|
||||||
go func() {
|
for _, chartData := range chartConfig.DataConfig {
|
||||||
for {
|
pollers = append(pollers,
|
||||||
select {
|
data.NewPoller(chart, chartData.Script, chartData.Label, chartConfig.RefreshRateMs))
|
||||||
case <-dataTicker.C:
|
|
||||||
if !pause {
|
|
||||||
value, err := cfg.LineCharts[0].Data[0].NextValue()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("failed to get value: %s", err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
p1.AddValue(value)
|
|
||||||
p2.AddValue(value)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}()
|
ticker := time.NewTicker(50 * time.Millisecond)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case e := <-uiEvents:
|
case e := <-events:
|
||||||
switch e.ID {
|
switch e.ID {
|
||||||
case "q", "<C-c>": // press 'q' or 'C-c' to quit
|
case "q", "<C-c>":
|
||||||
return
|
return
|
||||||
case "<Resize>":
|
case "<Resize>":
|
||||||
payload := e.Payload.(ui.Resize)
|
payload := e.Payload.(ui.Resize)
|
||||||
layout.ChangeDimensions(payload.Width, payload.Height)
|
lout.ChangeDimensions(payload.Width, payload.Height)
|
||||||
|
case "<MouseLeft>":
|
||||||
|
//payload := e.Payload.(ui.Mouse)
|
||||||
|
//x, y := payload.X, payload.Y
|
||||||
|
//log.Printf("x: %v, y: %v", x, y)
|
||||||
}
|
}
|
||||||
//case "<MouseLeft>":
|
|
||||||
// payload := e.Payload.(ui.Mouse)
|
|
||||||
// x, y := payload.X, payload.Y
|
|
||||||
// log.Printf("x: %v, y: %v", x, y)
|
|
||||||
//}
|
|
||||||
switch e.Type {
|
switch e.Type {
|
||||||
case ui.KeyboardEvent: // handle all key presses
|
case ui.KeyboardEvent:
|
||||||
//log.Printf("key: %v", e.ID)
|
|
||||||
switch e.ID {
|
switch e.ID {
|
||||||
case "<Left>":
|
case "<Left>":
|
||||||
layout.MoveItem(-1, 0)
|
// here we are going to move selection (special type of layout item)
|
||||||
|
//lout.GetItem("").MoveItem(-1, 0)
|
||||||
case "<Right>":
|
case "<Right>":
|
||||||
layout.MoveItem(1, 0)
|
//lout.GetItem(0).MoveItem(1, 0)
|
||||||
case "<Down>":
|
case "<Down>":
|
||||||
layout.MoveItem(0, 1)
|
//lout.GetItem(0).MoveItem(0, 1)
|
||||||
case "<Up>":
|
case "<Up>":
|
||||||
layout.MoveItem(0, -1)
|
//lout.GetItem(0).MoveItem(0, -1)
|
||||||
case "p":
|
case "p":
|
||||||
pause = !pause
|
for _, poller := range pollers {
|
||||||
|
poller.TogglePause()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-uiTicker.C:
|
|
||||||
if !pause {
|
|
||||||
ui.Render(layout)
|
|
||||||
}
|
}
|
||||||
|
case <-ticker.C:
|
||||||
|
ui.Render(lout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ const (
|
||||||
yBrailleMultiplier = 4
|
yBrailleMultiplier = 4
|
||||||
)
|
)
|
||||||
|
|
||||||
func braille(point image.Point) image.Point {
|
func braillePoint(point image.Point) image.Point {
|
||||||
return image.Point{X: point.X * xBrailleMultiplier, Y: point.Y * yBrailleMultiplier}
|
return image.Point{X: point.X * xBrailleMultiplier, Y: point.Y * yBrailleMultiplier}
|
||||||
}
|
}
|
||||||
|
|
||||||
func deBraille(point image.Point) image.Point {
|
func debraillePoint(point image.Point) image.Point {
|
||||||
return image.Point{X: point.X / xBrailleMultiplier, Y: point.Y / yBrailleMultiplier}
|
return image.Point{X: point.X / xBrailleMultiplier, Y: point.Y / yBrailleMultiplier}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,81 +0,0 @@
|
||||||
package widgets
|
|
||||||
|
|
||||||
import (
|
|
||||||
. "github.com/sqshq/termui"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Item struct {
|
|
||||||
drawable Drawable
|
|
||||||
coordinates ItemCoordinates
|
|
||||||
}
|
|
||||||
|
|
||||||
type ItemCoordinates struct {
|
|
||||||
x1 int
|
|
||||||
y1 int
|
|
||||||
x2 int
|
|
||||||
y2 int
|
|
||||||
}
|
|
||||||
|
|
||||||
type LayoutDimensions struct {
|
|
||||||
width int
|
|
||||||
height int
|
|
||||||
}
|
|
||||||
|
|
||||||
type Layout struct {
|
|
||||||
Block
|
|
||||||
dimensions LayoutDimensions
|
|
||||||
items []Item
|
|
||||||
}
|
|
||||||
|
|
||||||
const (
|
|
||||||
columnsCount = 12
|
|
||||||
rowsCount = 12
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewLayout(width, height int) *Layout {
|
|
||||||
|
|
||||||
b := *NewBlock()
|
|
||||||
b.SetRect(0, 0, width, height)
|
|
||||||
|
|
||||||
return &Layout{
|
|
||||||
Block: b,
|
|
||||||
dimensions: LayoutDimensions{width, height},
|
|
||||||
items: make([]Item, 0),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Layout) AddItem(drawable interface{}, x1, y1, x2, y2 int) {
|
|
||||||
self.items = append(self.items, Item{
|
|
||||||
drawable: drawable.(Drawable),
|
|
||||||
coordinates: ItemCoordinates{x1, y1, x2, y2},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Layout) MoveItem(x, y int) {
|
|
||||||
self.items[0].coordinates.x1 += x
|
|
||||||
self.items[0].coordinates.y1 += y
|
|
||||||
self.items[0].coordinates.x2 += x
|
|
||||||
self.items[0].coordinates.y2 += y
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Layout) ChangeDimensions(width, height int) {
|
|
||||||
self.dimensions = LayoutDimensions{width, height}
|
|
||||||
self.SetRect(0, 0, width, height)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Layout) Draw(buf *Buffer) {
|
|
||||||
|
|
||||||
columnWidth := float64(self.dimensions.width) / columnsCount
|
|
||||||
rowHeight := float64(self.dimensions.height) / rowsCount
|
|
||||||
|
|
||||||
for _, item := range self.items {
|
|
||||||
|
|
||||||
x1 := float64(item.coordinates.x1) * columnWidth
|
|
||||||
y1 := float64(item.coordinates.y1) * rowHeight
|
|
||||||
x2 := float64(item.coordinates.x2) * columnWidth
|
|
||||||
y2 := float64(item.coordinates.y2) * rowHeight
|
|
||||||
|
|
||||||
item.drawable.SetRect(int(x1), int(y1), int(x2), int(y2))
|
|
||||||
item.drawable.Draw(buf)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -3,21 +3,21 @@ package widgets
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"image"
|
"image"
|
||||||
|
"log"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "github.com/sqshq/termui"
|
. "github.com/sqshq/termui"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TimePlot struct {
|
type TimePlot struct { // TODO rename to linechart
|
||||||
Block
|
Block
|
||||||
DataLabels []string
|
DataLabels []string
|
||||||
MaxValueTimePoint TimePoint
|
MaxValueTimePoint TimePoint
|
||||||
LineColors []Color
|
LineColors []Color
|
||||||
ShowAxes bool
|
|
||||||
DotRune rune
|
DotRune rune
|
||||||
HorizontalScale int
|
HorizontalScale int
|
||||||
Marker PlotMarker
|
|
||||||
|
|
||||||
timePoints []TimePoint
|
timePoints []TimePoint
|
||||||
dataMutex *sync.Mutex
|
dataMutex *sync.Mutex
|
||||||
|
@ -37,21 +37,15 @@ type TimePoint struct {
|
||||||
Time time.Time
|
Time time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
type PlotMarker uint
|
func NewTimePlot(title string) *TimePlot {
|
||||||
|
block := *NewBlock()
|
||||||
const (
|
block.Title = title
|
||||||
MarkerBraille PlotMarker = iota
|
//self.LineColors[0] = ui.ColorYellow
|
||||||
MarkerDot
|
|
||||||
)
|
|
||||||
|
|
||||||
func NewTimePlot() *TimePlot {
|
|
||||||
return &TimePlot{
|
return &TimePlot{
|
||||||
Block: *NewBlock(),
|
Block: block,
|
||||||
LineColors: Theme.Plot.Lines,
|
LineColors: Theme.Plot.Lines,
|
||||||
DotRune: DOT,
|
DotRune: DOT,
|
||||||
HorizontalScale: 1,
|
HorizontalScale: 1,
|
||||||
ShowAxes: true,
|
|
||||||
Marker: MarkerBraille,
|
|
||||||
timePoints: make([]TimePoint, 0),
|
timePoints: make([]TimePoint, 0),
|
||||||
dataMutex: &sync.Mutex{},
|
dataMutex: &sync.Mutex{},
|
||||||
}
|
}
|
||||||
|
@ -93,10 +87,7 @@ func (self *TimePlot) Draw(buf *Buffer) {
|
||||||
self.dataMutex.Lock()
|
self.dataMutex.Lock()
|
||||||
self.Block.Draw(buf)
|
self.Block.Draw(buf)
|
||||||
self.grid = self.newPlotGrid()
|
self.grid = self.newPlotGrid()
|
||||||
|
|
||||||
if self.ShowAxes {
|
|
||||||
self.plotAxes(buf)
|
self.plotAxes(buf)
|
||||||
}
|
|
||||||
|
|
||||||
drawArea := image.Rect(
|
drawArea := image.Rect(
|
||||||
self.Inner.Min.X+yAxisLabelsWidth+1, self.Inner.Min.Y,
|
self.Inner.Min.X+yAxisLabelsWidth+1, self.Inner.Min.Y,
|
||||||
|
@ -107,13 +98,23 @@ func (self *TimePlot) Draw(buf *Buffer) {
|
||||||
self.dataMutex.Unlock()
|
self.dataMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *TimePlot) AddValue(value float64) {
|
func (self *TimePlot) ConsumeValue(value string, label string) {
|
||||||
|
|
||||||
|
float, err := strconv.ParseFloat(value, 64)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Expected float number, but got %v", value) // TODO visual notification
|
||||||
|
}
|
||||||
|
|
||||||
self.dataMutex.Lock()
|
self.dataMutex.Lock()
|
||||||
self.timePoints = append(self.timePoints, TimePoint{Value: value, Time: time.Now()})
|
self.timePoints = append(self.timePoints, TimePoint{Value: float, Time: time.Now()})
|
||||||
self.trimOutOfRangeValues()
|
self.trimOutOfRangeValues()
|
||||||
self.dataMutex.Unlock()
|
self.dataMutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *TimePlot) ConsumeError(err error) {
|
||||||
|
// TODO visual notification
|
||||||
|
}
|
||||||
|
|
||||||
func (self *TimePlot) trimOutOfRangeValues() {
|
func (self *TimePlot) trimOutOfRangeValues() {
|
||||||
|
|
||||||
lastOutOfRangeValueIndex := -1
|
lastOutOfRangeValueIndex := -1
|
||||||
|
@ -175,8 +176,8 @@ func (self *TimePlot) renderBraille(buf *Buffer, drawArea image.Rectangle) {
|
||||||
//)
|
//)
|
||||||
|
|
||||||
canvas.Line(
|
canvas.Line(
|
||||||
braille(previousPoint),
|
braillePoint(previousPoint),
|
||||||
braille(currentPoint),
|
braillePoint(currentPoint),
|
||||||
SelectColor(self.LineColors, 0), //i
|
SelectColor(self.LineColors, 0), //i
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue