Search Apps Documentation Source Content File Folder Download Copy Actions Download

gauge.gno

2.82 Kb · 115 lines
  1// Package gauge provides a simple way to render a gauge bar in SVG format.
  2package gauge
  3
  4import (
  5	"gno.land/p/demo/svg"
  6	"gno.land/p/nt/ufmt"
  7)
  8
  9type Config struct {
 10	PercentOnly  bool
 11	Width        int
 12	CanvasHeight int
 13	FontSize     int
 14	PaddingH     int
 15}
 16
 17var DefaultConfig = Config{
 18	PercentOnly:  false,
 19	Width:        300,
 20	CanvasHeight: 30,
 21	FontSize:     16,
 22	PaddingH:     6,
 23}
 24
 25// Render generates an SVG gauge bar.
 26// Parameters:
 27// - value: current value (must be <= total)
 28// - total: maximum value (must be > 0)
 29// - label: text label to display on the left side of the gauge
 30// - color: color of the filled part of the gauge (e.g., "#4caf50")
 31// - config: configuration options:
 32//   - PercentOnly: Only display the percentage on the right side; otherwise, display "value / total · percentage"
 33//   - Width: Width of the gauge in pixels
 34//   - CanvasHeight: Height of the gauge in pixels
 35//   - FontSize: Font size of the text in pixels
 36//   - PaddingH: Horizontal padding (for the text) in pixels
 37//
 38// Example usage: gauge.Render(30, 100, "Progress", "#4caf50", &gauge.Config{PercentOnly: true, Width: 400})
 39func Render(value int, total int, label string, color string, config Config) string {
 40	if total <= 0 {
 41		return "jauge fails: total must be greater than 0"
 42	}
 43	if value <= 0 {
 44		return "jauge fails: value must be greater than 0"
 45	}
 46	if value > total {
 47		return "jauge fails: value cannot be greater than total"
 48	}
 49
 50	canvasWidth := config.Width
 51	canvasHeight := config.CanvasHeight
 52	fontSize := config.FontSize
 53	paddingH := config.PaddingH
 54	canvas := svg.NewCanvas(canvasWidth, canvasHeight)
 55
 56	ratio := 0.0
 57	if total > 0 {
 58		ratio = float64(value) / float64(total)
 59	}
 60
 61	leftText := label
 62	rightText := ufmt.Sprintf("%d / %d · %0.0f%%", value, total, ratio*100)
 63	if config.PercentOnly {
 64		rightText = ufmt.Sprintf("%0.0f%%", ratio*100)
 65	}
 66
 67	// Background
 68	canvas.Append(svg.Rectangle{
 69		X:      0,
 70		Y:      0,
 71		Width:  canvasWidth,
 72		Height: canvasHeight,
 73		Fill:   "#e0e0e0",
 74		RX:     2,
 75		RY:     2,
 76	})
 77	// Filled bar
 78	canvas.Append(svg.Rectangle{
 79		X:      0,
 80		Y:      0,
 81		Width:  int(ratio * float64(canvasWidth)),
 82		Height: canvasHeight,
 83		Fill:   color,
 84		RX:     2,
 85		RY:     2,
 86	})
 87	// Left text (label)
 88	canvas.Append(svg.Text{
 89		X:    paddingH,
 90		Y:    canvasHeight / 2,
 91		Text: leftText,
 92		Fill: "#000000",
 93		Attr: svg.BaseAttrs{
 94			Style: ufmt.Sprintf(
 95				"font-family:'Inter var',sans-serif;font-size:%dpx;dominant-baseline:middle;text-anchor:start;",
 96				fontSize,
 97			),
 98		},
 99	})
100	// Right text (ratio + %)
101	canvas.Append(svg.Text{
102		X:    canvasWidth - paddingH,
103		Y:    canvasHeight / 2,
104		Text: rightText,
105		Fill: "#000000",
106		Attr: svg.BaseAttrs{
107			Style: ufmt.Sprintf(
108				"font-family:'Inter var',sans-serif;font-size:%dpx;dominant-baseline:middle;text-anchor:end;",
109				fontSize,
110			),
111		},
112	})
113
114	return canvas.Render("Jauge")
115}