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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

svg.gno

6.18 Kb · 316 lines
  1package svg
  2
  3import (
  4	"encoding/base64"
  5	"strings"
  6
  7	"gno.land/p/nt/bptree/v0"
  8	"gno.land/p/nt/ufmt/v0"
  9)
 10
 11type Canvas struct {
 12	Width, Height int
 13	ViewBox       string
 14	Elems         []Elem
 15	Style         *bptree.BPTree
 16}
 17
 18type Elem interface{ String() string }
 19
 20func NewCanvas(width, height int) *Canvas {
 21	return &Canvas{
 22		Width:  width,
 23		Height: height,
 24		Style:  nil,
 25	}
 26}
 27
 28func (c *Canvas) AddStyle(key, value string) *Canvas {
 29	if c.Style == nil {
 30		c.Style = bptree.NewBPTree32()
 31	}
 32	c.Style.Set(key, value)
 33	return c
 34}
 35
 36func (c *Canvas) WithViewBox(x, y, width, height int) *Canvas {
 37	c.ViewBox = ufmt.Sprintf("%d %d %d %d", x, y, width, height)
 38	return c
 39}
 40
 41// Render renders your canvas
 42func (c Canvas) Render(alt string) string {
 43	base64SVG := base64.StdEncoding.EncodeToString([]byte(c.String()))
 44	return ufmt.Sprintf("![%s](data:image/svg+xml;base64,%s)", alt, base64SVG)
 45}
 46
 47func (c Canvas) String() string {
 48	out := ""
 49	out += ufmt.Sprintf(`<svg xmlns="http://www.w3.org/2000/svg" width="%d" height="%d" viewBox="%s">`, c.Width, c.Height, c.ViewBox)
 50	if c.Style != nil {
 51		out += "<style>"
 52		c.Style.Iterate("", "", func(k string, val interface{}) bool {
 53			v := val.(string)
 54			out += ufmt.Sprintf("%s{%s}", k, v)
 55			return false
 56		})
 57		out += "</style>"
 58	}
 59	for _, elem := range c.Elems {
 60		out += elem.String()
 61	}
 62	out += "</svg>"
 63	return out
 64}
 65
 66func (c Canvas) Base64() string {
 67	out := c.String()
 68	return base64.StdEncoding.EncodeToString([]byte(out))
 69}
 70
 71func (c *Canvas) Append(elem ...Elem) {
 72	c.Elems = append(c.Elems, elem...)
 73}
 74
 75type BaseAttrs struct {
 76	ID          string
 77	Class       string
 78	Style       string
 79	Stroke      string
 80	StrokeWidth string
 81	Opacity     string
 82	Transform   string
 83	Visibility  string
 84}
 85
 86func (b BaseAttrs) String() string {
 87	var elems []string
 88
 89	if b.ID != "" {
 90		elems = append(elems, `id="`+b.ID+`"`)
 91	}
 92	if b.Class != "" {
 93		elems = append(elems, `class="`+b.Class+`"`)
 94	}
 95	if b.Style != "" {
 96		elems = append(elems, `style="`+b.Style+`"`)
 97	}
 98	if b.Stroke != "" {
 99		elems = append(elems, `stroke="`+b.Stroke+`"`)
100	}
101	if b.StrokeWidth != "" {
102		elems = append(elems, `stroke-width="`+b.StrokeWidth+`"`)
103	}
104	if b.Opacity != "" {
105		elems = append(elems, `opacity="`+b.Opacity+`"`)
106	}
107	if b.Transform != "" {
108		elems = append(elems, `transform="`+b.Transform+`"`)
109	}
110	if b.Visibility != "" {
111		elems = append(elems, `visibility="`+b.Visibility+`"`)
112	}
113	if len(elems) == 0 {
114		return ""
115	}
116	return strings.Join(elems, " ")
117}
118
119type Circle struct {
120	CX   int // center X
121	CY   int // center Y
122	R    int // radius
123	Fill string
124	Attr BaseAttrs
125}
126
127func (c Circle) String() string {
128	return ufmt.Sprintf(`<circle cx="%d" cy="%d" r="%d" fill="%s" %s/>`, c.CX, c.CY, c.R, c.Fill, c.Attr.String())
129}
130
131func NewCircle(cx, cy, r int, fill string) *Circle {
132	return &Circle{
133		CX:   cx,
134		CY:   cy,
135		R:    r,
136		Fill: fill,
137	}
138}
139
140func (c *Circle) WithClass(class string) *Circle {
141	c.Attr.Class = class
142	return c
143}
144
145type Ellipse struct {
146	CX   int // center X
147	CY   int // center Y
148	RX   int // radius X
149	RY   int // radius Y
150	Fill string
151	Attr BaseAttrs
152}
153
154func (e Ellipse) String() string {
155	return ufmt.Sprintf(`<ellipse cx="%d" cy="%d" rx="%d" ry="%d" fill="%s" %s/>`, e.CX, e.CY, e.RX, e.RY, e.Fill, e.Attr.String())
156}
157
158func NewEllipse(cx, cy int, fill string) *Ellipse {
159	return &Ellipse{
160		CX:   cx,
161		CY:   cy,
162		Fill: fill,
163	}
164}
165
166func (e *Ellipse) WithClass(class string) *Ellipse {
167	e.Attr.Class = class
168	return e
169}
170
171type Rectangle struct {
172	X, Y, Width, Height int
173	RX, RY              int // corner radiuses
174	Fill                string
175	Attr                BaseAttrs
176}
177
178func (r Rectangle) String() string {
179	return ufmt.Sprintf(`<rect x="%d" y="%d" width="%d" height="%d" rx="%d" ry="%d" fill="%s" %s/>`, r.X, r.Y, r.Width, r.Height, r.RX, r.RY, r.Fill, r.Attr.String())
180}
181
182func NewRectangle(x, y, width, height int, fill string) *Rectangle {
183	return &Rectangle{
184		X:      x,
185		Y:      y,
186		Width:  width,
187		Height: height,
188		Fill:   fill,
189	}
190}
191
192func (r *Rectangle) WithClass(class string) *Rectangle {
193	r.Attr.Class = class
194	return r
195}
196
197type Path struct {
198	D    string
199	Fill string
200	Attr BaseAttrs
201}
202
203func (p Path) String() string {
204	return ufmt.Sprintf(`<path d="%s" fill="%s" %s/>`, p.D, p.Fill, p.Attr.String())
205}
206
207func NewPath(d, fill string) *Path {
208	return &Path{
209		D:    d,
210		Fill: fill,
211	}
212}
213
214func (p *Path) WithClass(class string) *Path {
215	p.Attr.Class = class
216	return p
217}
218
219type Polygon struct { // closed shape
220	Points string
221	Fill   string
222	Attr   BaseAttrs
223}
224
225func (p Polygon) String() string {
226	return ufmt.Sprintf(`<polygon points="%s" fill="%s" %s/>`, p.Points, p.Fill, p.Attr.String())
227}
228
229func NewPolygon(points, fill string) *Polygon {
230	return &Polygon{
231		Points: points,
232		Fill:   fill,
233	}
234}
235
236func (p *Polygon) WithClass(class string) *Polygon {
237	p.Attr.Class = class
238	return p
239}
240
241type Polyline struct { // polygon but not necessarily closed
242	Points string
243	Fill   string
244	Attr   BaseAttrs
245}
246
247func (p Polyline) String() string {
248	return ufmt.Sprintf(`<polyline points="%s" fill="%s" %s/>`, p.Points, p.Fill, p.Attr.String())
249}
250
251func NewPolyline(points, fill string) *Polyline {
252	return &Polyline{
253		Points: points,
254		Fill:   fill,
255	}
256}
257
258func (p *Polyline) WithClass(class string) *Polyline {
259	p.Attr.Class = class
260	return p
261}
262
263type Text struct {
264	X, Y       int
265	DX, DY     int // shift text pos horizontally/ vertically
266	Rotate     string
267	Text, Fill string
268	Attr       BaseAttrs
269}
270
271func (c Text) String() string {
272	return ufmt.Sprintf(`<text x="%d" y="%d" dx="%d" dy="%d" rotate="%s" fill="%s" %s>%s</text>`, c.X, c.Y, c.DX, c.DY, c.Rotate, c.Fill, c.Attr.String(), c.Text)
273}
274
275func NewText(x, y int, text, fill string) *Text {
276	return &Text{
277		X:    x,
278		Y:    y,
279		Text: text,
280		Fill: fill,
281	}
282}
283
284func (c *Text) WithClass(class string) *Text {
285	c.Attr.Class = class
286	return c
287}
288
289type Group struct {
290	Elems []Elem
291	Fill  string
292	Attr  BaseAttrs
293}
294
295func (g Group) String() string {
296	out := ""
297	for _, e := range g.Elems {
298		out += e.String()
299	}
300	return ufmt.Sprintf(`<g fill="%s" %s>%s</g>`, g.Fill, g.Attr.String(), out)
301}
302
303func NewGroup(fill string) *Group {
304	return &Group{
305		Fill: fill,
306	}
307}
308
309func (g *Group) Append(elem ...Elem) {
310	g.Elems = append(g.Elems, elem...)
311}
312
313func (g *Group) WithClass(class string) *Group {
314	g.Attr.Class = class
315	return g
316}