1// Package piechart provides functionality to render a pie chart as an SVG image.2// It takes a list of PieSlice objects, each representing a slice of the pie with a value,3// color, and label, and generates an SVG representation of the pie chart.4package piechart56import (7 "math"89 "gno.land/p/nt/svg/v0"10 "gno.land/p/nt/ufmt/v0"11 "gno.land/p/sunspirit/md/v0"12)1314type PieSlice struct {15 Value float6416 Color string17 Label string18}1920// Render creates an SVG pie chart from given slices (value, color and label).21// It returns an img svg markup as a string, including a markdown header if a non-empty title is provided.22func Render(slices []PieSlice, title string) string {23 // Validate input slices length24 if len(slices) == 0 {25 return "\npiechart fails: no data provided"26 }2728 const (29 canvasWidth = 50030 canvasHeight = 20031 centerX = 100.032 centerY = 100.033 radius = 80.034 legendX = 21035 legendStartY = 3036 lineHeight = 2637 squareSize = 1638 fontSize = 1639 )4041 canvas := svg.NewCanvas(canvasWidth, canvasHeight)4243 // Sum all values to compute slices proportions44 var total float6445 for _, s := range slices {46 total += s.Value47 }4849 // Draw pie slices and legend in one pass50 startAngle := -math.Pi / 251 for i, s := range slices {52 if s.Value > 0 {53 // --- PIE SLICE ---54 // Calculate angle span for current slice55 angle := (s.Value / total) * 2 * math.Pi56 endAngle := startAngle + angle5758 // Compute start and end points on the circle circumference59 cosStart, sinStart := math.Cos(startAngle), math.Sin(startAngle)60 cosEnd, sinEnd := math.Cos(endAngle), math.Sin(endAngle)61 x1 := centerX + radius*cosStart62 y1 := centerY + radius*sinStart63 x2 := centerX + radius*cosEnd64 y2 := centerY + radius*sinEnd6566 // Determine if the arc should be a large arc (> 180 degrees) (Arc direction)67 largeArcFlag := 068 if angle > math.Pi {69 largeArcFlag = 170 }7172 // Build the SVG path for the pie slice73 path := ufmt.Sprintf(74 "M%.2f,%.2f L%.2f,%.2f A%.2f,%.2f 0 %d 1 %.2f,%.2f Z",75 centerX, centerY, x1, y1, radius, radius, largeArcFlag, x2, y2,76 )7778 // Colored slice79 canvas.Append(svg.Path{80 D: path,81 Fill: s.Color,82 })8384 startAngle = endAngle85 }8687 // --- LEGEND ---88 y := legendStartY + i*lineHeight89 // Colored square representing slice color90 canvas.Append(svg.Rectangle{91 X: legendX,92 Y: y - squareSize/2,93 Width: squareSize,94 Height: squareSize,95 Fill: s.Color,96 })9798 // Legend text showing label, value and percentage99 text := ufmt.Sprintf("%s: %.0f (%.1f%%)", s.Label, s.Value, s.Value*100/total)100 canvas.Append(svg.Text{101 X: legendX + squareSize + 8,102 Y: y + fontSize/3,103 Text: text,104 Fill: "#54595D",105 Attr: svg.BaseAttrs{106 Style: ufmt.Sprintf("font-family:'Inter var',sans-serif;font-size:%dpx;", fontSize),107 },108 })109 }110111 if title == "" {112 return canvas.Render("Pie Chart")113 }114 return md.H2(title) + canvas.Render("Pie Chart "+title)115}116Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.