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
line-charts:
run-charts:
- title: curl-latency
data:
- label: example.com

View File

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

View File

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

View File

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

12
main.go
View File

@ -30,9 +30,9 @@ func main() {
pollers := make([]data.Poller, 0)
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)
for _, chartData := range chartConfig.DataConfig {
@ -62,13 +62,13 @@ func main() {
switch e.ID {
case "<Left>":
// here we are going to move selection (special type of layout item)
//lout.GetItem("").MoveItem(-1, 0)
//lout.GetItem("").Move(-1, 0)
case "<Right>":
//lout.GetItem(0).MoveItem(1, 0)
//lout.GetItem(0).Move(1, 0)
case "<Down>":
//lout.GetItem(0).MoveItem(0, 1)
//lout.GetItem(0).Move(0, 1)
case "<Up>":
//lout.GetItem(0).MoveItem(0, -1)
//lout.GetItem(0).Move(0, -1)
case "p":
for _, poller := range pollers {
poller.TogglePause()

View File

@ -11,19 +11,6 @@ import (
. "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 (
xAxisLabelsHeight = 1
xAxisLabelsWidth = 8
@ -32,61 +19,77 @@ const (
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 {
Value float64
Time time.Time
}
func NewTimePlot(title string) *TimePlot {
func NewRunChart(title string) *RunChart {
block := *NewBlock()
block.Title = title
//self.LineColors[0] = ui.ColorYellow
return &TimePlot{
return &RunChart{
Block: block,
LineColors: Theme.Plot.Lines,
DotRune: DOT,
HorizontalScale: 1,
timePoints: make([]TimePoint, 0),
dataMutex: &sync.Mutex{},
}
}
type PlotGrid struct {
count int
maxTimeX int
maxTime time.Time
minTime time.Time
maxValue float64
minValue float64
spacingDuration time.Duration
spacingWidth int
type ChartGrid struct {
linesCount int
paddingDuration time.Duration
paddingWidth int
maxTimeWidth int
valueExtremum ValueExtremum
timeExtremum TimeExtremum
}
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)
spacingDuration := time.Duration(time.Second) // TODO support others and/or adjust automatically depending on refresh rate
maxTime := time.Now()
minTime := maxTime.Add(-time.Duration(spacingDuration.Nanoseconds() * int64(count)))
maxPoint, minPoint := GetMaxAndMinValueTimePoints(self.timePoints)
type ValueExtremum struct {
max float64
min float64
}
return PlotGrid{
count: count,
spacingDuration: spacingDuration,
spacingWidth: xAxisLabelsGap + xAxisLabelsWidth,
maxTimeX: self.Inner.Max.X - xAxisLabelsWidth/2 - xAxisLabelsGap,
maxTime: maxTime,
minTime: minTime,
maxValue: maxPoint.Value,
minValue: minPoint.Value,
func (self *RunChart) newChartGrid() ChartGrid {
linesCount := (self.Inner.Max.X - self.Inner.Min.X) / (xAxisLabelsGap + xAxisLabelsWidth)
paddingDuration := time.Duration(time.Second) // TODO support others and/or adjust automatically depending on refresh rate
return ChartGrid{
linesCount: linesCount,
paddingDuration: paddingDuration,
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.Block.Draw(buf)
self.grid = self.newPlotGrid()
self.grid = self.newChartGrid()
self.plotAxes(buf)
drawArea := image.Rect(
@ -98,7 +101,7 @@ func (self *TimePlot) Draw(buf *Buffer) {
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)
if err != nil {
@ -111,11 +114,11 @@ func (self *TimePlot) ConsumeValue(value string, label string) {
self.dataMutex.Unlock()
}
func (self *TimePlot) ConsumeError(err error) {
func (self *RunChart) ConsumeError(err error) {
// TODO visual notification
}
func (self *TimePlot) trimOutOfRangeValues() {
func (self *RunChart) trimOutOfRangeValues() {
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.Rectangle = drawArea
@ -144,12 +147,12 @@ func (self *TimePlot) renderBraille(buf *Buffer, drawArea image.Rectangle) {
continue
}
timeDeltaWithGridMaxTime := self.grid.maxTime.Sub(timePoint.Time)
deltaToSpacingRelation := float64(timeDeltaWithGridMaxTime.Nanoseconds()) / float64(self.grid.spacingDuration.Nanoseconds())
x := self.grid.maxTimeX - (int(float64(self.grid.spacingWidth) * deltaToSpacingRelation))
timeDeltaWithGridMaxTime := self.grid.timeExtremum.max.Sub(timePoint.Time)
deltaToPaddingRelation := float64(timeDeltaWithGridMaxTime.Nanoseconds()) / float64(self.grid.paddingDuration.Nanoseconds())
x := self.grid.maxTimeWidth - (int(float64(self.grid.paddingWidth) * deltaToPaddingRelation))
valuePerYDot := (self.grid.maxValue - self.grid.minValue) / float64(drawArea.Dy()-1)
y := int(float64(timePoint.Value-self.grid.minValue) / valuePerYDot)
valuePerYDot := (self.grid.valueExtremum.max - self.grid.valueExtremum.min) / float64(drawArea.Dy()-1)
y := int(float64(timePoint.Value-self.grid.valueExtremum.min) / valuePerYDot)
if _, exists := pointPerX[x]; exists {
continue
@ -185,11 +188,11 @@ func (self *TimePlot) renderBraille(buf *Buffer, drawArea image.Rectangle) {
canvas.Draw(buf)
}
func (self *TimePlot) isTimePointInRange(point TimePoint) bool {
return point.Time.After(self.grid.minTime.Add(self.grid.spacingDuration))
func (self *RunChart) isTimePointInRange(point TimePoint) bool {
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
buf.SetCell(
NewCell(BOTTOM_LEFT, NewStyle(ColorWhite)),
@ -206,10 +209,10 @@ func (self *TimePlot) plotAxes(buf *Buffer) {
// draw grid
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(
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
for i := 0; i < self.grid.count; i++ {
labelTime := self.grid.maxTime.Add(time.Duration(-i) * time.Second)
for i := 0; i < self.grid.linesCount; i++ {
labelTime := self.grid.timeExtremum.max.Add(time.Duration(-i) * time.Second)
buf.SetString(
labelTime.Format("15:04:05"),
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
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++ {
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),
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 {
return TimePoint{0, time.Now()}, TimePoint{0, time.Now()}
return ValueExtremum{0, 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))),
}
}