Abstract
SVGo is a Go Programming language [1] library that generates code as defined by the Scalable Vector Graphics 1.1 Recommendation. The library includes functions for structure, metadata (desc, title, defs, group), transformations (translate, rotate, scale, skew), links (a, use), and scripting with SVG shapes (circle, ellipse, polygon, rect), paths (general, arc, cubic and quadratic bezier paths), line, polyline, image, text, linear and radial gradients.
This paper describes the design of the library and its use for sketching, making generative art, data-driven IT architecture diagramming tools, serving SVG within web servers, and making pictures from Internet data and services.
Table of Contents
The library is designed to closely follow the semantics of the standard, where that the developer/designer works directly with SVG objects (function names strive to correspond directly with SVG elements) applying standard CSS styles to the elements using Go functions as the logical unit of work. A design goal of the library is to produce standard, clean, readable code that is close to tuned, hand-crafted code that makes full use of a variety of SVG elements, without resorting to representing all objects as paths.
In many ways the API and environment is inspired by Processing [2], and during early development, Processing sketches were translated to use SVGo to test usability and API design decisions.
SVGo runs anywhere the Go language is supported, and is completely portable across these architectures and operating systems: x86-64, x86, and ARM, on FreeBSD, Linux, Mac OS X, and Windows) [3]. The library uses the Go standard libraries for formatting, I/O, operating system, XML, and strings with no other dependencies. Hosted on Github [4], SVGo is tracked on the Go Dashboard [5], and as of this writing, is ranked in the top 25 of the most installed packages of all time.
There are 49 public functions organized in these groups:
shapes, paths, and lines (14)
structure and metadata (10)
transformations (10)
images (1)
text (3)
color (2)
gradients (2)
grouping (2)
links (3)
utility (1)
scripting (1)
A typical function call in SVGo looks like this:
canvas.Rect(100, 200, 250, 125, "fill:none;stroke:red")
Where canvas refers to a structure which contains a Go io.Writer [6] that specifies the destination for the generated SVG. The io.Writer interface is designed so that the destination can be files, web servers, network connections, etc.
Rect is the SVG object, (in Go, functions beginning with an upper-case character are public), followed by a set of integer parameters (100, 200, 250, 125). The final optional parameter is a string in CSS [7] format that applies style to the object. The generated SVG for the call above is:
<rect x="100" y="200" width="250" height="125" style="fill:none;stroke:red"/>
If the final parameter is omitted, the SVG implementation's default style is applied. The optional parameter(s) may be a single string, which generates a single SVG style attribute, or Go variadic parameters---a series strings which represent name, value pairs which generate XML attribute names and values applied to the SVG element. For example:
canvas.Rect(100, 200, 250, 125, `id="redbox"`, `fill="red"`)
generates:
<rect x="100" y="200" width="250" height="125" id="redbox" fill="red"/>
This alternative form is useful if the standard API needs to augmented by adding attributes and values. It is often useful to apply a global style to a graphic elements, for example those generated in a loop:
canvas.Gstyle("fill:blue;stroke:red")
for x,y := 10,10; y < 500; y+=50 {
canvas.Rect(x, y, 60, 40)
}
canvas.Gend()
Here is a complete Go program which generates SVG to the standard output file:
package main
import (
"os"
"github.com/ajstarks/svgo"
)
func main() {
width := 500
height := 500
canvas := svg.New(os.Stdout)
canvas.Start(width, height)
canvas.Rect(0, 0, width, height)
canvas.Ellipse(width/2, height, width/2,height/3,"fill:rgb(44,77,232)")
canvas.Text(width/2, height/2, "Hello, World", "fill:white;font-size:48pt;text-anchor:middle")
canvas.End()
}
The program begins with standard Go code to create a standalone
application, and imports the SVGo library along with the Go
standard operating system library, os. To
install an external library on your system, use the
goinstall program to fetch the library from
a code repository with the command goinstall github.com/ajstarks/svgo. Once installed, you refer to the library with the same name.
In the main function, variables represent the SVG canvas' width and height, and the destination for the generated SVG. Next, the SVG document begins, and the first call of Rect creates a black rectangle (note the lack of style string), followed by a blue ellipse, and white text centered on the canvas. The program generates this SVG:
<?xml version="1.0"?>
<!-- Generated by SVGo -->
<svg width="500" height="500"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<rect x="0" y="0" width="500" height="500" />
<ellipse cx="250" cy="500" rx="250" ry="166" style="fill:rgb(44,77,232)"/>
<text x="250" y="250" style="fill:white;font-size:48pt;text-anchor:middle">Hello, World</text>
</svg>
The general philosophy of SVGo is to decompose pictures into components, applying style and transformations, treating SVG as the "assembly language" for graphics, with the SVGo program as the compiler.
Go encourages programming with types, and here is the type definition that SVGo uses to specify gradients:
type Offcolor struct {
Offset uint8
Color string
Opacity float
}
Given the definition, you define gradient variables, and use them in your programs.
lg := []svg.Offcolor{
{0, "rgb(255,255,0)", 1.0}, // 0% offset, opaque yellow
{100, "rgb(255,0,0)", .5}, // 100% offset, transparent red
{0, "rgb(200,200,200)", .75}, // 0% offset, 75% transparent gray
{100, "rgb(0,0,255)", 1.0}, // 100% offset, opaque green
}
canvas := svg.New(os.Stdout)
canvas.Defs()
canvas.LinearGradient("h", 0, 100, 0, 0, lg)
canvas.LinearGradient("v", 0, 0, 100, 0, lg)
canvas.DefEnd()
canvas.Rect(300, 200, 100, 100, "fill:url(#h)")
canvas.Rect(100, 200, 100, 100, "fill:url(#v)")
This code defines a slice [8] of Offcolors, with four elements which define the offset, color and opacity of a linear gradient named lg. Next, two linear gradients are defined: "h" for for horizontal, and "v" for vertical, which are used as a fill pattern for Rects
A common pattern is to read data in XML or JSON, and produce a graphical representation in SVG. This pattern works for local files and is easily adapted for data fetched over the network from services that provide APIs like Flickr and Twitter.
Go's standard xml and json packages support unmarshaling input data into data structures which are then processed to make pictures. A typical program that uses this pattern:
package main
// Imports
import (
"github.com/ajstarks/svgo"
"xml"
"os"
"io"
"flag"
"fmt"
)
// <thing top="100" left="100" sep="50">
// <item width="75" height="100" name="Little" color="blue">This is small</item>
// <item width="150" height="200" name="Big" color="green">This is large</item>
// </thing>
type Thing struct {
Top int `xml:"attr"`
Left int `xml:"attr"`
Sep int `xml:"attr"`
Item []item
}
type item struct {
Width int `xml:"attr"`
Height int `xml:"attr"`
Name string `xml:"attr"`
Color string `xml:"attr"`
Text string `xml:"chardata"`
}
var (
width = flag.Int("w", 1024, "width")
height = flag.Int("h", 768, "height")
canvas = svg.New(os.Stdout)
)
// Open the file
func dothing(location string) {
f, err := os.Open(location)
defer f.Close()
if err == nil {
readthing(f)
} else {
fmt.Fprintf(os.Stderr, "%v\n", err)
}
}
// Read the file, loading the defined structure
func readthing(r io.Reader) {
var t Thing
if err := xml.Unmarshal(r, &t); err == nil {
drawthing(t)
} else {
fmt.Fprintf(os.Stderr, "Unable to parse components (%v)\n", err)
}
}
// use the items of "thing" to make the picture
func drawthing(t Thing) {
x := t.Left
y := t.Top
for _, v := range t.Item {
style := fmt.Sprintf("font-size:%dpx;fill:%s", v.Width/2, v.Color)
canvas.Circle(x, y, v.Height/4, "fill:"+v.Color)
canvas.Text(x+t.Sep, y, v.Name+":"+v.Text+"/"+v.Color, style)
y += v.Height
}
}
With the goplay command, a simple web application included in the standard Go distribution, the developer/designer uses a web browser (tested on Chrome, Firefox, and Safari on Windows and Mac OS X) to "play" with snippets of Go code and immediately see the results. The generated SVG is placed in-line, interpreted directly, showing the picture. After starting goplay and entering a URL like: http://localhost:3999/hellosvg.go, code is displayed in the left-hand textarea, ready to be edited and built. Pressing Shift-ENTER compiles and runs the code and shows the output on the right. If you want to tweak the program, move to the textarea, make the change, and press Shift-ENTER again. This method allows you to sketch in code [9], with immediate feedback. This mode of working is particularly useful when working out an algorithm, prototyping a visual effect, or simply playing around. For even greater interaction, goplay has an option to build/display on each keystroke.
Go's standard library includes a pseudo random number generator, which can be used to create variable visual effects. By loading a program in goplay, you can quickly try random iterations, and also tweak variables to alter the picture. For example, in the program below, you can alter the available colors, iterations, and maximum stroke width. Note how the program is structured: a single function, randarc embodies the picture, with its behavior controlled by its parameters and variables. In this case the picture is designed to scale with the overall SVG dimensions by tying the parameters to width and height. Also note how Go's Sprintf function is used dynamically create the CSS style.
package main
import (
"os"
"rand"
"time"
"fmt"
"github.com/ajstarks/svgo"
)
const arcfmt = "stroke:%s;stroke-opacity:%.2f;stroke-width:%dpx;fill:none"
var colors = []string{"red", "green", "blue", "white", "gray"}
func randarc(canvas *svg.SVG, aw, ah, sw int, f1, f2 bool) {
begin := rand.Intn(aw)
arclength := rand.Intn(aw)
end := begin + arclength
baseline := ah / 2
al := arclength / 2
cl := len(colors)
canvas.Arc(begin, baseline, al, al, 0, f1, f2, end, baseline,
fmt.Sprintf("stroke:%s;stroke-opacity:%.2f;stroke-width:%dpx;fill:none",
colors[rand.Intn(cl)], rand.Float64(), rand.Intn(sw)))
}
func main() {
rand.Seed(time.Nanoseconds() % 1e9)
width := 300
height := 300
aw := width / 2
maxstroke := height / 10
iterations := 50
canvas := svg.New(os.Stdout)
canvas.Start(width, height)
canvas.Rect(0, 0, width, height)
for i := 0; i < iterations; i++ {
randarc(canvas, aw, height, maxstroke, false, true)
randarc(canvas, aw, height, maxstroke, false, false)
}
canvas.End()
}
Even simple loops can be used to make interesting pictures. In this case the "tweakable" items are α and αi (controls the transparency), the text to be displayed ("s"), the rotation angle, θ with its interval θi
package main
import (
"os"
"fmt"
"github.com/ajstarks/svgo"
)
func main() {
width := 200
height := 200
α := 1.0
αi := 0.03
θi := 30.0
h2 := height/2
w2 := width/2
canvas := svg.New(os.Stdout)
canvas.Start(width, height)
canvas.Rect(0, 0, width, height)
canvas.Gstyle("font-family:serif;fill:white;font-size:72pt")
canvas.Gtransform(fmt.Sprintf("translate(%d,%d)", w2, h2))
for θ := 0.0; θ <= 360.0; θ += θi {
canvas.Text(0, 0, "s",
fmt.Sprintf(`transform="rotate(%.3f)"`, θ),
fmt.Sprintf(`fill-opacity="%.3f"`,α))
α -= αi
}
canvas.Gend()
canvas.Gend()
canvas.End()
}
Here is "s", "v", and "g":
Here is the result of drawing the letter "i", and varying the angle: 10, 30, 45, 90 degrees
Other comparative examples are found at the FORM+CODE website [10].
The Go standard library includes the http package, which facilites writing web servers and applications, and its use of the io.Writer interface allows you to flexibly specify the destination of the generated SVG, so that it's as easy to serve SVG in a web server as it is writing to the screen.
This code generates colored shapes based on a URL. The main function creates two handlers which match /circle/ and /rect/ URLs, and then the program listens for requests. The corresponding circle and rect functions then create shapes based on a style passed in the URL. After running the program, opening: http://localhost:1958/circle/green displays a green circle in the web browser.
package main
import (
"http"
"log"
"strings"
"github.com/ajstarks/svgo"
)
const defaultstyle = "fill:rgb(127,0,0)"
func main() {
http.Handle("/circle/", http.HandlerFunc(circle))
http.Handle("/rect/", http.HandlerFunc(rect))
err := http.ListenAndServe(1958, nil)
if err != nil {
log.Println("ListenAndServe:", err)
}
}
func circle(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "image/svg+xml")
s := svg.New(w)
s.Start(500, 500)
s.Title("Circle")
s.Circle(250, 250, 125, shapestyle(req.URL.Path))
s.End()
}
func rect(w http.ResponseWriter, req *http.Request) {
w.Header().Set("Content-Type", "image/svg+xml")
s := svg.New(w)
s.Start(500, 500)
s.Title("Rectangle")
s.Rect(250, 250, 100, 200, shapestyle(req.URL.Path))
s.End()
}
func shapestyle(path string) string {
i := strings.LastIndex(path, "/") + 1
if i > 0 && len(path[i:]) > 0 {
return "fill:" + path[i:]
}
return defaultstyle
}
This picture demonstrates Google Web Fonts [11] and its API with SVGo. The key to its operation is the URI:
http://fonts.googleapis.com/css?family={fonts}
where {fonts} is a pipe-delimited list of font names. The result of performing a HTTP GET on this URI is CSS code that specifies the fonts. For example,
http://fonts.googleapis.com/css?family=Pacifico
produces:
@font-face {
font-family: 'Pacifico';
font-style: normal;
font-weight: normal;
src: local('Pacifico'), url('http://themes.googleusercontent.com/font?kit=fKnfV28XkldRW297cFLeqfesZW2xOQ-xsNqO47m55DA') format('truetype');
}
The program to generate the picture works by using a Go function to perform the GET (googlefont(fontname string)), and place the resulting CSS in a SVG defs element. The program is then able to use the web fonts by name just like any other local font. In this case looping over the names in the list, and displaying "Hello, World" in the corresponding font.
SVGo includes the Script function that applies scripting to graphics elements. The following program uses Go's composite literals to specify data for polygons, displays the polygons, and applies JavaScript to the graphics elements to make them draggable [12].
func main() {
// HTML5 logo data from
// "Understanding and Optimizing Web Graphics", Session 508,
// Dean Jackson, Apple WWDC 2011
//
// Draggable elements via Jeff Schiller's dragsvg Javascript library
// shield
var sx = []int{71, 30, 481, 440, 255}
var sy = []int{460, 0, 0, 460, 512}
// highlight
var hx = []int{256, 405, 440, 256}
var hy = []int{472, 431, 37, 37}
// "five"
var fx = []int{181, 176, 392, 393, 396, 397, 114, 115, 129, 325, 318, 256, 192, 188, 132, 139, 256, 371, 372, 385, 387, 371}
var fy = []int{208, 150, 150, 138, 109, 94, 94, 109, 265, 265, 338, 355, 338, 293, 293, 382, 414, 382, 372, 223, 208, 208}
canvas := svg.New(os.Stdout)
width := 512
height := 512
// begin the document with the onload event, and namespace for dragging
canvas.Start(width, height, `onload="initializeDraggableElements();"`, `xmlns:drag="http://www.codedread.com/dragsvg"`)
canvas.Rect(0, 0, width, height) // black background
canvas.Script("application/javascript", "http://www.codedread.com/dragsvg.js") // reference the drag script
canvas.Polygon(sx, sy, `drag:enable="true"`, canvas.RGB(227, 79, 38)) // draggable shield
canvas.Polygon(fx, fy, `drag:enable="true"`, canvas.RGB(219, 219, 219)) // draggable five
canvas.Polygon(hx, hy, `drag:enable="true"`, canvas.RGBA(255, 255, 255, 0.3)) // draggable highlight
canvas.End()
}
SVGo is used to create a set of visualization tools for use in IT architecture and related disciplines. The tools operate from the principle that precise and consistent graphical views are generated from standard data representations in XML. Separation of data and view allows for independent analysis of data and the generation of alternative and combined/composite views with little extra effort. In all cases the user is not concerned with the details of layout, style, the tools automatically handle these aspects.
In addition to a general-purpose grid-based layout diagramming tool described below, SVGo has been used to develop tools to visualize timelines, server configurations, proportional maps, technology stacks, portfolio views, and roadmaps.
All tools have a common command line structure, and generate SVG to standard output. The common practice is to manage collections of visualizations from a project directory, and generate the visualization sets via batch files.
Compx is a tool for drawing "component" diagrams, where items are arranged on an explicit grid, optionally connected at compass points. Components can be labeled boxes, images, or symbols that represent objects such as databases, servers, roles, folders, networks, and textual notes.
XML describes the layout and connections. For example, this represents the layout and connections between four components:
<components top="30" left="30" gutter="100">
<comp id="t1" row="0" col="0" width="200" height="100" name="Thing 1" color="maroon"/>
<comp id="t2" row="0" col="1" width="200" height="100" name="Thing 2">
<connect sloc="w" dloc="e" dest="t1" mark="s">Stuff</connect>
<connect sloc="s" dloc="n" dest="t4" mark="d">Nonsense</connect>
</comp>
<comp id="t3" row="1" col="0" width="200" height="100" name="Thing 3" shape="db">
<connect sloc="n" dloc="s" dest="t1" mark="d">Data</connect>
</comp>
<comp id="t4" row="1" col="1" width="200" height="100" name="Thing 4"/>
</components>
By transcoding SVG to JPEG, PNG or PDF [13], the output of the tools integrate with tools such as Microsoft Visio, PowerPoint and Word. For example, If subsequent editing or distribution is required, SVG representations may be imported directly into Microsoft Visio with full object integrity. [14]
For example, these screenshots show using an editor to mange the input, a command line to run the tool, and the output in a browser and Microsoft Visio.
The Internet is full of interesting data that you use to make pictures, and most services include an API to get at the data. Using the same pattern described above, the developer/designer can retrieve the data from the network and transform the data to interesting pictures.
The program flickr50 uses the Flickr API to find the most interesting 50 pictures tagged with a search keyword, and produces a clickable picture grid.
The function that displays the grid is:
// imageGrid reads the response from Flickr, and creates a grid of images
func imageGrid(f FlickrResp, x, y, cols, gutter int, imgsize string) {
if f.Stat != "ok" {
fmt.Fprintf(os.Stderr, "%v\n", f)
return
}
xpos := x
for i, p := range f.Photos.Photo {
if i%cols == 0 && i > 0 {
xpos = x
y += (imageHeight + gutter)
}
canvas.Link(makeURI(p, ""), p.Title)
canvas.Image(xpos, y, imageWidth, imageHeight, makeURI(p, "s"))
canvas.LinkEnd()
xpos += (imageWidth + gutter)
}
}
Tweetfreq queries the twitter API and shows tweeting frequency of a list of twitter users over time:
Here's the code to generate a tweetfreq line:
// Draw the circles that represent tweets on a timeline
canvas.Gstyle(markerfill)
for i := 0; i < ntweets; i++ {
canvas.Circle(int(vmap(rfc1123sec(twitter.Results[i].Created_at),
isosec(b), isosec(e), pl, rmargin)),
int(y+(lineheight/2)), int(markerwidth/2))
}
canvas.Gend()
tsg is similar to flickr50, but uses the Twitter avatar as the picture element, with links to tweets.
// make a clickable grid of tweets from the Atom feed
func tgrid(x, y, w, h, nc int, t Feed) {
var slink, imlink string
xp := x
for i, entry := range t.Entry {
for _, link := range entry.Link {
switch link.Rel {
case "alternate":
slink = link.Href
case "image":
imlink = link.Href
}
}
if i%nc == 0 && i > 0 {
xp = x
y += h
}
canvas.Link(slink, slink)
canvas.Image(xp, y, imw, imh, imlink)
canvas.LinkEnd()
xp += w
}
}
Continuing the picture grid theme, tumblrpic parses the JSON [15] response from the tumblr API, picking out the photos and displaying them on a flexible grid (the layout flexes vertically and horizontally depending on the number of columns and tumblr blogs queried.)
tumblrpic is also designed to flexibly read from standard input, named file, or the network:
// resource gives a ReadCloser given a local file or URL
func resource(name string) (io.ReadCloser, os.Error) {
if len(name) == 0 {
return os.Stdin, nil
}
if localfile {
return os.Open(name)
}
h, err := http.Get(fmt.Sprintf(apifmt, name, apiKey, piclimit))
return h.Body, err
}
To visualize Layer Tennis matches [16], here are three views: poster, which shows all the volleys of an individual match: [17]
func ltposter(x, y, w, h int, f []string) {
canvas.Image(x, y, w*2, h*2, f[0]) // first file, assumed to be the banner
y = y + (h * 2)
for i := 1; i < len(f); i += 2 {
canvas.Image(x, y, w, h, f[i])
canvas.Image(x+w, y, w, h, f[i+1])
if i%2 == 1 {
y += h
}
}
}
the opacity style stacks all of the volleys in a single picture:
func ltop(x, y, w, h int, f []string) {
for i := 1; i < len(f); i++ { // skip the first file, assumed to be the banner
canvas.Image(x, y, w, h, f[i], "opacity:0.2")
}
}
and season view shows all of a season's matches row or column-wise [18]
func ltrow(x, y, w, h int, f []string) {
for i := 0; i < len(f); i++ {
canvas.Image(x, y, w, h, f[i])
x += w
}
}
func ltcol(x, y, w, h int, f []string) {
for i := 0; i < len(f); i++ {
canvas.Image(x, y, w, h, f[i])
y += h
}
}
Integer values are used for coordinates (x,y) and dimensions (w, h). Where applicable, a final variadic argument specifies the style to be applied to the object. The style strings follow the CSS standard; name:value pairs delimited by semicolons, or a series of name="value" pairs. For example: "fill:none; opacity:0.3" or fill="none" opacity="0.3"
The Offcolor type is used to specify the offset, color, and opacity of stop colors in linear and radial gradients:
type Offcolor struct {
Offset uint8
Color string
Opacity float
}
New(w io.Writer) *SVG Constructor, Specify the output destination.
Start(w int, h int, attributes ...string) begin the SVG document with the width w and height h. Optionally add additional elements (such as additional namespaces or scripting events).
Startview(w, h, minx, miny, vw, vh int) begin the SVG document with the width w, height h, with a viewBox at minx, miny, vw, vh.
End() end the SVG document
Script(scriptype string, data ...string) Script defines a script with a specified type, (for example "application/javascript"). if the first variadic parameter is a link, use only the link reference. Otherwise, treat variadic arguments as the text of the script (marked up as CDATA). If no data is specified, simply close the script element.
Gstyle(s string) begin a group, with the specified style.
Gtransform(s string) begin a group, with the specified transform, end with Gend().
Translate(x, y int) begins coordinate translation to (x,y), end with Gend().
Scale(n float64) scales the coordinate system by n, end with Gend().
ScaleXY(x, y float64) scales the coordinate system by x, y. End with Gend().
SkewX(a float64) SkewX skews the x coordinate system by angle a, end with Gend().
SkewY(a float64) SkewY skews the y coordinate system by angle a, end with Gend().
SkewXY(ax, ay float64) SkewXY skews x and y coordinate systems by ax, ay respectively, end with Gend().
Rotate(r float64) rotates the coordinate system by n degrees, end with Gend().
TranslateRotate(x, y int, r float64) translates the coordinate system to (x,y), then rotates to r degrees, end with Gend().
RotateTranslate(x, y int, r float64) rotates the coordinate system r degrees, then translates to (x,y), end with Gend().
Gid(s string) begin a group, with the specified id.
Gend() end the group (must be paired with Gstyle, Gtransform, Gid).
Def() begin a definition block.
DefEnd() end a definition block.
Mask(string, x int, y int, w int, h int, s ...string) creates a mask with a specified id, dimension, and optional style.
MaskEnd() ends the Mask element.
Desc(s string) specify the text of the description.
Title(s string) specify the text of the title.
Link(href string, title string) begin a link named "href", with the specified title.
LinkEnd() end the link.
Use(x int, y int, link string, s ...string) place the object referenced at link at the location x, y.
Circle(x int, y int, r int, s ...string) draw a circle, centered at x,y with radius r.
Ellipse(x int, y int, w int, h int, s ...string) draw an ellipse, centered at x,y with radii w, and h.
Polygon(x []int, y []int, s ...string) draw a series of line segments using an array of x, y coordinates.
Rect(x int, y int, w int, h int, s ...string) draw a rectangle with upper left-hand corner at x,y, with width w, and height h.
CenterRect(x int, y int, w int, h int, s ...string) draw a rectangle with its center at x,y, with width w, and height h.
Roundrect(x int, y int, w int, h int, rx int, ry int, s ...string) draw a rounded rectangle with upper the left-hand corner at x,y, with width w, and height h. The radii for the rounded portion is specified by rx (width), and ry (height).
Square(x int, y int, s int, style ...string) draw a square with upper left corner at x,y with sides of length s.
Path(p string, s ...style) draw the arbitrary path as specified in p, according to the style specified in s.
Arc(sx int, sy int, ax int, ay int, r int, large bool, sweep bool, ex int, ey int, s ...string) draw an elliptical arc beginning coordinate at sx,sy, ending coordinate at ex, ey. The width and height of the arc are specified by ax, ay, the x axis rotation is r.
If sweep is true, then the arc will be drawn in a "positive-angle" direction (clockwise), if false, the arc is drawn counterclockwise.
if large is true, the arc sweep angle is greater than or equal to 180 degrees, otherwise the arc sweep is less than 180 degrees.
Bezier(sx int, sy int, cx int, cy int, px int, py int, ex int, ey int, s ...string) draw a cubic bezier curve, beginning at sx,sy, ending at ex,ey with control points at cx,cy and px,py.
Qbez(sx int, sy int, cx int, cy int, ex int, ey int, s...string) draws a quadratic bezier curve, with optional style beginning at sx,sy, ending at ex, sy, with the control point at cx, cy.
Line(x1 int, y1 int, x2 int, y2 int, s ...string) draw a line segment between x1,y1 and x2,y2.
Polyline(x []int, y []int, s ...string) draw a polygon using coordinates specified in x,y arrays.
Image(x int, y int, w int, h int, link string, s ...string) place at x,y (upper left hand corner), the image with width w, and height h, referenced at link.
Text(x int, y int, t string, s ...string) Place the specified text, t at x,y according to the style specified in s.
Textlines(x, y int, s []string, size, spacing int, fill, align string) Places lines of text in s, starting at x,y, at the specified size, fill, and alignment, and spacing.
Textpath(t string, pathid string, s ...string) places optionally styled text along a previously defined path.
RGB(r int, g int, b int) string creates a style string for the fill color designated by the (r)ed, g(reen), (b)lue components.
RGBA(r int, g int, b int, a float64) string as above, but includes the color's opacity as a value between 0.0 (fully transparent) and 1.0 (opaque).
LinearGradient(id string, x1, y1, x2, y2 uint8, sc []Offcolor) constructs a linear color gradient identified by id, along the vector defined by (x1,y1), and (x2,y2). The stop color sequence defined in sc. Coordinates are expressed as percentages.
RadialGradient(id string, cx, cy, r, fx, fy uint8, sc []Offcolor) constructs a radial color gradient identified by id, centered at (cx,cy), with a radius of r. (fx, fy) define the location of the focal point of the light source. The stop color sequence defined in sc. Coordinates are expressed as percentages.
[1] The Go Programming Language
[2] Processing
[3] Go supported architectures
[4] SVGo Github link
[6] io.Writer
[7] Styling with CSS
[8] Slice type -- Go Programming Language Specification
[9] Processing Development Environment (PDE)
[10] Reas, Casey and McWilliams, Chandler, FORM+CODE in Design, Art, and Architecture - Code examples: Repeat: Embedded Iteration, Parameterize: Wave
[11] Google Web Fonts API
[12] Schiller, Jeff, Draggable SVG (Web)
[13] Batik toolkit, SVG Rasterizer
[14] See, Richard et al., SVG Scenarios using Microsoft Office Visio 2003
[15] Introducing JSON
[16] Coudal Partners' Layer Tennis Presented by Adobe Creative Suite | Tennis HQ.
[17] Layer Tennis Season Three, Match 2: Aaron Scamihorn vs Nick Campbel
[18] Layer Tennis Season 3 Recap
[20] Proportional Maps: an alternative to pie charts
[21] Layer Tennis Remix