2019-02-15 04:34:45 +00:00
|
|
|
package runchart
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2019-03-08 04:04:46 +00:00
|
|
|
"github.com/sqshq/sampler/console"
|
2019-02-15 04:34:45 +00:00
|
|
|
ui "github.com/sqshq/termui"
|
|
|
|
"image"
|
|
|
|
"math"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
2019-02-15 04:44:25 +00:00
|
|
|
xAxisLegendIndent = 10
|
|
|
|
yAxisLegendIndent = 1
|
|
|
|
heightOnDefault = 2
|
|
|
|
heightOnPinpoint = 4
|
|
|
|
heightOnDetails = 6
|
2019-02-16 02:52:03 +00:00
|
|
|
|
|
|
|
timeFormat = "15:04:05.000"
|
2019-02-15 04:34:45 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Legend struct {
|
|
|
|
Enabled bool
|
|
|
|
Details bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c *RunChart) renderLegend(buffer *ui.Buffer, rectangle image.Rectangle) {
|
|
|
|
|
|
|
|
if !c.legend.Enabled {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2019-02-15 04:44:25 +00:00
|
|
|
height := heightOnDefault
|
|
|
|
|
|
|
|
if c.mode == ModePinpoint {
|
|
|
|
height = heightOnPinpoint
|
|
|
|
} else if c.legend.Details {
|
|
|
|
height = heightOnDetails
|
2019-02-15 04:34:45 +00:00
|
|
|
}
|
|
|
|
|
2019-02-16 03:46:03 +00:00
|
|
|
rowCount := (c.Dy() - 2*yAxisLegendIndent) / (height + yAxisLegendIndent)
|
2019-02-15 04:34:45 +00:00
|
|
|
columnCount := int(math.Ceil(float64(len(c.lines)) / float64(rowCount)))
|
2019-02-19 04:07:32 +00:00
|
|
|
columnWidth := getColumnWidth(c.mode, c.lines, c.scale)
|
2019-02-15 04:34:45 +00:00
|
|
|
|
|
|
|
for col := 0; col < columnCount; col++ {
|
|
|
|
for row := 0; row < rowCount; row++ {
|
|
|
|
|
|
|
|
lineIndex := row + rowCount*col
|
|
|
|
if len(c.lines) <= lineIndex {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
line := c.lines[row+rowCount*col]
|
2019-02-15 04:44:25 +00:00
|
|
|
|
2019-02-15 04:34:45 +00:00
|
|
|
x := c.Inner.Max.X - (columnWidth+xAxisLegendIndent)*(col+1)
|
2019-02-15 04:44:25 +00:00
|
|
|
y := c.Inner.Min.Y + yAxisLegendIndent + row*height
|
2019-02-15 04:34:45 +00:00
|
|
|
|
|
|
|
titleStyle := ui.NewStyle(line.color)
|
2019-03-08 04:04:46 +00:00
|
|
|
detailsStyle := ui.NewStyle(console.ColorWhite)
|
2019-02-15 04:34:45 +00:00
|
|
|
|
|
|
|
buffer.SetString(string(ui.DOT), titleStyle, image.Pt(x-2, y))
|
|
|
|
buffer.SetString(line.label, titleStyle, image.Pt(x, y))
|
|
|
|
|
2019-02-15 04:44:25 +00:00
|
|
|
if c.mode == ModePinpoint {
|
2019-02-16 02:52:03 +00:00
|
|
|
buffer.SetString(fmt.Sprintf("time %s", line.selectionPoint.time.Format("15:04:05.000")), detailsStyle, image.Pt(x, y+1))
|
2019-02-19 04:07:32 +00:00
|
|
|
buffer.SetString(fmt.Sprintf("value %s", formatValue(line.selectionPoint.value, c.scale)), detailsStyle, image.Pt(x, y+2))
|
2019-02-15 04:44:25 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2019-02-15 04:34:45 +00:00
|
|
|
if !c.legend.Details {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
details := [4]string{
|
2019-02-19 04:07:32 +00:00
|
|
|
fmt.Sprintf("cur %s", formatValue(getCurrentValue(line), c.scale)),
|
|
|
|
fmt.Sprintf("dlt %s", formatValueWithSign(getDiffWithPreviousValue(line), c.scale)),
|
|
|
|
fmt.Sprintf("max %s", formatValue(line.extrema.max, c.scale)),
|
|
|
|
fmt.Sprintf("min %s", formatValue(line.extrema.min, c.scale)),
|
2019-02-15 04:34:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for i, detail := range details {
|
|
|
|
buffer.SetString(detail, detailsStyle, image.Pt(x, y+i+yAxisLegendIndent))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-02-19 04:07:32 +00:00
|
|
|
func getColumnWidth(mode Mode, lines []TimeLine, scale int) int {
|
2019-02-16 02:52:03 +00:00
|
|
|
|
|
|
|
if mode == ModePinpoint {
|
|
|
|
return len(timeFormat)
|
|
|
|
}
|
|
|
|
|
2019-02-19 04:07:32 +00:00
|
|
|
width := len(formatValue(0, scale))
|
2019-02-15 04:34:45 +00:00
|
|
|
for _, line := range lines {
|
|
|
|
if len(line.label) > width {
|
|
|
|
width = len(line.label)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return width
|
|
|
|
}
|
|
|
|
|
2019-02-16 02:52:03 +00:00
|
|
|
func getDiffWithPreviousValue(line TimeLine) float64 {
|
|
|
|
if len(line.points) < 2 {
|
|
|
|
return 0
|
|
|
|
} else {
|
2019-02-18 04:49:40 +00:00
|
|
|
return line.points[len(line.points)-1].value - line.points[len(line.points)-2].value
|
2019-02-15 04:34:45 +00:00
|
|
|
}
|
2019-02-16 02:52:03 +00:00
|
|
|
}
|
2019-02-15 04:34:45 +00:00
|
|
|
|
2019-02-16 02:52:03 +00:00
|
|
|
func getCurrentValue(line TimeLine) float64 {
|
2019-02-17 23:00:00 +00:00
|
|
|
if len(line.points) == 0 {
|
|
|
|
return 0
|
|
|
|
} else {
|
|
|
|
return line.points[len(line.points)-1].value
|
|
|
|
}
|
2019-02-15 04:34:45 +00:00
|
|
|
}
|