Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

svg.gno

2.45 Kb · 78 lines
 1// Package svg draws the small on-chain SVGs of GnoRadio (covers, tickets,
 2// charts) with a strings.Builder, which keeps vm/qrender gas low.
 3package svg
 4
 5import (
 6	"encoding/base64"
 7	"strconv"
 8	"strings"
 9
10	"gno.land/p/nt/markdown/sanitize/v0"
11)
12
13type Canvas struct{ b strings.Builder }
14
15// New opens a w×h SVG whose <style> holds css.
16func New(w, h int, css string) *Canvas {
17	c := &Canvas{}
18	c.b.WriteString(`<svg xmlns="http://www.w3.org/2000/svg" width="` + itoa(w) + `" height="` + itoa(h) +
19		`" viewBox="0 0 ` + itoa(w) + ` ` + itoa(h) + `"><style>` + css + `</style>`)
20	return c
21}
22
23func (c *Canvas) Raw(s string) { c.b.WriteString(s) }
24
25// Rect draws a rectangle; extra holds more attributes, e.g. ` mask="url(#h)"`.
26func (c *Canvas) Rect(x, y, w, h, rx int, fill, extra string) {
27	c.b.WriteString(`<rect x="` + itoa(x) + `" y="` + itoa(y) + `" width="` + itoa(w) + `" height="` + itoa(h) +
28		`" rx="` + itoa(rx) + `" fill="` + fill + `"` + extra + `/>`)
29}
30
31func (c *Canvas) Circle(cx, cy, r int, fill string) {
32	c.b.WriteString(`<circle cx="` + itoa(cx) + `" cy="` + itoa(cy) + `" r="` + itoa(r) + `" fill="` + fill + `"/>`)
33}
34
35// Text writes s escaped; attrs follows font-size, e.g. ` text-anchor="end" class="m"`.
36func (c *Canvas) Text(x, y int, s, fill string, size int, attrs string) {
37	c.b.WriteString(`<text x="` + itoa(x) + `" y="` + itoa(y) + `" fill="` + fill + `" font-size="` + itoa(size) +
38		`"` + attrs + `>` + Escape(s) + `</text>`)
39}
40
41// Data closes the SVG and returns it as a base64 data URI.
42func (c *Canvas) Data() string {
43	c.b.WriteString("</svg>")
44	return "data:image/svg+xml;base64," + base64.StdEncoding.EncodeToString([]byte(c.b.String()))
45}
46
47// Image closes the SVG and returns it as a markdown image.
48func (c *Canvas) Image(alt string) string {
49	return "![" + sanitize.InlineText(alt) + "](" + c.Data() + ")"
50}
51
52// Escape makes text safe inside SVG: titles and names may hold '&'.
53func Escape(s string) string {
54	s = strings.ReplaceAll(s, "&", "&amp;")
55	s = strings.ReplaceAll(s, "<", "&lt;")
56	return strings.ReplaceAll(s, ">", "&gt;")
57}
58
59// Clip shortens s to n runes, ending with an ellipsis.
60func Clip(s string, n int) string {
61	r := []rune(s)
62	if len(r) <= n {
63		return s
64	}
65	return string(r[:n-1]) + "…"
66}
67
68// FNV is the 32-bit FNV-1a hash, used to pick a composition from a title.
69func FNV(s string) uint32 {
70	h := uint32(2166136261)
71	for i := 0; i < len(s); i++ {
72		h ^= uint32(s[i])
73		h *= 16777619
74	}
75	return h
76}
77
78func itoa(n int) string { return strconv.Itoa(n) }