renaming and refactoring
This commit is contained in:
parent
dd146c72f0
commit
b71d5556c2
|
@ -1,5 +1,5 @@
|
|||
theme: dark / bright
|
||||
line-charts:
|
||||
run-charts:
|
||||
- title: curl-latency
|
||||
data:
|
||||
- label: example.com
|
||||
|
|
|
@ -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"`
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
type Layout struct {
|
||||
Block
|
||||
items []Item
|
||||
components []Component
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -20,13 +20,13 @@ func NewLayout(width, height int) *Layout {
|
|||
block.SetRect(0, 0, width, height)
|
||||
|
||||
return &Layout{
|
||||
Block: block,
|
||||
items: make([]Item, 0),
|
||||
Block: block,
|
||||
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
12
main.go
|
@ -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()
|
||||
|
|
|
@ -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{
|
||||
Block: block,
|
||||
LineColors: Theme.Plot.Lines,
|
||||
DotRune: DOT,
|
||||
HorizontalScale: 1,
|
||||
timePoints: make([]TimePoint, 0),
|
||||
dataMutex: &sync.Mutex{},
|
||||
return &RunChart{
|
||||
Block: block,
|
||||
LineColors: Theme.Plot.Lines,
|
||||
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))),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue