minor refactoring
This commit is contained in:
parent
ec79619f38
commit
41b1fa59a5
16
config.yml
16
config.yml
|
@ -1,22 +1,26 @@
|
||||||
theme: dark
|
theme: dark
|
||||||
run-charts:
|
run-charts:
|
||||||
- title: curl-latency
|
- title: CURL-LATENCY
|
||||||
data:
|
data:
|
||||||
- label: google.com
|
- label: GOOGLE
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' http://google.com
|
script: curl -o /dev/null -s -w '%{time_total}' http://google.com
|
||||||
- label: yahoo.com
|
- label: YAHOO
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' http://yahoo.com
|
script: curl -o /dev/null -s -w '%{time_total}' http://yahoo.com
|
||||||
- label: example.com
|
- label: YANDEX
|
||||||
script: curl -o /dev/null -s -w '%{time_total}' http://example.com
|
script: curl -o /dev/null -s -w '%{time_total}' http://yandex.com
|
||||||
refresh-rate-ms: 300
|
refresh-rate-ms: 300
|
||||||
time-scale-sec: 1
|
time-scale-sec: 1
|
||||||
|
decimal-places: 1
|
||||||
|
legend:
|
||||||
|
labels: true
|
||||||
|
details: true
|
||||||
position:
|
position:
|
||||||
x: 0
|
x: 0
|
||||||
y: 0
|
y: 0
|
||||||
size:
|
size:
|
||||||
x: 15
|
x: 15
|
||||||
y: 15
|
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
|
||||||
|
|
|
@ -2,8 +2,8 @@ package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/sqshq/vcmd/data"
|
"github.com/sqshq/vcmd/data"
|
||||||
. "github.com/sqshq/vcmd/layout"
|
|
||||||
"github.com/sqshq/vcmd/settings"
|
"github.com/sqshq/vcmd/settings"
|
||||||
|
. "github.com/sqshq/vcmd/widgets"
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"log"
|
"log"
|
||||||
|
@ -11,10 +11,10 @@ import (
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Theme settings.Theme `yaml:"theme"`
|
Theme settings.Theme `yaml:"theme"`
|
||||||
RunCharts []RunChart `yaml:"run-charts"`
|
RunCharts []RunChartConfig `yaml:"run-charts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RunChart struct {
|
type RunChartConfig struct {
|
||||||
Title string `yaml:"title"`
|
Title string `yaml:"title"`
|
||||||
Items []data.Item `yaml:"data"`
|
Items []data.Item `yaml:"data"`
|
||||||
Position Position `yaml:"position"`
|
Position Position `yaml:"position"`
|
||||||
|
|
|
@ -7,13 +7,12 @@ import (
|
||||||
type Poller struct {
|
type Poller struct {
|
||||||
consumer Consumer
|
consumer Consumer
|
||||||
item Item
|
item Item
|
||||||
pause bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPoller(consumer Consumer, item Item, rateMs int) Poller {
|
func NewPoller(consumer Consumer, item Item, rateMs int) Poller {
|
||||||
|
|
||||||
ticker := time.NewTicker(time.Duration(rateMs * int(time.Millisecond)))
|
ticker := time.NewTicker(time.Duration(rateMs * int(time.Millisecond)))
|
||||||
poller := Poller{consumer, item, false}
|
poller := Poller{consumer, item}
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
|
@ -27,16 +26,8 @@ func NewPoller(consumer Consumer, item Item, rateMs int) Poller {
|
||||||
return poller
|
return poller
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *Poller) TogglePause() {
|
|
||||||
self.pause = !self.pause
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *Poller) poll() {
|
func (self *Poller) poll() {
|
||||||
|
|
||||||
if self.pause {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
value, err := self.item.nextValue()
|
value, err := self.item.nextValue()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
29
main.go
29
main.go
|
@ -4,7 +4,7 @@ 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/data"
|
||||||
"github.com/sqshq/vcmd/layout"
|
"github.com/sqshq/vcmd/settings"
|
||||||
"github.com/sqshq/vcmd/widgets"
|
"github.com/sqshq/vcmd/widgets"
|
||||||
"log"
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
@ -12,6 +12,8 @@ import (
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
|
print("\033]0;vcmd\007")
|
||||||
|
|
||||||
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")
|
||||||
|
|
||||||
if err := ui.Init(); err != nil {
|
if err := ui.Init(); err != nil {
|
||||||
|
@ -22,7 +24,7 @@ func main() {
|
||||||
events := ui.PollEvents()
|
events := ui.PollEvents()
|
||||||
|
|
||||||
pollers := make([]data.Poller, 0)
|
pollers := make([]data.Poller, 0)
|
||||||
lout := layout.NewLayout(ui.TerminalDimensions())
|
lout := widgets.NewLayout(ui.TerminalDimensions())
|
||||||
|
|
||||||
for _, chartConfig := range cfg.RunCharts {
|
for _, chartConfig := range cfg.RunCharts {
|
||||||
|
|
||||||
|
@ -36,17 +38,18 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
ticker := time.NewTicker(30 * time.Millisecond)
|
ticker := time.NewTicker(30 * time.Millisecond)
|
||||||
|
pause := false
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case e := <-events:
|
case e := <-events:
|
||||||
switch e.ID {
|
switch e.ID {
|
||||||
case "q", "<C-c>":
|
case settings.EventQuit, settings.EventExit:
|
||||||
return
|
return
|
||||||
case "<Resize>":
|
case settings.EventResize:
|
||||||
payload := e.Payload.(ui.Resize)
|
payload := e.Payload.(ui.Resize)
|
||||||
lout.ChangeDimensions(payload.Width, payload.Height)
|
lout.ChangeDimensions(payload.Width, payload.Height)
|
||||||
case "<MouseLeft>":
|
case settings.EventMouseClick:
|
||||||
//payload := e.Payload.(ui.Mouse)
|
//payload := e.Payload.(ui.Mouse)
|
||||||
//x, y := payload.X, payload.Y
|
//x, y := payload.X, payload.Y
|
||||||
//log.Printf("x: %v, y: %v", x, y)
|
//log.Printf("x: %v, y: %v", x, y)
|
||||||
|
@ -54,23 +57,23 @@ func main() {
|
||||||
switch e.Type {
|
switch e.Type {
|
||||||
case ui.KeyboardEvent:
|
case ui.KeyboardEvent:
|
||||||
switch e.ID {
|
switch e.ID {
|
||||||
case "<Left>":
|
case settings.EventKeyboardLeft:
|
||||||
// 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("").Move(-1, 0)
|
//lout.GetItem("").Move(-1, 0)
|
||||||
case "<Right>":
|
case settings.EventKeyboardRight:
|
||||||
//lout.GetItem(0).Move(1, 0)
|
//lout.GetItem(0).Move(1, 0)
|
||||||
case "<Down>":
|
case settings.EventKeyboardDown:
|
||||||
//lout.GetItem(0).Move(0, 1)
|
//lout.GetItem(0).Move(0, 1)
|
||||||
case "<Up>":
|
case settings.EventKeyboardUp:
|
||||||
//lout.GetItem(0).Move(0, -1)
|
//lout.GetItem(0).Move(0, -1)
|
||||||
case "p":
|
case settings.EventPause:
|
||||||
for _, poller := range pollers {
|
pause = !pause
|
||||||
poller.TogglePause()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
if !pause {
|
||||||
ui.Render(lout)
|
ui.Render(lout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package settings
|
||||||
|
|
||||||
|
type Event string
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventPause = "p"
|
||||||
|
EventQuit = "q"
|
||||||
|
EventResize = "<Resize>"
|
||||||
|
EventExit = "<C-c>"
|
||||||
|
EventMouseClick = "<MouseLeft>"
|
||||||
|
EventKeyboardLeft = "<Left>"
|
||||||
|
EventKeyboardRight = "<Right>"
|
||||||
|
EventKeyboardUp = "<Up>"
|
||||||
|
EventKeyboardDown = "<Down>"
|
||||||
|
)
|
|
@ -1,4 +1,4 @@
|
||||||
package layout
|
package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "github.com/sqshq/termui"
|
. "github.com/sqshq/termui"
|
|
@ -1,4 +1,4 @@
|
||||||
package layout
|
package widgets
|
||||||
|
|
||||||
import (
|
import (
|
||||||
. "github.com/sqshq/termui"
|
. "github.com/sqshq/termui"
|
|
@ -20,6 +20,7 @@ const (
|
||||||
xAxisLabelsGap = 2
|
xAxisLabelsGap = 2
|
||||||
yAxisLabelsWidth = 5
|
yAxisLabelsWidth = 5
|
||||||
yAxisLabelsGap = 1
|
yAxisLabelsGap = 1
|
||||||
|
xAxisLegendWidth = 15
|
||||||
)
|
)
|
||||||
|
|
||||||
type RunChart struct {
|
type RunChart struct {
|
||||||
|
@ -79,7 +80,7 @@ func (self *RunChart) newChartGrid() ChartGrid {
|
||||||
paddingWidth: xAxisLabelsGap + xAxisLabelsWidth,
|
paddingWidth: xAxisLabelsGap + xAxisLabelsWidth,
|
||||||
maxTimeWidth: self.Inner.Max.X - xAxisLabelsWidth/2 - xAxisLabelsGap,
|
maxTimeWidth: self.Inner.Max.X - xAxisLabelsWidth/2 - xAxisLabelsGap,
|
||||||
timeExtremum: GetTimeExtremum(linesCount, paddingDuration),
|
timeExtremum: GetTimeExtremum(linesCount, paddingDuration),
|
||||||
valueExtremum: GetValueExtremum(self.lines),
|
valueExtremum: GetChartValueExtremum(self.lines),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +89,7 @@ func (self *RunChart) Draw(buf *Buffer) {
|
||||||
self.mutex.Lock()
|
self.mutex.Lock()
|
||||||
self.Block.Draw(buf)
|
self.Block.Draw(buf)
|
||||||
self.grid = self.newChartGrid()
|
self.grid = self.newChartGrid()
|
||||||
self.plotAxes(buf)
|
self.renderAxes(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,
|
||||||
|
@ -96,6 +97,7 @@ func (self *RunChart) Draw(buf *Buffer) {
|
||||||
)
|
)
|
||||||
|
|
||||||
self.renderItems(buf, drawArea)
|
self.renderItems(buf, drawArea)
|
||||||
|
self.renderLegend(buf, drawArea)
|
||||||
self.mutex.Unlock()
|
self.mutex.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,7 +153,61 @@ func (self *RunChart) trimOutOfRangeValues() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RunChart) renderItems(buf *Buffer, drawArea image.Rectangle) {
|
func (self *RunChart) renderAxes(buffer *Buffer) {
|
||||||
|
// draw origin cell
|
||||||
|
buffer.SetCell(
|
||||||
|
NewCell(BOTTOM_LEFT, NewStyle(ColorWhite)),
|
||||||
|
image.Pt(self.Inner.Min.X+yAxisLabelsWidth, self.Inner.Max.Y-xAxisLabelsHeight-1),
|
||||||
|
)
|
||||||
|
|
||||||
|
// draw x axis line
|
||||||
|
for i := yAxisLabelsWidth + 1; i < self.Inner.Dx(); i++ {
|
||||||
|
buffer.SetCell(
|
||||||
|
NewCell(HORIZONTAL_DASH, NewStyle(ColorWhite)),
|
||||||
|
image.Pt(i+self.Inner.Min.X, self.Inner.Max.Y-xAxisLabelsHeight-1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw grid
|
||||||
|
for y := 0; y < self.Inner.Dy()-xAxisLabelsHeight-1; y = y + 2 {
|
||||||
|
for x := 0; x < self.grid.linesCount; x++ {
|
||||||
|
buffer.SetCell(
|
||||||
|
NewCell(VERTICAL_DASH, NewStyle(settings.ColorDarkGrey)),
|
||||||
|
image.Pt(self.grid.maxTimeWidth-x*self.grid.paddingWidth, y+self.Inner.Min.Y+1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw y axis line
|
||||||
|
for i := 0; i < self.Inner.Dy()-xAxisLabelsHeight-1; i++ {
|
||||||
|
buffer.SetCell(
|
||||||
|
NewCell(VERTICAL_DASH, NewStyle(ColorWhite)),
|
||||||
|
image.Pt(self.Inner.Min.X+yAxisLabelsWidth, i+self.Inner.Min.Y),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw x axis time labels
|
||||||
|
for i := 0; i < self.grid.linesCount; i++ {
|
||||||
|
labelTime := self.grid.timeExtremum.max.Add(time.Duration(-i) * time.Second)
|
||||||
|
buffer.SetString(
|
||||||
|
labelTime.Format("15:04:05"),
|
||||||
|
NewStyle(ColorWhite),
|
||||||
|
image.Pt(self.grid.maxTimeWidth-xAxisLabelsWidth/2-i*(self.grid.paddingWidth), self.Inner.Max.Y-1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw y axis labels
|
||||||
|
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++ {
|
||||||
|
buffer.SetString(
|
||||||
|
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 (self *RunChart) renderItems(buffer *Buffer, drawArea image.Rectangle) {
|
||||||
|
|
||||||
canvas := NewCanvas()
|
canvas := NewCanvas()
|
||||||
canvas.Rectangle = drawArea
|
canvas.Rectangle = drawArea
|
||||||
|
@ -193,7 +249,7 @@ func (self *RunChart) renderItems(buf *Buffer, drawArea image.Rectangle) {
|
||||||
previousPoint = xToPoint[pointsOrder[i-1]]
|
previousPoint = xToPoint[pointsOrder[i-1]]
|
||||||
}
|
}
|
||||||
|
|
||||||
//buf.SetCell(
|
//buffer.SetCell(
|
||||||
// NewCell(self.DotRune, NewStyle(SelectColor(self.LineColors, 0))),
|
// NewCell(self.DotRune, NewStyle(SelectColor(self.LineColors, 0))),
|
||||||
// currentPoint,
|
// currentPoint,
|
||||||
//)
|
//)
|
||||||
|
@ -206,68 +262,47 @@ func (self *RunChart) renderItems(buf *Buffer, drawArea image.Rectangle) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.Draw(buf)
|
canvas.Draw(buffer)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RunChart) renderLegend(buffer *Buffer, rectangle image.Rectangle) {
|
||||||
|
for i, line := range self.lines {
|
||||||
|
|
||||||
|
extremum := GetLineValueExtremum(line.points)
|
||||||
|
|
||||||
|
buffer.SetString(
|
||||||
|
fmt.Sprintf("•"),
|
||||||
|
NewStyle(line.item.Color),
|
||||||
|
image.Pt(self.Inner.Max.X-xAxisLegendWidth-2, self.Inner.Min.Y+1+i*5),
|
||||||
|
)
|
||||||
|
buffer.SetString(
|
||||||
|
fmt.Sprintf("%s", line.item.Label),
|
||||||
|
NewStyle(line.item.Color),
|
||||||
|
image.Pt(self.Inner.Max.X-xAxisLegendWidth, self.Inner.Min.Y+1+i*5),
|
||||||
|
)
|
||||||
|
buffer.SetString(
|
||||||
|
fmt.Sprintf("max %.3f", extremum.max),
|
||||||
|
NewStyle(ColorWhite),
|
||||||
|
image.Pt(self.Inner.Max.X-xAxisLegendWidth, self.Inner.Min.Y+2+i*5),
|
||||||
|
)
|
||||||
|
buffer.SetString(
|
||||||
|
fmt.Sprintf("min %.3f", extremum.min),
|
||||||
|
NewStyle(ColorWhite),
|
||||||
|
image.Pt(self.Inner.Max.X-xAxisLegendWidth, self.Inner.Min.Y+3+i*5),
|
||||||
|
)
|
||||||
|
buffer.SetString(
|
||||||
|
fmt.Sprintf("cur %.3f", line.points[len(line.points)-1].Value),
|
||||||
|
NewStyle(ColorWhite),
|
||||||
|
image.Pt(self.Inner.Max.X-xAxisLegendWidth, self.Inner.Min.Y+4+i*5),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RunChart) isTimePointInRange(point TimePoint) bool {
|
func (self *RunChart) isTimePointInRange(point TimePoint) bool {
|
||||||
return point.Time.After(self.grid.timeExtremum.min.Add(self.grid.paddingDuration))
|
return point.Time.After(self.grid.timeExtremum.min.Add(self.grid.paddingDuration))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *RunChart) plotAxes(buf *Buffer) {
|
func GetChartValueExtremum(items []TimeLine) ValueExtremum {
|
||||||
// draw origin cell
|
|
||||||
buf.SetCell(
|
|
||||||
NewCell(BOTTOM_LEFT, NewStyle(ColorWhite)),
|
|
||||||
image.Pt(self.Inner.Min.X+yAxisLabelsWidth, self.Inner.Max.Y-xAxisLabelsHeight-1),
|
|
||||||
)
|
|
||||||
|
|
||||||
// draw x axis line
|
|
||||||
for i := yAxisLabelsWidth + 1; i < self.Inner.Dx(); i++ {
|
|
||||||
buf.SetCell(
|
|
||||||
NewCell(HORIZONTAL_DASH, NewStyle(ColorWhite)),
|
|
||||||
image.Pt(i+self.Inner.Min.X, self.Inner.Max.Y-xAxisLabelsHeight-1),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw grid
|
|
||||||
for y := 0; y < self.Inner.Dy()-xAxisLabelsHeight-1; y = y + 2 {
|
|
||||||
for x := 0; x < self.grid.linesCount; x++ {
|
|
||||||
buf.SetCell(
|
|
||||||
NewCell(VERTICAL_DASH, NewStyle(settings.ColorDarkGrey)),
|
|
||||||
image.Pt(self.grid.maxTimeWidth-x*self.grid.paddingWidth, y+self.Inner.Min.Y+1),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw y axis line
|
|
||||||
for i := 0; i < self.Inner.Dy()-xAxisLabelsHeight-1; i++ {
|
|
||||||
buf.SetCell(
|
|
||||||
NewCell(VERTICAL_DASH, NewStyle(ColorWhite)),
|
|
||||||
image.Pt(self.Inner.Min.X+yAxisLabelsWidth, i+self.Inner.Min.Y),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw x axis time labels
|
|
||||||
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.maxTimeWidth-xAxisLabelsWidth/2-i*(self.grid.paddingWidth), self.Inner.Max.Y-1),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw y axis labels
|
|
||||||
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.valueExtremum.min*verticalScale*(yAxisLabelsGap+1)),
|
|
||||||
NewStyle(ColorWhite),
|
|
||||||
image.Pt(self.Inner.Min.X, self.Inner.Max.Y-(i*(yAxisLabelsGap+1))-2),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetValueExtremum(items []TimeLine) ValueExtremum {
|
|
||||||
|
|
||||||
if len(items) == 0 {
|
if len(items) == 0 {
|
||||||
return ValueExtremum{0, 0}
|
return ValueExtremum{0, 0}
|
||||||
|
@ -289,6 +324,26 @@ func GetValueExtremum(items []TimeLine) ValueExtremum {
|
||||||
return ValueExtremum{max: max, min: min}
|
return ValueExtremum{max: max, min: min}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetLineValueExtremum(points []TimePoint) ValueExtremum {
|
||||||
|
|
||||||
|
if len(points) == 0 {
|
||||||
|
return ValueExtremum{0, 0}
|
||||||
|
}
|
||||||
|
|
||||||
|
var max, min = -math.MaxFloat64, math.MaxFloat64
|
||||||
|
|
||||||
|
for _, point := range points {
|
||||||
|
if point.Value > max {
|
||||||
|
max = point.Value
|
||||||
|
}
|
||||||
|
if point.Value < min {
|
||||||
|
min = point.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ValueExtremum{max: max, min: min}
|
||||||
|
}
|
||||||
|
|
||||||
func GetTimeExtremum(linesCount int, paddingDuration time.Duration) TimeExtremum {
|
func GetTimeExtremum(linesCount int, paddingDuration time.Duration) TimeExtremum {
|
||||||
maxTime := time.Now()
|
maxTime := time.Now()
|
||||||
return TimeExtremum{
|
return TimeExtremum{
|
||||||
|
|
Loading…
Reference in New Issue