pinggraph/generic.go

108 lines
1.8 KiB
Go

package main
import (
"net/http"
"sync"
"time"
"gonum.org/v1/plot"
"gonum.org/v1/plot/plotter"
"gonum.org/v1/plot/plotutil"
"gonum.org/v1/plot/vg"
"gonum.org/v1/plot/vg/draw"
"gonum.org/v1/plot/vg/vgsvg"
)
type statSheet struct {
Values []float64
Ok bool
}
type provider struct {
Current int
Values [3600]statSheet
Fetch func() []float64
NoVals int
ValTags []string
Name string
Y string
}
func (p *provider) Run() {
tick := time.NewTicker(time.Second)
for {
<-tick.C
vals := p.Fetch()
// fmt.Println("tick", p.Name, vals)
p.Values[p.Current] = statSheet{vals, true}
p.Current++
if p.Current >= 3600 {
p.Current = 0
}
}
}
var xypool = sync.Pool{
New: func() interface{} {
return make(plotter.XYs, 3600)
},
}
func (prov *provider) Render(w http.ResponseWriter, r *http.Request) {
p := plot.New()
p.Legend.Top = true
p.Title.Text = prov.Name
p.X.Label.Text = "Time (seconds)"
p.Y.Label.Text = prov.Y
var points = make([]plotter.XYs, prov.NoVals)
var allocs = make([]plotter.XYs, prov.NoVals)
defer func() {
for _, x := range allocs {
xypool.Put(x)
}
}()
for i := range points {
alloc := xypool.Get().(plotter.XYs)
points[i] = alloc
allocs[i] = alloc
}
for i, x := range prov.Values {
if !x.Ok {
for yi := range points {
points[yi] = points[yi][:i]
}
break
}
for yi, y := range x.Values {
points[yi][i] = plotter.XY{
Y: y,
X: float64(i),
}
}
}
for i, x := range points {
line, err := plotter.NewLine(x)
if err != nil {
panic(err)
}
line.Color = plotutil.Color(i)
line.Dashes = plotutil.Dashes(i)
p.Add(line)
p.Legend.Add(prov.ValTags[i], line)
}
canv := vgsvg.New(vg.Millimeter*290, vg.Millimeter*200)
p.Draw(draw.New(canv))
w.Header().Set("content-type", "image/svg+xml")
canv.WriteTo(w)
}