// Package sparkline renders inline SVG sparklines and trend // charts for the dashboard and host repo page. All output is // pure server-rendered SVG with no JavaScript, no external // stylesheet, and no client library. package sparkline import ( "fmt" "html/template" "math" "strings" ) // RenderSparkline returns an inline SVG element of the // given size containing a single polyline normalised across the // full y-range of points. NaN entries break the polyline. With // fewer than two real points the SVG still renders but contains // only a faint baseline + an em-dash placeholder. func RenderSparkline(points []float64, width, height int) template.HTML { const pad = 2 w := width h := height innerW := w - 2*pad innerH := h - 2*pad var real []float64 for _, p := range points { if !math.IsNaN(p) { real = append(real, p) } } var b strings.Builder fmt.Fprintf(&b, ``, w, h) if len(real) < 2 { fmt.Fprintf(&b, ``, pad, h/2, w-pad, h/2) fmt.Fprintf(&b, ``, w/2, h/2+4, h-6) b.WriteString(``) return template.HTML(b.String()) } min, max := real[0], real[0] for _, v := range real { if v < min { min = v } if v > max { max = v } } span := max - min if span == 0 { span = 1 } stepX := 0.0 if len(points) > 1 { stepX = float64(innerW) / float64(len(points)-1) } var seg strings.Builder flush := func() { if seg.Len() == 0 { return } fmt.Fprintf(&b, ``, strings.TrimSpace(seg.String())) seg.Reset() } for i, v := range points { if math.IsNaN(v) { flush() continue } x := float64(pad) + stepX*float64(i) y := float64(pad) + float64(innerH) - (v-min)/span*float64(innerH) fmt.Fprintf(&seg, "%.2f,%.2f ", x, y) } flush() cur := real[len(real)-1] first := real[0] delta := cur - first sign := "+" if delta < 0 { sign = "-" delta = -delta } fmt.Fprintf(&b, `current %.0f, %s%.0f over window`, cur, sign, delta) b.WriteString(``) return template.HTML(b.String()) }