bosun.org@v0.0.0-20210513094433-e25bc3e69a1f/cmd/bosun/sched/chart.go (about) 1 package sched 2 3 import ( 4 "image" 5 "image/color" 6 "image/png" 7 "io" 8 9 "bosun.org/cmd/bosun/expr" 10 "github.com/MiniProfiler/go/miniprofiler" 11 "github.com/ajstarks/svgo" 12 "github.com/bradfitz/slice" 13 "github.com/vdobler/chart" 14 "github.com/vdobler/chart/imgg" 15 "github.com/vdobler/chart/svgg" 16 ) 17 18 var chartColors = []color.Color{ 19 color.NRGBA{0x37, 0x7e, 0xb8, 0xff}, 20 color.NRGBA{0x4d, 0xaf, 0x4a, 0xff}, 21 color.NRGBA{0x98, 0x4e, 0xa3, 0xff}, 22 color.NRGBA{0xff, 0x7f, 0x00, 0xff}, 23 color.NRGBA{0xa6, 0x56, 0x28, 0xff}, 24 color.NRGBA{0xf7, 0x81, 0xbf, 0xff}, 25 color.NRGBA{0x99, 0x99, 0x99, 0xff}, 26 color.NRGBA{0xe4, 0x1a, 0x1c, 0xff}, 27 } 28 29 // Autostyle styles a chart series. 30 func Autostyle(i int) chart.Style { 31 c := chartColors[i%len(chartColors)] 32 s := chart.Symbol[i%len(chart.Symbol)] 33 return chart.Style{ 34 Symbol: s, 35 SymbolSize: .5, 36 SymbolColor: c, 37 LineStyle: chart.SolidLine, 38 LineWidth: 1, 39 LineColor: c, 40 } 41 } 42 43 var white = color.RGBA{0xff, 0xff, 0xff, 0xff} 44 45 func (s *Schedule) ExprSVG(t miniprofiler.Timer, w io.Writer, width, height int, unit string, res []*expr.Result) error { 46 ch, err := s.ExprGraph(t, unit, res) 47 if err != nil { 48 return err 49 } 50 g := svg.New(w) 51 g.StartviewUnit(100, 100, "%", 0, 0, width, height) 52 g.Rect(0, 0, width, height, "fill: #ffffff") 53 sgr := svgg.AddTo(g, 0, 0, width, height, "", 12, white) 54 ch.Plot(sgr) 55 g.End() 56 return nil 57 } 58 59 func (s *Schedule) ExprPNG(t miniprofiler.Timer, w io.Writer, width, height int, unit string, res []*expr.Result) error { 60 ch, err := s.ExprGraph(t, unit, res) 61 if err != nil { 62 return err 63 } 64 g := image.NewRGBA(image.Rectangle{Min: image.ZP, Max: image.Pt(width, height)}) 65 sgr := imgg.AddTo(g, 0, 0, width, height, white, nil, nil) 66 ch.Plot(sgr) 67 return png.Encode(w, g) 68 } 69 70 func (s *Schedule) ExprGraph(t miniprofiler.Timer, unit string, res []*expr.Result) (chart.Chart, error) { 71 c := chart.ScatterChart{ 72 Key: chart.Key{Pos: "itl"}, 73 YRange: chart.Range{Label: unit}, 74 } 75 c.XRange.Time = true 76 for ri, r := range res { 77 rv := r.Value.(expr.Series) 78 pts := make([]chart.EPoint, len(rv)) 79 idx := 0 80 for k, v := range rv { 81 pts[idx].X = float64(k.Unix()) 82 pts[idx].Y = v 83 idx++ 84 } 85 slice.Sort(pts, func(i, j int) bool { 86 return pts[i].X < pts[j].X 87 }) 88 c.AddData(r.Group.String(), pts, chart.PlotStyleLinesPoints, Autostyle(ri)) 89 } 90 return &c, nil 91 }