renaming and refactoring

This commit is contained in:
sqshq 2019-01-30 20:41:51 -05:00
parent dd146c72f0
commit b71d5556c2
6 changed files with 104 additions and 93 deletions

View File

@ -1,5 +1,5 @@
theme: dark / bright theme: dark / bright
line-charts: run-charts:
- title: curl-latency - title: curl-latency
data: data:
- label: example.com - label: example.com

View File

@ -8,7 +8,7 @@ import (
) )
type Config struct { type Config struct {
LineChartConfigs []LineChartConfig `yaml:"line-charts"` RunCharts []RunChart `yaml:"run-charts"`
} }
type DataConfig struct { type DataConfig struct {
@ -16,7 +16,7 @@ type DataConfig struct {
Label string `yaml:"label"` Label string `yaml:"label"`
} }
type LineChartConfig struct { type RunChart struct {
Title string `yaml:"title"` Title string `yaml:"title"`
DataConfig []DataConfig `yaml:"data"` DataConfig []DataConfig `yaml:"data"`
Position Position `yaml:"position"` Position Position `yaml:"position"`

View File

@ -4,8 +4,8 @@ import (
. "github.com/sqshq/termui" . "github.com/sqshq/termui"
) )
type Item struct { type Component struct {
Data Drawable Drawable Drawable
Position Position Position Position
Size Size Size Size
} }
@ -20,12 +20,12 @@ type Size struct {
Y int `yaml:"y"` Y int `yaml:"y"`
} }
func (self *Item) MoveItem(x, y int) { func (self *Component) Move(x, y int) {
self.Position.X += x self.Position.X += x
self.Position.Y += y self.Position.Y += y
} }
func (self *Item) ResizeItem(x, y int) { func (self *Component) Resize(x, y int) {
self.Size.X += x self.Size.X += x
self.Size.Y += y self.Size.Y += y
} }

View File

@ -6,7 +6,7 @@ import (
type Layout struct { type Layout struct {
Block Block
items []Item components []Component
} }
const ( const (
@ -21,12 +21,12 @@ func NewLayout(width, height int) *Layout {
return &Layout{ return &Layout{
Block: block, Block: block,
items: make([]Item, 0), components: make([]Component, 0),
} }
} }
func (self *Layout) AddItem(drawable Drawable, position Position, size Size) { func (self *Layout) AddItem(drawable Drawable, position Position, size Size) {
self.items = append(self.items, Item{drawable, position, size}) self.components = append(self.components, Component{drawable, position, size})
} }
func (self *Layout) ChangeDimensions(width, height int) { func (self *Layout) ChangeDimensions(width, height int) {
@ -38,14 +38,14 @@ func (self *Layout) Draw(buf *Buffer) {
columnWidth := float64(self.GetRect().Dx()) / columnsCount columnWidth := float64(self.GetRect().Dx()) / columnsCount
rowHeight := float64(self.GetRect().Dy()) / rowsCount rowHeight := float64(self.GetRect().Dy()) / rowsCount
for _, item := range self.items { for _, component := range self.components {
x1 := float64(item.Position.X) * columnWidth x1 := float64(component.Position.X) * columnWidth
y1 := float64(item.Position.Y) * rowHeight y1 := float64(component.Position.Y) * rowHeight
x2 := x1 + float64(item.Size.X)*columnWidth x2 := x1 + float64(component.Size.X)*columnWidth
y2 := y1 + float64(item.Size.Y)*rowHeight y2 := y1 + float64(component.Size.Y)*rowHeight
item.Data.SetRect(int(x1), int(y1), int(x2), int(y2)) component.Drawable.SetRect(int(x1), int(y1), int(x2), int(y2))
item.Data.Draw(buf) component.Drawable.Draw(buf)
} }
} }

12
main.go
View File

@ -30,9 +30,9 @@ func main() {
pollers := make([]data.Poller, 0) pollers := make([]data.Poller, 0)
lout := layout.NewLayout(ui.TerminalDimensions()) lout := layout.NewLayout(ui.TerminalDimensions())
for _, chartConfig := range cfg.LineChartConfigs { for _, chartConfig := range cfg.RunCharts {
chart := widgets.NewTimePlot(chartConfig.Title) chart := widgets.NewRunChart(chartConfig.Title)
lout.AddItem(chart, chartConfig.Position, chartConfig.Size) lout.AddItem(chart, chartConfig.Position, chartConfig.Size)
for _, chartData := range chartConfig.DataConfig { for _, chartData := range chartConfig.DataConfig {
@ -62,13 +62,13 @@ func main() {
switch e.ID { switch e.ID {
case "<Left>": case "<Left>":
// here we are going to move selection (special type of layout item) // here we are going to move selection (special type of layout item)
//lout.GetItem("").MoveItem(-1, 0) //lout.GetItem("").Move(-1, 0)
case "<Right>": case "<Right>":
//lout.GetItem(0).MoveItem(1, 0) //lout.GetItem(0).Move(1, 0)
case "<Down>": case "<Down>":
//lout.GetItem(0).MoveItem(0, 1) //lout.GetItem(0).Move(0, 1)
case "<Up>": case "<Up>":
//lout.GetItem(0).MoveItem(0, -1) //lout.GetItem(0).Move(0, -1)
case "p": case "p":
for _, poller := range pollers { for _, poller := range pollers {
poller.TogglePause() poller.TogglePause()

View File

@ -11,19 +11,6 @@ import (
. "github.com/sqshq/termui" . "github.com/sqshq/termui"
) )
type TimePlot struct { // TODO rename to linechart
Block
DataLabels []string
MaxValueTimePoint TimePoint
LineColors []Color
DotRune rune
HorizontalScale int
timePoints []TimePoint
dataMutex *sync.Mutex
grid PlotGrid
}
const ( const (
xAxisLabelsHeight = 1 xAxisLabelsHeight = 1
xAxisLabelsWidth = 8 xAxisLabelsWidth = 8
@ -32,61 +19,77 @@ const (
yAxisLabelsGap = 1 yAxisLabelsGap = 1
) )
type RunChart struct {
Block
DataLabels []string
LineColors []Color
timePoints []TimePoint
dataMutex *sync.Mutex
grid ChartGrid
}
type Item struct {
timePoints []TimePoint
color Color
label string
}
type TimePoint struct { type TimePoint struct {
Value float64 Value float64
Time time.Time Time time.Time
} }
func NewTimePlot(title string) *TimePlot { func NewRunChart(title string) *RunChart {
block := *NewBlock() block := *NewBlock()
block.Title = title block.Title = title
//self.LineColors[0] = ui.ColorYellow //self.LineColors[0] = ui.ColorYellow
return &TimePlot{ return &RunChart{
Block: block, Block: block,
LineColors: Theme.Plot.Lines, LineColors: Theme.Plot.Lines,
DotRune: DOT,
HorizontalScale: 1,
timePoints: make([]TimePoint, 0), timePoints: make([]TimePoint, 0),
dataMutex: &sync.Mutex{}, dataMutex: &sync.Mutex{},
} }
} }
type PlotGrid struct { type ChartGrid struct {
count int linesCount int
maxTimeX int paddingDuration time.Duration
maxTime time.Time paddingWidth int
minTime time.Time maxTimeWidth int
maxValue float64 valueExtremum ValueExtremum
minValue float64 timeExtremum TimeExtremum
spacingDuration time.Duration
spacingWidth int
} }
func (self *TimePlot) newPlotGrid() PlotGrid { type TimeExtremum struct {
max time.Time
min time.Time
}
count := (self.Inner.Max.X - self.Inner.Min.X) / (xAxisLabelsGap + xAxisLabelsWidth) type ValueExtremum struct {
spacingDuration := time.Duration(time.Second) // TODO support others and/or adjust automatically depending on refresh rate max float64
maxTime := time.Now() min float64
minTime := maxTime.Add(-time.Duration(spacingDuration.Nanoseconds() * int64(count))) }
maxPoint, minPoint := GetMaxAndMinValueTimePoints(self.timePoints)
return PlotGrid{ func (self *RunChart) newChartGrid() ChartGrid {
count: count,
spacingDuration: spacingDuration, linesCount := (self.Inner.Max.X - self.Inner.Min.X) / (xAxisLabelsGap + xAxisLabelsWidth)
spacingWidth: xAxisLabelsGap + xAxisLabelsWidth, paddingDuration := time.Duration(time.Second) // TODO support others and/or adjust automatically depending on refresh rate
maxTimeX: self.Inner.Max.X - xAxisLabelsWidth/2 - xAxisLabelsGap,
maxTime: maxTime, return ChartGrid{
minTime: minTime, linesCount: linesCount,
maxValue: maxPoint.Value, paddingDuration: paddingDuration,
minValue: minPoint.Value, paddingWidth: xAxisLabelsGap + xAxisLabelsWidth,
maxTimeWidth: self.Inner.Max.X - xAxisLabelsWidth/2 - xAxisLabelsGap,
timeExtremum: GetTimeExtremum(linesCount, paddingDuration),
valueExtremum: GetValueExtremum(self.timePoints),
} }
} }
func (self *TimePlot) Draw(buf *Buffer) { func (self *RunChart) Draw(buf *Buffer) {
self.dataMutex.Lock() self.dataMutex.Lock()
self.Block.Draw(buf) self.Block.Draw(buf)
self.grid = self.newPlotGrid() self.grid = self.newChartGrid()
self.plotAxes(buf) self.plotAxes(buf)
drawArea := image.Rect( drawArea := image.Rect(
@ -98,7 +101,7 @@ func (self *TimePlot) Draw(buf *Buffer) {
self.dataMutex.Unlock() self.dataMutex.Unlock()
} }
func (self *TimePlot) ConsumeValue(value string, label string) { func (self *RunChart) ConsumeValue(value string, label string) {
float, err := strconv.ParseFloat(value, 64) float, err := strconv.ParseFloat(value, 64)
if err != nil { if err != nil {
@ -111,11 +114,11 @@ func (self *TimePlot) ConsumeValue(value string, label string) {
self.dataMutex.Unlock() self.dataMutex.Unlock()
} }
func (self *TimePlot) ConsumeError(err error) { func (self *RunChart) ConsumeError(err error) {
// TODO visual notification // TODO visual notification
} }
func (self *TimePlot) trimOutOfRangeValues() { func (self *RunChart) trimOutOfRangeValues() {
lastOutOfRangeValueIndex := -1 lastOutOfRangeValueIndex := -1
@ -130,7 +133,7 @@ func (self *TimePlot) trimOutOfRangeValues() {
} }
} }
func (self *TimePlot) renderBraille(buf *Buffer, drawArea image.Rectangle) { func (self *RunChart) renderBraille(buf *Buffer, drawArea image.Rectangle) {
canvas := NewCanvas() canvas := NewCanvas()
canvas.Rectangle = drawArea canvas.Rectangle = drawArea
@ -144,12 +147,12 @@ func (self *TimePlot) renderBraille(buf *Buffer, drawArea image.Rectangle) {
continue continue
} }
timeDeltaWithGridMaxTime := self.grid.maxTime.Sub(timePoint.Time) timeDeltaWithGridMaxTime := self.grid.timeExtremum.max.Sub(timePoint.Time)
deltaToSpacingRelation := float64(timeDeltaWithGridMaxTime.Nanoseconds()) / float64(self.grid.spacingDuration.Nanoseconds()) deltaToPaddingRelation := float64(timeDeltaWithGridMaxTime.Nanoseconds()) / float64(self.grid.paddingDuration.Nanoseconds())
x := self.grid.maxTimeX - (int(float64(self.grid.spacingWidth) * deltaToSpacingRelation)) x := self.grid.maxTimeWidth - (int(float64(self.grid.paddingWidth) * deltaToPaddingRelation))
valuePerYDot := (self.grid.maxValue - self.grid.minValue) / float64(drawArea.Dy()-1) valuePerYDot := (self.grid.valueExtremum.max - self.grid.valueExtremum.min) / float64(drawArea.Dy()-1)
y := int(float64(timePoint.Value-self.grid.minValue) / valuePerYDot) y := int(float64(timePoint.Value-self.grid.valueExtremum.min) / valuePerYDot)
if _, exists := pointPerX[x]; exists { if _, exists := pointPerX[x]; exists {
continue continue
@ -185,11 +188,11 @@ func (self *TimePlot) renderBraille(buf *Buffer, drawArea image.Rectangle) {
canvas.Draw(buf) canvas.Draw(buf)
} }
func (self *TimePlot) isTimePointInRange(point TimePoint) bool { func (self *RunChart) isTimePointInRange(point TimePoint) bool {
return point.Time.After(self.grid.minTime.Add(self.grid.spacingDuration)) return point.Time.After(self.grid.timeExtremum.min.Add(self.grid.paddingDuration))
} }
func (self *TimePlot) plotAxes(buf *Buffer) { func (self *RunChart) plotAxes(buf *Buffer) {
// draw origin cell // draw origin cell
buf.SetCell( buf.SetCell(
NewCell(BOTTOM_LEFT, NewStyle(ColorWhite)), NewCell(BOTTOM_LEFT, NewStyle(ColorWhite)),
@ -206,10 +209,10 @@ func (self *TimePlot) plotAxes(buf *Buffer) {
// draw grid // draw grid
for y := 0; y < self.Inner.Dy()-xAxisLabelsHeight-1; y = y + 2 { for y := 0; y < self.Inner.Dy()-xAxisLabelsHeight-1; y = y + 2 {
for x := 0; x < self.grid.count; x++ { for x := 0; x < self.grid.linesCount; x++ {
buf.SetCell( buf.SetCell(
NewCell(VERTICAL_DASH, NewStyle(ColorDarkGrey)), NewCell(VERTICAL_DASH, NewStyle(ColorDarkGrey)),
image.Pt(self.grid.maxTimeX-x*self.grid.spacingWidth, y+self.Inner.Min.Y+1), image.Pt(self.grid.maxTimeWidth-x*self.grid.paddingWidth, y+self.Inner.Min.Y+1),
) )
} }
} }
@ -223,30 +226,30 @@ func (self *TimePlot) plotAxes(buf *Buffer) {
} }
// draw x axis time labels // draw x axis time labels
for i := 0; i < self.grid.count; i++ { for i := 0; i < self.grid.linesCount; i++ {
labelTime := self.grid.maxTime.Add(time.Duration(-i) * time.Second) labelTime := self.grid.timeExtremum.max.Add(time.Duration(-i) * time.Second)
buf.SetString( buf.SetString(
labelTime.Format("15:04:05"), labelTime.Format("15:04:05"),
NewStyle(ColorWhite), NewStyle(ColorWhite),
image.Pt(self.grid.maxTimeX-xAxisLabelsWidth/2-i*(self.grid.spacingWidth), self.Inner.Max.Y-1), image.Pt(self.grid.maxTimeWidth-xAxisLabelsWidth/2-i*(self.grid.paddingWidth), self.Inner.Max.Y-1),
) )
} }
// draw y axis labels // draw y axis labels
verticalScale := self.grid.maxValue - self.grid.minValue/float64(self.Inner.Dy()-xAxisLabelsHeight-1) verticalScale := self.grid.valueExtremum.max - self.grid.valueExtremum.min/float64(self.Inner.Dy()-xAxisLabelsHeight-1)
for i := 1; i*(yAxisLabelsGap+1) <= self.Inner.Dy()-1; i++ { for i := 1; i*(yAxisLabelsGap+1) <= self.Inner.Dy()-1; i++ {
buf.SetString( buf.SetString(
fmt.Sprintf("%.3f", float64(i)*self.grid.minValue*verticalScale*(yAxisLabelsGap+1)), fmt.Sprintf("%.3f", float64(i)*self.grid.valueExtremum.min*verticalScale*(yAxisLabelsGap+1)),
NewStyle(ColorWhite), NewStyle(ColorWhite),
image.Pt(self.Inner.Min.X, self.Inner.Max.Y-(i*(yAxisLabelsGap+1))-2), image.Pt(self.Inner.Min.X, self.Inner.Max.Y-(i*(yAxisLabelsGap+1))-2),
) )
} }
} }
func GetMaxAndMinValueTimePoints(points []TimePoint) (TimePoint, TimePoint) { func GetValueExtremum(points []TimePoint) ValueExtremum {
if len(points) == 0 { if len(points) == 0 {
return TimePoint{0, time.Now()}, TimePoint{0, time.Now()} return ValueExtremum{0, 0}
} }
var max, min = points[0], points[0] var max, min = points[0], points[0]
@ -260,5 +263,13 @@ func GetMaxAndMinValueTimePoints(points []TimePoint) (TimePoint, TimePoint) {
} }
} }
return max, min return ValueExtremum{max: max.Value, min: min.Value}
}
func GetTimeExtremum(linesCount int, paddingDuration time.Duration) TimeExtremum {
maxTime := time.Now()
return TimeExtremum{
max: maxTime,
min: maxTime.Add(-time.Duration(paddingDuration.Nanoseconds() * int64(linesCount))),
}
} }