diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json new file mode 100644 index 0000000..b22a6f2 --- /dev/null +++ b/Godeps/Godeps.json @@ -0,0 +1,14 @@ +{ + "ImportPath": "github.com/cupcake/sigil", + "GoVersion": "go1.5.1", + "Packages": [ + "./..." + ], + "Deps": [ + { + "ImportPath": "github.com/ajstarks/svgo", + "Comment": "go.weekly.2012-01-27-112-g7729261", + "Rev": "77292617dc6b7ef6c9813385a6b6089969997285" + } + ] +} diff --git a/Godeps/Readme b/Godeps/Readme new file mode 100644 index 0000000..4cdaa53 --- /dev/null +++ b/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/README.md b/README.md index c8b58e7..878452c 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Sigil +![Deploy To Heroku](https://heroku.com/deploy?template=https://github.com/cupcake/sigil/tree/master) + ![Sigil's inverted Sigil](https://sigil.cupcake.io/Sigil?inverted=1) ![Sigil's Sigil](https://sigil.cupcake.io/Sigil) diff --git a/app.json b/app.json new file mode 100644 index 0000000..f46ffb5 --- /dev/null +++ b/app.json @@ -0,0 +1,15 @@ +{ + "name": "sigil", + "description": "Deterministic identicon generator", + "keywords": [ + "go", + "identicon" + ], + "image": "heroku/go", + "mount_dir": "src/github.com/cupcake/sigil", + "website": "https://sigil.cupcake.io/", + "repository": "http://github.com/cupcake/sigil", + "env": { + "GO15VENDOREXPERIMENT": "1" + } +} diff --git a/vendor/github.com/ajstarks/svgo/LICENSE b/vendor/github.com/ajstarks/svgo/LICENSE new file mode 100644 index 0000000..ea5a772 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/LICENSE @@ -0,0 +1,3 @@ +The contents of this repository are Licensed under +the Creative Commons Attribution 3.0 license as described in +http://creativecommons.org/licenses/by/3.0/us/ diff --git a/vendor/github.com/ajstarks/svgo/README.markdown b/vendor/github.com/ajstarks/svgo/README.markdown new file mode 100644 index 0000000..2e5fadb --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/README.markdown @@ -0,0 +1,668 @@ +#SVGo: A Go library for SVG generation# + +The library generates SVG as defined by the Scalable Vector Graphics 1.1 Specification (). +Output goes to the specified io.Writer. + +## Supported SVG elements and functions ## + +### Shapes, lines, text + + circle, ellipse, polygon, polyline, rect (including roundrects), line, text + +### Paths + + general, arc, cubic and quadratic bezier paths, + +### Image and Gradients + + image, linearGradient, radialGradient, + +### Transforms ### + + translate, rotate, scale, skewX, skewY + +### Filter Effects + + filter, feBlend, feColorMatrix, feColorMatrix, feComponentTransfer, feComposite, feConvolveMatrix, feDiffuseLighting, + feDisplacementMap, feDistantLight, feFlood, feGaussianBlur, feImage, feMerge, feMorphology, feOffset, fePointLight, + feSpecularLighting, feSpotLight,feTile, feTurbulence + + +### Metadata elements ### + + desc, defs, g (style, transform, id), marker, mask, pattern, title, (a)ddress, link, script, use + +## Building and Usage ## + +See svgdef.[svg|png|pdf] for a graphical view of the function calls + + +Usage: (assuming GOPATH is set) + + go get github.com/ajstarks/svgo + go install github.com/ajstarks/svgo/... + + +You can use godoc to browse the documentation from the command line: + + $ godoc github.com/ajstarks/svgo + + +a minimal program, to generate SVG to standard output. + + package main + + import ( + "github.com/ajstarks/svgo" + "os" + ) + + func main() { + width := 500 + height := 500 + canvas := svg.New(os.Stdout) + canvas.Start(width, height) + canvas.Circle(width/2, height/2, 100) + canvas.Text(width/2, height/2, "Hello, SVG", "text-anchor:middle;font-size:30px;fill:white") + canvas.End() + } + +Drawing in a web server: (http://localhost:2003/circle) + + package main + + import ( + "log" + "github.com/ajstarks/svgo" + "net/http" + ) + + func main() { + http.Handle("/circle", http.HandlerFunc(circle)) + err := http.ListenAndServe(":2003", nil) + if err != nil { + log.Fatal("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.Circle(250, 250, 125, "fill:none;stroke:black") + s.End() + } + +You may view the SVG output with a browser that supports SVG (tested on Chrome, Opera, Firefox and Safari), or any other SVG user-agent such as Batik Squiggle. + +### Graphics Sketching with SVGo and svgplay ### + +Combined with the svgplay command, SVGo can be used to "sketch" with code in a browser. + +To use svgplay and SVGo, first go to a directory with your code, and run: + + $ svgplay + 2014/06/25 22:05:28 ☠ ☠ ☠ Warning: this server allows a client connecting to 127.0.0.1:1999 to execute code on this computer ☠ ☠ ☠ + +Next open your browser to the svgplay server you just started. +svgplay only listens on localhost, and uses port 1999 (guess which year SVG was first introduced) by default + + http://localhost:1999/ + +Enter your code in the textarea, and when you are ready to run press Shift--Enter. The code will be compiled, with the results +on the right. To update, change the code and repeat. Note that compilation errors are shown in red under the code. In order for svgplay/SVGo to work, make sure that the io.Writer specified with the New function is os.Stdout. + + +If you want to sketch with an existing file, enter its URL: + + http://localhost:1999/foo.go + +![SVGplay](https://farm4.staticflickr.com/3859/14322978157_31c0114850.jpg) + + +### SVGo Papers and presentations ### + +* SVGo paper from SVGOpen 2011 + +* Programming Pictures with SVGo + +* SVGo Workshop + + +### Tutorial Video ### + +A video describing how to use the package can be seen on YouTube at + +## Package contents ## + +* svg.go: Library +* newsvg: Coding template command +* svgdef: Creates a SVG representation of the API +* android: The Android logo +* bubtrail: Bubble trails +* bulletgraph: Bullet Graphs (via Stephen Few) +* colortab: Display SVG named colors with RGB values +* compx: Component diagrams +* flower: Random "flowers" +* fontcompare: Compare two fonts +* f50: Get 50 photos from Flickr based on a query +* fe: Filter effects +* funnel: Funnel from transparent circles +* gradient: Linear and radial gradients +* html5logo: HTML5 logo with draggable elements +* imfade: Show image fading +* lewitt: Version of Sol Lewitt's Wall Drawing 91 +* ltr: Layer Tennis Remixes +* marker: Test markers +* paths: Demonstrate SVG paths +* pattern: Test patterns +* planets: Show the scale of the Solar system +* pmap: Proportion maps +* randcomp: Compare random number generators +* richter: Gerhard Richter's 256 colors +* rl: Random lines (port of a Processing demo) +* skewabc: Skew ABC +* stockproduct: Visualize product and stock prices +* svgopher: SVGo Mascot +* svgplay: SVGo sketching server +* svgplot: Plot data +* svgrid: Compose SVG files in a grid +* tsg: Twitter Search Grid +* tumblrgrid: Tumblr picture grid +* turbulence: Turbulence filter effect +* vismem: Visualize data from files +* webfonts: "Hello, World" with Google Web Fonts +* websvg: Generate SVG as a web server + + +## Functions and types ## + +Many functions use x, y to specify an object's location, and w, h to specify the object's width and height. +Where applicable, a final optional argument specifies the style to be applied to the object. +The style strings follow the SVG 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"` (see: ) + +The Offcolor type: + + type Offcolor struct { + Offset uint8 + Color string + Opacity float + } + +is used to specify the offset, color, and opacity of stop colors in linear and radial gradients + +The Filterspec type: + + type Filterspec struct { + In string + In2 string + Result string + } + +is used to specify inputs and results for filter effects + + +### Structure, Scripting, Metadata, Transformation and Links ### + + 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 elememts + (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. + + + Startunit(w int, h int, unit string, ns ...string) + begin the SVG document, with width and height in the specified units. Optionally add additional elememts + (such as additional namespaces or scripting events) + + + + Startpercent(w int, h int, ns ...string) + begin the SVG document, with width and height in percent. Optionally add additional elememts + (such as additional namespaces or scripting events) + + + + StartviewUnit(w, h int, unit string, minx, miny, vw, vh int) + begin the SVG document with the width w, height h, in the specified unit, 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 argument 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. + + + Group(s ...string) + begin a group, with arbitrary attributes + + + Gstyle(s string) + begin a group, with the specified style. + + + Gid(s string) + begin a group, with the specified id. + + 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 r 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(). + + Gend() + end the group (must be paired with Gstyle, Gtransform, Gid). + + ClipPath(s ...string) + Begin a ClipPath + + + ClipEnd() + End a ClipPath + + + Def() + begin a definition block. + + + DefEnd() + end a definition block. + + Marker(id string, x, y, w, h int, s ...string) + define a marker + + + + MarkerEnd() + end a marker + + + Mask(id 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. + + + Pattern(id string, x, y, width, height int, putype string, s ...string) + define a Pattern with the specified dimensions, the putype can be either "user" or "obj", which sets the patternUnits + attribute to be either userSpaceOnUse or objectBoundingBox. + + + 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. + + +### Shapes ### + + Circle(x int, y int, r int, s ...string) + draw a circle, centered at x,y with radius r. + + + ![Circle](http://farm5.static.flickr.com/4144/5187953823_01a1741489_m.jpg) + + Ellipse(x int, y int, w int, h int, s ...string) + draw an ellipse, centered at x,y with radii w, and h. + + + ![Ellipse](http://farm2.static.flickr.com/1271/5187953773_a9d1fc406c_m.jpg) + + Polygon(x []int, y []int, s ...string) + draw a series of line segments using an array of x, y coordinates. + + + ![Polygon](http://farm2.static.flickr.com/1006/5187953873_337dc26597_m.jpg) + + 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. + + + ![Rect](http://farm2.static.flickr.com/1233/5188556032_86c90e354b_m.jpg) + + 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). + + ![Roundrect](http://farm2.static.flickr.com/1275/5188556120_e2a9998fee_m.jpg) + + Square(x int, y int, s int, style ...string) + draw a square with upper left corner at x,y with sides of length s. + + ![Square](http://farm5.static.flickr.com/4110/5187953659_54dcce242e_m.jpg) + +### Paths ### + + 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 + 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. + + + ![Arc](http://farm2.static.flickr.com/1300/5188556148_df1a176074_m.jpg) + + + + 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. + + + ![Bezier](http://farm2.static.flickr.com/1233/5188556246_a03e67d013.jpg) + + + + Qbezier(sx int, sy int, cx int, cy int, ex int, ey int, tx int, ty int, s ...string) + draw a quadratic bezier curve, beginning at sx, sy, ending at tx,ty + with control points are at cx,cy, ex,ey. + + + ![Qbezier](http://farm2.static.flickr.com/1018/5187953917_9a43cf64fb.jpg) + + + Qbez(sx int, sy int, cx int, cy int, ex int, ey int, s...string) + draws a quadratic bezier curver, with optional style beginning at sx,sy, ending at ex, sy + with the control point at cx, cy. + + + ![Qbez](http://farm6.static.flickr.com/5176/5569879349_5f726aab5e.jpg) + +### Lines ### + + Line(x1 int, y1 int, x2 int, y2 int, s ...string) + draw a line segment between x1,y1 and x2,y2. + + + ![Line](http://farm5.static.flickr.com/4154/5188556080_0be19da0bc.jpg) + + + Polyline(x []int, y []int, s ...string) + draw a polygon using coordinates specified in x,y arrays. + + + ![Polyline](http://farm2.static.flickr.com/1266/5188556384_a863273a69.jpg) + +### Image and Text ### + + 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. + + + ![Image](http://farm5.static.flickr.com/4058/5188556346_e5ce3dcbc2_m.jpg) + + 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. + + ![Image](http://farm4.static.flickr.com/3149/5694580737_4b291df768_m.jpg) + +### Color ### + + 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). + +### Gradients ### + + 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. + + ![LinearGradient](http://farm5.static.flickr.com/4153/5187954033_3972f63fa9.jpg) + + 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. + + + ![RadialGradient](http://farm2.static.flickr.com/1302/5187954065_7ddba7b819.jpg) + +### Filter Effects ### + + Filter(id string, s ...string) + Filter begins a filter set +Standard reference: + + Fend() +Fend ends a filter set +Standard reference: + + FeBlend(fs Filterspec, mode string, s ...string) +FeBlend specifies a Blend filter primitive +Standard reference: + + FeColorMatrix(fs Filterspec, values [20]float64, s ...string) +FeColorMatrix specifies a color matrix filter primitive, with matrix values +Standard reference: + + FeColorMatrixHue(fs Filterspec, value float64, s ...string) +FeColorMatrix specifies a color matrix filter primitive, with hue values +Standard reference: + + FeColorMatrixSaturate(fs Filterspec, value float64, s ...string) +FeColorMatrix specifies a color matrix filter primitive, with saturation values +Standard reference: + + FeColorMatrixLuminence(fs Filterspec, s ...string) +FeColorMatrix specifies a color matrix filter primitive, with luminence values +Standard reference: + + FeComponentTransfer() +FeComponentTransfer begins a feComponent filter Element> +Standard reference: + + FeCompEnd() +FeCompEnd ends a feComponent filter Element> + + FeComposite(fs Filterspec, operator string, k1, k2, k3, k4 int, s ...string) +FeComposite specifies a feComposite filter primitive +Standard reference: + + FeConvolveMatrix(fs Filterspec, matrix [9]int, s ...string) +FeConvolveMatrix specifies a feConvolveMatrix filter primitive +Standard referencd: + + + FeDiffuseLighting(fs Filterspec, scale, constant float64, s ...string) +FeDiffuseLighting specifies a diffuse lighting filter primitive, +a container for light source Element>s, end with DiffuseEnd() + + FeDiffEnd() +FeDiffuseEnd ends a diffuse lighting filter primitive container +Standard reference: + + + FeDisplacementMap(fs Filterspec, scale float64, xchannel, ychannel string, s ...string) +FeDisplacementMap specifies a feDisplacementMap filter primitive +Standard reference: + + FeDistantLight(fs Filterspec, azimuth, elevation float64, s ...string) +FeDistantLight specifies a feDistantLight filter primitive +Standard reference: + + FeFlood(fs Filterspec, color string, opacity float64, s ...string) +FeFlood specifies a flood filter primitive +Standard reference: + + FeFuncLinear(channel string, slope, intercept float64) +FeFuncLinear is the linear form of feFunc +Standard reference: + + FeFuncGamma(channel, amplitude, exponent, offset float64) +FeFuncGamma is the gamma curve form of feFunc +Standard reference: + + FeFuncTable(channel string, tv []float64) +FeFuncGamma is the form of feFunc using a table of values +Standard reference: + + FeFuncDiscrete(channel string, tv []float64) +FeFuncGamma is the form of feFunc using discrete values +Standard reference: + + FeGaussianBlur(fs Filterspec, stdx, stdy float64, s ...string) +FeGaussianBlur specifies a Gaussian Blur filter primitive +Standard reference: + + FeImage(href string, result string, s ...string) +FeImage specifies a feImage filter primitive +Standard reference: + + FeMerge(nodes []string, s ...string) +FeMerge specifies a feMerge filter primitive, containing feMerge Element>s +Standard reference: + + FeMorphology(fs Filterspec, operator string, xradius, yradius float64, s ...string) +FeMorphologyLight specifies a feMorphologyLight filter primitive +Standard reference: + + FeOffset(fs Filterspec, dx, dy int, s ...string) +FeOffset specifies the feOffset filter primitive +Standard reference: + + FePointLight(x, y, z float64, s ...string) +FePointLight specifies a fePpointLight filter primitive +Standard reference: + + FeSpecularLighting(fs Filterspec, scale, constant float64, exponent int, color string, s ...string) +FeSpecularLighting specifies a specular lighting filter primitive, +a container for light source elements, end with SpecularEnd() + + + FeSpecEnd() +FeSpecularEnd ends a specular lighting filter primitive container +Standard reference: + + + FeSpotLight(fs Filterspec, x, y, z, px, py, pz float64, s ...string) +FeSpotLight specifies a feSpotLight filter primitive +Standard reference: + + FeTile(fs Filterspec, in string, s ...string) +FeTile specifies the tile utility filter primitive +Standard reference: + + + FeTurbulence(fs Filterspec, ftype string, bfx, bfy float64, octaves int, seed int64, stitch bool, s ...string) +FeTurbulence specifies a turbulence filter primitive +Standard reference: + +### Filter convenience functions (modeled on CSS filter effects) ### + + Blur(p float64) +Blur function by standard deviation + + Brightness(p float64) +Brightness function (0-100) + + Grayscale() +Apply a grayscale filter to the image + + HueRotate(a float64) +Rotate Hues (0-360 degrees) + + Invert() +Invert the image's colors + + Saturate(p float64) +Percent saturation, 0 is grayscale + + Sepia() +Apply sepia tone + + +### Utility ### + + Grid(x int, y int, w int, h int, n int, s ...string) + draws a grid of straight lines starting at x,y, with a width w, and height h, and a size of n. + + ![Grid](http://farm5.static.flickr.com/4133/5190957924_7a31d0db34.jpg) + +### Credits ### + +Thanks to Jonathan Wright for the io.Writer update. diff --git a/vendor/github.com/ajstarks/svgo/android/android.go b/vendor/github.com/ajstarks/svgo/android/android.go new file mode 100644 index 0000000..1fa57c4 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/android/android.go @@ -0,0 +1,55 @@ +// android draws bugdroid, the Android mascot +// +build !appengine + +package main + +import ( + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +var ( + width = 500 + height = 500 + canvas = svg.New(os.Stdout) +) + +const androidcolor = "rgb(164,198,57)" + +func background(v int) { canvas.Rect(0, 0, width, height, canvas.RGB(v, v, v)) } + +func android(x, y int, fill string, opacity float64) { + var linestyle = []string{`stroke="` + fill + `"`, `stroke-linecap="round"`, `stroke-width="5"`} + globalstyle := fmt.Sprintf("fill:%s;opacity:%.2f", fill, opacity) + canvas.Gstyle(globalstyle) + canvas.Arc(x+30, y+70, 35, 35, 0, false, true, x+130, y+70) // head + canvas.Line(x+60, y+25, x+50, y+10, linestyle[0], linestyle[1], linestyle[2]) // left antenna + canvas.Line(x+100, y+25, x+110, y+10, linestyle[0], linestyle[1], linestyle[2]) // right antenna + canvas.Circle(x+60, y+45, 5, "fill:white") // left eye + canvas.Circle(x+100, y+45, 5, `fill="white"`) // right eye + canvas.Roundrect(x+30, y+75, 100, 90, 10, 10) // body + canvas.Rect(x+30, y+75, 100, 80) + canvas.Roundrect(x+5, y+80, 20, 70, 10, 10) // left arm + canvas.Roundrect(x+135, y+80, 20, 70, 10, 10) // right arm + canvas.Roundrect(x+50, y+150, 20, 50, 10, 10) // left leg + canvas.Roundrect(x+90, y+150, 20, 50, 10, 10) // right leg + canvas.Gend() +} + +func main() { + canvas.Start(width, height) + canvas.Title("Android") + background(255) + + android(100, 100, androidcolor, 1.0) + canvas.Scale(3.0) + android(50, 50, "gray", 0.5) + canvas.Gend() + + canvas.Scale(0.5) + android(100, 100, "red", 1.0) + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/barchart/barchart.go b/vendor/github.com/ajstarks/svgo/barchart/barchart.go new file mode 100644 index 0000000..7c0e767 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/barchart/barchart.go @@ -0,0 +1,472 @@ +// barchart - bar chart +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "github.com/ajstarks/svgo" + "io" + "math" + "os" + "strconv" + "strings" +) + +var ( + width, height, iscale, fontsize, barheight, gutter, cornerRadius, labelimit int + bgcolor, barcolor, title, inbar, valformat string + showtitle, showdata, showgrid, showscale, endtitle, trace bool +) + +const ( + gstyle = "font-family:Calibri,sans-serif;font-size:%dpx" + borderstyle = "stroke:lightgray;stroke-width:1px" + scalestyle = "text-anchor:middle;font-size:75%" + btitlestyle = "font-style:italic;font-size:150%;text-anchor:" + notestyle = "font-style:italic;text-anchor:" + datastyle = "text-anchor:end;fill:" + titlestyle = "text-anchor:start;font-size:300%" + labelstyle = "fill:black;baseline-shift:-25%" +) + +// a Barchart Defintion +// +// This is a note +// More expository text +// +// +// +// +// +// + +type Barchart struct { + Top int `xml:"top,attr"` + Left int `xml:"left,attr"` + Right int `xml:"right,attr"` + Title string `xml:"title,attr"` + Bdata []bdata `xml:"bdata"` + Note []note `xml:"note"` +} + +type bdata struct { + Title string `xml:"title,attr"` + Scale string `xml:"scale,attr"` + Color string `xml:"color,attr"` + Unit string `xml:"unit,attr"` + Showdata bool `xml:"showdata,attr"` + Showgrid bool `xml:"showgrid,attr"` + Samebar bool `xml:"samebar,attr"` + Bitem []bitem `xml:"bitem"` + Bstack []bstack `xml:"bstack"` + Note []note `xml:"note"` +} + +type bitem struct { + Name string `xml:"name,attr"` + Value float64 `xml:"value,attr"` + Color string `xml:"color,attr"` + Samebar bool `xml:"samebar,attr"` +} + +type bstack struct { + Name string `xml:"name,attr"` + Value string `xml:"value,attr"` + Color string `xml:"color,attr"` +} + +type note struct { + Text string `xml:",chardata"` +} + +// dobc does file i/o +func dobc(location string, s *svg.SVG) { + var f *os.File + var err error + if len(location) > 0 { + f, err = os.Open(location) + } else { + f = os.Stdin + } + if err == nil { + readbc(f, s) + f.Close() + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// readbc reads and parses the XML specification +func readbc(r io.Reader, s *svg.SVG) { + var bc Barchart + if err := xml.NewDecoder(r).Decode(&bc); err == nil { + drawbc(bc, s) + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// drawbc draws the bar chart +func drawbc(bg Barchart, canvas *svg.SVG) { + + if bg.Left == 0 { + bg.Left = 250 + } + if bg.Right == 0 { + bg.Right = 50 + } + if bg.Top == 0 { + bg.Top = 50 + } + if len(title) > 0 { + bg.Title = title + } + labelimit = bg.Left/8 + cr := cornerRadius + maxwidth := width - (bg.Left + bg.Right) + x := bg.Left + y := bg.Top + sep := 10 + color := barcolor + scfmt := "%v" + canvas.Title(bg.Title) + + // for each bdata element... + for _, b := range bg.Bdata { + if trace { + fmt.Fprintf(os.Stderr, "# %s\n", b.Title) + } + // overide the color if specified + if len(b.Color) > 0 { + color = b.Color + } else { + color = barcolor + } + // extract the scale data from the XML attributes + // if not specified, compute the scale factors + sc := strings.Split(b.Scale, ",") + var scalemin, scalemax, scaleincr float64 + + if len(sc) != 3 { + if len(b.Bitem) > 0 { + scalemin, scalemax, scaleincr = scalevalues(b.Bitem) + } + + if len(b.Bstack) > 0 { + scalemin, scalemax, scaleincr = scalestack(b.Bstack) + } + } else { + scalemin, _ = strconv.ParseFloat(sc[0], 64) + scalemax, _ = strconv.ParseFloat(sc[1], 64) + scaleincr, _ = strconv.ParseFloat(sc[2], 64) + } + // label the graph + canvas.Text(x, y, b.Title, btitlestyle+anchor()) + + y += sep * 2 + chartop := y + + // draw the data items + canvas.Gstyle(datastyle + color) + + // stacked bars + for _, stack := range b.Bstack { + if trace { + fmt.Fprintf(os.Stderr, "%s~%s\n", stack.Value, stack.Name) + } + stackdata := stackvalues(stack.Value) + if len(stackdata) < 1 { + continue + } + sx := x + canvas.Text(x-sep, y+barheight/2, textlimit(stack.Name, labelimit), labelstyle) + barop := colorange(1.0, 0.3, len(stackdata)) + for ns, sd := range stackdata { + dw := vmap(sd, scalemin, scalemax, 0, float64(maxwidth)) + if len(stack.Color) > 0 { + canvas.Roundrect(sx, y, int(dw), barheight, cr, cr, fmt.Sprintf("fill:%s;fill-opacity:%.2f", stack.Color, barop[ns])) + } else { + canvas.Roundrect(sx, y, int(dw), barheight, cr, cr, fmt.Sprintf("fill-opacity:%.2f", barop[ns])) + } + + + if (showdata || b.Showdata) && sd > 0 { + var valuestyle = "fill-opacity:1;font-style:italic;font-size:75%;text-anchor:middle;baseline-shift:-25%;" + var ditem string + var datax int + if len(b.Unit) > 0 { + ditem = fmt.Sprintf(valformat+"%s", sd, b.Unit) + } else { + ditem = fmt.Sprintf(valformat, sd) + } + if len(inbar) > 0 { + valuestyle += inbar + } else { + valuestyle += "fill:black" + } + datax = sx + int(dw)/2 + canvas.Text(datax, y+barheight/2, ditem, valuestyle) + } + sx += int(dw) + } + y += barheight + gutter + } + + // plain bars + for _, d := range b.Bitem { + if trace { + fmt.Fprintf(os.Stderr, "%.2f~%s\n", d.Value, d.Name) + } + canvas.Text(x-sep, y+barheight/2, textlimit(d.Name, labelimit), labelstyle) + dw := vmap(d.Value, scalemin, scalemax, 0, float64(maxwidth)) + var barop float64 + if b.Samebar { + barop = 0.3 + } else { + barop = 1.0 + } + if len(d.Color) > 0 { + canvas.Roundrect(x, y, int(dw), barheight, cr, cr, fmt.Sprintf("fill:%s;fill-opacity:%.2f", d.Color, barop)) + } else { + canvas.Roundrect(x, y, int(dw), barheight, cr, cr, fmt.Sprintf("fill-opacity:%.2f", barop)) + } + if showdata || b.Showdata { + var valuestyle = "fill-opacity:1;font-style:italic;font-size:75%;text-anchor:start;baseline-shift:-25%;" + var ditem string + var datax int + if len(b.Unit) > 0 { + ditem = fmt.Sprintf(valformat+"%s", d.Value, b.Unit) + } else { + ditem = fmt.Sprintf(valformat, d.Value) + } + if len(inbar) > 0 { + valuestyle += inbar + datax = x + fontsize/2 + } else { + valuestyle += "fill:black" + datax = x + int(dw) + fontsize/2 + } + canvas.Text(datax, y+barheight/2, ditem, valuestyle) + } + if !d.Samebar { + y += barheight + gutter + } + } + canvas.Gend() + + // draw the scale and borders + chartbot := y + gutter + if showgrid || b.Showgrid { + canvas.Line(x, chartop, x+maxwidth, chartop, borderstyle) // top border + canvas.Line(x, chartbot-gutter, x+maxwidth, chartbot-gutter, borderstyle) // bottom border + } + if showscale { + if scaleincr < 1 { + scfmt = "%.1f" + } else { + scfmt = "%0.f" + } + canvas.Gstyle(scalestyle) + for sc := scalemin; sc <= scalemax; sc += scaleincr { + scx := vmap(sc, scalemin, scalemax, 0, float64(maxwidth)) + canvas.Text(x+int(scx), chartbot+fontsize, fmt.Sprintf(scfmt, sc)) + if showgrid || b.Showgrid { + canvas.Line(x+int(scx), chartbot, x+int(scx), chartop, borderstyle) // grid line + } + } + canvas.Gend() + } + + // apply the note if present + if len(b.Note) > 0 { + canvas.Gstyle(notestyle + anchor()) + y += fontsize * 2 + leading := 3 + for _, note := range b.Note { + canvas.Text(bg.Left, y, note.Text) + y += fontsize + leading + } + canvas.Gend() + } + y += sep * 7 // advance vertically for the next chart + } + // if requested, place the title below the last chart + if showtitle && len(bg.Title) > 0 { + y += fontsize * 2 + canvas.Text(bg.Left, y, bg.Title, titlestyle) + } + // apply overall note if present + if len(bg.Note) > 0 { + canvas.Gstyle(notestyle + anchor()) + y += fontsize * 2 + leading := 3 + for _, note := range bg.Note { + canvas.Text(bg.Left, y, note.Text) + y += fontsize + leading + } + canvas.Gend() + } +} + +func anchor() string { + if endtitle { + return "end" + } + return "start" +} + +// vmap maps one interval to another +func vmap(value float64, low1 float64, high1 float64, low2 float64, high2 float64) float64 { + return low2 + (high2-low2)*(value-low1)/(high1-low1) +} + +// maxitem finds the maxima is a collection of bar items +func maxitem(data []bitem) float64 { + max := -math.SmallestNonzeroFloat64 + for _, d := range data { + if d.Value > max { + max = d.Value + } + } + return max +} + +// maxstack finds the maxima is a stack of bars +func maxstack(stacks []bstack) float64 { + max := -math.SmallestNonzeroFloat64 + for _, s := range stacks { + sv := stackvalues(s.Value) + sum := 0.0 + for _, d := range sv { + sum += d + } + if sum > max { + max = sum + } + } + return max +} + +// scale values returns the min, max, increment from a set of bar items +func scalevalues(data []bitem) (float64, float64, float64) { + var m, max, increment float64 + rui := 5 + m = maxitem(data) + max = roundup(m, 100) + if max > 2 { + increment = roundup(max/float64(rui), 10) + } else { + increment = 0.4 + } + return 0, max, increment +} + +// scalestack returns the min, max, increment from a stack of bars +func scalestack(data []bstack) (float64, float64, float64) { + var m, max, increment float64 + rui := 5 + m = maxstack(data) + max = roundup(m, 100) + if max > 2 { + increment = roundup(max/float64(rui), 10) + } else { + increment = 0.4 + } + return 0, max, increment +} + +// roundup rouds a floating point number up +func roundup(n float64, m int) float64 { + i := int(n) + if i <= 2 { + return 2 + } + for ; i%m != 0; i++ { + } + return float64(i) +} + +// stack value returns the values from the value string of a stack +func stackvalues(s string) []float64 { + v := strings.Split(s, "/") + if len(v) <= 0 { + return nil + } + vals := make([]float64, len(v)) + for i, x := range v { + f, err := strconv.ParseFloat(x, 64) + if err != nil { + vals[i] = 0 + } else { + vals[i] = f + } + } + return vals +} + + +// colorange evenly distributes opacity across a range of values +func colorange(start, end float64, n int) []float64 { + v := make([]float64, n) + v[0] = start + v[n-1] = end + if n == 2 { + return v + } + incr := (end-start)/float64(n-1) + for i:=1; i < n-1; i++ { + v[i] = v[i-1] + incr + } + return v +} + + +func textlimit(s string, n int) string { + l := len(s) + if l <= n { + return s + } + + return s[0:n-3]+"..." +} + +// init sets up the command flags +func init() { + flag.StringVar(&bgcolor, "bg", "white", "background color") + flag.StringVar(&barcolor, "bc", "rgb(200,200,200)", "bar color") + flag.StringVar(&valformat, "vfmt", "%v", "value format") + flag.IntVar(&width, "w", 1024, "width") + flag.IntVar(&height, "h", 800, "height") + flag.IntVar(&barheight, "bh", 20, "bar height") + flag.IntVar(&gutter, "g", 5, "gutter") + flag.IntVar(&cornerRadius, "cr", 0, "corner radius") + flag.IntVar(&fontsize, "f", 18, "fontsize (px)") + flag.BoolVar(&showscale, "showscale", true, "show scale") + flag.BoolVar(&showgrid, "showgrid", false, "show grid") + flag.BoolVar(&showdata, "showdata", false, "show data values") + flag.BoolVar(&showtitle, "showtitle", false, "show title") + flag.BoolVar(&endtitle, "endtitle", false, "align title to the end") + flag.BoolVar(&trace, "trace", false, "show name/value pairs") + flag.StringVar(&inbar, "inbar", "", "data in bar format") + flag.StringVar(&title, "t", "", "title") +} + +// for every input file (or stdin), draw a bar graph +// as specified by command flags +func main() { + flag.Parse() + canvas := svg.New(os.Stdout) + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:"+bgcolor) + canvas.Gstyle(fmt.Sprintf(gstyle, fontsize)) + if len(flag.Args()) == 0 { + dobc("", canvas) + } else { + for _, f := range flag.Args() { + dobc(f, canvas) + } + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/benchviz/benchviz.go b/vendor/github.com/ajstarks/svgo/benchviz/benchviz.go new file mode 100644 index 0000000..5f2bb07 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/benchviz/benchviz.go @@ -0,0 +1,238 @@ +// benchviz: visualize benchmark data from benchcmp +package main + +import ( + "bufio" + "bytes" + "flag" + "fmt" + "io" + "math" + "os" + "strconv" + "strings" + + "github.com/ajstarks/svgo" +) + +// geometry defines the layout of the visualization +type geometry struct { + top, left, width, height, vwidth, vp, barHeight int + dolines, coldata bool + title, rcolor, scolor, style string + deltamax, speedupmax float64 +} + +// process reads the input and calls the visualization function +func process(canvas *svg.SVG, filename string, g geometry) int { + if filename == "" { + return g.visualize(canvas, filename, os.Stdin) + } + f, err := os.Open(filename) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return 0 + } + defer f.Close() + return g.visualize(canvas, filename, f) +} + +// vmap maps world to canvas coordinates +func vmap(value, low1, high1, low2, high2 float64) float64 { + return low2 + (high2-low2)*(value-low1)/(high1-low1) +} + +// visualize performs the visualization of the input, reading a line a time +func (g *geometry) visualize(canvas *svg.SVG, filename string, f io.Reader) int { + var ( + err error + line, vs, bmtitle string + dmin, dmax float64 + ) + + bh := g.barHeight + vizwidth := g.vwidth + vspacing := g.barHeight + (g.barHeight / 3) // vertical spacing + bmtype := "delta" + + in := bufio.NewReader(f) + canvas.Gstyle(fmt.Sprintf("font-size:%dpx;font-family:sans-serif", bh)) + if g.title == "" { + bmtitle = filename + } else { + bmtitle = g.title + } + canvas.Text(g.left, g.top, bmtitle, "font-size:150%") + + height := 0 + for x, y, nr := g.left+g.vp, g.top+vspacing, 0; err == nil; nr++ { + line, err = in.ReadString('\n') + fields := strings.Split(strings.TrimSpace(line), ` `) + + if len(fields) <= 1 || len(line) < 2 { + continue + } + name := fields[0] + value := fields[len(fields)-1] + if len(value) > 2 { + vs = value[:len(value)-1] + } + v, _ := strconv.ParseFloat(vs, 64) + av := math.Abs(v) + + switch { + case strings.HasPrefix(value, "delt"): + bmtype = "delta" + dmin = 0.0 + dmax = g.deltamax // 100.0 + y += vspacing * 2 + continue + + case strings.HasPrefix(value, "speed"): + bmtype = "speedup" + dmin = 0.0 + dmax = g.speedupmax // 10.0 + y += vspacing * 2 + continue + + case strings.HasPrefix(name, "#"): + y += vspacing + canvas.Text(g.left, y, line[1:], "font-style:italic;fill:gray") + continue + } + + bw := int(vmap(av, dmin, dmax, 0, float64(vizwidth))) + switch g.style { + case "bar": + g.bars(canvas, x, y, bw, bh, vspacing/2, bmtype, name, value, v) + case "inline": + g.inline(canvas, g.left, y, bw, bh, bmtype, name, value, v) + default: + g.bars(canvas, x, y, bw, bh, vspacing/2, bmtype, name, value, v) + } + y += vspacing + height = y + } + canvas.Gend() + return height +} + +// inline makes the inline style pf visualization +func (g *geometry) inline(canvas *svg.SVG, x, y, w, h int, bmtype, name, value string, v float64) { + var color string + switch bmtype { + case "delta": + if v > 0 { + color = g.rcolor + } else { + color = g.scolor + } + case "speedup": + if v < 1.0 { + color = g.rcolor + } else { + color = g.scolor + } + } + canvas.Text(x-10, y, value, "text-anchor:end") + canvas.Text(x, y, name) + canvas.Rect(x, y-h, w, h, "fill-opacity:0.3;fill:"+color) +} + +// bars creates barchart style visualization +func (g *geometry) bars(canvas *svg.SVG, x, y, w, h, vs int, bmtype, name, value string, v float64) { + canvas.Gstyle("font-style:italic;font-size:75%") + toffset := h / 4 + var tx int + var tstyle string + switch bmtype { + case "delta": + if v > 0 { + canvas.Rect(x-w, y-h/2, w, h, "fill-opacity:0.3;fill:"+g.rcolor) + tx = x - w - toffset + tstyle = "text-anchor:end" + } else { + canvas.Rect(x, y-h/2, w, h, "fill-opacity:0.3;fill:"+g.scolor) + tx = x + w + toffset + tstyle = "text-anchor:start" + } + case "speedup": + if v < 1.0 { + canvas.Rect(x-w, y-h/2, w, h, "fill-opacity:0.3;fill:"+g.rcolor) + tx = x - w - toffset + tstyle = "text-anchor:end" + } else { + canvas.Rect(x, y-h/2, w, h, "fill-opacity:0.3;fill:"+g.scolor) + tx = x + w + toffset + tstyle = "text-anchor:start" + } + } + if g.coldata { + canvas.Text(x-toffset, y+toffset, value, "text-anchor:end") + } else { + canvas.Text(tx, y+toffset, value, tstyle) + } + canvas.Gend() + canvas.Text(g.left, y+(h/2), name, "text-anchor:start") + if g.dolines { + canvas.Line(g.left, y+vs, g.left+(g.width-g.left), y+vs, "stroke:lightgray;stroke-width:1") + } +} + +func main() { + var ( + width = flag.Int("w", 1024, "width") + top = flag.Int("top", 50, "top") + left = flag.Int("left", 100, "left margin") + vp = flag.Int("vp", 512, "visualization point") + vw = flag.Int("vw", 300, "visual area width") + bh = flag.Int("bh", 20, "bar height") + smax = flag.Float64("sm", 10, "maximum speedup") + dmax = flag.Float64("dm", 100, "maximum delta") + title = flag.String("title", "", "title") + speedcolor = flag.String("scolor", "green", "speedup color") + regresscolor = flag.String("rcolor", "red", "regression color") + style = flag.String("style", "bar", "set the style (bar or inline)") + lines = flag.Bool("line", false, "show lines between entries") + coldata = flag.Bool("col", false, "show data in a single column") + ) + flag.Parse() + + g := geometry{ + width: *width, + top: *top, + left: *left, + vp: *vp, + vwidth: *vw, + barHeight: *bh, + title: *title, + scolor: *speedcolor, + rcolor: *regresscolor, + style: *style, + dolines: *lines, + coldata: *coldata, + speedupmax: *smax, + deltamax: *dmax, + } + + // For every named file or stdin, render the SVG in memory, accumulating the height. + var b bytes.Buffer + canvas := svg.New(&b) + height := 0 + if len(flag.Args()) > 0 { + for _, f := range flag.Args() { + height = process(canvas, f, g) + g.top = height + 50 + } + } else { + height = process(canvas, "", g) + } + g.height = height + 15 + + // Write the rendered SVG to stdout + out := svg.New(os.Stdout) + out.Start(g.width, g.height) + out.Rect(0, 0, g.width, g.height, "fill:white;stroke-width:2px;stroke:lightgray") + b.WriteTo(os.Stdout) + out.End() +} diff --git a/vendor/github.com/ajstarks/svgo/bubtrail/bubtrail.go b/vendor/github.com/ajstarks/svgo/bubtrail/bubtrail.go new file mode 100644 index 0000000..99ceaa8 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/bubtrail/bubtrail.go @@ -0,0 +1,67 @@ +// bubtrail draws a randmonized trail of bubbles +// +build !appengine + +package main + +import ( + "flag" + "fmt" + "math/rand" + "os" + "time" + + "github.com/ajstarks/svgo" +) + +var ( + width = 1200 + height = 600 + opacity = 0.5 + size = 40 + niter = 200 + canvas = svg.New(os.Stdout) +) + +func init() { + flag.IntVar(&size, "s", 40, "bubble size") + flag.IntVar(&niter, "n", 200, "number of iterations") + flag.Float64Var(&opacity, "o", 0.5, "opacity") + flag.Parse() + rand.Seed(int64(time.Now().Nanosecond()) % 1e9) +} + +func background(v int) { canvas.Rect(0, 0, width, height, canvas.RGB(v, v, v)) } + +func random(howsmall, howbig int) int { + if howsmall >= howbig { + return howsmall + } + return rand.Intn(howbig-howsmall) + howsmall +} + +func main() { + var style string + + canvas.Start(width, height) + canvas.Title("Bubble Trail") + background(200) + canvas.Gstyle(fmt.Sprintf("fill-opacity:%.2f;stroke:none", opacity)) + for i := 0; i < niter; i++ { + x := random(0, width) + y := random(height/3, (height*2)/3) + r := random(0, 10000) + switch { + case r >= 0 && r <= 2500: + style = "fill:rgb(255,255,255)" + case r > 2500 && r <= 5000: + style = "fill:rgb(127,0,0)" + case r > 5000 && r <= 7500: + style = "fill:rgb(127,127,127)" + case r > 7500 && r <= 10000: + style = "fill:rgb(0,0,0)" + } + canvas.Circle(x, y, size, style) + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/bulletgraph/bulletgraph.go b/vendor/github.com/ajstarks/svgo/bulletgraph/bulletgraph.go new file mode 100644 index 0000000..d4269e0 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/bulletgraph/bulletgraph.go @@ -0,0 +1,233 @@ +// bulletgraph - bullet graphs +// (Design Specification http://www.perceptualedge.com/articles/misc/Bullet_Graph_Design_Spec.pdf) +// +build !appengine + +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "io" + "os" + "strconv" + "strings" + + "github.com/ajstarks/svgo" +) + +var ( + width, height, fontsize, barheight, gutter, circleradius int + bgcolor, barcolor, datacolor, compcolor, title, font string + showtitle, circlemark bool + gstyle = "font-family:'%s',sans-serif;font-size:%dpx" +) + +// a Bulletgraph Defintion +// +// This is a note +// More expository text +// +// +// +// +// +// + +// Bulletgraph is the top-level drawing +type Bulletgraph struct { + Top int `xml:"top,attr"` + Left int `xml:"left,attr"` + Right int `xml:"right,attr"` + Title string `xml:"title,attr"` + Bdata []bdata `xml:"bdata"` + Note []note `xml:"note"` +} + +type bdata struct { + Title string `xml:"title,attr"` + Subtitle string `xml:"subtitle,attr"` + Scale string `xml:"scale,attr"` + Qmeasure string `xml:"qmeasure,attr"` + Cmeasure float64 `xml:"cmeasure,attr"` + Measure float64 `xml:"measure,attr"` +} + +type note struct { + Text string `xml:",chardata"` +} + +// dobg does file i/o +func dobg(location string, s *svg.SVG) { + var f *os.File + var err error + if len(location) > 0 { + f, err = os.Open(location) + } else { + f = os.Stdin + } + if err == nil { + readbg(f, s) + f.Close() + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// readbg reads and parses the XML specification +func readbg(r io.Reader, s *svg.SVG) { + var bg Bulletgraph + if err := xml.NewDecoder(r).Decode(&bg); err == nil { + drawbg(bg, s) + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// drawbg draws the bullet graph +func drawbg(bg Bulletgraph, canvas *svg.SVG) { + qmheight := barheight / 3 + + if bg.Left == 0 { + bg.Left = 250 + } + if bg.Right == 0 { + bg.Right = 50 + } + if bg.Top == 0 { + bg.Top = 50 + } + if len(title) > 0 { + bg.Title = title + } + + maxwidth := width - (bg.Left + bg.Right) + x := bg.Left + y := bg.Top + scalesep := 4 + tx := x - fontsize + + canvas.Title(bg.Title) + // for each bdata element... + for _, v := range bg.Bdata { + + // extract the data from the XML attributes + sc := strings.Split(v.Scale, ",") + qm := strings.Split(v.Qmeasure, ",") + + // you must have min,max,increment for the scale, at least one qualitative measure + if len(sc) != 3 || len(qm) < 1 { + continue + } + // get the qualitative measures + qmeasures := make([]float64, len(qm)) + for i, q := range qm { + qmeasures[i], _ = strconv.ParseFloat(q, 64) + } + scalemin, _ := strconv.ParseFloat(sc[0], 64) + scalemax, _ := strconv.ParseFloat(sc[1], 64) + scaleincr, _ := strconv.ParseFloat(sc[2], 64) + + // label the graph + canvas.Text(tx, y+(barheight/2), fmt.Sprintf("%s (%g)", v.Title, v.Measure), "text-anchor:end;font-weight:bold") + canvas.Text(tx, y+(barheight/2)+fontsize, v.Subtitle, "fill:darkgray;text-anchor:end;font-size:75%") + + // draw the scale + scfmt := "%g" + if fraction(scaleincr) > 0 { + scfmt = "%.1f" + } + canvas.Gstyle("text-anchor:middle;font-size:75%") + for sc := scalemin; sc <= scalemax; sc += scaleincr { + scx := vmap(sc, scalemin, scalemax, 0, float64(maxwidth)) + canvas.Text(x+int(scx), y+scalesep+barheight+fontsize/2, fmt.Sprintf(scfmt, sc)) + } + canvas.Gend() + + // draw the qualitative measures + canvas.Gstyle("fill-opacity:0.5;fill:" + barcolor) + canvas.Rect(x, y, maxwidth, barheight) + for _, q := range qmeasures { + qbarlength := vmap(q, scalemin, scalemax, 0, float64(maxwidth)) + canvas.Rect(x, y, int(qbarlength), barheight) + } + canvas.Gend() + + // draw the measure and the comparative measure + barlength := int(vmap(v.Measure, scalemin, scalemax, 0, float64(maxwidth))) + canvas.Rect(x, y+qmheight, barlength, qmheight, "fill:"+datacolor) + cmx := int(vmap(v.Cmeasure, scalemin, scalemax, 0, float64(maxwidth))) + if circlemark { + canvas.Circle(x+cmx, y+barheight/2, circleradius, "fill-opacity:0.3;fill:"+compcolor) + } else { + cbh := barheight / 4 + canvas.Line(x+cmx, y+cbh, x+cmx, y+barheight-cbh, "stroke-width:3;stroke:"+compcolor) + } + + y += barheight + gutter // adjust vertical position for the next iteration + } + // if requested, place the title below the last bar + if showtitle && len(bg.Title) > 0 { + y += fontsize * 2 + canvas.Text(bg.Left, y, bg.Title, "text-anchor:start;font-size:200%") + } + + if len(bg.Note) > 0 { + canvas.Gstyle("font-size:100%;text-anchor:start") + y += fontsize * 2 + leading := 3 + for _, note := range bg.Note { + canvas.Text(bg.Left, y, note.Text) + y += fontsize + leading + } + canvas.Gend() + } +} + +//vmap maps one interval to another +func vmap(value float64, low1 float64, high1 float64, low2 float64, high2 float64) float64 { + return low2 + (high2-low2)*(value-low1)/(high1-low1) +} + +// fraction returns the fractions portion of a floating point number +func fraction(n float64) float64 { + i := int(n) + return n - float64(i) +} + +// init sets up the command flags +func init() { + flag.StringVar(&bgcolor, "bg", "white", "background color") + flag.StringVar(&barcolor, "bc", "rgb(240,240,240)", "bar color") + flag.StringVar(&datacolor, "dc", "rgb(200,200,200)", "data color") + flag.StringVar(&compcolor, "cc", "rgb(127,0,0)", "comparative color") + flag.StringVar(&font, "font", "Calibri", "font") + flag.IntVar(&width, "w", 1024, "width") + flag.IntVar(&height, "h", 800, "height") + flag.IntVar(&barheight, "bh", 32, "bar height") + flag.IntVar(&circleradius, "cr", 8, "circle radius") + flag.IntVar(&gutter, "g", 36, "gutter") + flag.IntVar(&fontsize, "f", 18, "fontsize (px)") + flag.BoolVar(&circlemark, "circle", false, "circle mark") + flag.BoolVar(&showtitle, "showtitle", true, "show title") + flag.StringVar(&title, "t", "", "title") + flag.Parse() +} + +// for every input file (or stdin), draw a bullet graph +// as specified by command flags +func main() { + canvas := svg.New(os.Stdout) + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:"+bgcolor) + canvas.Gstyle(fmt.Sprintf(gstyle, font, fontsize)) + if len(flag.Args()) == 0 { + dobg("", canvas) + } else { + for _, f := range flag.Args() { + dobg(f, canvas) + } + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/codepic/codepic.go b/vendor/github.com/ajstarks/svgo/codepic/codepic.go new file mode 100644 index 0000000..7ec73f2 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/codepic/codepic.go @@ -0,0 +1,182 @@ +// codepic -- produce code+output sample suitable for slides +// +build !appengine + +package main + +import ( + "bufio" + "encoding/xml" + "flag" + "fmt" + "io" + "os" + "strings" + + "github.com/ajstarks/svgo" +) + +var ( + canvas = svg.New(os.Stdout) + font string + codeframe, picframe, syntax bool + linespacing, fontsize, top, left, boxwidth, width, height int +) + +const ( + framestyle = "stroke:gray;stroke-dasharray:1,1;fill:none" + codefmt = "font-family:%s;font-size:%dpx" + labelfmt = "text-anchor:middle;" + codefmt + kwfmt = `%s` + commentfmt = `%s` + textfmt = "%s\n" + svgofmt = `font-weight="bold" fill="rgb(0,0,127)"` + gokwfmt = `font-style="italic" fill="rgb(127,0,0)"` +) + +// SVG is the incoming SVG file, capture everything into between and +// in the Doc string. This code will be translated to form the "picture" portion +type SVG struct { + Width int `xml:"width,attr"` + Height int `xml:"height,attr"` + Doc string `xml:",innerxml"` +} + +var gokw = []string{ + "defer ", "go ", "range ", "chan ", " continue", "if ", "for ", "func ", + "uint8", "uint", "uint16", "uint32", "complex64", "complex128", " byte", "int8", "int16", "int32", + "int64", " int", "float64", "float32", " string", "import ", "const ", + "package ", "return", "var ", "type ", "switch ", "case ", "default:", +} + +var svgokw = []string{ + ".Start", ".Startview,", ".End", ".Script", ".Gstyle", ".Gtransform", ".Scale", ".Offcolor", + ".ScaleXY", ".SkewX", ".SkewY", ".SkewXY,", ".Rotate", ".TranslateRotate", ".RotateTranslate", ".Translate", + ".Group", ".Gid", ".Gend", ".ClipPath", ".ClipEnd", ".DefEnd", ".Def", ".Desc", ".Title", ".Linkf", + ".LinkEnd", ".Use", ".Mask", ".MaskEnd", ".Circle", ".Ellipse", ".Polygon", ".Rect", ".CenterRect", + ".Roundrect", ".Square", ".Path", ".Arc", ".Bezier", ".Qbez", ".Qbezier", ".Line", ".Polyline", ".Image", + ".Textpath", ".Textlines,", ".Text", ".RGBA", ".RGB", ".LinearGradient", ".RadialGradient", ".Grid", +} + +// codepic makes a code+picture SVG file, given a go source file +// and conventionally named output -- given .go, .svg +func codepic(filename string) { + var basename string + + bn := strings.Split(filename, ".") + if len(bn) > 0 { + basename = bn[0] + } else { + fmt.Fprintf(os.Stderr, "cannot get the basename for %s\n", filename) + return + } + canvas.Start(width, height) + canvas.Title(basename) + canvas.Rect(0, 0, width, height, "fill:white") + placepic(width/2, top, basename) + canvas.Gstyle(fmt.Sprintf(codefmt, font, fontsize)) + placecode(left+fontsize, top+fontsize*2, filename) + canvas.Gend() + canvas.End() +} + +// placecode places the code section on the left +func placecode(x, y int, filename string) { + var rerr error + var line string + var ic bool + f, err := os.Open(filename) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + defer f.Close() + in := bufio.NewReader(f) + + for xp := left + fontsize; rerr == nil; y += linespacing { + line, rerr = in.ReadString('\n') + if len(line) > 0 { + line, ic = svgtext(xp, y, line[0:len(line)-1]) + if !ic && syntax { + line = keyword(line, gokwfmt, gokw) + line = keyword(line, svgofmt, svgokw) + } + io.WriteString(canvas.Writer, line) + } + } + if codeframe { + canvas.Rect(top, left, left+boxwidth, y, framestyle) + } +} + +// keyword styles keywords in a line of code +func keyword(line string, style string, kw []string) string { + for _, k := range kw { + line = strings.Replace(line, k, fmt.Sprintf(kwfmt, style, k), 1) + } + return line +} + +// svgtext +func svgtext(x, y int, s string) (string, bool) { + var iscomment = false + s = strings.Replace(s, "&", "&", -1) + s = strings.Replace(s, "<", "<", -1) + s = strings.Replace(s, ">", ">", -1) + + if syntax { + i := strings.Index(s, "// ") + if i >= 0 { + iscomment = true + s = strings.Replace(s, s[i:], fmt.Sprintf(commentfmt, s[i:]), 1) + } + } + return fmt.Sprintf(textfmt, x, y, s), iscomment +} + +// placepic places the picture on the right +func placepic(x, y int, basename string) { + var s SVG + f, err := os.Open(basename + ".svg") + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + defer f.Close() + if err := xml.NewDecoder(f).Decode(&s); err != nil { + fmt.Fprintf(os.Stderr, "Unable to parse (%v)\n", err) + return + } + canvas.Text(x, height-10, basename+".go", fmt.Sprintf(labelfmt, font, fontsize*2)) + canvas.Group(`clip-path="url(#pic)"`, fmt.Sprintf(`transform="translate(%d,%d)"`, x, y)) + canvas.ClipPath(`id="pic"`) + canvas.Rect(0, 0, s.Width, s.Height) + canvas.ClipEnd() + io.WriteString(canvas.Writer, s.Doc) + canvas.Gend() + if picframe { + canvas.Rect(x, y, s.Width, s.Height, framestyle) + } +} + +// init initializes flags +func init() { + flag.BoolVar(&codeframe, "codeframe", false, "frame the code") + flag.BoolVar(&picframe, "picframe", false, "frame the picture") + flag.BoolVar(&syntax, "syntax", false, "syntax coloring") + flag.IntVar(&width, "w", 1024, "width") + flag.IntVar(&height, "h", 768, "height") + flag.IntVar(&linespacing, "ls", 16, "linespacing") + flag.IntVar(&fontsize, "fs", 14, "fontsize") + flag.IntVar(&top, "top", 20, "top") + flag.IntVar(&left, "left", 20, "left") + flag.IntVar(&boxwidth, "boxwidth", 450, "boxwidth") + flag.StringVar(&font, "font", "Inconsolata", "font name") + flag.Parse() +} + +// for every file, make a code+pic SVG file +func main() { + for _, f := range flag.Args() { + codepic(f) + } +} diff --git a/vendor/github.com/ajstarks/svgo/colortab/colortab.go b/vendor/github.com/ajstarks/svgo/colortab/colortab.go new file mode 100644 index 0000000..979fe6a --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/colortab/colortab.go @@ -0,0 +1,89 @@ +// colortab -- make a color/code placemat +// +build !appengine + +package main + +import ( + "bufio" + "flag" + "fmt" + "os" + "strings" + + "github.com/ajstarks/svgo" +) + +func main() { + var ( + canvas = svg.New(os.Stdout) + filename = flag.String("f", "svgcolors.txt", "input file") + fontname = flag.String("font", "Calibri,sans-serif", "fontname") + outline = flag.Bool("o", false, "outline") + neg = flag.Bool("n", false, "negative") + showrgb = flag.Bool("rgb", false, "show RGB") + showcode = flag.Bool("showcode", true, "only show colors") + circsw = flag.Bool("circle", true, "circle swatch") + fontsize = flag.Int("fs", 12, "fontsize") + width = flag.Int("w", 1600, "width") + height = flag.Int("h", 900, "height") + rowsize = flag.Int("r", 32, "rowsize") + colw = flag.Int("c", 320, "column size") + swatch = flag.Int("s", 16, "swatch size") + gutter = flag.Int("g", 11, "gutter") + err error + colorfmt, tcolor, line string + ) + + flag.Parse() + f, oerr := os.Open(*filename) + if oerr != nil { + fmt.Fprintf(os.Stderr, "%v\n", oerr) + return + } + canvas.Start(*width, *height) + canvas.Title("SVG Color Table") + if *neg { + canvas.Rect(0, 0, *width, *height, "fill:black") + tcolor = "white" + } else { + canvas.Rect(0, 0, *width, *height, "fill:white") + tcolor = "black" + } + top := 32 + left := 32 + in := bufio.NewReader(f) + canvas.Gstyle(fmt.Sprintf("font-family:%s;font-size:%dpt;fill:%s", + *fontname, *fontsize, tcolor)) + for x, y, nr := left, top, 0; err == nil; nr++ { + line, err = in.ReadString('\n') + fields := strings.Split(strings.TrimSpace(line), "\t") + if nr%*rowsize == 0 && nr > 0 { + x += *colw + y = top + } + if len(fields) == 3 { + colorfmt = "fill:" + fields[1] + if *outline { + colorfmt = colorfmt + ";stroke-width:1;stroke:" + tcolor + } + if *circsw { + canvas.Circle(x, y, *swatch/2, colorfmt) + } else { + canvas.CenterRect(x, y, *swatch, *swatch, colorfmt) + } + canvas.Text(x+*swatch+*fontsize/2, y+(*swatch/4), fields[0], "stroke:none") + var label string + if *showcode { + if *showrgb { + label = fields[1] + } else { + label = fields[2] + } + canvas.Text(x+((*colw*4)/5), y+(*swatch/4), label, "text-anchor:end;fill:gray") + } + } + y += (*swatch + *gutter) + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/colortab/svgcolors.txt b/vendor/github.com/ajstarks/svgo/colortab/svgcolors.txt new file mode 100644 index 0000000..88ae603 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/colortab/svgcolors.txt @@ -0,0 +1,147 @@ +aliceblue #F0F8FF 240,248,255 +antiquewhite #FAEBD7 250,235,215 +aqua #00FFFF 0,255,25 +aquamarine #7FFFD4 127,255,21 +azure #F0FFFF 240,255,255 +beige #F5F5DC 245,245,220 +bisque #FFE4C4 255,228,196 +black #000000 0,0,0 +blanchedalmond #FFEBCD 255,235,205 +blue #0000FF 0,0,255 +blueviolet #8A2BE2 138,43,226 +brown #A52A2A 165,42,42 +burlywood #DEB887 222,184,135 +cadetblue #5F9EA0 95,158,160 +chartreuse #7FFF00 127,255,0 +chocolate #D2691E 210,105,30 +coral #FF7F50 255,127,80 +cornflowerblue #6495ED 100,149,237 +cornsilk #FFF8DC 255,248,220 +crimson #DC143C 220,20,60 +cyan #00FFFF 0,255,255 +darkblue #00008B 0,0,139 +darkcyan #008B8B 0,139,139 +darkgoldenrod #B8860B 184,134,11 +darkgray #A9A9A9 169,169,169 +darkgreen #006400 0,100,0 +darkgrey #A9A9A9 169,169,169 +darkkhaki #BDB76B 189,183,107 +darkmagenta #8B008B 139,0,139 +darkolivegreen #556B2F 85,107,47 +darkorange #FF8C00 255,140,0 +darkorchid #9932CC 153,50,204 +darkred #8B0000 139,0,0 +darksalmon #E9967A 233,150,122 +darkseagreen #8FBC8F 143,188,143 +darkslateblue #483D8B 72,61,139 +darkslategray #2F4F4F 47,79,79 +darkslategrey #2F4F4F 47,79,79 +darkturquoise #00CED1 0,206,209 +darkviolet #9400D3 148,0,211 +deeppink #FF1493 255,20,147 +deepskyblue #00BFFF 0,191,255 +dimgray #696969 105,105,105 +dimgrey #696969 105,105,105 +dodgerblue #1E90FF 30,144,255 +firebrick #B22222 178,34,34 +floralwhite #FFFAF0 255,250,240 +forestgreen #228B22 34,139,34 +fuchsia #FF00FF 255,0,255 +gainsboro #DCDCDC 220,220,220 +ghostwhite #F8F8FF 248,248,255 +gold #FFD700 255,215,0 +goldenrod #DAA520 218,165,32 +gray #808080 128,128,128 +green #008000 0,128,0 +greenyellow #ADFF2F 173,255,47 +grey #808080 128,128,128 +honeydew #F0FFF0 240,255,240 +hotpink #FF69B4 255,105,180 +indianred #CD5C5C 205,92,92 +indigo #4B0082 75,0,130 +ivory #FFFFF0 255,255,240 +khaki #F0E68C 240,230,140 +lavender #E6E6FA 230,230,250 +lavenderblush #FFF0F5 255,240,245 +lawngreen #7CFC00 124,252,0 +lemonchiffon #FFFACD 255,250,205 +lightblue #ADD8E6 173,216,230 +lightcoral #F08080 240,128,128 +lightcyan #E0FFFF 224,255,255 +lightgoldenrodyellow #FAFAD2 250,250,210 +lightgray #D3D3D3 211,211,211 +lightgreen #90EE90 144,238,144 +lightgrey #D3D3D3 211,211,211 +lightpink #FFB6C1 255,182,193 +lightsalmon #FFA07A 255,160,122 +lightseagreen #20B2AA 32,178,170 +lightskyblue #87CEFA 135,206,250 +lightslategray #778899 119,136,153 +lightslategrey #778899 119,136,153 +lightsteelblue #B0C4DE 176,196,222 +lightyellow #FFFFE0 255,255,224 +lime #00FF00 0,255,0 +limegreen #32CD32 50,205,50 +linen #FAF0E6 250,240,230 +magenta #FF00FF 255,0,255 +maroon #800000 128,0,0 +mediumaquamarine #66CDAA 102,205,170 +mediumblue #0000CD 0,0,205 +mediumorchid #BA55D3 186,85,211 +mediumpurple #9370DB 147,112,219 +mediumseagreen #3CB371 60,179,113 +mediumslateblue #7B68EE 123,104,238 +mediumspringgreen #00FA9A 0,250,154 +mediumturquoise #48D1CC 72,209,204 +mediumvioletred #C71585 199,21,133 +midnightblue #191970 25,25,112 +mintcream #F5FFFA 245,255,250 +mistyrose #FFE4E1 255,228,225 +moccasin #FFE4B5 255,228,181 +navajowhite #FFDEAD 255,222,173 +navy #000080 0,0,128 +oldlace #FDF5E6 253,245,230 +olive #808000 128,128,0 +olivedrab #6B8E23 107,142,35 +orange #FFA500 255,165,0 +orangered #FF4500 255,69,0 +orchid #DA70D6 218,112,214 +palegoldenrod #EEE8AA 238,232,170 +palegreen #98FB98 152,251,152 +paleturquoise #AFEEEE 175,238,238 +palevioletred #DB7093 219,112,147 +papayawhip #FFEFD5 255,239,213 +peachpuff #FFDAB9 255,218,185 +peru #CD853F 205,133,63 +pink #FFC0CB 255,192,203 +plum #DDA0DD 221,160,221 +powderblue #B0E0E6 176,224,230 +purple #800080 128,0,128 +red #FF0000 255,0,0 +rosybrown #BC8F8F 188,143,143 +royalblue #4169E1 65,105,225 +saddlebrown #8B4513 139,69,19 +salmon #FA8072 250,128,114 +sandybrown #F4A460 244,164,96 +seagreen #2E8B57 46,139,87 +seashell #FFF5EE 255,245,238 +sienna #A0522D 160,82,45 +silver #C0C0C0 192,192,192 +skyblue #87CEEB 135,206,235 +slateblue #6A5ACD 106,90,205 +slategray #708090 112,128,144 +slategrey #708090 112,128,144 +snow #FFFAFA 255,250,250 +springgreen #00FF7F 0,255,127 +steelblue #4682B4 70,130,180 +tan #D2B48C 210,180,140 +teal #008080 0,128,128 +thistle #D8BFD8 216,191,216 +tomato #FF6347 255,99,71 +turquoise #40E0D0 64,224,208 +violet #EE82EE 238,130,238 +wheat #F5DEB3 245,222,179 +white #FFFFFF 255,255,255 +whitesmoke #F5F5F5 245,245,245 +yellow #FFFF00 255,255,0 +yellowgreen #9ACD32 154,205,50 diff --git a/vendor/github.com/ajstarks/svgo/compx/comps.xml b/vendor/github.com/ajstarks/svgo/compx/comps.xml new file mode 100644 index 0000000..178afc2 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/compx/comps.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/vendor/github.com/ajstarks/svgo/compx/compx.go b/vendor/github.com/ajstarks/svgo/compx/compx.go new file mode 100644 index 0000000..c9c1891 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/compx/compx.go @@ -0,0 +1,894 @@ +// compx: display components and connections on a grid, given a XML description +// +build !appengine + +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "github.com/ajstarks/svgo" + "io" + "math" + "os" + "strconv" + "strings" + "time" +) + +// Component XML structures +type Component struct { + Top int `xml:"top,attr"` + Left int `xml:"left,attr"` + Gutter int `xml:"gutter,attr"` + Gw int `xml:"gw,attr"` + Gh int `xml:"gh,attr"` + Gc string `xml:"gc,attr"` + Legend []legend `xml:"legend"` + Note []note `xml:"note"` + Group []group `xml:"group"` + Comp []comp `xml:"comp"` +} + +type group struct { + Brow int `xml:"brow,attr"` + Bcol int `xml:"bcol,attr"` + Erow int `xml:"erow,attr"` + Ecol int `xml:"ecol,attr"` + Width int `xml:"width,attr"` + Height int `xml:"height,attr"` + Label string `xml:"label,attr"` + Color string `xml:"color,attr"` + Opacity float64 `xml:"opacity,attr"` +} + +type note struct { + Row int `xml:"row,attr"` + Col int `xml:"col,attr"` + Width int `xml:"width,attr"` + Height int `xml:"height,attr"` + Size int `xml:"size,attr"` + Spacing int `xml:"spacing,attr"` + Align string `xml:"align,attr"` + Nitem []nitem `xml:"nitem"` +} + +type legend struct { + Title string `xml:"title,attr"` + Row int `xml:"row,attr"` + Col int `xml:"col,attr"` + Width int `xml:"width,attr"` + Height int `xml:"height,attr"` + Size int `xml:"size,attr"` + Litem []litem `xml:"litem"` +} + +type comp struct { + Id string `xml:"id,attr"` + Col int `xml:"col,attr"` + Row int `xml:"row,attr"` + Width int `xml:"width,attr"` + Height int `xml:"height,attr"` + Name string `xml:"name,attr"` + Os string `xml:"os,attr"` + Sw string `xml:"sw,attr"` + Color string `xml:"color,attr"` + Shape string `xml:"shape,attr"` + Image string `xml:"image,attr"` + Connect []Connect `xml:"connect"` +} + +type litem struct { + Color string `xml:"color,attr"` + Type string `xml:"type,attr"` + Label string `xml:",chardata"` +} + +type nitem struct { + Color string `xml:"color,attr"` + Align string `xml:"align,attr"` + Text string `xml:",chardata"` +} + +// Connect defines connections +type Connect struct { + Sloc string `xml:"sloc,attr"` + Dloc string `xml:"dloc,attr"` + Dest string `xml:"dest,attr"` + Mark string `xml:"mark,attr"` + Color string `xml:"color,attr"` + Dir string `xml:"dir,attr"` + Label string `xml:",chardata"` +} + +type gcomp struct { + x, y, w, h int +} + +var ( + width, height, fontscale int + linesize, labelfs, notchsize, groupmargin int + showtitle, showtimestamp, roundbox, arc, italiclabel bool + title, bgcolor, guide string + gridw = 0 + gridh = 0 + globalcolor = "black" + canvas = svg.New(os.Stdout) +) + +const ( + lcolor = "rgb(190,190,190)" + boxradius = 10 + lopacity = "1.0" + defcolor = "black" + linefmt = "stroke:%s;fill:none" + globalstyle = "font-family:Calibri,sans-serif;font-size:%dpx;fill:black;text-anchor:middle;stroke-linecap:round;stroke-width:%dpx;stroke-opacity:%s" + ltstyle = "text-anchor:%s;fill:black" + legendstyle = "text-anchor:start;fill:black;font-size:%dpx" + gridstyle = "fill:none; stroke:gray; stroke-opacity:0.3" + notefmt = "font-size:%dpx" + ntfmt = "text-anchor:%s;fill:%s" +) + +func background(fc string) { canvas.Rect(0, 0, width, height, "fill:"+fc) } + +// docomp does XML file processing +func docomp(location string) { + var f *os.File + var err error + if len(location) > 0 { + f, err = os.Open(location) + } else { + f = os.Stdin + } + + if err == nil { + readcomp(f) + f.Close() + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// readcomp reads the XML into the component data structure +func readcomp(r io.Reader) { + var c Component + if err := xml.NewDecoder(r).Decode(&c); err == nil { + drawc(c) + } else { + fmt.Fprintf(os.Stderr, "Unable to parse components (%v)\n", err) + } +} + +// drawc interprets the compoment data structure, and displays it +func drawc(c Component) { + gridw = c.Gw + gridh = c.Gh + if len(c.Gc) == 0 { + globalcolor = c.Gc + } else { + globalcolor = c.Gc + } + + // Groups + for _, group := range c.Group { + dogroup(group, c.Top, c.Left, c.Gutter) + } + + // Legends + for _, leg := range c.Legend { + dolegend(leg, c.Top, c.Left, c.Gutter, labelfs, labelfs+4) + } + + // Notes + for _, note := range c.Note { + donote(note, c.Top, c.Left, c.Gutter) + } + + // Components + for _, x := range c.Comp { + for _, y := range x.Connect { + connect(gc(x, c.Top, c.Left, c.Gutter), y.Sloc, + lookup(y.Dest, c.Comp, c.Top, c.Left, c.Gutter), + y.Dloc, y.Label, y.Mark, y.Dir, y.Color) + } + display(x, c.Top, c.Left, c.Gutter) + } + + if len(guide) > 0 { + grid(c.Top, c.Left, c.Gutter) + } + if showtitle { + dotitle(c.Left, 30, title) + } + if showtimestamp { + timestamp(30) + } +} + +// lookup returns a graphic object given an id +func lookup(id string, c []comp, t, l, g int) gcomp { + var x gcomp + for _, v := range c { + if id == v.Id { + return gc(v, t, l, g) + } + } + return x +} + +// dotitle positions the title relative to the bottom of the drawing +func dotitle(left, offset int, t string) { + canvas.Text(left, height-offset, t, "font-size:200%;text-anchor:start") +} + +// timestamp draws a timestamp in the lower right of the drawing +func timestamp(offset int) { + t := time.Now() + canvas.Text(width-offset, height-offset, t.Format(time.ANSIC), "text-anchor:end") +} + +// grid displays a grid overlay, useful for determining optimal positioning +func grid(top, left, gutter int) { + gs := strings.SplitN(guide, `x`, 4) + if len(gs) != 4 { + return + } + w, _ := strconv.Atoi(gs[0]) + h, _ := strconv.Atoi(gs[1]) + nr, _ := strconv.Atoi(gs[2]) + nc, _ := strconv.Atoi(gs[3]) + canvas.Gstyle(gridstyle) + y := top + for r := 0; r < nr; r++ { + x := left + for c := 0; c < nc; c++ { + canvas.Rect(x, y, w, h) + canvas.Text(x+w/2, y+h/2, fmt.Sprintf("%d,%d", r, c), + "font-size:150%;fill:lightgray;stroke:none") + x += w + gutter + } + y += h + gutter + } + canvas.Gend() +} + +// dogroup displays a colored rectangular area +func dogroup(g group, top, left, gutter int) { + margin := groupmargin + bx := colx(g.Bcol, g.Width, gutter, left) + by := rowy(g.Brow, g.Height, gutter, top) + ex := colx(g.Ecol, g.Width, gutter, left) + ey := rowy(g.Erow, g.Height, gutter, top) + gw := (ex + g.Width) - bx + gh := (ey + g.Height) - by + var gop float64 + if g.Opacity <= 0 { + gop = 1.0 + } else { + gop = g.Opacity + } + canvas.Rect(bx-margin, by-margin, gw+margin*2, gh+margin*2, + fmt.Sprintf("fill-opacity:%.2f;fill:%s", gop, g.Color)) + if len(g.Label) > 0 { + canvas.Text(bx+gw/2, by+gh/2, g.Label, "fill:gray") + } +} + +// dolegend displays the legend +func dolegend(leg legend, top, left, gutter, fs, ls int) { + if leg.Size > 0 { + fs = leg.Size + ls = fs + 4 + } + fsh := fs / 2 + x := colx(leg.Col, leg.Width, gutter, left) + y := rowy(leg.Row, leg.Height, gutter, top) + + canvas.Gstyle(fmt.Sprintf(legendstyle, fs)) + for _, v := range leg.Litem { + if v.Type == "line" { + canvas.Rect(x, y+fs/4, fs, fs/4, "fill:"+v.Color) + } else { + canvas.Square(x, y, fs, "fill:"+v.Color) + } + canvas.Text(x+(fs*2), y+fsh, v.Label, "baseline-shift:-30%") + y += ls + } + canvas.Gend() +} + +// donote displays a note +func donote(n note, top, left, gutter int) { + var align, color string + + size := n.Size + ls := n.Spacing + x := colx(n.Col, n.Width, gutter, left) + y := rowy(n.Row, n.Height, gutter, top) + if n.Align == "middle" { + y += n.Height / 2 + } + if size <= 0 { + size = labelfs + } + if ls == 0 { + ls = size + 2 + } + xp := x + canvas.Gstyle(fmt.Sprintf(notefmt, size)) + for _, v := range n.Nitem { + switch v.Align { + case "left", "start", "begin": + align = "start" + xp = x + case "right", "end": + align = "end" + xp = x + n.Width + case "middle", "mid", "center": + align = "middle" + xp = x + (n.Width / 2) + default: + align = "start" + xp = x + } + if len(v.Color) == 0 { + color = "black" + } else { + color = v.Color + } + canvas.Text(xp, y, v.Text, fmt.Sprintf(ntfmt, align, color)) + y += ls + } + canvas.Gend() +} + +// gc computes the components coordinates +func gc(c comp, top, left, gutter int) gcomp { + var g gcomp + + // the object and grid dimensions equal, unless explicitly overridden + + if gridw > 0 && gridh > 0 { + g.x = colx(c.Col, gridw, gutter, left) + g.y = rowy(c.Row, gridh, gutter, top) + } else { + g.x = colx(c.Col, c.Width, gutter, left) + g.y = rowy(c.Row, c.Height, gutter, top) + } + g.w = c.Width + g.h = c.Height + return g +} + +// display a component in the context of the grid +func display(c comp, top, left, gutter int) { + g := gc(c, top, left, gutter) + component(g, c) +} + +// component positions and draws a components and its attributes +func component(g gcomp, c comp) { + x := g.x + y := g.y + w := g.w + h := g.h + fs := w / fontscale + fs2 := fs / 2 + w2 := w / 2 + h3 := h / 3 + + var boxcolor string + if len(c.Color) == 0 { + boxcolor = globalcolor + } else { + boxcolor = c.Color + } + rectstyle := fmt.Sprintf("stroke:%s;stroke-width:1;fill:%s", boxcolor, boxcolor) + + if len(c.Image) > 0 { + canvas.Image(x, y, w, h, c.Image) + if len(c.Name) > 0 { + canvas.Text(x+w2, y+h/3, c.Name, + fmt.Sprintf("font-size:%dpx;fill:%s;baseline-shift:50%%", fs, boxcolor)) + } + return + } + + if strings.HasPrefix(c.Shape, "#") { + uselibrary(x, y, w, h, c.Shape) + return + } + + switch c.Shape { + + case "mobile", "screen": + screen(x, y, w, h, 10, boxcolor, bgcolor) + canvas.Gstyle(fmt.Sprintf("font-size:%dpx", fs)) + canvas.Text(x+w/2, y+h/3, c.Name) + if len(c.Os) > 0 { + canvas.Text(x+w/2, y+h3+fs+2, c.Os, "font-size:60%") + } + if len(c.Sw) > 0 { + canvas.Text(x+w/2, y+h3+fs*2, c.Sw, "font-size:75%") + } + canvas.Gend() + + case "server": + server(x, y, w, h, 10, boxcolor, lcolor) + canvas.Text(x+w/2, y+h-10, c.Name, fmt.Sprintf("font-size:%dpx;fill:white", fs)) + + case "desktop": + l := h / 20 + desktop(x, y, w, h, l, boxcolor, bgcolor) + canvas.Gstyle(fmt.Sprintf("font-size:%dpx", fs)) + canvas.Text(x+w/2, y+h/3, c.Name) + if len(c.Os) > 0 { + canvas.Text(x+w/2, y+h3+fs+2, c.Os, "font-size:60%") + } + if len(c.Sw) > 0 { + canvas.Text(x+w/2, y+h3+fs*2, c.Sw, "font-size:75%") + } + canvas.Gend() + + case "message": + l := h / 20 + pmy := h / 8 + message(x, y, w, h, l, lcolor, boxcolor) + canvas.Gstyle(fmt.Sprintf("font-size:%dpx;fill:white", fs)) + if len(c.Os) > 0 { + canvas.Text(x+w2, y+pmy+fs, c.Os, "font-size:75%") + } + canvas.Text(x+w2, y+h-10, c.Name, fmt.Sprintf("font-size:%dpx;fill:%s", fs, bgcolor)) + canvas.Gend() + + case "cloud": + r := w / 3 + xc := (x + w/2) + r/4 + yc := y + h/2 + cloud(xc, yc, r, boxcolor) + canvas.Text(xc-(r/4), yc+r/2, c.Name, fmt.Sprintf("font-size:%dpx;fill:white", fs)) + + case "db": + cylinder(x, y+(h/4), w, h-(h/2), h/4, lcolor, boxcolor) + canvas.Text(x+w2, y+h3, c.Name, fmt.Sprintf("font-size:%dpx;fill:white", fs)) + if len(c.Sw) > 0 { + canvas.Text(x+w2, y+2*h3, c.Sw, "font-size:75%") + } + + case "folder": + l := w / 10 + folder(x, y, w, h, l, boxcolor, lcolor) + yp := y + h/2 + canvas.Gstyle(fmt.Sprintf("font-size:%dpx;fill:white", fs)) + canvas.Text(x+w/2, yp, c.Name) + if len(c.Os) > 0 { + canvas.Text(x+w/2, yp+fs+2, c.Os, "font-size:60%") + } + if len(c.Sw) > 0 { + canvas.Text(x+w/2, yp+fs*2, c.Sw, "font-size:75%") + } + canvas.Gend() + + case "face": + fr := (w / 4) - (fs / 2) // (h*3)/8 + face(x+w/2, y+h/2, fr, linesize, boxcolor, bgcolor) + canvas.Text(x+w/2, y+(h/2)+fr+15, c.Name, fmt.Sprintf("font-size:%dpx;fill:black", fs)) + + case "role": + role(x, y, w, h, boxcolor) + canvas.Text(x+w/2, y+h-5, c.Name, fmt.Sprintf("font-size:%dpx;fill:%s", fs, bgcolor)) + + case "eaec": + l := w / 10 + eaec(x, y, w, h, l, boxcolor, bgcolor) + canvas.Text(x+w/2, y+h-5, c.Name, fmt.Sprintf("font-size:%dpx;fill:%s", fs, bgcolor)) + + case "plain": + if roundbox { + canvas.Roundrect(x, y, w, h, fs2, fs2, rectstyle) + } else { + canvas.Rect(x, y, w, h, rectstyle) + } + canvas.Text(x+w2, y+(h/2), c.Name, fmt.Sprintf("font-size:%dpx;fill:white;baseline-shift:-25%%", fs)) + + default: + canvas.Rect(x, y, w, h3, rectstyle) + canvas.Rect(x, y+h3, w, h-h3, "fill:white;stroke-width:1;stroke:gray") + canvas.Gstyle(fmt.Sprintf("font-size:%dpx", fs)) + canvas.Text(x+w2, y+h3, c.Name, "fill:white;baseline-shift:50%") + canvas.Text(x+w2, y+h3+fs2, c.Os, "font-size:60%") + wordstack(x+w2, (y+h)-fs2, fs, strings.Split(c.Sw, `\n`), "fill-opacity:0.75;font-size:75%") + canvas.Gend() + } +} + +// uselibrary draws a previously defined object +func uselibrary(x, y, w, h int, name string) { + canvas.Use(x, y, name, fmt.Sprintf(`width="%d"`, w), fmt.Sprintf(`height="%d"`, h)) +} + +// Object functions +func cylinder(x, y, w, h, eh int, fill, tfill string) { + f := "fill:" + fill + tf := "fill:" + tfill + canvas.Rect(x, y, w, h, f) + canvas.Ellipse(x+w/2, y+h, w/2, eh, f) + canvas.Ellipse(x+w/2, y, w/2, eh, tf) +} + +// folder object +func folder(x, y, w, h, l int, bcolor, color string) { + nl := w / 10 + xl := x + nl + xw := x + w + yl := y + nl + yh := y + h + l2 := nl * 2 + l3 := nl * 3 + lh := nl / 2 + var ( + xn = []int{xl, xl + l2, xl + l3, xw, xw, xl} + yn = []int{y, y, y + lh, y + lh, yh, yh} + xf = []int{xw, xw - l, x, x + l} + yf = []int{yh, yl + lh, yl + lh, yh} + ) + canvas.Polygon(xn, yn, "fill:"+color) + canvas.Polygon(xf, yf, "fill:"+bcolor) +} + +// cloud object +func cloud(x, y, r int, style string) { + small := r / 2 + medium := (r * 6) / 10 + canvas.Gstyle("fill:" + style) + canvas.Circle(x, y, r) + canvas.Circle(x+r, y+small, small) + canvas.Circle(x-r-small, y+small, small) + canvas.Circle(x-r, y, medium) + canvas.Rect(x-r-small, y, r*2+small, r) + canvas.Gend() +} + +// message object +func message(x, y, w, h, l int, bcolor, scolor string) { + et := h / 3 + w2 := w / 2 + px := w / 8 + py := h / 8 + e1x := []int{x, x, x + w, x + w, x + w2, x} + e1y := []int{y + et, y + h, y + h, y + et, y + (et * 2), y + et} + e2x := []int{x, x + w2, x + w, x + w2, x} + e2y := []int{y + et, y, y + et, y + (et * 2), y + et} + + canvas.Polygon(e2x, e2y, "fill:"+bcolor) + canvas.Polygon(e1x, e1y, "fill:"+scolor) + canvas.Roundrect(x+px, y+py, w-(px*2), h-py, l, l, "fill:"+scolor) + canvas.Line(x, y+et, x+w2, y+(et*2), "stroke-width:1;stroke:"+bcolor) + canvas.Line(x+w, y+et, x+w2, y+(et*2), "stroke-width:1;stroke:"+bcolor) +} + +// eaec person object +func eaec(x, y, w, h, l int, scolor, bcolor string) { + wu := w / 8 + hu := h / 12 + wh := w / 2 + hh := h / 2 + sx := []int{x + wu*2, x + wu*6, x + wh} + sy := []int{y + hu*6, y + hu*6, y + hu*11} + tx := []int{x + wh, x + wh + wu, x + wh, x + wh - wu, x + wh} + ty := []int{y + hu*6, y + hu*7, y + hu*10, y + hu*7, y + hu*6} + + canvas.Ellipse(x+wh, y+hu*4, wu+wu/2, hu*2, "fill:"+bcolor) + canvas.Roundrect(x+wu, y+hh, w-wu*2, hu*6, l, l, "fill:"+bcolor) + canvas.Polygon(sx, sy, "fill:"+scolor) + canvas.Polygon(tx, ty, "fill:"+bcolor) +} + +// screen object +func screen(x, y, w, h, l int, bcolor, color string) { + canvas.Roundrect(x, y, w, h, l, l, "fill:"+bcolor) + canvas.Rect(x+l, y+l, w-(l*2), h-(l*2), "fill:"+color) +} + +// kb (keyboard) object +func kb(x, y, w, h, l int, color string) { + var xp = []int{x + l, x, x + w, x + w - l} + var yp = []int{y, y + h, y + h, y} + canvas.Polygon(xp, yp, "fill:"+color) +} + +// desktop object +func desktop(x, y, w, h, l int, bcolor, color string) { + screen(x, y, w, h-l*3, l, bcolor, color) + kb(x, y+h-(l*2), w+l, l*2, l*2, bcolor) +} + +// face object +func face(x, y, r, l int, color, fcolor string) { + fu := r / 10 // "face unit" + ep := 3 * fu + my := y + ep + canvas.Circle(x, y, r, fmt.Sprintf("fill:%s;stroke-width:%dpx;stroke:%s", fcolor, l, color)) + canvas.Circle(x+ep, y-ep, r/10, "fill:"+color) + canvas.Circle(x-ep, y-ep, r/10, "fill:"+color) + canvas.Qbez(x+ep, my, x, y+ep*2, x-ep, my, fmt.Sprintf("fill:%s;stroke-width:%dpx;stroke:%s", color, l, color)) +} + +// server object +func server(x, y, w, h, l int, bcolor, color string) { + var xp = []int{x + (l * 2), (x + w) - (l * 2), (x + w) - l, x + l} + var yp = []int{y, y, y + l, y + l} + canvas.Polygon(xp, yp, "fill:"+color) + canvas.Roundrect(x, y+l, w, h-l, 5, 5, "fill:"+bcolor) + canvas.Gstyle("stroke:" + color) + yl := y + (l / 2) + h/4 + spacing := w / 5 + for r := 0; r < 2; r++ { + xl := x + l + for c := 0; c < 2; c++ { + canvas.Line(xl, yl, xl+spacing, yl) + xl += spacing + 10 + } + yl += h / 4 + } + canvas.Gend() + canvas.Circle((x+w)-l, y+h/2, l/2, "fill:"+color) +} + +// role object +func role(x, y, w, h int, color string) { + hs := h / 20 + var xp = []int{x, x, x + w/3, x + w/2, x + (w / 2) + (w / 6), x + w, x + w} + var yp = []int{y + h, y + (16 * hs), y + (12 * hs), y + (14 * hs), y + (12 * hs), y + (16 * hs), y + h} + + // var xp = []int{x, x, x + w/2, x + w, x + w} + // var yp = []int{y + h, y + (h5 * 4), y + (h5 * 2), y + (h5 * 4), y + h} + canvas.Gstyle("fill:" + color) + canvas.Polygon(xp, yp) + canvas.Ellipse(x+w/2, (y + h/3), w/5, h/3) // "stroke:white;stroke-width:2") + canvas.Gend() +} + +// sloper computes the slope and r of a line +func sloper(x1, y1, x2, y2 int) (m, r float64) { + dy := float64(y1 - y2) + dx := float64(x1 - x2) + m = dy / dx + r = math.Atan2(dy, dx) * (180 / math.Pi) + return m, r +} + +// rowy computes the y position of a row +func rowy(n, h, g, t int) int { return t + (n * g) + (n * h) } + +// colx computes the x position of a column +func colx(n, w, g, l int) int { return l + (n * g) + (n * w) } + +// compass returns the coordinates of a compass point +func compass(g gcomp, point string) (cx, cy int, dir string) { + switch point { + case "nw": + cx, cy, dir = g.x, g.y, "r" + case "nnw": + cx, cy, dir = g.x+g.w/4, g.y, "d" + case "nne": + cx, cy, dir = (g.x+g.w)-(g.w/4), g.y, "d" + case "n": + cx, cy, dir = g.x+(g.w/2), g.y, "d" + case "ne": + cx, cy, dir = g.x+g.w, g.y, "l" + case "w": + cx, cy, dir = g.x, g.y+g.h/2, "r" + case "wnw": + cx, cy, dir = g.x, g.y+g.h/4, "r" + case "wsw": + cx, cy, dir = g.x, (g.y+g.h)-(g.h/4), "r" + case "ese": + cx, cy, dir = g.x+g.w, (g.y+g.h)-(g.h/4), "l" + case "ene": + cx, cy, dir = g.x+g.w, g.y+(g.h/4), "l" + case "c": + cx, cy, dir = g.x+(g.w/2), g.y+(g.h/2), "n" + case "e": + cx, cy, dir = g.x+g.w, g.y+(g.h/2), "l" + case "sw": + cx, cy, dir = g.x, g.y+g.h, "r" + case "ssw": + cx, cy, dir = g.x+(g.w/4), g.y+g.h, "u" + case "sse": + cx, cy, dir = (g.x+g.w)-(g.w/4), g.y+g.h, "u" + case "s": + cx, cy, dir = g.x+(g.w/2), g.y+g.h, "u" + case "se": + cx, cy, dir = g.x+g.w, g.y+g.h, "l" + } + return cx, cy, dir +} + +// connect two components +func connect(c1 gcomp, p1 string, c2 gcomp, p2 string, label string, mark string, dir string, color string) { + x1, y1, d1 := compass(c1, p1) + x2, y2, d2 := compass(c2, p2) + linelabel(x1, y1, x2, y2, label, mark, d1, d2, dir, color) +} + +// linestyle returns the style for lines +func linestyle(color string) string { + return fmt.Sprintf(linefmt, color) +} + +// linelabel determines the connection and arrow geometry +func linelabel(x1, y1, x2, y2 int, label string, mark string, d1 string, d2 string, dir string, color string) { + aw := linesize * 4 + ah := linesize * 3 + + if len(color) == 0 { + color = lcolor + } + switch mark { + case "b": + lx1, ly1 := arrow(x1, y1, aw, ah, d1, color) + lx2, ly2 := arrow(x2, y2, aw, ah, d2, color) + doline(lx1, ly1, lx2, ly2, linestyle(color), dir, label) + + case "s": + lx1, ly1 := arrow(x1, y1, aw, ah, d1, color) + doline(lx1, ly1, x2, y2, linestyle(color), dir, label) + + case "d": + lx2, ly2 := arrow(x2, y2, aw, ah, d2, color) + doline(x1, y1, lx2, ly2, linestyle(color), dir, label) + + default: + doline(x1, y1, x2, y2, linestyle(color), dir, label) + } +} + +// doline draws a line between to coordinates +func doline(x1, y1, x2, y2 int, style, direction, label string) { + var labelstyle string + var upflag bool + + if italiclabel { + labelstyle = "font-style:italic;" + } + + tadjust := 6 + mx := (x2 - x1) / 2 + my := (y2 - y1) / 2 + lx := x1 + mx + ly := y1 + my + m, _ := sloper(x1, y1, x2, y2) + hline := m == 0 + vline := m == math.Inf(-1) || m == math.Inf(1) + straight := hline || vline + + switch { + case m < 0: // upwards line + upflag = true + labelstyle += "text-anchor:end;" + lx -= tadjust + case hline: // horizontal line + labelstyle += "text-anchor:middle;baseline-shift:20%;" + ly -= tadjust + case m > 0: // downwards line + upflag = false + labelstyle += "text-anchor:start;" + lx += tadjust + } + if arc && !straight { + cx, cy := x1, y2 // initial control points + // fmt.Fprintf(os.Stderr, "%s slope = %.3f\n", label, m) + if upflag { + if direction == "ccw" { + cx, cy = x2, y1 + } else { + cx, cy = x1, y2 + } + } else { + if direction == "ccw" { + cx, cy = x1, y2 + } else { + cx, cy = x2, y1 + } + } + canvas.Qbez(x1, y1, cx, cy, x2, y2, style) + labelstyle += "text-anchor:middle" + canvas.Text(lx, ly, label, labelstyle) + } else { + canvas.Line(x1, y1, x2, y2, style) + canvas.Text(lx, ly, label, labelstyle) // midpoint + } +} + +// wordstack displays text in a left-justified stack +func wordstack(x, y, fs int, s []string, style ...string) { + ls := fs + 2 + for i := len(s); i > 0; i-- { + canvas.Text(x, y, s[i-1], style...) + y -= ls + } +} + +// arrow constructs line-ending arrows according to connecting points +func arrow(x, y, w, h int, dir string, color string) (xl, yl int) { + var xp = []int{x, x, x, x} + var yp = []int{y, y, y, y} + + n := notchsize + switch dir { + case "r": + xp[1] = x - w + yp[1] = y - h/2 + xp[2] = (x - w) + n + yp[2] = y + xp[3] = x - w + yp[3] = y + h/2 + xl, yl = xp[2], y + case "l": + xp[1] = x + w + yp[1] = y - h/2 + xp[2] = (x + w) - n + yp[2] = y + xp[3] = x + w + yp[3] = y + h/2 + xl, yl = xp[2], y + case "u": + xp[1] = x - w/2 + yp[1] = y + h + xp[2] = x + yp[2] = (y + h) - n + xp[3] = x + w/2 + yp[3] = y + h + xl, yl = x, yp[2] + case "d": + xp[1] = x - w/2 + yp[1] = y - h + xp[2] = x + yp[2] = (y - h) + n + xp[3] = x + w/2 + yp[3] = y - h + xl, yl = x, yp[2] + } + canvas.Polygon(xp, yp, "fill:"+color+";fill-opacity:"+lopacity) + return xl, yl +} + +// init processes command line arguments +func init() { + flag.IntVar(&width, "w", 1024, "width") + flag.IntVar(&height, "h", 768, "height") + flag.IntVar(&linesize, "l", 4, "line weight") + flag.IntVar(&labelfs, "lf", 16, "label font size (px)") + flag.IntVar(&fontscale, "f", 10, "font scaling factor") + flag.IntVar(¬chsize, "n", 0, "arrow notch size") + flag.IntVar(&groupmargin, "gm", 10, "group margin") + flag.StringVar(&bgcolor, "bg", "white", "background color") + flag.StringVar(&title, "t", "comp grid", "title") + flag.BoolVar(&italiclabel, "il", false, "italic labels") + flag.BoolVar(&showtitle, "showtitle", false, "Show the title") + flag.BoolVar(&showtimestamp, "time", false, "Show a timestamp") + flag.BoolVar(&roundbox, "roundbox", false, "make boxes round") + flag.BoolVar(&arc, "arc", false, "use arcs to connect") + flag.StringVar(&guide, "g", "", "grid guide: WxHxRxC") + flag.Parse() +} + +// for every file (or stdin) make a component diagram +func main() { + canvas.Start(width, height) + canvas.Title(title) + background(bgcolor) + canvas.Gstyle(fmt.Sprintf(globalstyle, labelfs, linesize, lopacity)) + + if len(flag.Args()) == 0 { + docomp("") + } else { + for _, f := range flag.Args() { + docomp(f) + } + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/compx/testcomp.xml b/vendor/github.com/ajstarks/svgo/compx/testcomp.xml new file mode 100644 index 0000000..acbfb92 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/compx/testcomp.xml @@ -0,0 +1,69 @@ + + + + Component + Another Thing + + + Public + Confidential + Restricted + Highly Restricted + + + Note + This is the test pattern for compx + for best results, set the width to be + at least 1300 + + the management + + + Here is another Note + This one is bigger + + + a stupid note + you did not specify anything + + + + + + + + + + + + + + + [1] + [2] + [3] + North to East + + + [4] + [5] + [6] + [7] + [8] + West to North + + + [9] + [10] + [11] + South to West + + + [12] + [13] + [14] + [15] + [16] + East to South + + diff --git a/vendor/github.com/ajstarks/svgo/cube/cube.go b/vendor/github.com/ajstarks/svgo/cube/cube.go new file mode 100644 index 0000000..1c4897a --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/cube/cube.go @@ -0,0 +1,71 @@ +// cube: draw cubes +package main + +import ( + "crypto/rand" + "flag" + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +// randcolor returns a random color +func randcolor() string { + rgb := []byte{0, 0, 0} // read error returns black + rand.Read(rgb) + return fmt.Sprintf("fill:rgb(%d,%d,%d)", rgb[0], rgb[1], rgb[2]) +} + +// rcube makes a cube with three visible faces, each with a random color +func rcube(x, y, l int) { + tx := []int{x, x + (l * 3), x, x - (l * 3), x} + ty := []int{y, y + (l * 2), y + (l * 4), y + (l * 2), y} + + lx := []int{x - (l * 3), x, x, x - (l * 3), x - (l * 3)} + ly := []int{y + (l * 2), y + (l * 4), y + (l * 8), y + (l * 6), y + (l * 2)} + + rx := []int{x + (l * 3), x + (l * 3), x, x, x + (l * 3)} + ry := []int{y + (l * 2), y + (l * 6), y + (l * 8), y + (l * 4), y + (l * 2)} + + canvas.Polygon(tx, ty, randcolor()) + canvas.Polygon(lx, ly, randcolor()) + canvas.Polygon(rx, ry, randcolor()) +} + +// lattice draws a grid of cubes, n rows deep. +// The grid begins at (xp, yp), with hspace between cubes in a row, and vspace between rows. +func lattice(xp, yp, w, h, size, hspace, vspace, n int, bgcolor string) { + if bgcolor == "" { + canvas.Rect(0, 0, w, h, randcolor()) + } else { + canvas.Rect(0, 0, w, h, "fill:"+bgcolor) + } + y := yp + for r := 0; r < n; r++ { + for x := xp; x < w; x += hspace { + rcube(x, y, size) + } + y += vspace + } +} + +func main() { + var ( + width = flag.Int("w", 600, "canvas width") + height = flag.Int("h", 600, "canvas height") + x = flag.Int("x", 60, "begin x location") + y = flag.Int("y", 60, "begin y location") + size = flag.Int("size", 20, "cube size") + rows = flag.Int("rows", 3, "rows") + hs = flag.Int("hs", 120, "horizontal spacing") + vs = flag.Int("vs", 160, "vertical spacing") + bg = flag.String("bg", "", "background") + ) + flag.Parse() + canvas.Start(*width, *height) + lattice(*x, *y, *width, *height, *size, *hs, *vs, *rows, *bg) + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/doc.go b/vendor/github.com/ajstarks/svgo/doc.go new file mode 100644 index 0000000..a6b22f9 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/doc.go @@ -0,0 +1,118 @@ +/* +Package svg generates SVG as defined by the Scalable Vector Graphics 1.1 Specification (). +Output goes to the specified io.Writer. + +Supported SVG elements and functions + +Shapes, lines, text + + circle, ellipse, polygon, polyline, rect (including roundrects), line, text + +Paths + + general, arc, cubic and quadratic bezier paths, + +Image and Gradients + + image, linearGradient, radialGradient, + +Transforms + + translate, rotate, scale, skewX, skewY + +Filter Effects + + filter, feBlend, feColorMatrix, feColorMatrix, feComponentTransfer, feComposite, feConvolveMatrix, feDiffuseLighting, + feDisplacementMap, feDistantLight, feFlood, feGaussianBlur, feImage, feMerge, feMorphology, feOffset, fePointLight, + feSpecularLighting, feSpotLight,feTile, feTurbulence + + +Metadata elements + + desc, defs, g (style, transform, id), mask, marker, pattern, title, (a)ddress, link, script, use + +Usage: (assuming GOPATH is set) + + go get github.com/ajstarks/svgo + go install github.com/ajstarks/svgo/... + + +You can use godoc to browse the documentation from the command line: + + $ godoc github.com/ajstarks/svgo + + +a minimal program, to generate SVG to standard output. + + package main + + import ( + "github.com/ajstarks/svgo" + "os" + ) + + func main() { + width := 500 + height := 500 + canvas := svg.New(os.Stdout) + canvas.Start(width, height) + canvas.Circle(width/2, height/2, 100) + canvas.Text(width/2, height/2, "Hello, SVG", "text-anchor:middle;font-size:30px;fill:white") + canvas.End() + } + +Drawing in a web server: (http://localhost:2003/circle) + + package main + + import ( + "log" + "github.com/ajstarks/svgo" + "net/http" + ) + + func main() { + http.Handle("/circle", http.HandlerFunc(circle)) + err := http.ListenAndServe(":2003", nil) + if err != nil { + log.Fatal("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.Circle(250, 250, 125, "fill:none;stroke:black") + s.End() + } + +Functions and types + +Many functions use x, y to specify an object's location, and w, h to specify the object's width and height. +Where applicable, a final optional argument specifies the style to be applied to the object. +The style strings follow the SVG 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"` (see: ) + +The Offcolor type: + + type Offcolor struct { + Offset uint8 + Color string + Opacity float + } + +is used to specify the offset, color, and opacity of stop colors in linear and radial gradients + +The Filterspec type: + + type Filterspec struct { + In string + In2 string + Result string + } + +is used to specify inputs and results for filter effects + +*/ +package svg diff --git a/vendor/github.com/ajstarks/svgo/f50/f50.go b/vendor/github.com/ajstarks/svgo/f50/f50.go new file mode 100644 index 0000000..3f96a1c --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/f50/f50.go @@ -0,0 +1,120 @@ +// f50 -- given a search term, display 10x5 image grid, sorted by interestingness +// +build !appengine + +package main + +import ( + "encoding/xml" + "fmt" + "net/http" + "net/url" + "os" + + "github.com/ajstarks/svgo" +) + +// FlickrResp defines the Flickr response +type FlickrResp struct { + Stat string `xml:"stat,attr"` + Photos Photos `xml:"photos"` +} + +// Photos defines a set of Flickr photos +type Photos struct { + Page string `xml:"page,attr"` + Pages string `xml:"pages,attr"` + Perpage string `xml:"perpage,attr"` + Total string `xml:"total,attr"` + Photo []Photo `xml:"photo"` +} + +// Photo defines a Flickr photo +type Photo struct { + Id string `xml:"id,attr"` + Owner string `xml:"owner,attr"` + Secret string `xml:"secret,attr"` + Server string `xml:"server,attr"` + Farm string `xml:"farm,attr"` + Title string `xml:"title,attr"` + Ispublic string `xml:"ispublic,attr"` + Isfriend string `xml:"isfriend,attr"` + IsFamily string `xml:"isfamily,attr"` +} + +var ( + width = 805 + height = 500 + canvas = svg.New(os.Stdout) +) + +const ( + apifmt = "https://api.flickr.com/services/rest/?method=%s&api_key=%s&%s=%s&per_page=50&sort=interestingness-desc" + urifmt = "http://farm%s.static.flickr.com/%s/%s.jpg" + apiKey = "YOURKEY" + textStyle = "font-family:Calibri,sans-serif; font-size:48px; fill:white; text-anchor:start" + imageWidth = 75 + imageHeight = 75 +) + +// FlickrAPI calls the API given a method with single name/value pair +func flickrAPI(method, name, value string) string { + return fmt.Sprintf(apifmt, method, apiKey, name, value) +} + +// makeURI converts the elements of a photo into a Flickr photo URI +func makeURI(p Photo, imsize string) string { + im := p.Id + "_" + p.Secret + + if len(imsize) > 0 { + im += "_" + imsize + } + return fmt.Sprintf(urifmt, p.Farm, p.Server, im) +} + +// 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, "Status: %v\n", f.Stat) + 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) + } +} + +// fs calls the Flickr API to perform a photo search +func fs(s string) { + var f FlickrResp + r, weberr := http.Get(flickrAPI("flickr.photos.search", "text", s)) + if weberr != nil { + fmt.Fprintf(os.Stderr, "%v\n", weberr) + return + } + defer r.Body.Close() + xmlerr := xml.NewDecoder(r.Body).Decode(&f) + if xmlerr != nil || r.StatusCode != http.StatusOK { + fmt.Fprintf(os.Stderr, "%v (status=%d)\n", xmlerr, r.StatusCode) + return + } + canvas.Title(s) + imageGrid(f, 5, 5, 10, 5, "s") + canvas.Text(20, height-40, s, textStyle) +} + +// for each search term on the commandline, create a photo grid +func main() { + for i := 1; i < len(os.Args); i++ { + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:black") + fs(url.QueryEscape(os.Args[i])) + canvas.End() + } +} diff --git a/vendor/github.com/ajstarks/svgo/fe/fe.go b/vendor/github.com/ajstarks/svgo/fe/fe.go new file mode 100644 index 0000000..1681192 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/fe/fe.go @@ -0,0 +1,53 @@ +// fe: SVG Filter Effect example from http://www.w3.org/TR/SVG/filters.html#AnExample +// +build !appengine + +package main + + +import ( + "github.com/ajstarks/svgo" + "os" +) + +func main() { + + canvas := svg.New(os.Stdout) + width := 410 + height := 120 + + canvas.Start(width, height) + canvas.Title(`SVGo Filter Example`) + canvas.Desc(`Combines multiple filter primitives to produce a 3D lighting effect`) + + gfs := svg.Filterspec{In: "SourceAlpha", Result: "blur"} + ofs := svg.Filterspec{In: "blur", Result: "offsetBlur"} + sfs := svg.Filterspec{In: "blur", Result: "specOut"} + cfs1 := svg.Filterspec{In: "specOut", In2: "SourceAlpha", Result: "specOut"} + cfs2 := svg.Filterspec{In: "SourceGraphic", In2: "specOut", Result: "litPaint"} + + // define the filters + canvas.Def() + canvas.Filter("myFilter") + canvas.FeGaussianBlur(gfs, 4, 4) + canvas.FeOffset(ofs, 4, 4) + canvas.FeSpecularLighting(sfs, 5, .75, 20, "#bbbbbb") + canvas.FePointLight(-5000, -10000, 20000) + canvas.FeSpecEnd() + canvas.FeComposite(cfs1, "in", 0, 0, 0, 0) + canvas.FeComposite(cfs2, "arithmetic", 0, 1, 1, 0) + canvas.FeMerge([]string{ofs.Result, cfs2.Result}) + canvas.Fend() + canvas.DefEnd() + + // specify the graphic + canvas.Gid("SVG") + canvas.Path("M50,90 C0,90 0,30 50,30 L150,30 C200,30 200,90 150,90 z", "fill:none;stroke:#D90000;stroke-width:10") + canvas.Path("M60,80 C30,80 30,40 60,40 L140,40 C170,40 170,80 140,80 z", "fill:#D90000") + canvas.Text(52, 76, "SVG", "fill:white;stroke:black;font-size:45;font-family:Verdana") + canvas.Gend() + + canvas.Rect(0, 0, width, height, "stroke:black;fill:white") + canvas.Use(0, 0, "#SVG") // plain graphic + canvas.Use(200, 0, "#SVG", `filter="url(#myFilter)"`) // filter applied + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/flower/flower.go b/vendor/github.com/ajstarks/svgo/flower/flower.go new file mode 100644 index 0000000..515ddb2 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/flower/flower.go @@ -0,0 +1,79 @@ +// flower - draw random flowers, inspired by Evelyn Eastmond's DesignBlocks gererated "grain2" +// +build !appengine + +package main + +import ( + "flag" + "fmt" + "math" + "math/rand" + "os" + "time" + + "github.com/ajstarks/svgo" +) + +var ( + canvas = svg.New(os.Stdout) + niter = flag.Int("n", 200, "number of iterations") + width = flag.Int("w", 500, "width") + height = flag.Int("h", 500, "height") + thickness = flag.Int("t", 10, "max petal thinkness") + np = flag.Int("p", 15, "max number of petals") + psize = flag.Int("s", 30, "max length of petals") + opacity = flag.Int("o", 50, "max opacity (10-100)") +) + +const flowerfmt = `stroke:rgb(%d,%d,%d); stroke-opacity:%.2f; stroke-width:%d` + +func radial(xp int, yp int, n int, l int, style ...string) { + var x, y, r, t, limit float64 + limit = 2.0 * math.Pi + r = float64(l) + canvas.Gstyle(style[0]) + for t = 0.0; t < limit; t += limit / float64(n) { + x = r * math.Cos(t) + y = r * math.Sin(t) + canvas.Line(xp, yp, xp+int(x), yp+int(y)) + } + canvas.Gend() +} + +func random(howsmall, howbig int) int { + if howsmall >= howbig { + return howsmall + } + return rand.Intn(howbig-howsmall) + howsmall +} + +func randrad(w int, h int, n int) { + var x, y, r, g, b, o, s, t, p int + for i := 0; i < n; i++ { + x = rand.Intn(w) + y = rand.Intn(h) + r = rand.Intn(255) + g = rand.Intn(255) + b = rand.Intn(255) + o = random(10, *opacity) + s = random(10, *psize) + t = random(2, *thickness) + p = random(10, *np) + radial(x, y, p, s, fmt.Sprintf(flowerfmt, r, g, b, float64(o)/100.0, t)) + } +} + +func background(v int) { canvas.Rect(0, 0, *width, *height, canvas.RGB(v, v, v)) } + +func init() { + flag.Parse() + rand.Seed(int64(time.Now().Nanosecond()) % 1e9) +} + +func main() { + canvas.Start(*width, *height) + canvas.Title("Random Flowers") + background(255) + randrad(*width, *height, *niter) + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/fontcompare/fontcompare.go b/vendor/github.com/ajstarks/svgo/fontcompare/fontcompare.go new file mode 100644 index 0000000..120aac1 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/fontcompare/fontcompare.go @@ -0,0 +1,52 @@ +// fontcompare: compare two fonts +// +build !appengine + +package main + +import ( + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +var ( + canvas = svg.New(os.Stdout) + width = 1000 + height = 600 + chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789(){}[],.:;-+*/\\&_^%$#@!~`'\"<>" + gstyle = "font-family:%s;font-size:%dpt;text-anchor:middle;fill:%s;fill-opacity:%.2f" +) + +func letters(top, left int, font, color string, opacity float32) { + rows := 7 + cols := 13 + glyph := 0 + fontsize := 32 + spacing := fontsize * 2 + x := left + y := top + canvas.Gstyle(fmt.Sprintf(gstyle, font, fontsize, color, opacity)) + for r := 0; r < rows; r++ { + for c := 0; c < cols; c++ { + canvas.Text(x, y, chars[glyph:glyph+1]) + glyph++ + x += spacing + } + x = left + y += spacing + } + canvas.Gend() +} + +func main() { + if len(os.Args) > 2 { + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:white") + canvas.Text(80, 540, os.Args[1], "font-size:14pt; fill:blue; font-family:"+os.Args[1]) + canvas.Text(80, 560, os.Args[2], "font-size:14pt; fill:red; font-family:"+os.Args[2]) + letters(100, 100, os.Args[1], "blue", 0.5) + letters(100, 100, os.Args[2], "red", 0.5) + canvas.End() + } +} diff --git a/vendor/github.com/ajstarks/svgo/funnel/funnel.go b/vendor/github.com/ajstarks/svgo/funnel/funnel.go new file mode 100644 index 0000000..901a6bd --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/funnel/funnel.go @@ -0,0 +1,29 @@ +// funnel draws a funnel-like shape +// +build !appengine + +package main + +import ( + "os" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) +var width = 320 +var height = 480 + +func funnel(bg int, fg int, grid int, dim int) { + h := dim / 2 + canvas.Rect(0, 0, width, height, canvas.RGB(bg, bg, bg)) + for size := grid; size < width; size += grid { + canvas.Ellipse(h, size, size/2, size/2, canvas.RGBA(fg, fg, fg, 0.2)) + } +} + +func main() { + canvas.Start(width, height) + canvas.Title("Funnel") + funnel(0, 255, 25, width) + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/gradient/gradient.go b/vendor/github.com/ajstarks/svgo/gradient/gradient.go new file mode 100644 index 0000000..534321e --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/gradient/gradient.go @@ -0,0 +1,58 @@ +// gradient shows sample gradient fills +// +build !appengine + +package main + +import ( + "os" + "strconv" + + "github.com/ajstarks/svgo" +) + +func main() { + width := 500 + height := 500 + + lg := []svg.Offcolor{ + {0, "rgb(255,255,0)", 1.0}, + {100, "rgb(255,0,0)", .5}, + {0, "rgb(200,200,200)", 0.0}, + {100, "rgb(0,0,255)", 1.0}} + + rainbow := []svg.Offcolor{ + {10, "#00cc00", 1}, + {30, "#006600", 1}, + {70, "#cc0000", 1}, + {90, "#000099", 1}} + + rg := []svg.Offcolor{ + {1, "powderblue", 1}, + {10, "lightskyblue", 1}, + {100, "darkblue", 1}} + + g := svg.New(os.Stdout) + g.Start(width, height) + g.Title("Gradients") + g.Rect(0, 0, width, height, "fill:white") + g.Def() + g.LinearGradient("h", 0, 100, 0, 0, lg) + g.LinearGradient("v", 0, 0, 100, 0, lg) + g.LinearGradient("rainbow", 0, 0, 100, 0, rainbow) + g.RadialGradient("rad100", 50, 50, 100, 25, 25, rg) + g.RadialGradient("rad50", 50, 50, 50, 20, 50, rg) + for i := 50; i < 100; i += 10 { + g.RadialGradient("grad"+strconv.Itoa(i), 50, 50, uint8(i), 20, 50, rg) + } + g.DefEnd() + + g.Ellipse(width/2, height/2, 100, 100, "fill:url(#rad100)") + g.Rect(300, 200, 100, 100, "fill:url(#h)") + g.Rect(100, 200, 100, 100, "fill:url(#v)") + g.Roundrect(10, 10, width-20, 50, 10, 10, "fill:url(#rainbow)") + + for i := 50; i < 100; i += 10 { + g.Circle(i*5, 100, 15, "fill:url(#grad"+strconv.Itoa(i)+")") + } + g.End() +} diff --git a/vendor/github.com/ajstarks/svgo/html5logo/html5logo.go b/vendor/github.com/ajstarks/svgo/html5logo/html5logo.go new file mode 100644 index 0000000..f532528 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/html5logo/html5logo.go @@ -0,0 +1,41 @@ +// html5logo draws the w3c HTML5 logo, with scripting added +// +build !appengine + +package main + +import ( + "github.com/ajstarks/svgo" + "os" +) + +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.Title("HTML5 Logo") + 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(hx, hy, `drag:enable="true"`, canvas.RGBA(255, 255, 255, 0.3)) // draggable highlight + canvas.Polygon(fx, fy, `drag:enable="true"`, canvas.RGB(219, 219, 219)) // draggable five + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/imfade/imfade.go b/vendor/github.com/ajstarks/svgo/imfade/imfade.go new file mode 100644 index 0000000..c00b82f --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/imfade/imfade.go @@ -0,0 +1,32 @@ +// imfade progressively fades the Go gopher image +// +build !appengine + +package main + +import ( + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +func main() { + width := 768 + height := 128 + image := "gophercolor128x128.png" + if len(os.Args) > 1 { + image = os.Args[1] + } + canvas.Start(width, height) + canvas.Title("Image Fade") + opacity := 1.0 + for i := 0; i < width-128; i += 100 { + canvas.Image(i, 0, 128, 128, image, fmt.Sprintf("opacity:%.2f", opacity)) + opacity -= 0.10 + } + canvas.Grid(0, 0, width, height, 16, "stroke:gray; opacity:0.2") + + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/lewitt/lewitt.go b/vendor/github.com/ajstarks/svgo/lewitt/lewitt.go new file mode 100644 index 0000000..fea90da --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/lewitt/lewitt.go @@ -0,0 +1,84 @@ +// lewitt: inspired by by Sol LeWitt's Wall Drawing 91: +// +build !appengine + +package main + +// +// A six-inch (15 cm) grid covering the wall. +// Within each square, not straight lines from side to side, using +// red, yellow and blue pencils. Each square contains at least +// one line of each color. +// +// This version violates the original instructions in that straight lines +// as well as arcs are used + +import ( + "flag" + "fmt" + "math/rand" + "os" + "time" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +const tilestyle = `stroke-width:1; stroke:rgb(128,128,128); stroke-opacity:0.5; fill:white` +const penstyle = `stroke:rgb%s; fill:none; stroke-opacity:%.2f; stroke-width:%d` + +var width = 720 +var height = 720 + +var nlines = flag.Int("n", 20, "number of lines/square") +var nw = flag.Int("w", 3, "maximum pencil width") +var pencils = []string{"(250, 13, 44)", "(247, 212, 70)", "(52, 114, 245)"} + +func background(v int) { canvas.Rect(0, 0, width, height, canvas.RGB(v, v, v)) } + +func lewitt(x int, y int, gsize int, n int, w int) { + var x1, x2, y1, y2 int + var op float64 + canvas.Rect(x, y, gsize, gsize, tilestyle) + for i := 0; i < n; i++ { + choice := rand.Intn(len(pencils)) + op = float64(random(1, 10)) / 10.0 + x1 = random(x, x+gsize) + y1 = random(y, y+gsize) + x2 = random(x, x+gsize) + y2 = random(y, y+gsize) + if random(0, 100) > 50 { + canvas.Line(x1, y1, x2, y2, fmt.Sprintf(penstyle, pencils[choice], op, random(1, w))) + } else { + canvas.Arc(x1, y1, gsize, gsize, 0, false, true, x2, y2, fmt.Sprintf(penstyle, pencils[choice], op, random(1, w))) + } + } +} + +func random(howsmall, howbig int) int { + if howsmall >= howbig { + return howsmall + } + return rand.Intn(howbig-howsmall) + howsmall +} + +func init() { + flag.Parse() + rand.Seed(int64(time.Now().Nanosecond()) % 1e9) +} + +func main() { + + canvas.Start(width, height) + canvas.Title("Sol Lewitt's Wall Drawing 91") + background(255) + gsize := 120 + nc := width / gsize + nr := height / gsize + for cols := 0; cols < nc; cols++ { + for rows := 0; rows < nr; rows++ { + lewitt(cols*gsize, rows*gsize, gsize, *nlines, *nw) + } + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/ltr/ltr.go b/vendor/github.com/ajstarks/svgo/ltr/ltr.go new file mode 100644 index 0000000..d58a9e1 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/ltr/ltr.go @@ -0,0 +1,178 @@ +// ltr: Layer Tennis remixes + +package main + +import ( + "flag" + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +var ( + canvas = svg.New(os.Stdout) + poster, opacity, row, col, offset bool + title string + width, height int +) + +const ( + stdwidth = 900 + stdheight = 280 + ni = 11 +) + +// imagefiles returns a list of files in the specifed directory +// or nil on error. Each file includes the prepended directory name +func imagefiles(directory string) []string { + f, ferr := os.Open(directory) + if ferr != nil { + return nil + } + defer f.Close() + files, derr := f.Readdir(-1) + if derr != nil || len(files) == 0 { + return nil + } + names := make([]string, len(files)) + for i, v := range files { + names[i] = directory + "/" + v.Name() + } + return names +} + +// ltposter creates poster style: a title, followed by a list +// of volleys +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 + } + } +} + +// ltcol creates a single column of volley images +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 + } +} + +// ltop creates a view with each volley stacked together with +// semi-transparent opacity +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") + } +} + +// ltrow creates a row-wise view of volley images. +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 + } +} + +// ltoffset creates a view where each volley is offset from its opposing volley. +func ltoffset(x, y, w, h int, f []string) { + for i := 1; i < len(f); i++ { // skip the first file, assumed to be the banner + + if i%2 == 0 { + x += w + } else { + x = 0 + } + canvas.Image(x, y, w, h, f[i]) + y += h + } +} + +// dotitle creates the title +func dotitle(s string) { + if len(title) > 0 { + canvas.Title(title) + } else { + canvas.Title(s) + } +} + +// init sets up the command line flags. +func init() { + flag.BoolVar(&poster, "poster", false, "poster style") + flag.BoolVar(&opacity, "opacity", false, "opacity style") + flag.BoolVar(&row, "row", false, "display is a single row") + flag.BoolVar(&col, "col", false, "display in a single column") + flag.BoolVar(&offset, "offset", false, "display in a row, even layers offset") + flag.IntVar(&width, "width", stdwidth, "image width") + flag.IntVar(&height, "height", stdheight, "image height") + flag.StringVar(&title, "title", "", "title") + flag.Parse() +} + +func main() { + x := 0 + y := 0 + nd := len(flag.Args()) + for i, dir := range flag.Args() { + filelist := imagefiles(dir) + if len(filelist) != ni || filelist == nil { + fmt.Fprintf(os.Stderr, "in the %s directory, need %d images, read %d\n", dir, ni, len(filelist)) + continue + } + switch { + + case opacity: + if i == 0 { + canvas.Start(width*nd, height*nd) + dotitle(dir) + } + ltop(x, y, width, height, filelist) + y += height + + case poster: + if i == 0 { + canvas.Start(width, ((height*(ni-1)/4)+height)*nd) + dotitle(dir) + } + ltposter(x, y, width/2, height/2, filelist) + y += (height * 3) + (height / 2) + + case col: + if i == 0 { + canvas.Start(width*nd, height*ni) + dotitle(dir) + } + ltcol(x, y, width, height, filelist) + x += width + + case row: + if i == 0 { + canvas.Start(width*ni, height*nd) + dotitle(dir) + } + ltrow(x, y, width, height, filelist) + y += height + + case offset: + n := ni - 1 + pw := width * 2 + ph := nd * (height * (n)) + if i == 0 { + canvas.Start(pw, ph) + canvas.Rect(0, 0, pw, ph, "fill:white") + dotitle(dir) + } + ltoffset(x, y, width, height, filelist) + y += n * height + + } + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/marker/marker.go b/vendor/github.com/ajstarks/svgo/marker/marker.go new file mode 100644 index 0000000..bb7b642 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/marker/marker.go @@ -0,0 +1,39 @@ +// marker test +// +build !appengine + +package main + +import ( + "github.com/ajstarks/svgo" + "os" +) + +func main() { + canvas := svg.New(os.Stdout) + canvas.Start(500, 500) + canvas.Title("Marker") + + canvas.Def() + canvas.Marker("dot", 5, 5, 8, 8) + canvas.Circle(5, 5, 3, "fill:black") + canvas.MarkerEnd() + + canvas.Marker("box", 5, 5, 8, 8) + canvas.CenterRect(5, 5, 6, 6, "fill:green") + canvas.MarkerEnd() + + canvas.Marker("arrow", 2, 6, 13, 13) + canvas.Path("M2,2 L2,11 L10,6 L2,2", "fill:blue") + canvas.MarkerEnd() + canvas.DefEnd() + + x := []int{100, 250, 100} + y := []int{100, 250, 400} + canvas.Polyline(x, y, + `fill="none"`, + `stroke="red"`, + `marker-start="url(#dot)"`, + `marker-mid="url(#arrow)"`, + `marker-end="url(#box)"`) + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/newsvg b/vendor/github.com/ajstarks/svgo/newsvg new file mode 100644 index 0000000..46c7099 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/newsvg @@ -0,0 +1,39 @@ +#!/bin/sh + +if test $# -lt 1 +then + echo "specify a file" + exit 2 +fi + +if test ! -f $1 +then +cat < $1 +package main + +import ( + "github.com/ajstarks/svgo" + "os" +) + +var ( + width = 500 + height = 500 + canvas = svg.New(os.Stdout) +) + +func background(v int) { canvas.Rect(0, 0, width, height, canvas.RGB(v, v, v)) } + + +func main() { + canvas.Start(width, height) + background(255) + + // your code here + + canvas.Grid(0, 0, width, height, 10, "stroke:black;opacity:0.1") + canvas.End() +} +! +fi +$EDITOR $1 diff --git a/vendor/github.com/ajstarks/svgo/paths/paths.go b/vendor/github.com/ajstarks/svgo/paths/paths.go new file mode 100644 index 0000000..5a9283a --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/paths/paths.go @@ -0,0 +1,31 @@ +// paths draws the W3C logo as a paths +// +build !appengine + +package main + +import ( + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +func w3c() { + w3path := `M36,5l12,41l12-41h33v4l-13,21c30,10,2,69-21,28l7-2c15,27,33,-22,3,-19v-4l12-20h-15l-17,59h-1l-13-42l-12,42h-1l-20-67h9l12,41l8-28l-4-13h9` + cpath := `M94,53c15,32,30,14,35,7l-1-7c-16,26-32,3-34,0M122,16c-10-21-34,0-21,30c-5-30 16,-38 23,-21l5-10l-2-9` + canvas.Path(w3path, "fill:#005A9C") + canvas.Path(cpath) +} + +func main() { + canvas.Startview(700, 200, 0, 0, 700, 200) + canvas.Title("Paths") + for i := 0; i < 5; i++ { + canvas.Gtransform(fmt.Sprintf("translate(%d,0)", i*130)) + w3c() + canvas.Gend() + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/pattern/pattern.go b/vendor/github.com/ajstarks/svgo/pattern/pattern.go new file mode 100644 index 0000000..0545683 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/pattern/pattern.go @@ -0,0 +1,33 @@ +// pattern: test the pattern function +package main + +import ( + "fmt" + "github.com/ajstarks/svgo" + "os" +) + +func main() { + canvas := svg.New(os.Stdout) + w, h := 500, 500 + pct := 5 + pw, ph := (w*pct)/100, (h*pct)/100 + canvas.Start(w, h) + + // define the pattern + canvas.Def() + canvas.Pattern("hatch", 0, 0, pw, ph, "user") + canvas.Gstyle("fill:none;stroke-width:1") + canvas.Path(fmt.Sprintf("M0,0 l%d,%d", pw, ph), "stroke:red") + canvas.Path(fmt.Sprintf("M%d,0 l-%d,%d", pw, pw, ph), "stroke:blue") + canvas.Gend() + canvas.PatternEnd() + canvas.DefEnd() + + // use the pattern + canvas.Gstyle("stroke:black; stroke-width:2") + canvas.Circle(w/2, h/2, h/8, "fill:url(#hatch)") + canvas.CenterRect((w*4)/5, h/2, h/4, h/4, "fill:url(#hatch)") + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/picserv/index.go b/vendor/github.com/ajstarks/svgo/picserv/index.go new file mode 100644 index 0000000..9feb426 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/picserv/index.go @@ -0,0 +1,127 @@ +package main +const ( +index = ` + + pic256 + + + +

Pic256

+

Programmed pictures in a 256x256 square

+

Defaults

+ +
rotext
+
flower
+
cube
+
funnel
+
rshape
+
lewitt
+
mondrian
+
face
+
clock
+
pacman
+
tux
+
ubuntu
+ +

Variations

+ +

rotext

+

+

char=a
+
char=b&ti=40
+
char=c&ti=60
+
char=d&ti=90&font=Courier
+

+ +

flower

+

+

petals=10&n=100
+
petals=15&n=50
+
petals=30&n=20
+
petals=30&n=10
+

+ +

cube

+

+

y=80&row=1
+
y=50&row=2
+
&row=3
+
y=0&row=4
+

+ +

funnel

+

+

step=10
+
step=15
+
step=25
+
step=25&bg=white&fg=black
+

+ +

rshape

+

+

shape=c
+
shape=r
+
same=f
+
shape=r&same=t
+

+ +

lewitt

+

+

pen=1&lines=20
+
pen=2&lines=30
+
pen=3&lines=40
+
pen=5&?lines=100
+

+ + +

mondrian

+

+

random=true
+
random=t
+
random=1
+
random=f
+

+ +

face

+

+

mood=happy&glance=u
+
mood=neutral&glance=d
+
mood=sad&glance=l
+
mood=happy&glance=r
+

+ +

clock

+

+

clock
+
hour=23
+
hour=12&min=34
+
hour=6&min=30&sec=0
+

+ +

pacman

+

+

pacman
+
angle=10
+
angle=40
+
angle=60
+

+ + + +`) diff --git a/vendor/github.com/ajstarks/svgo/picserv/pic256.html b/vendor/github.com/ajstarks/svgo/picserv/pic256.html new file mode 100644 index 0000000..6873184 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/picserv/pic256.html @@ -0,0 +1,124 @@ + + + pic256 + + + +

Pic256

+

Programmed pictures in a 256x256 square

+

Defaults

+ +
rotext
+
flower
+
cube
+
funnel
+
rshape
+
lewitt
+
mondrian
+
face
+
clock
+
pacman
+
tux
+
ubuntu
+ +

Variations

+ +

rotext

+

+

char=a
+
char=b&ti=40
+
char=c&ti=60
+
char=d&ti=90&font=Courier
+

+ +

flower

+

+

petals=10&n=100
+
petals=15&n=50
+
petals=30&n=20
+
petals=30&n=10
+

+ +

cube

+

+

y=80&row=1
+
y=50&row=2
+
&row=3
+
y=0&row=4
+

+ +

funnel

+

+

step=10
+
step=15
+
step=25
+
step=25&bg=white&fg=black
+

+ +

rshape

+

+

shape=c
+
shape=r
+
same=f
+
shape=r&same=t
+

+ +

lewitt

+

+

pen=1&lines=20
+
pen=2&lines=30
+
pen=3&lines=40
+
pen=5&?lines=100
+

+ + +

mondrian

+

+

random=true
+
random=t
+
random=1
+
random=f
+

+ +

face

+

+

mood=happy&glance=u
+
mood=neutral&glance=d
+
mood=sad&glance=l
+
mood=happy&glance=r
+

+ +

clock

+

+

clock
+
hour=23
+
hour=12&min=34
+
hour=6&min=30&sec=0
+

+ +

pacman

+

+

pacman
+
angle=10
+
angle=40
+
angle=60
+

+ + + diff --git a/vendor/github.com/ajstarks/svgo/picserv/picserv.go b/vendor/github.com/ajstarks/svgo/picserv/picserv.go new file mode 100644 index 0000000..48970cd --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/picserv/picserv.go @@ -0,0 +1,672 @@ +// picserv: serve pictures +package main + +import ( + "flag" + "fmt" + "io" + "log" + "math" + "math/rand" + "net/http" + "net/url" + "strconv" + "time" + + "github.com/ajstarks/svgo" +) + +var listen = flag.String("listen", ":1958", "http service address") + +const ( + arcstyle = "stroke:red;stroke-linecap:round;fill:none;stroke-width:10" + rotextfmt = "fill:%s;font-family:%s;font-size:%dpt" + flowerfmt = "stroke:rgb(%d,%d,%d); stroke-opacity:%.2f; stroke-width:%d" + tilestyle = "stroke-width:1; stroke:rgb(128,128,128); stroke-opacity:0.5; fill:white" + penstyle = "stroke:rgb%s; fill:none; stroke-opacity:%.2f; stroke-width:%d" + width = 256 + height = 256 +) + +// include index +//go:generate ih -v index -o index.go pic256.html + +// init seeds the RNG +func init() { + rand.Seed(time.Now().Unix() % 1e9) +} + +// serve stuff +func main() { + flag.Parse() + http.Handle("/", http.HandlerFunc(picindex)) + http.Handle("/index/", http.HandlerFunc(picindex)) + http.Handle("/pic256.html", http.HandlerFunc(picindex)) + http.Handle("/rotext/", http.HandlerFunc(rotext)) + http.Handle("/rshape/", http.HandlerFunc(rshape)) + http.Handle("/face/", http.HandlerFunc(face)) + http.Handle("/flower/", http.HandlerFunc(flower)) + http.Handle("/cube/", http.HandlerFunc(cube)) + http.Handle("/lewitt/", http.HandlerFunc(lewitt)) + http.Handle("/mondrian/", http.HandlerFunc(mondrian)) + http.Handle("/funnel/", http.HandlerFunc(funnel)) + http.Handle("/clock/", http.HandlerFunc(clock)) + http.Handle("/pacman/", http.HandlerFunc(pacman)) + http.Handle("/ubuntu/", http.HandlerFunc(ubuntu)) + http.Handle("/tux/", http.HandlerFunc(tux)) + log.Printf("listen on %s", *listen) + err := http.ListenAndServe(*listen, nil) + if err != nil { + log.Fatal("ListenAndServe:", err) + } +} + +// qstring returns the string value of the query string +func qstring(q url.Values, key, defval string, length int) string { + var retval string + p, ok := q[key] + if ok { + retval = p[0] + } else { + return defval + } + if len(retval) > length { + return retval[:length] + } + return retval +} + +// qfloat returns the float64 value of a query string, within limits +func qfloat(q url.Values, key string, defval float64, min, max float64) float64 { + var retval float64 + var err error + p, ok := q[key] + if ok { + retval, err = strconv.ParseFloat(p[0], 64) + if err != nil { + return defval + } + } else { + return defval + } + if retval < min || retval > max { + return defval + } + return retval +} + +// qfint returns the integer value of a query string, within limits +func qint(q url.Values, key string, defval int, min, max int) int { + var retval int + var err error + p, ok := q[key] + if ok { + retval, err = strconv.Atoi(p[0]) + if err != nil { + return defval + } + } else { + return defval + } + if retval < min || retval > max { + return defval + } + return retval +} + +// qbool returns the boolean value of a query string +func qbool(q url.Values, key string, defval bool) bool { + p, ok := q[key] + if ok { + switch p[0] { + case "t", "true", "T", "1", "on": + return true + case "f", "false", "F", "0", "off": + return false + default: + return defval + } + } else { + return defval + } +} + +func random(howsmall, howbig int) int { + if howsmall >= howbig { + return howsmall + } + return rand.Intn(howbig-howsmall) + howsmall +} + +func randcolor() string { + return fmt.Sprintf("fill:rgb(%d,%d,%d)", rand.Intn(255), rand.Intn(255), rand.Intn(255)) +} + +// picindex shows an HTML document that describes the service +// The "index" variable is a string that holds the document, +// made with go generate +func picindex(w http.ResponseWriter, req *http.Request) { + log.Printf("index: %s %s %s", req.RemoteAddr, req.URL.Path, req.UserAgent()) + io.WriteString(w, index) +} + +// rotext makes rotated and faded text +func rotext(w http.ResponseWriter, req *http.Request) { + + log.Printf("rotext: %s", req.RemoteAddr) + query := req.URL.Query() + + rchar := qstring(query, "char", "a", 3) // the string + ti := qfloat(query, "ti", 10, 5, 360) // angle interval + bg := qstring(query, "bg", "black", 20) // background color + fg := qstring(query, "fg", "white", 20) // text color + font := qstring(query, "font", "serif", 50) // font name + a, ai := 1.0, 0.03 + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Title("Rotated Text") + canvas.Rect(0, 0, width, height, "fill:"+bg) + canvas.Gstyle(fmt.Sprintf(rotextfmt, fg, font, width/(len(rchar)+1))) + for t := 0.0; t <= 360.0; t += ti { + canvas.TranslateRotate(width/2, height/2, t) + canvas.Text(0, 0, rchar, fmt.Sprintf("fill-opacity:%.2f", a)) + canvas.Gend() + a -= ai + } + canvas.Gend() + canvas.End() +} + +// face draws a face, with mood (happy, sad, neutral), +// and glance (up, down, left, right, middle) +func face(w http.ResponseWriter, req *http.Request) { + + log.Printf("face: %s", req.RemoteAddr) + query := req.URL.Query() + + mood := qstring(query, "mood", "h", 10) + glance := qstring(query, "glance", "m", 10) + ex1 := width / 4 // left eye x 25% from the left + ex2 := (width * 3) / 4 // right eye x 25% from the right + ey := height / 3 // eye y one third from the bottom + sy := (height * 2) / 3 // mouth y two-thirds from the bottom + er := width / 12 // eye radius + ax := height / 3 // mouth arc x + ay := height / 3 // mounth arc y + aflag := false + pupilsize := er / 3 + xoffset := 0 + yoffset := 0 + + // adjust mouth according to mood + switch mood { + case "n", "neutral": + ay = 0 + case "s", "sad": + sy = (height * 4) / 5 + aflag = true + } + + // adjust pupils according to glance + switch glance { + case "l", "left": + xoffset = -pupilsize + case "r", "right": + xoffset = pupilsize + case "d", "down": + yoffset = pupilsize + case "u", "up": + yoffset = -pupilsize + } + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Title("Face") + canvas.Rect(0, 0, width, height, "fill:white") // background + canvas.Circle(ex1, ey, er) // lefteye + canvas.Circle(ex2, ey, er) // righteye + canvas.Circle(ex1+xoffset, ey+yoffset, pupilsize, "fill:white") // left pupil + canvas.Circle(ex2+xoffset, ey+yoffset, pupilsize, "fill:white") // right pupil + canvas.Arc(ex1, sy, ax, ay, 0, false, aflag, ex2, sy, arcstyle) // mouth + canvas.End() +} + +// rshape draws random shapes +func rshape(w http.ResponseWriter, req *http.Request) { + + log.Printf("rshape: %s", req.RemoteAddr) + query := req.URL.Query() + + n := qint(query, "n", 150, 5, 200) // number of shapes + shape := qstring(query, "shape", "c", 10) // type of shape + bg := qstring(query, "bg", "white", 20) // background color + samesize := qbool(query, "same", false) // regular or oblong + canvas := svg.New(w) + + // draw rect, square, ellipse or circle according to the specified shape + shapefunc := canvas.Ellipse + switch shape { + case "r", "box": + shapefunc = canvas.Rect + samesize = false + case "s", "sq", "square": + shapefunc = canvas.Rect + samesize = true + case "e", "ellipse": + shapefunc = canvas.Ellipse + samesize = false + case "c", "circle", "dot": + shapefunc = canvas.Ellipse + samesize = true + } + + w.Header().Set("Content-type", "image/svg+xml") + var s1, s2 int + canvas.Start(width, height) + canvas.Title("Random Shapes") + canvas.Rect(0, 0, width, height, "fill:"+bg) + for i := 0; i < n; i++ { + s1 = rand.Intn(width / 5) + if samesize { + s2 = s1 + } else { + s2 = rand.Intn(height / 5) + } + shapefunc(rand.Intn(width), rand.Intn(height), s1, s2, + fmt.Sprintf("fill-opacity:%.2f;fill:rgb(%d,%d,%d)", + rand.Float64(), rand.Intn(256), rand.Intn(256), rand.Intn(256))) + } + canvas.End() +} + +func flower(w http.ResponseWriter, req *http.Request) { + + log.Printf("flower: %s", req.RemoteAddr) + query := req.URL.Query() + + n := qint(query, "n", 200, 10, 200) // number of "flowers" + np := qint(query, "petals", 15, 10, 60) // number of "petals" per flower + opacity := qint(query, "op", 50, 20, 100) // opacity + psize := qint(query, "size", 30, 5, 50) // length of the petals + thickness := qint(query, "thick", 10, 3, 20) // petal thickness + + limit := 2.0 * math.Pi + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Title("Flowers") + canvas.Rect(0, 0, width, height, "fill:white") + + for i := 0; i < n; i++ { + x := rand.Intn(width) + y := rand.Intn(height) + r := float64(random(10, psize)) + + canvas.Gstyle(fmt.Sprintf(flowerfmt, rand.Intn(255), rand.Intn(255), rand.Intn(255), + float64(random(10, opacity))/100.0, random(2, thickness))) + for theta := 0.0; theta < limit; theta += limit / float64(random(10, np)) { + xr := r * math.Cos(theta) + yr := r * math.Sin(theta) + canvas.Line(x, y, x+int(xr), y+int(yr)) + } + canvas.Gend() + } + canvas.End() +} + +// rcube makes a cube with three visible faces, each with a random color +func rcube(canvas *svg.SVG, x, y, l int) { + + // top face + tx := []int{x, x + (l * 3), x, x - (l * 3), x} + ty := []int{y, y + (l * 2), y + (l * 4), y + (l * 2), y} + + // left face + lx := []int{x - (l * 3), x, x, x - (l * 3), x - (l * 3)} + ly := []int{y + (l * 2), y + (l * 4), y + (l * 8), y + (l * 6), y + (l * 2)} + + // right face + rx := []int{x + (l * 3), x + (l * 3), x, x, x + (l * 3)} + ry := []int{y + (l * 2), y + (l * 6), y + (l * 8), y + (l * 4), y + (l * 2)} + + canvas.Polygon(tx, ty, randcolor()) + canvas.Polygon(lx, ly, randcolor()) + canvas.Polygon(rx, ry, randcolor()) +} + +// cube draws a grid of cubes, n rows deep. +// The grid begins at (xp, yp), with hspace between cubes in a row, and vspace between rows. +func cube(w http.ResponseWriter, req *http.Request) { + + log.Printf("cube: %s", req.RemoteAddr) + query := req.URL.Query() + + bgcolor := qstring(query, "bg", randcolor(), 30) // background color + n := qint(query, "row", 3, 1, 20) // number of rows + hspace := qint(query, "hs", width/5, 0, width) // horizontal space + vspace := qint(query, "vs", height/4, 0, height) // vertical space + size := qint(query, "size", width/30, 2, width/4) // cube size + xp := qint(query, "x", width/10, 0, width/2) // initial x position + yp := qint(query, "y", height/10, 0, height/2) // initial y position + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Title("Cubes") + canvas.Rect(0, 0, width, height, bgcolor) + y := yp + for r := 0; r < n; r++ { + for x := xp; x < width; x += hspace { + rcube(canvas, x, y, size) + } + y += vspace + } + canvas.End() +} + +var pencils = []string{"(250, 13, 44)", "(247, 212, 70)", "(52, 114, 245)"} + +func lew(canvas *svg.SVG, x int, y int, gsize int, n int, w int) { + var x1, x2, y1, y2 int + var op float64 + canvas.Rect(x, y, gsize, gsize, tilestyle) + for i := 0; i < n; i++ { + choice := rand.Intn(len(pencils)) + op = float64(random(1, 10)) / 10.0 + x1 = random(x, x+gsize) + y1 = random(y, y+gsize) + x2 = random(x, x+gsize) + y2 = random(y, y+gsize) + if random(0, 100) > 50 { + canvas.Line(x1, y1, x2, y2, fmt.Sprintf(penstyle, pencils[choice], op, random(1, w))) + } else { + canvas.Arc(x1, y1, gsize, gsize, 0, false, true, x2, y2, fmt.Sprintf(penstyle, pencils[choice], op, random(1, w))) + } + } +} + +// lewitt simulates Sol Lewitt's Wall Drawing 91 +func lewitt(w http.ResponseWriter, req *http.Request) { + query := req.URL.Query() + log.Printf("lewitt: %s", req.RemoteAddr) + + nlines := qint(query, "lines", 20, 5, 100) + nw := qint(query, "pen", 3, 1, 5) + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Title("Sol Lewitt's Wall Drawing 91") + canvas.Rect(0, 0, width, height, "fill:white") + gsize := width / 6 + nc := width / gsize + nr := height / gsize + for cols := 0; cols < nc; cols++ { + for rows := 0; rows < nr; rows++ { + lew(canvas, cols*gsize, rows*gsize, gsize, nlines, nw) + } + } + canvas.End() +} + +// pmcolor returns a random color from Mondrian's set, or a specified standard color +func pmcolor(randcolor bool, standard string) string { + moncolors := []string{"white", "red", "blue", "yellow"} + if randcolor { + return moncolors[rand.Intn(10000)%4] + } + return standard +} + +// mondrian draws a view inspired by Piet Mondrian's Composition red, blue, white and yellow +func mondrian(w http.ResponseWriter, req *http.Request) { + log.Printf("mondrian: %s", req.RemoteAddr) + query := req.URL.Query() + rc := qbool(query, "random", false) + w3 := width / 3 + w6 := w3 / 2 + w23 := w3 * 2 + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Title("Mondrian Composition in red, blue, white and yellow") + canvas.Gstyle("stroke:black;stroke-width:6") + canvas.Rect(0, 0, w3, w3, "fill:"+pmcolor(rc, "white")) + canvas.Rect(0, w3, w3, w3, "fill:"+pmcolor(rc, "white")) + canvas.Rect(0, w23, w3, w3, "fill:"+pmcolor(rc, "blue")) + canvas.Rect(w3, 0, w23, w23, "fill:"+pmcolor(rc, "red")) + canvas.Rect(w3, w23, w23, w3, "fill:"+pmcolor(rc, "white")) + canvas.Rect(width-w6, height-w3, w3-w6, w6, "fill:"+pmcolor(rc, "white")) + canvas.Rect(width-w6, height-w6, w3-w6, w6, "fill:"+pmcolor(rc, "yellow")) + canvas.Gend() + canvas.Rect(0, 0, width, height, "fill:none;stroke:black;stroke-width:12") + canvas.End() +} + +// funnel makes a funnel from fading ellipses +func funnel(w http.ResponseWriter, req *http.Request) { + log.Printf("funnel: %s", req.RemoteAddr) + query := req.URL.Query() + bg := qstring(query, "bg", "black", 20) + fg := qstring(query, "fg", "white", 20) + grid := qint(query, "step", 25, 10, height/3) + h := width / 2 + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Title("Funnel") + canvas.Rect(0, 0, width, height, "fill:"+bg) + canvas.Gstyle("fill-opacity:0.2;fill:" + fg) + for size := grid; size < width; size += grid { + canvas.Ellipse(h, size, size/2, size/2) + } + canvas.Gend() + canvas.End() +} + +var ( + digits = [12]string{"12", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11"} + hrangles = [12]float64{90, 60, 30, 0, 330, 300, 270, 240, 210, 180, 150, 120} + minangles = [60]float64{ + 90, 84, 78, 72, 66, 60, 54, 48, 42, 36, 30, 24, 18, 12, 6, + 0, 354, 348, 342, 336, 330, 324, 318, 312, 306, + 300, 294, 288, 282, 276, 270, 264, 258, 252, 246, 240, 234, 228, 222, 216, + 210, 204, 198, 192, 186, 180, 174, 168, 162, 156, + 150, 144, 138, 132, 126, 120, 114, 108, 102, 96, + } +) + +const ( + radians = math.Pi / 180.0 + hrcolor = "rgb(127,0,0)" + secolor = "rgb(0,0,255)" + mincolor = "rgb(127,127,127)" + bgcolor = "rgb(140,140,140)" + linefmt = "stroke:%s;stroke-width:%d" + digitfmt = "font-family:Helvetica,Calibri,sans-serif;text-anchor:middle;font-size:%dpx" +) + +// clock draws an analog clock +func clock(w http.ResponseWriter, req *http.Request) { + log.Printf("clock: %s", req.RemoteAddr) + query := req.URL.Query() + size := width / 3 + basesize := size / 12 + fs := (size * 2) + (size / 2) + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + + // clock face + cx, cy := width/2, height/2 + now := time.Now() + hour, min, sec := now.Hour(), now.Minute(), now.Second() + + hour = qint(query, "hour", hour, 0, 23) + min = qint(query, "min", min, 0, 59) + sec = qint(query, "sec", sec, 0, 59) + + canvas.Rect(0, 0, width, height, "fill:black") + canvas.Roundrect(cx-(fs/2), cy-(fs/2), fs, fs, basesize, basesize, "fill:"+bgcolor) + canvas.Circle(cx, cy, size+(size/6), "fill:white") + canvas.Gstyle(fmt.Sprintf(digitfmt, basesize*2)) + + // draw the clock-face digits + r := float64(size) + rx := float64(cx) + ry := float64(cy) + for h := 12; h > 0; h-- { + t := hrangles[h%12] * radians + x := rx + r*math.Cos(t) + y := ry + r*math.Sin(t) + canvas.Text(int(x), height-int(y), digits[h%12], "baseline-shift:-30%") + } + canvas.Gend() + + // hour hand: special case: if the minute is greater than 30, + // adjust the hour hand the move proportionally closer to the upcoming hour. + t := hrangles[hour%12] + if min > 30 { + t = t - (30.0 * (float64(min) / 60.0)) + } + hr := r * 0.6 + hx := rx + hr*math.Cos(t*radians) + hy := ry + hr*math.Sin(t*radians) + + // minute hand + mr := r * 0.9 + t = minangles[min] * radians + mx := rx + mr*math.Cos(t) + my := ry + mr*math.Sin(t) + + // second hand + sr := r + t = minangles[sec] * radians + sx := rx + sr*math.Cos(t) + sy := ry + sr*math.Sin(t) + + // draw the hands and center dot + canvas.Line(cx, cy, int(hx), height-int(hy), fmt.Sprintf(linefmt, hrcolor, basesize)) + canvas.Line(cx, cy, int(mx), height-int(my), fmt.Sprintf(linefmt, mincolor, basesize/2)) + canvas.Line(cx, cy, int(sx), height-int(sy), fmt.Sprintf(linefmt, secolor, basesize/4)) + canvas.Circle(cx, cy, basesize, "fill:black") + canvas.End() +} + +// pacman draws pacman with dots +func pacman(w http.ResponseWriter, req *http.Request) { + log.Printf("pacman: %s", req.RemoteAddr) + query := req.URL.Query() + angle := qfloat(query, "angle", 30.0, 10.0, 70.0) + + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + cx, cy := width/2, height/2 + r := width / 5 + p := r / 8 + canvas.Start(width, height) + canvas.Rect(0, 0, width, height) + + // draw dots + canvas.Gstyle("fill:white") + for x := 0; x < 100; x += 12 { + if x < 50 { + canvas.Circle((width*x)/100, cy, p, "fill-opacity:0.5") + } else { + canvas.Circle((width*x)/100, cy, p, "fill-opacity:1") + } + } + canvas.Gend() + + // draw pacman: two arcs, rotated, + // the angle determines how wide the mouth is open + canvas.Gstyle("fill:yellow") + + canvas.TranslateRotate(cx, cy, -angle) + canvas.Arc(-r, 0, r, r, 30, false, true, r, 0) + canvas.Gend() + + canvas.TranslateRotate(cx, cy, angle) + canvas.Arc(-r, 0, r, r, 30, false, false, r, 0) + canvas.Gend() + + canvas.Gend() + canvas.End() +} +func tux(w http.ResponseWriter, req *http.Request) { + log.Printf("tux: %s", req.RemoteAddr) + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:white") + canvas.Circle(width/2, height/2, height/2-20, "fill:black") + canvas.Ellipse(width/2, height, width/2, height/2, "fill:black") + canvas.Ellipse(width/3, height/2, 20, 40, "fill:white") + canvas.Ellipse(2*width/3, height/2, 20, 40, "fill:white") + canvas.Ellipse(width/3, height/2+18, 15, 20) + canvas.Ellipse(2*width/3, height/2+18, 15, 20) + + canvas.Circle(width/3+7, height/2+20, 5, "fill:white") + canvas.Circle(2*width/3+7, height/2+20, 5, "fill:white") + + canvas.Arc(60, height-60, width/3, 50, 0, false, true, width-60, height-60, + "stroke-width:3;stroke-linecap:round;stroke:yellow;fill:yellow") + + canvas.Arc(60, height-60, width/3, 140, 0, false, false, width-60, height-60, + "stroke-width:3;stroke-linecap:round;stroke:yellow") + + beakx := []int{58, width - 58, width / 2} + beaky := []int{height - 62, height - 62, height - 20} + canvas.Polygon(beakx, beaky, "fill:yellow") + + canvas.End() +} + +const ( + d2r = math.Pi / 180 + ustyle = "stroke:#DD4814;stroke-width:8" +) + +func polar(cx, cy, r, t int) (int, int) { + fr := float64(r) + ft := float64(t) * d2r + x := fr * math.Cos(ft) + y := fr * math.Sin(ft) + return cx + int(x), cy + int(y) +} + +func ubuntu(w http.ResponseWriter, req *http.Request) { + log.Printf("ubuntu: %s", req.RemoteAddr) + w.Header().Set("Content-type", "image/svg+xml") + canvas := svg.New(w) + cx, cy := width/2, height/2 + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:white") + canvas.Circle(cx, cy, cx, "fill:#DD4814") + r := width / 3 + + canvas.Circle(cx, cy, r-10, "fill:none;stroke:white;stroke-width:25") + canvas.Gstyle("fill:white;" + ustyle) + for _, t := range []int{300, 180, 60} { + px, py := polar(cx, cy, r+10, t) + canvas.Circle(px, py, 20) + } + canvas.Gend() + + canvas.Gstyle(ustyle) + for _, t := range []int{120, 0, 240} { + lx2, ly2 := polar(cx, cy, r+25, t) + canvas.Line(cx, cy, lx2, ly2) + } + canvas.Gend() + + canvas.End() +} + diff --git a/vendor/github.com/ajstarks/svgo/planets/planets.go b/vendor/github.com/ajstarks/svgo/planets/planets.go new file mode 100644 index 0000000..5393d1b --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/planets/planets.go @@ -0,0 +1,122 @@ +// planets: an exploration of scale +// +build !appengine + +package main + +import ( + "flag" + "image/png" + "os" + + "github.com/ajstarks/svgo" +) + +var ssDist = []float64{ + 0.00, // Sun + 0.34, // Mercury + 0.72, // Venus + 1.00, // Earth + 1.54, // Mars + 5.02, // Jupiter + 9.46, // Saturn + 20.11, // Uranus + 30.08} // Netpune + +var ssRad = []float64{ // Miles + 423200.0, // Sun + 1516.0, // Mercury + 3760.0, // Venus + 3957.0, // Earth + 2104.0, // Mars + 42980.0, // Jupiter + 35610.0, // Saturn + 15700.0, // Uranus + 15260.0} // Neptune + +var ssColor = []string{ // R, G, B + // Eyeballed from image + "F7730C", // Sun + "FAF8F2", // Mercury + "FFFFF2", // Venus + "0B5CE3", // Earth + "F0C61D", // Mars + "FDC791", // Jupiter + "E0C422", // Saturn + "DCF1F5", // Uranus + "39B6F7"} // Neptune + +var ssImages = []string{ + "sun.png", + "mercury.png", + "venus.png", + "earth.png", + "mars.png", + "jupiter.png", + "saturn.png", + "uranus.png", + "neptune.png"} + +var showdisk = flag.Bool("d", false, "show disk") +var canvas = svg.New(os.Stdout) + +func vmap(value float64, low1 float64, high1 float64, low2 float64, high2 float64) float64 { + return low2 + (high2-low2)*(value-low1)/(high1-low1) +} + +func main() { + + width := 1200 + height := 200 + + flag.Parse() + canvas.Start(width, height) + canvas.Title("Planets") + canvas.Rect(0, 0, width, height, "fill:black") + nobj := len(ssDist) + y := height / 2 + margin := 100 + minsize := 7.0 + labeloc := height / 4 + + var x, r, imScale, maxh float64 + var px, po int + + if *showdisk { + maxh = float64(height) / minsize + } else { + maxh = float64(height) / 4.0 + } + for i := 1; i < nobj; i++ { + x = vmap(ssDist[i], ssDist[1], ssDist[nobj-1], float64(margin), float64(width-margin)) + r = (vmap(ssRad[i], ssRad[1], ssRad[nobj-1], minsize, maxh)) / 2 + px = int(x) + if *showdisk { + po = 0 + canvas.Circle(px, y, int(r), "fill:#"+ssColor[i]) + } else { // show images + f, err := os.Open(ssImages[i]) + if err != nil { + println("bad image file:", ssImages[i]) + continue + } + defer f.Close() + p, perr := png.DecodeConfig(f) + if perr != nil { + println("bad decode:", ssImages[i]) + continue + } + imScale = r / float64(p.Width) + hs := float64(p.Height) * imScale + dy := y - (int(hs) / 2) // center the image + po = int(r) / 2 + canvas.Image(px, dy, int(r), int(hs), ssImages[i]) + } + if ssDist[i] == 1.0 { // earth + canvas.Line(px+po, y-po, px+po, y-labeloc, + "stroke-width:1px;stroke:white") + canvas.Text(px+po, y-labeloc-10, "You are here", + "fill:white; font-size:14px; font-family:Calibri; text-anchor:middle") + } + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/pmap/pmap.go b/vendor/github.com/ajstarks/svgo/pmap/pmap.go new file mode 100644 index 0000000..489fe25 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/pmap/pmap.go @@ -0,0 +1,244 @@ +// pmap percentage maps +// +build !appengine + +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "io" + "os" + + "github.com/ajstarks/svgo" +) + +// Pmap defines a porportional map +type Pmap struct { + Top int `xml:"top,attr"` + Left int `xml:"left,attr"` + Title string `xml:"title,attr"` + Pdata []Pdata `xml:"pdata"` +} + +// Pdata defines data with a portpotional map +type Pdata struct { + Legend string `xml:"legend,attr"` + Stagger string `xml:"stagger,attr"` + Alternate string `xml:"alternate,attr"` + Item []Item `xml:"item"` +} + +// Item defines an item with porpotional map data +type Item struct { + Name string `xml:",chardata"` + Value float64 `xml:"value,attr"` +} + +var ( + width, height, fontsize, fontscale, round, gutter, pred, pgreen, pblue, oflen int + bgcolor, olcolor, colorspec, title string + showpercent, showdata, alternate, showtitle, stagger, showlegend, showtotal bool + ofpct float64 + leftmargin = 40 + topmargin = 40 + canvas = svg.New(os.Stdout) +) + +const ( + globalfmt = "stroke-width:1;font-family:Calibri,sans-serif;text-anchor:middle;font-size:%dpt" + legendstyle = "text-anchor:start;font-size:150%" + linefmt = "stroke:%s" +) + +func dopmap(location string) { + var f *os.File + var err error + if len(location) > 0 { + f, err = os.Open(location) + } else { + f = os.Stdin + } + if err == nil { + readpmap(f) + f.Close() + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +func readpmap(r io.Reader) { + var pm Pmap + if err := xml.NewDecoder(r).Decode(&pm); err == nil { + drawpmap(pm) + } else { + fmt.Fprintf(os.Stderr, "Unable to parse pmap (%v)\n", err) + } +} + +func drawpmap(m Pmap) { + fs := fontsize + if m.Left > 0 { + leftmargin = m.Left + } + if m.Top > 0 { + topmargin = m.Top + } else { + topmargin = fs * fontscale + } + x := leftmargin + y := topmargin + if len(m.Title) > 0 { + title = m.Title + } + canvas.Title(title) + if showtitle { + dotitle(title) + } + for _, p := range m.Pdata { + pmap(x, y, fs, p) + y += fs*fontscale + (gutter + fs*2) + } +} + +func pmap(x, y, fs int, m Pdata) { + var tfill, vfmt, oc string + var up bool + h := fs * fontscale + fw := fs * 80 + slen := fs + (fs / 2) + up = false + + sum := 0.0 + for _, v := range m.Item { + sum += v.Value + } + + if len(olcolor) > 0 { + oc = olcolor + } else { + oc = bgcolor + } + loffset := (fs * fontscale) + fs + gline := fmt.Sprintf(linefmt, "gray") + wline := fmt.Sprintf(linefmt, oc) + if len(m.Legend) > 0 && showlegend { + if showtotal { + canvas.Text(x, y-fs, fmt.Sprintf("%s (total: "+floatfmt(sum)+")", m.Legend, sum), legendstyle) + } else { + canvas.Text(x, y-fs, m.Legend, legendstyle) + } + } + for i, p := range m.Item { + k := p.Name + v := p.Value + if v == 0.0 { + continue + } + pct := v / sum + pw := int(pct * float64(fw)) + xw := x + (pw / 2) + yh := y + (h / 2) + if pct >= .4 { + tfill = "fill:white" + } else { + tfill = "fill:black" + } + if round > 0 { + canvas.Roundrect(x, y, pw, h, round, round, canvas.RGBA(pred, pgreen, pblue, pct)) + } else { + canvas.Rect(x, y, pw, h, canvas.RGBA(pred, pgreen, pblue, pct)) + } + + dy := yh + fs + (fs / 2) + if pct <= ofpct || len(k) > oflen { // overflow label + if up { + dy -= loffset + yh -= loffset + canvas.Line(xw, y, xw, dy+(fs/2), gline) + } else { + dy += loffset + yh += loffset + canvas.Line(xw, y+h, xw, dy-(fs*3), gline) + } + if alternate { + up = !up + slen = fs * 2 + } else { + slen = fs * 3 + } + if stagger { + loffset += slen + } + tfill = "fill:black" + } + canvas.Text(xw, yh, k, tfill) + dpfmt := tfill + ";font-size:75%" + vfmt = floatfmt(v) + switch { + case showpercent && !showdata: + canvas.Text(xw, dy, fmt.Sprintf("%.1f%%", pct*100), dpfmt) + case showpercent && showdata: + canvas.Text(xw, dy, fmt.Sprintf(vfmt+", %.1f%%", v, pct*100), dpfmt) + case showdata && !showpercent: + canvas.Text(xw, dy, fmt.Sprintf(vfmt, v), dpfmt) + } + x += pw + if i < len(m.Item) { + canvas.Line(x, y, x, y+h, wline) + } + } +} + +func floatfmt(v float64) string { + var vfmt = "%.1f" + if v-float64(int(v)) == 0.0 { + vfmt = "%.0f" + } + return vfmt +} + +func dotitle(s string) { + offset := 40 + canvas.Text(leftmargin, height-offset, s, "text-anchor:start;font-size:250%") +} + +func init() { + flag.IntVar(&width, "w", 1024, "width") + flag.IntVar(&height, "h", 768, "height") + flag.IntVar(&fontsize, "f", 12, "font size (pt)") + flag.IntVar(&fontscale, "s", 5, "font scaling factor") + flag.IntVar(&round, "r", 0, "rounded corner size") + flag.IntVar(&gutter, "g", 100, "gutter") + flag.IntVar(&oflen, "ol", 20, "overflow length") + flag.StringVar(&bgcolor, "bg", "white", "background color") + flag.StringVar(&olcolor, "oc", "", "outline color") + flag.StringVar(&colorspec, "c", "0,0,0", "color (r,g,b)") + flag.StringVar(&title, "t", "Proportions", "title") + flag.BoolVar(&showpercent, "p", false, "show percentage") + flag.BoolVar(&showdata, "d", false, "show data") + flag.BoolVar(&alternate, "a", false, "alternate overflow labels") + flag.BoolVar(&stagger, "stagger", false, "stagger labels") + flag.BoolVar(&showlegend, "showlegend", true, "show the legend") + flag.BoolVar(&showtitle, "showtitle", false, "show the title") + flag.BoolVar(&showtotal, "showtotal", false, "show totals in the legend") + flag.Float64Var(&ofpct, "op", 0.05, "overflow percentage") + flag.Parse() + fmt.Sscanf(colorspec, "%d,%d,%d", &pred, &pgreen, &pblue) +} + +func main() { + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:"+bgcolor) + canvas.Gstyle(fmt.Sprintf(globalfmt, fontsize)) + + if len(flag.Args()) == 0 { + dopmap("") + } else { + for _, f := range flag.Args() { + dopmap(f) + } + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/randcomp/randcomp.go b/vendor/github.com/ajstarks/svgo/randcomp/randcomp.go new file mode 100644 index 0000000..696f67a --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/randcomp/randcomp.go @@ -0,0 +1,59 @@ +// randcomp visualizes random number generators +// +build !appengine + +package main + +import ( + "fmt" + "math/rand" + "os" + "strconv" + "time" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +func main() { + width := 512 + height := 256 + var n = 256 + var rx, ry int + + if len(os.Args) > 1 { + n, _ = strconv.Atoi(os.Args[1]) + } + + f, _ := os.Open("/dev/urandom") + x := make([]byte, n) + y := make([]byte, n) + f.Read(x) + f.Read(y) + f.Close() + + rand.Seed(int64(time.Now().Nanosecond()) % 1e9) + canvas.Start(600, 400) + canvas.Title("Random Integer Comparison") + canvas.Desc("Comparison of Random integers: the random device & the Go rand package") + canvas.Rect(0, 0, width/2, height, "fill:white; stroke:gray") + canvas.Rect(width/2, 0, width/2, height, "fill:white; stroke:gray") + + canvas.Desc("Left: Go rand package (red), Right: /dev/urandom") + canvas.Gstyle("stroke:none; fill-opacity:0.5") + for i := 0; i < n; i++ { + rx = rand.Intn(255) + ry = rand.Intn(255) + canvas.Circle(rx, ry, 5, canvas.RGB(127, 0, 0)) + canvas.Circle(int(x[i])+255, int(y[i]), 5, "fill:black") + } + canvas.Gend() + + canvas.Desc("Legends") + canvas.Gstyle("text-anchor:middle; font-size:18; font-family:Calibri") + canvas.Text(128, 280, "Go rand package", "") + canvas.Text(384, 280, "/dev/urandom") + canvas.Text(256, 280, fmt.Sprintf("n=%d", n), "font-size:12") + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/richter/richter.go b/vendor/github.com/ajstarks/svgo/richter/richter.go new file mode 100644 index 0000000..a99bdee --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/richter/richter.go @@ -0,0 +1,35 @@ +// richter -- inspired by Gerhard Richter's 256 colors, 1974 +// +build !appengine + +package main + +import ( + "math/rand" + "os" + "time" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +var width = 700 +var height = 400 + +func main() { + rand.Seed(int64(time.Now().Nanosecond()) % 1e9) + canvas.Start(width, height) + canvas.Title("Richter") + canvas.Rect(0, 0, width, height, "fill:white") + rw := 32 + rh := 18 + margin := 5 + for i, x := 0, 20; i < 16; i++ { + x += (rw + margin) + for j, y := 0, 20; j < 16; j++ { + canvas.Rect(x, y, rw, rh, canvas.RGB(rand.Intn(255), rand.Intn(255), rand.Intn(255))) + y += (rh + margin) + } + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/rl/rl.go b/vendor/github.com/ajstarks/svgo/rl/rl.go new file mode 100644 index 0000000..a233d4c --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/rl/rl.go @@ -0,0 +1,34 @@ +// rl - draw random lines +// +build !appengine + +package main + +import ( + "fmt" + "math/rand" + "os" + "time" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +func main() { + width := 200 + height := 200 + canvas.Start(width, height) + canvas.Title("Random Lines") + canvas.Rect(0, 0, width, height, "fill:black") + rand.Seed(int64(time.Now().Nanosecond()) % 1e9) + canvas.Gstyle("stroke-width:10") + r := 0 + for i := 0; i < width; i++ { + r = rand.Intn(255) + canvas.Line(i, 0, rand.Intn(width), height, fmt.Sprintf("stroke:rgb(%d,%d,%d); opacity:0.39", r, r, r)) + } + canvas.Gend() + + canvas.Text(width/2, height/2, "Random Lines", "fill:white; font-size:20; font-family:Calibri; text-anchor:middle") + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/rpd/rpd.go b/vendor/github.com/ajstarks/svgo/rpd/rpd.go new file mode 100644 index 0000000..397c418 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/rpd/rpd.go @@ -0,0 +1,80 @@ +package main + +// Imports +import ( + "encoding/xml" + "flag" + "fmt" + "github.com/ajstarks/svgo" + "io" + "os" +) + +// +// This is small +// This is medium +// This is large +// + +type Thing struct { + Top int `xml:"top,attr"` + Left int `xml:"left,attr"` + Sep int `xml:"sep,attr"` + Item []item `xml:"item"` +} + +type item struct { + Width int `xml:"width,attr"` + Height int `xml:"height,attr"` + Name string `xml:"name,attr"` + Color string `xml:"color,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) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + defer f.Close() + readthing(f) +} + +// Read the file, loading the defined structure +func readthing(r io.Reader) { + var t Thing + if err := xml.NewDecoder(r).Decode(&t); err != nil { + fmt.Fprintf(os.Stderr, "Unable to parse components (%v)\n", err) + return + } + drawthing(t) +} + +// 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 + } +} + +func main() { + flag.Parse() + for _, f := range flag.Args() { + canvas.Start(*width, *height) + dothing(f) + canvas.End() + } +} diff --git a/vendor/github.com/ajstarks/svgo/rpd/thing.xml b/vendor/github.com/ajstarks/svgo/rpd/thing.xml new file mode 100644 index 0000000..fbd9d0c --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/rpd/thing.xml @@ -0,0 +1,5 @@ + + This is small + This is medium + This is large + diff --git a/vendor/github.com/ajstarks/svgo/rr/rr.go b/vendor/github.com/ajstarks/svgo/rr/rr.go new file mode 100644 index 0000000..0f93c83 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/rr/rr.go @@ -0,0 +1,208 @@ +// radar roadmap (via Ernst and Young) +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "github.com/ajstarks/svgo" + "io" + "math" + "os" + "strings" +) + +var ( + width, height, iscale, fontsize, margin int + bgcolor, itemcolor, title string + opacity float64 + showtitle bool + gstyle = "font-family:Calibri;font-size:%dpx;text-anchor:middle" + canvas = svg.New(os.Stdout) +) + +// Roadmap XML structure: +// a roadmap consists of sections, which contain items, which indicate maturity and impact +type Roadmap struct { + Title string `xml:"title,attr"` + Duration int `xml:"duration,attr"` + Unit string `xml:"unit,attr"` + Section []section `xml:"section"` +} + +type section struct { + Name string `xml:"name,attr"` + Spacing float64 `xml:"spacing,attr"` + Item []item `xml:"item"` +} + +type item struct { + Impact int `xml:"impact,attr"` + Effort int `xml:"effort,attr"` + Begin string `xml:"begin,attr"` + Age float64 `xml:"age,attr"` + Name string `xml:",chardata"` + Desc desc `xml:"desc"` +} + +type desc struct { + Description string `xml:",chardata"` +} + +// dorr does file i/o +func dorr(location string) { + var f *os.File + var err error + if len(location) > 0 { + f, err = os.Open(location) + } else { + f = os.Stdin + } + if err == nil { + readrr(f) + f.Close() + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// readrr reads and parses the XML specification +func readrr(r io.Reader) { + var rm Roadmap + if err := xml.NewDecoder(r).Decode(&rm); err == nil { + drawrr(rm) + } else { + fmt.Fprintf(os.Stderr, "%v\n", err) + } +} + +// drawrr draws the roadmap +func drawrr(rm Roadmap) { + + if len(rm.Title) > 0 { + title = rm.Title + } + canvas.Title(title) + canvas.Gstyle(fmt.Sprintf(gstyle, fontsize)) + canvas.Rect(0, 0, width, height, "fill:"+bgcolor) + duration := rm.Duration + if duration <= 0 { + duration = 3 + } + ns := len(rm.Section) + cx := (width / 2) + cy := (height / 2) + r := ((width - margin) / duration) / 2 + sr := r + midsize := width / 100 + + // for each unit of time, draw cencentric circles + for i := 0; i < duration; i++ { + canvas.Circle(cx, cy, sr, "fill:none;stroke:lightgray;stroke-dasharray:7,7") + canvas.Text(cx, (cy - sr), fmt.Sprintf("%s %d", rm.Unit, i+1), "font-size:150%;fill:gray") + sr += r + } + // for each section, define its boundaries and draw its label + angle := 360.0 / float64(ns) + a := angle + a2 := a / 2 + for _, s := range rm.Section { + drawseclines(cx, cy, float64(r*duration), a, a2, s.Name) + spacing := s.Spacing + if spacing == 0 { + spacing = (angle / float64(len(s.Item))) - 1 + } + iangle := a + spacing + // for each item in the section, place the marker and label + for _, i := range s.Item { + itemx, itemy := dpolar(cx, cy, i.Age*float64(r), iangle) + drawitem(itemx, itemy, i.Impact*iscale, i.Effort, i.Name) + iangle += spacing + } + a += angle + } + + canvas.Circle(cx, cy, midsize, "fill:red") + canvas.Text(cx, cy, "READY", "baseline-shift:-25%") + if showtitle { + dotitle(title) + } + canvas.Gend() +} + +// radians converts degrees to radians +func radians(d float64) float64 { + return d * (math.Pi / 180.0) +} + +// dotitle places the title text +func dotitle(s string) { + canvas.Text(width/2, height-10, s, "font-size:200%;text-anchor:middle") +} + +// dpolar returns the cartesion coordinates given the center, size, and angle (in degrees) +func dpolar(cx, cy int, r, d float64) (int, int) { + x := r * math.Cos(radians(d)) + y := r * math.Sin(radians(d)) + return cx + int(x), cy + int(y) +} + +// drawseclines defines and labels the sections +func drawseclines(cx, cy int, size, a, h float64, s string) { + fs := fontsize + (fontsize / 2) + ix, iy := dpolar(cx, cy, size, a) + ix2, iy2 := dpolar(cx, cy, size+50, a+h) + canvas.Line(cx, cy, ix, iy, "stroke:lightgray") + textlines(ix2, iy2, fs, fs+2, "middle", "black", strings.Split(s, "\\n")) +} + +// drawitem draws a roadmap item +func drawitem(x, y, isize, ieffort int, s string) { + var op float64 + if ieffort > 0 { + op = opacity * (float64(ieffort) / 10.0) + } else { + op = opacity + } + style := fmt.Sprintf("fill:%s;fill-opacity:%.2f;stroke:white", itemcolor, op) + canvas.Circle(x, y, isize/2, style) + textlines(x-(isize/2)-2, y, fontsize, fontsize+2, "end", "black", strings.Split(s, "\\n")) +} + +// textlines displays text at a specified size, leading, fill, and alignment +func textlines(x, y, fs, leading int, align, fill string, s []string) { + canvas.Gstyle(fmt.Sprintf("font-size:%dpx;text-anchor:%s;fill:%s", fs, align, fill)) + for _, v := range s { + canvas.Text(x, y, v) + y += leading + } + canvas.Gend() +} + +// init sets up the command flags +func init() { + flag.StringVar(&bgcolor, "bg", "white", "background color") + flag.StringVar(&itemcolor, "ic", "rgb(131,206,226)", "item color") + flag.IntVar(&width, "w", 800, "width") + flag.IntVar(&height, "h", 800, "height") + flag.IntVar(&fontsize, "f", 12, "fontsize (px)") + flag.IntVar(&iscale, "s", int(float64(width)*.009), "impact scale") + flag.IntVar(&margin, "m", 150, "outside margin") + flag.BoolVar(&showtitle, "showtitle", false, "show title") + flag.StringVar(&title, "t", "Roadmap", "title") + flag.Float64Var(&opacity, "o", 1.0, "opacity") + flag.Parse() +} + +// for every input file (or stdin), draw a roadmap as specified by command flags +func main() { + canvas.Start(width, height) + if len(flag.Args()) == 0 { + dorr("") + } else { + for _, f := range flag.Args() { + dorr(f) + } + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/shotchart/shotchart.go b/vendor/github.com/ajstarks/svgo/shotchart/shotchart.go new file mode 100644 index 0000000..107834c --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/shotchart/shotchart.go @@ -0,0 +1,150 @@ +// shotchart: make NBA shotcharts +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "net/http" + "os" + + "github.com/ajstarks/svgo" +) + +// shotdata defines the shotchart JSON response from stats.nba.com +type shotdata struct { + Resource string `json:"resource"` + Parameters struct { + Leagueid string `json:"LeagueID"` + Season string `json:"Season"` + Seasontype string `json:"SeasonType"` + Teamid int `json:"TeamID"` + Playerid int `json:"PlayerID"` + Contextfilter string `json:"ContextFilter"` + Contextmeasure string `json:"ContextMeasure"` + } `json:"parameters"` + Resultsets []struct { + Name string `json:"name"` + Headers []string `json:"headers"` + Rowset [][]interface{} `json:"rowSet"` + } `json:"resultSets"` +} + +// vmap maps one range into another +func vmap(value, low1, high1, low2, high2 float64) float64 { + return low2 + (high2-low2)*(value-low1)/(high1-low1) +} + +const ( + shotsURLfmt = "http://stats.nba.com/stats/shotchartdetail?PlayerID=%s&CFID=33&CFPARAMS=2014-15&ContextFilter=&ContextMeasure=FGA&DateFrom=&DateTo=&GameID=&GameSegment=&LastNGames=0&LeagueID=00&Location=&MeasureType=Base&Month=0&OpponentTeamID=0&Outcome=&PaceAdjust=N&PerMode=PerGame&Period=0&PlusMinus=N&Position=&Rank=N&RookieYear=&Season=2014-15&SeasonSegment=&SeasonType=Regular+Season&TeamID=0&VsConference=&VsDivision=&mode=Advanced&showDetails=0&showShots=1&showZones=0" + picURLfmt = "http://stats.nba.com/media/players/230x185/%s.png" + activepicURLfmt = "http://stats.nba.com/media/players/700/%s.png" +) + +// shotAPI retrieves shotchart data from the source (currently stats.nba.com) +func shotAPI(id string) (io.ReadCloser, error) { + resp, err := http.Get(fmt.Sprintf(shotsURLfmt, id)) + if err != nil { + return nil, err + } + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unable to retreive network data for %s (%s)", id, resp.Status) + } + return resp.Body, nil +} + +// shotchart retrieves shot data given an id, either from local files or the network API +func shotchart(id string, network bool) { + var ( + shots shotdata + r io.ReadCloser + err error + picture string + ) + + if network { + r, err = shotAPI(id) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + picture = fmt.Sprintf(activepicURLfmt, id) + } else { + r, err = os.Open(id + ".json") + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + picture = id + ".png" + } + + defer r.Close() + err = json.NewDecoder(r).Decode(&shots) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + + // define the canvas, read and parse the response + canvas := svg.New(os.Stdout) + width, height := 900, 846 + fw, fh := float64(width), float64(height) + //imw, imh := 230, 185 + imw, imh := 700, 440 + top := fw / 10 + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:white;stroke:black;stroke-width:2") + //canvas.Image(width-imw, height-imh, imw, imh, picture) + canvas.Image(width/2, height-imh, imw, imh, picture) + canvas.Gstyle("font-family:Calibri;sans-serif;font-size:24px") + nfg := 0 + for _, r := range shots.Resultsets { + if r.Name == "Shot_Chart_Detail" { + var playername string + attempts := len(r.Rowset) + for _, rs := range r.Rowset { + var x, y float64 + var fill string + for i, v := range rs { + if i == 4 { + playername = v.(string) + } + if i == 17 { + x = v.(float64) + } + if i == 18 { + y = v.(float64) + } + if i == 20 { + xp := int(vmap(x, -300, 300, 0, fw)) + yp := int(vmap(y, -300, 300, top, fh)) + if v.(float64) == 0 { + fill = "red" + } else { + nfg++ + fill = "black" + } + canvas.Circle(xp, (yp-(height/2))+10, 4, "fill-opacity:0.3;fill:"+fill) + } + } + } + fgpct := (float64(nfg) / float64(attempts)) * 100 + canvas.Text(10, height-40, playername, "fill:gray") + canvas.Text(10, height-10, fmt.Sprintf("%d out of %d", attempts, nfg), "fill:gray") + canvas.Text(width/2, height-10, fmt.Sprintf("%.1f%%", fgpct), "text-anchor:middle;font-size:120%;fill:gray") + canvas.Gend() + } + } + canvas.End() + +} +func main() { + var network bool + flag.BoolVar(&network, "net", false, "retrieve data from the network") + flag.Parse() + + for _, file := range flag.Args() { + shotchart(file, network) + } +} diff --git a/vendor/github.com/ajstarks/svgo/skewabc/skewabc.go b/vendor/github.com/ajstarks/svgo/skewabc/skewabc.go new file mode 100644 index 0000000..01e15d3 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/skewabc/skewabc.go @@ -0,0 +1,37 @@ +// skewabc - exercise the skew functions +// +build !appengine + +package main + +import ( + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +var ( + g = svg.New(os.Stdout) + width = 500 + height = 500 +) + +func sky(x, y, w, h int, a float64, s string) { + g.Gstyle(fmt.Sprintf("font-family:sans-serif;font-size:%dpx;text-anchor:middle", w/2)) + g.SkewY(a) + g.Rect(x, y, w, h, `fill:black; fill-opacity:0.3`) + g.Text(x+w/2, y+h/2, s, `fill:white;baseline-shift:-33%`) + g.Gend() + g.Gend() +} + +func main() { + g.Start(width, height) + g.Title("Skew") + g.Rect(0, 0, width, height, "fill:white") + g.Grid(0, 0, width, height, 50, "stroke:lightblue") + sky(100, 100, 100, 100, 30, "A") + sky(200, 332, 100, 100, -30, "B") + sky(300, -15, 100, 100, 30, "C") + g.End() +} diff --git a/vendor/github.com/ajstarks/svgo/stockproduct/stockproduct.go b/vendor/github.com/ajstarks/svgo/stockproduct/stockproduct.go new file mode 100644 index 0000000..a59a15e --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/stockproduct/stockproduct.go @@ -0,0 +1,179 @@ +// stockproduct draws a bar chart comparing stock price to products +// +build !appengine + +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "os" + + "github.com/ajstarks/svgo" +) + +// Parameters defines options +type Parameters struct { + showline, showimage, showproduct, showprice, showdate, showgrid bool + x, y, w, h, width, height, spacing, fontsize, dot int + minvalue, maxvalue, ginterval, opacity, rotatetext float64 + barcolor string +} + +// +// +// +// +// +// +// +// + +// StockProduct is the top-level drawing +type StockProduct struct { + Title string `xml:"title,attr"` + Sdata []Sdata `xml:"sdata"` +} + +// Sdata defines stock data +type Sdata struct { + Price float64 `xml:"price,attr"` + Date string `xml:"date,attr"` + Product string `xml:"product,attr"` + Image string `xml:"image,attr"` +} + +// vmap maps ranges +func vmap(value float64, low1 float64, high1 float64, low2 float64, high2 float64) float64 { + return low2 + (high2-low2)*(value-low1)/(high1-low1) + +} + +// barchart draws a chart from data read at location, on a SVG canvas +// if the location is the empty string, read from standard input. +// Data items are scaled according to the width, with parameters controlling the visibility +// of lines, products, images, and dates +func (p *Parameters) barchart(location string, canvas *svg.SVG) { + var ( + f *os.File + err error + sp StockProduct + ) + if len(location) > 0 { + f, err = os.Open(location) + } else { + f = os.Stdin + } + if err != nil { + fmt.Fprintln(os.Stderr, err) + return + } + defer f.Close() + if err := xml.NewDecoder(f).Decode(&sp); err != nil { + fmt.Fprintln(os.Stderr, err) + return + } + + bottom := p.y + p.h + interval := p.w / (len(sp.Sdata) - 1) + bw := interval - p.spacing + offset := 120 + halfoffset := offset / 2 + + if bw < 2 { + bw = 2 + } + canvas.Text(p.x, p.y-halfoffset, sp.Title, "font-size:400%") + if p.showgrid { + canvas.Gstyle("stroke:lightgray;stroke-width:1px") + gx := p.x - (bw / 2) + for i := p.maxvalue; i >= p.minvalue; i -= p.ginterval { + yp := int(vmap(i, p.minvalue, p.maxvalue, float64(p.y), float64(bottom))) + by := p.y + (bottom - yp) + canvas.Line(gx, by, p.x+p.w+(bw/2), by) + canvas.Text(gx-halfoffset, by, fmt.Sprintf("%.0f", i), "fill:black;stroke:none") + } + canvas.Gend() + } + canvas.Gstyle(fmt.Sprintf("stroke-opacity:%.2f;stroke:%s;stroke-width:%d;text-anchor:middle", p.opacity, p.barcolor, bw)) + for _, d := range sp.Sdata { + yp := int(vmap(d.Price, p.minvalue, p.maxvalue, float64(p.y), float64(bottom))) + by := p.y + (bottom - yp) + if p.showline { + canvas.Line(p.x, bottom, p.x, by) + } + if p.dot > 0 { + canvas.Circle(p.x, by, p.dot, fmt.Sprintf("stroke:none;fill-opacity:%.2f;fill:%s", p.opacity, p.barcolor)) + } + if p.showimage { + if len(d.Image) > 0 { + canvas.Image(p.x-bw/2, by-offset-2, bw, offset, d.Image) + } + } + canvas.Gstyle("stroke:none;fill:black") + if p.showproduct { + if p.rotatetext != 0 { + canvas.TranslateRotate(p.x, bottom+40, p.rotatetext) + canvas.Text(0, 0, d.Product) + canvas.Gend() + } else { + canvas.Text(p.x, bottom+40, d.Product) + } + } + if p.showprice { + canvas.Text(p.x, by, fmt.Sprintf("%.2f", d.Price), "font-weight:bold") + } + if p.showdate { + canvas.Text(p.x, bottom+20, d.Date) + } + canvas.Gend() + p.x += interval + } + canvas.Gend() +} + +var param Parameters + +// set parameters according to command flags +func init() { + flag.BoolVar(¶m.showline, "line", true, "show lines") + flag.BoolVar(¶m.showimage, "image", true, "show images") + flag.BoolVar(¶m.showproduct, "product", true, "show products") + flag.BoolVar(¶m.showprice, "price", true, "show prices") + flag.BoolVar(¶m.showdate, "date", true, "show dates") + flag.BoolVar(¶m.showgrid, "grid", true, "show grid") + flag.IntVar(¶m.width, "w", 1600, "overall width") + flag.IntVar(¶m.height, "h", 900, "overall height") + flag.IntVar(¶m.x, "left", 150, "left") + flag.IntVar(¶m.y, "top", 120, "top") + flag.IntVar(¶m.w, "gw", 1400, "graph width") + flag.IntVar(¶m.h, "gh", 700, "graph height") + flag.IntVar(¶m.dot, "dot", 0, "dotsize") + flag.IntVar(¶m.fontsize, "fs", 14, "font size (px)") + flag.IntVar(¶m.spacing, "spacing", 15, "bar spacing") + flag.Float64Var(¶m.maxvalue, "max", 400, "max value") + flag.Float64Var(¶m.minvalue, "min", 0, "max value") + flag.Float64Var(¶m.ginterval, "ginterval", 50, "max value") + flag.Float64Var(¶m.opacity, "opacity", 0.5, "bar opacity") + flag.Float64Var(¶m.rotatetext, "rt", 0, "rotate text") + flag.StringVar(¶m.barcolor, "color", "lightgray", "bar color") + flag.Parse() +} + +func main() { + width := 1600 + height := 900 + canvas := svg.New(os.Stdout) + canvas.Start(param.width, param.height) + canvas.Rect(0, 0, width, height, canvas.RGB(255, 255, 255)) + canvas.Gstyle(fmt.Sprintf("font-family:Calibri;font-size:%dpx", param.fontsize)) + if len(flag.Args()) == 0 { + param.barchart("", canvas) + } else { + for _, f := range flag.Args() { + param.barchart(f, canvas) + } + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/svg.go b/vendor/github.com/ajstarks/svgo/svg.go new file mode 100644 index 0000000..b3b7661 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svg.go @@ -0,0 +1,978 @@ +// Package svg provides an API for generating Scalable Vector Graphics (SVG) +package svg + +// package main +// +// import ( +// "github.com/ajstarks/svgo" +// "os" +// ) +// +// var ( +// width = 500 +// height = 500 +// canvas = svg.New(os.Stdout) +// ) +// +// func main() { +// canvas.Start(width, height) +// canvas.Circle(width/2, height/2, 100) +// canvas.Text(width/2, height/2, "Hello, SVG", +// "text-anchor:middle;font-size:30px;fill:white") +// canvas.End() +// } +// + +import ( + "fmt" + "io" + + "encoding/xml" + "strings" +) + +// SVG defines the location of the generated SVG +type SVG struct { + Writer io.Writer +} + +// Offcolor defines the offset and color for gradients +type Offcolor struct { + Offset uint8 + Color string + Opacity float64 +} + +// Filterspec defines the specification of SVG filters +type Filterspec struct { + In, In2, Result string +} + +const ( + svgtop = ` + +` + vbfmt = `viewBox="%d %d %d %d"` + + emptyclose = "/>\n" +) + +// New is the SVG constructor, specifying the io.Writer where the generated SVG is written. +func New(w io.Writer) *SVG { return &SVG{w} } + +func (svg *SVG) print(a ...interface{}) (n int, errno error) { + return fmt.Fprint(svg.Writer, a...) +} + +func (svg *SVG) println(a ...interface{}) (n int, error error) { + return fmt.Fprintln(svg.Writer, a...) +} + +func (svg *SVG) printf(format string, a ...interface{}) (n int, errno error) { + return fmt.Fprintf(svg.Writer, format, a...) +} + +func (svg *SVG) genattr(ns []string) { + for _, v := range ns { + svg.printf("\n %s", v) + } + svg.println(svgns) +} + +// Structure, Metadata, Scripting, Transformation, and Links + +// Start begins the SVG document with the width w and height h. +// Other attributes may be optionally added, for example viewbox or additional namespaces +// Standard Reference: http://www.w3.org/TR/SVG11/struct.html#SVGElement +func (svg *SVG) Start(w int, h int, ns ...string) { + svg.printf(svginitfmt, svgtop, w, "", h, "") + svg.genattr(ns) +} + +// Startunit begins the SVG document, with width and height in the specified units +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) Startunit(w int, h int, unit string, ns ...string) { + svg.printf(svginitfmt, svgtop, w, unit, h, unit) + svg.genattr(ns) +} + +// Startpercent begins the SVG document, with width and height as percentages +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) Startpercent(w int, h int, ns ...string) { + svg.printf(svginitfmt, svgtop, w, "%", h, "%") + svg.genattr(ns) +} + +// Startview begins the SVG document, with the specified width, height, and viewbox +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) Startview(w, h, minx, miny, vw, vh int) { + svg.Start(w, h, fmt.Sprintf(vbfmt, minx, miny, vw, vh)) +} + +func (svg *SVG) StartviewUnit(w, h int, unit string, minx, miny, vw, vh int) { + svg.Startunit(w, h, unit, fmt.Sprintf(vbfmt, minx, miny, vw, vh)) +} + +// Startraw begins the SVG document, passing arbitrary attributes +func (svg *SVG) Startraw(ns ...string) { + svg.printf(svgtop) + svg.genattr(ns) +} + +// End the SVG document +func (svg *SVG) End() { svg.println("") } + +// Script defines a script with a specified type, (for example "application/javascript"). +// if the first variadic argument is a link, use only the link reference. +// Otherwise, treat those arguments as the text of the script (marked up as CDATA). +// if no data is specified, just close the script element +func (svg *SVG) Script(scriptype string, data ...string) { + svg.printf(`\n") + + default: + svg.println(`/>`) + } +} + +// Gstyle begins a group, with the specified style. +// Standard Reference: http://www.w3.org/TR/SVG11/struct.html#GElement +func (svg *SVG) Gstyle(s string) { svg.println(group("style", s)) } + +// Gtransform begins a group, with the specified transform +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) Gtransform(s string) { svg.println(group("transform", s)) } + +// Translate begins coordinate translation, end with Gend() +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) Translate(x, y int) { svg.Gtransform(translate(x, y)) } + +// Scale scales the coordinate system by n, end with Gend() +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) Scale(n float64) { svg.Gtransform(scale(n)) } + +// ScaleXY scales the coordinate system by dx and dy, end with Gend() +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) ScaleXY(dx, dy float64) { svg.Gtransform(scaleXY(dx, dy)) } + +// SkewX skews the x coordinate system by angle a, end with Gend() +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) SkewX(a float64) { svg.Gtransform(skewX(a)) } + +// SkewY skews the y coordinate system by angle a, end with Gend() +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) SkewY(a float64) { svg.Gtransform(skewY(a)) } + +// SkewXY skews x and y coordinates by ax, ay respectively, end with Gend() +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) SkewXY(ax, ay float64) { svg.Gtransform(skewX(ax) + " " + skewY(ay)) } + +// Rotate rotates the coordinate system by r degrees, end with Gend() +// Standard Reference: http://www.w3.org/TR/SVG11/coords.html#TransformAttribute +func (svg *SVG) Rotate(r float64) { svg.Gtransform(rotate(r)) } + +// TranslateRotate translates the coordinate system to (x,y), then rotates to r degrees, end with Gend() +func (svg *SVG) TranslateRotate(x, y int, r float64) { + svg.Gtransform(translate(x, y) + " " + rotate(r)) +} + +// RotateTranslate rotates the coordinate system r degrees, then translates to (x,y), end with Gend() +func (svg *SVG) RotateTranslate(x, y int, r float64) { + svg.Gtransform(rotate(r) + " " + translate(x, y)) +} + +// Group begins a group with arbitrary attributes +func (svg *SVG) Group(s ...string) { svg.printf("`)) } + +// Gid begins a group, with the specified id +func (svg *SVG) Gid(s string) { + svg.print(``) +} + +// Gend ends a group (must be paired with Gsttyle, Gtransform, Gid). +func (svg *SVG) Gend() { svg.println(``) } + +// ClipPath defines a clip path +func (svg *SVG) ClipPath(s ...string) { svg.printf(``)) } + +// ClipEnd ends a ClipPath +func (svg *SVG) ClipEnd() { + svg.println(``) +} + +// Def begins a defintion block. +// Standard Reference: http://www.w3.org/TR/SVG11/struct.html#DefsElement +func (svg *SVG) Def() { svg.println(``) } + +// DefEnd ends a defintion block. +func (svg *SVG) DefEnd() { svg.println(``) } + +// Marker defines a marker +// Standard reference: http://www.w3.org/TR/SVG11/painting.html#MarkerElement +func (svg *SVG) Marker(id string, x, y, width, height int, s ...string) { + svg.printf(`\n")) +} + +// MarkEnd ends a marker +func (svg *SVG) MarkerEnd() { svg.println(``) } + +// Pattern defines a pattern with the specified dimensions. +// The putype can be either "user" or "obj", which sets the patternUnits +// attribute to be either userSpaceOnUse or objectBoundingBox +// Standard reference: http://www.w3.org/TR/SVG11/pservers.html#Patterns +func (svg *SVG) Pattern(id string, x, y, width, height int, putype string, s ...string) { + puattr := "userSpaceOnUse" + if putype != "user" { + puattr = "objectBoundingBox" + } + svg.printf(`\n")) +} + +// PatternEnd ends a marker +func (svg *SVG) PatternEnd() { svg.println(``) } + +// Desc specified the text of the description tag. +// Standard Reference: http://www.w3.org/TR/SVG11/struct.html#DescElement +func (svg *SVG) Desc(s string) { svg.tt("desc", s) } + +// Title specified the text of the title tag. +// Standard Reference: http://www.w3.org/TR/SVG11/struct.html#TitleElement +func (svg *SVG) Title(s string) { svg.tt("title", s) } + +// Link begins a link named "name", with the specified title. +// Standard Reference: http://www.w3.org/TR/SVG11/linking.html#Links +func (svg *SVG) Link(href string, title string) { + svg.printf("") +} + +// LinkEnd ends a link. +func (svg *SVG) LinkEnd() { svg.println(``) } + +// Use places the object referenced at link at the location x, y, with optional style. +// Standard Reference: http://www.w3.org/TR/SVG11/struct.html#UseElement +func (svg *SVG) Use(x int, y int, link string, s ...string) { + svg.printf(``)) +} + +// MaskEnd ends a Mask. +func (svg *SVG) MaskEnd() { svg.println(``) } + +// Shapes + +// Circle centered at x,y, with radius r, with optional style. +// Standard Reference: http://www.w3.org/TR/SVG11/shapes.html#CircleElement +func (svg *SVG) Circle(x int, y int, r int, s ...string) { + svg.printf(`")) + xml.Escape(svg.Writer, []byte(t)) + svg.println(``) +} + +// Textpath places text optionally styled text along a previously defined path +// Standard Reference: http://www.w3.org/TR/SVG11/text.html#TextPathElement +func (svg *SVG) Textpath(t string, pathid string, s ...string) { + svg.printf("", endstyle(s, ">"), pathid) + xml.Escape(svg.Writer, []byte(t)) + svg.println(``) +} + +// Textlines places a series of lines of text starting at x,y, at the specified size, fill, and alignment. +// Each line is spaced according to the spacing argument +func (svg *SVG) Textlines(x, y int, s []string, size, spacing int, fill, align string) { + svg.Gstyle(fmt.Sprintf("font-size:%dpx;fill:%s;text-anchor:%s", size, fill, align)) + for _, t := range s { + svg.Text(x, y, t) + y += spacing + } + svg.Gend() +} + +// Colors + +// RGB specifies a fill color in terms of a (r)ed, (g)reen, (b)lue triple. +// Standard reference: http://www.w3.org/TR/css3-color/ +func (svg *SVG) RGB(r int, g int, b int) string { + return fmt.Sprintf(`fill:rgb(%d,%d,%d)`, r, g, b) +} + +// RGBA specifies a fill color in terms of a (r)ed, (g)reen, (b)lue triple and opacity. +func (svg *SVG) RGBA(r int, g int, b int, a float64) string { + return fmt.Sprintf(`fill-opacity:%.2f; %s`, a, svg.RGB(r, g, b)) +} + +// Gradients + +// LinearGradient 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. +func (svg *SVG) LinearGradient(id string, x1, y1, x2, y2 uint8, sc []Offcolor) { + svg.printf("\n", + id, pct(x1), pct(y1), pct(x2), pct(y2)) + svg.stopcolor(sc) + svg.println("") +} + +// RadialGradient 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. +func (svg *SVG) RadialGradient(id string, cx, cy, r, fx, fy uint8, sc []Offcolor) { + svg.printf("\n", + id, pct(cx), pct(cy), pct(r), pct(fx), pct(fy)) + svg.stopcolor(sc) + svg.println("") +} + +// stopcolor is a utility function used by the gradient functions +// to define a sequence of offsets (expressed as percentages) and colors +func (svg *SVG) stopcolor(oc []Offcolor) { + for _, v := range oc { + svg.printf("\n", + pct(v.Offset), v.Color, v.Opacity) + } +} + +// Filter Effects: +// Most functions have common attributes (in, in2, result) defined in type Filterspec +// used as a common first argument. + +// Filter begins a filter set +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#FilterElement +func (svg *SVG) Filter(id string, s ...string) { + svg.printf(`\n")) +} + +// Fend ends a filter set +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#FilterElement +func (svg *SVG) Fend() { + svg.println(``) +} + +// FeBlend specifies a Blend filter primitive +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feBlendElement +func (svg *SVG) FeBlend(fs Filterspec, mode string, s ...string) { + switch mode { + case "normal", "multiply", "screen", "darken", "lighten": + break + default: + mode = "normal" + } + svg.printf(` 360 { + value = 0 + } + svg.printf(` 1 { + value = 1 + } + svg.printf(``) +} + +// FeCompEnd ends a feComponent filter element +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement +func (svg *SVG) FeCompEnd() { + svg.println(``) +} + +// FeComposite specifies a feComposite filter primitive +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feCompositeElement +func (svg *SVG) FeComposite(fs Filterspec, operator string, k1, k2, k3, k4 int, s ...string) { + switch operator { + case "over", "in", "out", "atop", "xor", "arithmetic": + break + default: + operator = "over" + } + svg.printf(``)) +} + +// FeDiffEnd ends a diffuse lighting filter primitive container +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement +func (svg *SVG) FeDiffEnd() { + svg.println(``) +} + +// FeDisplacementMap specifies a feDisplacementMap filter primitive +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feDisplacementMapElement +func (svg *SVG) FeDisplacementMap(fs Filterspec, scale float64, xchannel, ychannel string, s ...string) { + svg.printf(``) + for _, n := range nodes { + svg.printf("\n", n) + } + svg.println(``) +} + +// FeMorphology specifies a feMorphologyLight filter primitive +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feMorphologyElement +func (svg *SVG) FeMorphology(fs Filterspec, operator string, xradius, yradius float64, s ...string) { + switch operator { + case "erode", "dilate": + break + default: + operator = "erode" + } + svg.printf(`\n")) +} + +// FeSpecEnd ends a specular lighting filter primitive container +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feSpecularLightingElement +func (svg *SVG) FeSpecEnd() { + svg.println(``) +} + +// FeSpotLight specifies a feSpotLight filter primitive +// Standard reference: http://www.w3.org/TR/SVG11/filters.html#feSpotLightElement +func (svg *SVG) FeSpotLight(fs Filterspec, x, y, z, px, py, pz float64, s ...string) { + svg.printf(` 1 { + bfx = 0 + } + if bfy < 0 || bfy > 1 { + bfy = 0 + } + switch ftype[0:1] { + case "f", "F": + ftype = "fractalNoise" + case "t", "T": + ftype = "turbulence" + default: + ftype = "turbulence" + } + + var ss string + if stitch { + ss = "stitch" + } else { + ss = "noStitch" + } + svg.printf(` 0 { + svg.Gstyle(s[0]) + } + for ix := x; ix <= x+w; ix += n { + svg.Line(ix, y, ix, y+h) + } + + for iy := y; iy <= y+h; iy += n { + svg.Line(x, iy, x+w, iy) + } + if len(s) > 0 { + svg.Gend() + } + +} + +// Support functions + +// style returns a style name,attribute string +func style(s string) string { + if len(s) > 0 { + return fmt.Sprintf(`style="%s"`, s) + } + return s +} + +// pp returns a series of polygon points +func (svg *SVG) pp(x []int, y []int, tag string) { + svg.print(tag) + if len(x) != len(y) { + svg.print(" ") + return + } + lx := len(x) - 1 + for i := 0; i < lx; i++ { + svg.print(coord(x[i], y[i]) + " ") + } + svg.print(coord(x[lx], y[lx])) +} + +// endstyle modifies an SVG object, with either a series of name="value" pairs, +// or a single string containing a style +func endstyle(s []string, endtag string) string { + if len(s) > 0 { + nv := "" + for i := 0; i < len(s); i++ { + if strings.Index(s[i], "=") > 0 { + nv += (s[i]) + " " + } else { + nv += style(s[i]) + } + } + return nv + endtag + } + return endtag + +} + +// tt creates a xml element, tag containing s +func (svg *SVG) tt(tag string, s string) { + svg.print("<" + tag + ">") + xml.Escape(svg.Writer, []byte(s)) + svg.println("") +} + +// poly compiles the polygon element +func (svg *SVG) poly(x []int, y []int, tag string, s ...string) { + svg.pp(x, y, "<"+tag+" points=\"") + svg.print(`" ` + endstyle(s, "/>\n")) +} + +// onezero returns "0" or "1" +func onezero(flag bool) string { + if flag { + return "1" + } + return "0" +} + +// pct returns a percetage, capped at 100 +func pct(n uint8) uint8 { + if n > 100 { + return 100 + } + return n +} + +// islink determines if a string is a script reference +func islink(link string) bool { + return strings.HasPrefix(link, "http://") || strings.HasPrefix(link, "#") || + strings.HasPrefix(link, "../") || strings.HasPrefix(link, "./") +} + +// group returns a group element +func group(tag string, value string) string { return fmt.Sprintf(``, tag, value) } + +// scale return the scale string for the transform +func scale(n float64) string { return fmt.Sprintf(`scale(%g)`, n) } + +// scaleXY return the scale string for the transform +func scaleXY(dx, dy float64) string { return fmt.Sprintf(`scale(%g,%g)`, dx, dy) } + +// skewx returns the skewX string for the transform +func skewX(angle float64) string { return fmt.Sprintf(`skewX(%g)`, angle) } + +// skewx returns the skewX string for the transform +func skewY(angle float64) string { return fmt.Sprintf(`skewY(%g)`, angle) } + +// rotate returns the rotate string for the transform +func rotate(r float64) string { return fmt.Sprintf(`rotate(%g)`, r) } + +// translate returns the translate string for the transform +func translate(x, y int) string { return fmt.Sprintf(`translate(%d,%d)`, x, y) } + +// coord returns a coordinate string +func coord(x int, y int) string { return fmt.Sprintf(`%d,%d`, x, y) } + +// ptag returns the beginning of the path element +func ptag(x int, y int) string { return fmt.Sprintf(` 0 { + attrs += fmt.Sprintf(`in="%s" `, s.In) + } + if len(s.In2) > 0 { + attrs += fmt.Sprintf(`in2="%s" `, s.In2) + } + if len(s.Result) > 0 { + attrs += fmt.Sprintf(`result="%s" `, s.Result) + } + return attrs +} + +// tablevalues outputs a series of values as a XML attribute +func (svg *SVG) tablevalues(s string, t []float64) { + svg.printf(` %s="`, s) + for i := 0; i < len(t)-1; i++ { + svg.printf("%g ", t[i]) + } + svg.printf(`%g"%s`, t[len(t)-1], emptyclose) +} + +// imgchannel validates the image channel indicator +func imgchannel(c string) string { + switch c { + case "R", "G", "B", "A": + return c + case "r", "g", "b", "a": + return strings.ToUpper(c) + case "red", "green", "blue", "alpha": + return strings.ToUpper(c[0:1]) + case "Red", "Green", "Blue", "Alpha": + return c[0:1] + } + return "R" +} diff --git a/vendor/github.com/ajstarks/svgo/svgdef.pdf b/vendor/github.com/ajstarks/svgo/svgdef.pdf new file mode 100644 index 0000000..cc8ff60 Binary files /dev/null and b/vendor/github.com/ajstarks/svgo/svgdef.pdf differ diff --git a/vendor/github.com/ajstarks/svgo/svgdef.svg b/vendor/github.com/ajstarks/svgo/svgdef.svg new file mode 100644 index 0000000..46c80c2 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgdef.svg @@ -0,0 +1,395 @@ + + + +Object Definitions + + + + + + + + + + + + + + + + +x, y + +w +Square(x, y, w int, style ...string) + + + +x, y + +h +w +Rect(x, y, w, h int, style ...string) + + + +x, y + +h +w +CenterRect(x, y, w, h int, style ...string) + + + +x, y + +h +w + + +ry +rx +Roundrect(x, y, w, h, rx, ry int, style ...string) + + + +x, y + +x, y + +x, y + +x, y + +x, y + +x, y + +Polygon(x, y []int, style ...string) + + + + +x, y + + +r +Circle(x, y, r int, style ...string) + + + + + +x, y + + + +rx +ry +Ellipse(x, y, rx, ry int, style ...string) + + + + +x1, y1 + +x2, y2 + +Line(x1, y1, x2, y2 int, style ...string) + + + +x, y + +x, y + +x, y + +x, y + +Polyline(x, y []int, style ...string) + + + +sx, sy + +ex, ey + +Arc(sx, sy, ax, ay, r int, lflag, sflag bool, ex, ey int, style ...string) + + + + + +x, y +Path(s string, style ...string) + + + +sx, sy + +cx, cy + +ex, ey + +Qbez(sx, sy, cx, cy, ex, ey int, style ...string) + + + +sx, sy + +cx, cy + +px, py + +ex, ey + +Bezier(sx, sy, cx, cy, px, py, ex, ey int, style ...string) + + + +x, y + +h +w + +Image(x, y, w, h, int path string, style ...string) + + + + +x1%, y1% + +x2%, y2% +LinearGradient(s string, x1, y1, x2, y2 uint8, oc []Offcolor) + + + + +cx%, cy% + +fx%, fy% +RadialGradient(s string, cx, cy, r, fx, fy uint8, oc []Offcolor) + + + +0, 0 + +x, y +Translate(x, y int) + + + + + + + +x, y +h +w +n + + + + + + + + + + + + + + + + +Grid(x, y, w, h, n int, style ...string) + + + +x, y +hello, this is SVG +Text(x, y int, s string, style ...string) + + + +0, 0 + + + + +Scale(n float64) + + + +0, 0 + + + + +ScaleXY(x, y float64) + + + +0, 0 + + + + +SkewX(a float64) + + + +0, 0 + + + + +SkewY(a float64) + + + +0, 0 + + + + +SkewXY(x, y float64) + + + +0, 0 +Rotate(r float64) + + +r + + + + + +It's "fine" & "dandy" to draw text along a path +Textpath(s, pathid string, style ...string) + + + +New(w io Writer) +Start(w, h int, options ...string)/End() +Startview(w, h, minx, miny, vw, vh int) +Group(s ...string)/Gend() +Gstyle(s string)/Gend() +Gtransform(s string)/Gend() +Gid(id string)/Gend() +ClipPath(s ...string)/ClipEnd() +Def()/DefEnd() +Marker()/MarkerEnd() +Pattern()/PatternEnd() +Desc(s string) +Title(s string) +Script(type, data ...string) +Mask(id string, x,y,w,h int, style ...string)/MaskEnd() +Link(href string, title string)/LinkEnd() +Use(x int, y int, link string, style ...string) + + +specify destination +begin/end the document +begin/end the document with viewport +begin/end group with attributes +begin/end group style +begin/end group transform +begin/end group id +begin/end clip path +begin/end a defintion block +begin/end markers +begin/end pattern +set the description element +set the title element +define a script +begin/end mask element +begin/end link to href, with a title +use defined objects + +Textlines(x, y int, s []string, size, spacing int, fill, align string) + + + + + + + +r +g +b +-> + +RGB(r, g, b int) + + + + + + + + +alpha +r +g +b +-> + +RGBA(r, g, b int, opacity float64) + + +SVG Go Library Description + + + +SVG Go Library +github.com/ajstarks/svgo + +Object Usage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vendor/github.com/ajstarks/svgo/svgdef/svgdef.go b/vendor/github.com/ajstarks/svgo/svgdef/svgdef.go new file mode 100644 index 0000000..6daba5f --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgdef/svgdef.go @@ -0,0 +1,536 @@ +// svgdef - SVG Object Definition and Use +// +build !appengine + +package main + +import ( + "math" + "os" + + "github.com/ajstarks/svgo" +) + +const ( + textsize = 24 + coordsize = 4 + objcolor = "rgb(0,0,127)" + objstyle = "fill:none; stroke-width:2;stroke:" + objcolor + fobjstyle = "fill-opacity:0.25;fill:" + objcolor + legendstyle = "fill:gray; text-anchor:middle" + titlestyle = "fill:black; text-anchor:middle;font-size:24px" + linestyle = "stroke:black; stroke-width:1" + gtextstyle = "font-family:Calibri,sans; text-anchor:middle; font-size:24px" + coordstring = "x, y" + tpathstring = `It's "fine" & "dandy" to draw text along a path` +) + +var ( + canvas = svg.New(os.Stdout) + grayfill = canvas.RGB(220, 220, 220) + oc1 = svg.Offcolor{Offset: 0, Color: "white", Opacity: 1.0} + oc2 = svg.Offcolor{Offset: 25, Color: "lightblue", Opacity: 1.0} + oc3 = svg.Offcolor{Offset: 75, Color: "blue", Opacity: 1.0} + oc4 = svg.Offcolor{Offset: 100, Color: objcolor, Opacity: 1.0} + ga = []svg.Offcolor{oc1, oc2, oc3, oc4} +) + +// defcoodstr defines coordinate strings: (x,y) +func defcoordstr(x int, y int, s string) { + canvas.Circle(x, y, coordsize, grayfill) + canvas.Text(x, y-textsize, s, legendstyle) +} + +// defcoord defines a coordinate +func defcoord(x, y, n int) { + canvas.Circle(x, y, coordsize, grayfill) + canvas.Text(x, y+n, coordstring, legendstyle) +} + +// deflegend makes object legends +func deflegend(x int, y int, size int, legend string) { + canvas.Text(x, y+size+textsize, legend, titlestyle) +} + +// defcircle defines the circle object for arbitrary placement and size +func defcircle(id string, w, h int, legend string) { + canvas.Gid(id) + canvas.Translate(w, h) + defcoord(0, 0, -textsize) + canvas.Circle(0, 0, h, objstyle) + canvas.Line(0, 0, h, 0, linestyle) + canvas.Text(h/2, textsize, "r", legendstyle) + deflegend(0, 0, h, legend) + canvas.Gend() + canvas.Gend() +} + +// defellipse defines the ellipse object for arbitrary placement and size +func defellipse(id string, w int, h int, legend string) { + canvas.Gid(id) + canvas.Translate(w, h) + defcoord(0, 0, -textsize) + canvas.Ellipse(0, 0, w, h, objstyle) + canvas.Line(0, 0, w, 0, linestyle) + canvas.Line(0, 0, 0, h, linestyle) + canvas.Text(w/2, textsize, "rx", legendstyle) + canvas.Text(-textsize, (h / 2), "ry", legendstyle) + deflegend(0, 0, h, legend) + canvas.Gend() + canvas.Gend() +} + +// defrect defines the rectangle object for arbitrary placement and size +func defrect(id string, w int, h int, legend string) { + canvas.Gid(id) + defcoord(0, 0, -textsize) + canvas.Rect(0, 0, w, h, objstyle) + canvas.Text(-textsize, (h / 2), "h", legendstyle) + canvas.Text((w / 2), -textsize, "w", legendstyle) + deflegend((w / 2), 0, h, legend) + canvas.Gend() +} + +// defcrect defines the centered rectangle object for arbitrary placement and size +func defcrect(id string, w int, h int, legend string) { + canvas.Gid(id) + defcoord(w/2, h/2, -textsize) + canvas.Rect(0, 0, w, h, objstyle) + canvas.Text(-textsize, (h / 2), "h", legendstyle) + canvas.Text((w / 2), -textsize, "w", legendstyle) + deflegend((w / 2), 0, h, legend) + canvas.Gend() +} + +// defsquare defines the square object for arbitrary placement and size +func defsquare(id string, w int, legend string) { + canvas.Gid(id) + defcoord(0, 0, -textsize) + canvas.Square(0, 0, w, objstyle) + canvas.Text((w / 2), -textsize, "w", legendstyle) + deflegend((w / 2), 0, w, legend) + canvas.Gend() +} + +// defimage defines the image object for arbitrary placement and size +func defimage(id string, w int, h int, s string, legend string) { + canvas.Gid(id) + defcoord(0, 0, -textsize) + canvas.Rect(0, 0, w, h, objstyle) + canvas.Text(-textsize, (h / 2), "h", legendstyle) + canvas.Text((w / 2), -textsize, "w", legendstyle) + canvas.Image(0, 0, w, h, s) + deflegend(w/2, h, 0, legend) + canvas.Gend() +} + +// defline defines the line object for arbitrary placement and size +func defline(id string, w int, h int, legend string) { + canvas.Gid(id) + defcoordstr(0, 0, "x1, y1") + defcoordstr(w, 0, "x2, y2") + canvas.Line(0, 0, w, 0, objstyle) + deflegend(w/2, h, 0, legend) + canvas.Gend() +} + +// defarc defines the arc object for arbitrary placement and size +func defarc(id string, w int, h int, legend string) { + canvas.Gid(id) + defcoordstr(0, 0, "sx, sy") + defcoordstr(w*2, 0, "ex, ey") + canvas.Arc(0, 0, h, h, 0, false, true, w*2, 0, objstyle) + deflegend(w, h, h, legend) + canvas.Gend() +} + +// defbez defines the cublic bezier object for arbitrary placement and size +func defbez(id string, x int, y int, h int, legend string) { + sx, sy := 0, 0 + cx, cy := x, -y + px, py := x, y + ex, ey := x*2, 0 + canvas.Gid(id) + defcoordstr(sx, sy, "sx, sy") + defcoordstr(cx, cy, "cx, cy") + defcoordstr(px, py, "px, py") + defcoordstr(ex, ey, "ex, ey") + canvas.Bezier(sx, sy, cx, cy, px, py, ex, ey, objstyle) + deflegend(px, h, 0, legend) + canvas.Gend() +} + +// defqbez defines the quadratic bezier object for arbitrary placement and size +func defqbez(id string, px int, py int, h int, legend string) { + sx, sy := 0, 0 + ex, ey := px*2, 0 + cx, cy := (ex-px)/3, -py-(py/2) + canvas.Gid(id) + defcoordstr(sx, sy, "sx, sy") + defcoordstr(cx, cy, "cx, cy") + defcoordstr(ex, ey, "ex, ey") + canvas.Qbez(sx, sy, cx, cy, ex, ey, objstyle) + deflegend(px, h, 0, legend) + canvas.Gend() +} + +// defroundrect defines the roundrect object for arbitrary placement and size +func defroundrect(id string, w int, h int, rx int, ry int, legend string) { + canvas.Gid(id) + defcoord(0, 0, -textsize) + canvas.Roundrect(0, 0, w, h, rx, ry, objstyle) + canvas.Text(-textsize, (h / 2), "h", legendstyle) + canvas.Text((w / 2), -textsize, "w", legendstyle) + canvas.Line(rx, 0, rx, ry, linestyle) + canvas.Line(0, ry, rx, ry, linestyle) + canvas.Text(rx+textsize, ry-(ry/2), "ry", legendstyle) + canvas.Text((rx / 2), ry+textsize, "rx", legendstyle) + deflegend((w / 2), 0, h, legend) + canvas.Gend() +} + +// defpolygon defines the polygon object for arbitrary placement and size +func defpolygon(id string, w int, h int, legend string) { + var x = []int{0, w / 2, w, w, w / 2, 0} + var y = []int{0, -h / 4, 0, (h * 3) / 4, h / 2, (h * 3) / 4} + canvas.Gid(id) + for i := 0; i < len(x); i++ { + defcoord(x[i], y[i], -textsize) + } + canvas.Polygon(x, y, objstyle) + deflegend(w/2, h, 0, legend) + canvas.Gend() +} + +// defpolyline defines the polyline object for arbitrary placement and size +func defpolyline(id string, w int, h int, legend string) { + var x = []int{0, w / 3, (w * 3) / 4, w} + var y = []int{0, -(h / 2), -(h / 3), -h} + canvas.Gid(id) + for i := 0; i < len(x); i++ { + defcoord(x[i], y[i], -textsize) + } + canvas.Polyline(x, y, objstyle) + deflegend(w/2, h, 0, legend) + canvas.Gend() +} + +// defpath defines the path object for arbitrary placement and size +func defpath(id string, x, y int, legend string) { + var w3path = `M36,5l12,41l12-41h33v4l-13,21c30,10,2,69-21,28l7-2c15,27,33,-22,3,-19v-4l12-20h-15l-17,59h-1l-13-42l-12,42h-1l-20-67h9l12,41l8-28l-4-13h9` + var cpath = `M94,53c15,32,30,14,35,7l-1-7c-16,26-32,3-34,0M122,16c-10-21-34,0-21,30c-5-30 16,-38 23,-21l5-10l-2-9` + canvas.Gid(id) + canvas.Path(w3path, `fill="`+objcolor+`"`) + canvas.Path(cpath, canvas.RGBA(0, 0, 0, 0.5)) + defcoord(0, 0, -textsize) + deflegend(x/2, y+50, textsize, legend) + canvas.Gend() +} + +// deflg defines the linear gradient object for arbitrary placement and size +func deflg(id string, w int, h int, legend string) { + canvas.Gid(id) + canvas.Rect(0, 0, w, h, "fill:url(#linear)") + defcoordstr(0, 0, "x1%, y1%") + defcoordstr(w, 0, "x2%, y2%") + deflegend((w / 2), 0, h, legend) + canvas.Gend() +} + +// defrg defines the radial gradient object for arbitrary placement and size +func defrg(id string, w int, h int, legend string) { + canvas.Gid(id) + canvas.Rect(0, 0, w, h, "fill:url(#radial)") + defcoordstr(0, 0, "cx%, cy%") + defcoordstr(w/2, h/2, "fx%, fy%") + deflegend((w / 2), 0, h, legend) + canvas.Gend() +} + +// deftrans defines the trans object for arbitrary placement and size +func deftrans(id string, w, h int, legend string) { + tx := w / 3 + canvas.Gid(id) + defcoordstr(0, 0, "0, 0") + defcoordstr(w-tx, 0, "x, y") + deflegend(w/2, 0, h, legend) + canvas.Rect(0, 0, tx, h, objstyle) + canvas.Translate(w-tx, 0) + canvas.Rect(0, 0, tx, h, fobjstyle) + canvas.Gend() + canvas.Gend() +} + +// defgrid defines the grid object for arbitrary placement and size +func defgrid(id string, w, h int, legend string) { + n := h / 4 + canvas.Gid(id) + defcoord(0, 0, -textsize) + canvas.Text(-textsize, (h / 2), "h", legendstyle) + canvas.Text((w / 2), -textsize, "w", legendstyle) + canvas.Text(n+textsize, n/2, "n", legendstyle) + canvas.Grid(0, 0, w, h, n, "stroke:"+objcolor) + deflegend((w / 2), 0, h, legend) + canvas.Gend() +} + +// deftext defines the text object for arbitrary placement and size +func deftext(id string, w, h int, text string, legend string) { + canvas.Gid(id) + defcoord(0, h/2, textsize) + canvas.Text(0, h/2, text, "text-anchor:start;font-size:32pt") + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// deftextpath defines the textpath object for arbitrary placement and size +func deftextpath(id string, pathid string, s string, w, h int, legend string) { + canvas.Gid(id) + canvas.Textpath(s, pathid, `fill="`+objcolor+`"`, `text-anchor="start"`, `font-size="16pt"`) + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// defscale defines the scale object for arbitrary placement and size +func defscale(id string, w, h int, n float64, legend string) { + canvas.Gid(id) + defcoordstr(0, 0, "0, 0") + canvas.Rect(0, 0, w, h, objstyle) + canvas.Scale(n) + canvas.Rect(0, 0, w, h, fobjstyle) + canvas.Gend() + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// defscaleXY defines the scaleXY object for arbitrary placement and size +func defscaleXY(id string, w, h int, dx, dy float64, legend string) { + canvas.Gid(id) + defcoordstr(0, 0, "0, 0") + canvas.Rect(0, 0, w, h, objstyle) + canvas.ScaleXY(dx, dy) + canvas.Rect(0, 0, w, h, fobjstyle) + canvas.Gend() + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// defskewX defines the skewX object for arbitrary placement and size +func defskewX(id string, w, h int, angle float64, legend string) { + canvas.Gid(id) + defcoordstr(0, 0, "0, 0") + canvas.Rect(0, 0, w, h, objstyle) + canvas.SkewX(angle) + canvas.Rect(0, 0, w, h, fobjstyle) + canvas.Gend() + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// defskewY defines the skewY object for arbitrary placement and size +func defskewY(id string, w, h int, angle float64, legend string) { + canvas.Gid(id) + defcoordstr(0, 0, "0, 0") + canvas.Rect(0, 0, w, h, objstyle) + canvas.SkewY(angle) + canvas.Rect(0, 0, w, h, fobjstyle) + canvas.Gend() + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// defskewXY defines the skewXY object for arbitrary placement and size +func defskewXY(id string, w, h int, ax, ay float64, legend string) { + canvas.Gid(id) + defcoordstr(0, 0, "0, 0") + canvas.Rect(0, 0, w, h, objstyle) + canvas.SkewXY(ax, ay) + canvas.Rect(0, 0, w, h, fobjstyle) + canvas.Gend() + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// defrotate defines the rotate object for arbitrary placement and size +func defrotate(id string, w, h int, deg float64, legend string) { + t := deg * (math.Pi / 180.0) + r := float64(w / 2) + rx := r * math.Cos(t) + ry := r * math.Sin(t) + canvas.Gid(id) + defcoordstr(0, 0, "0, 0") + deflegend(w/2, 0, h, legend) + canvas.Rect(0, 0, w, h, objstyle) + canvas.Qbez(w/2, 0, (w/2)+10, int(ry)/2, int(rx), int(ry), "fill:none;stroke:gray") + canvas.Text(w/4, textsize, "r", legendstyle) + canvas.Rotate(deg) + canvas.Rect(0, 0, w, h, fobjstyle) + canvas.Gend() + canvas.Gend() +} + +// defmeta defines the metadata objects +func defmeta(id string, w int, name, desc []string, legend string) { + canvas.Gid(id) + canvas.Textlines(0, textsize, name, 24, 28, "black", "start") + canvas.Textlines(w+150, textsize, desc, 24, 28, "rgb(127,127,127)", "start") + deflegend(w, 0, 30*len(name), legend) + canvas.Gend() +} + +// defrgb defines the rgb object for arbitrary placement and size +func defrgb(id string, w, h, r, g, b int, opacity float64, legend string) { + size := h / 8 + canvas.Gid(id) + canvas.Gstyle(legendstyle) + colordot(w/4, 0, size, r, 0, 0, 1.0) + colordot(w/2, 0, size, 0, g, 0, 1.0) + colordot(w*3/4, 0, size, 0, 0, b, 1.0) + colordot(w, 0, size, r, g, b, opacity) + if opacity < 1.0 { + colordot(w+10, 0, size, r, g, b, opacity) + canvas.Text(w, h/2, "alpha") + } + canvas.Text(w/4, h/2, "r") + canvas.Text(w/2, h/2, "g") + canvas.Text(w*3/4, h/2, "b") + canvas.Text(w-(w/8), size-size/2, "->") + canvas.Gend() + deflegend(w/2, 0, h, legend) + canvas.Gend() +} + +// defobjects defines a set of objects with the specified dimensions, +// once defined, the objects are referenced for placement +func defobjects(w, h int) { + var ( + metatext = []string{ + "New(w io Writer)", + "Start(w, h int, options ...string)/End()", + "Startview(w, h, minx, miny, vw, vh int)", + "Group(s ...string)/Gend()", + "Gstyle(s string)/Gend()", + "Gtransform(s string)/Gend()", + "Gid(id string)/Gend()", + "ClipPath(s ...string)/ClipEnd()", + "Def()/DefEnd()", + "Marker()/MarkerEnd()", + "Pattern()/PatternEnd()", + "Desc(s string)", + "Title(s string)", + "Script(type, data ...string)", + "Mask(id string, x,y,w,h int, style ...string)/MaskEnd()", + "Link(href string, title string)/LinkEnd()", + "Use(x int, y int, link string, style ...string)", + } + metadesc = []string{ + "specify destination", + "begin/end the document", + "begin/end the document with viewport", + "begin/end group with attributes", + "begin/end group style", + "begin/end group transform", + "begin/end group id", + "begin/end clip path", + "begin/end a defintion block", + "begin/end markers", + "begin/end pattern", + "set the description element", + "set the title element", + "define a script", + "begin/end mask element", + "begin/end link to href, with a title", + "use defined objects", + } + ) + h2 := h / 2 + canvas.Desc("Object Definitions") + canvas.Def() + canvas.LinearGradient("linear", 0, 0, 100, 0, ga) + canvas.RadialGradient("radial", 0, 0, 100, 50, 50, ga) + canvas.Path("M 0,0 A62,62 0 0 1 250,0", `id="tpath"`) + defsquare("square", h, "Square(x, y, w int, style ...string)") + defrect("rect", w, h, "Rect(x, y, w, h int, style ...string)") + defcrect("crect", w, h, "CenterRect(x, y, w, h int, style ...string)") + defroundrect("roundrect", w, h, 25, 25, "Roundrect(x, y, w, h, rx, ry int, style ...string)") + defpolygon("polygon", w, h, "Polygon(x, y []int, style ...string)") + defcircle("circle", h, h2, "Circle(x, y, r int, style ...string)") + defellipse("ellipse", h, h2, "Ellipse(x, y, rx, ry int, style ...string)") + defline("line", w, h, "Line(x1, y1, x2, y2 int, style ...string)") + defpolyline("polyline", w, h, "Polyline(x, y []int, style ...string)") + defarc("arc", h, h2, "Arc(sx, sy, ax, ay, r int, lflag, sflag bool, ex, ey int, style ...string)") + defpath("path", h, h2, "Path(s string, style ...string)") + defqbez("qbez", h, h2, h, "Qbez(sx, sy, cx, cy, ex, ey int, style ...string)") + defbez("bezier", h, h2, h, "Bezier(sx, sy, cx, cy, px, py, ex, ey int, style ...string)") + defimage("image", 128, 128, "gophercolor128x128.png", "Image(x, y, w, h, int path string, style ...string)") + deflg("lgrad", w, h, "LinearGradient(s string, x1, y1, x2, y2 uint8, oc []Offcolor)") + defrg("rgrad", w, h, "RadialGradient(s string, cx, cy, r, fx, fy uint8, oc []Offcolor)") + deftrans("trans", w, h, "Translate(x, y int)") + defgrid("grid", w, h, "Grid(x, y, w, h, n int, style ...string)") + deftext("text", w, h, "hello, this is SVG", "Text(x, y int, s string, style ...string)") + defscale("scale", w, h, 0.5, "Scale(n float64)") + defscaleXY("scalexy", w, h, 0.5, 0.75, "ScaleXY(x, y float64)") + defskewX("skewx", w, h, 30, "SkewX(a float64)") + defskewY("skewy", w, h, 10, "SkewY(a float64)") + defskewXY("skewxy", w, h, 10, 10, "SkewXY(x, y float64)") + defrotate("rotate", w, h, 30, "Rotate(r float64)") + deftextpath("textpath", "#tpath", tpathstring, w, h, "Textpath(s, pathid string, style ...string)") + defmeta("meta", w*2, metatext, metadesc, "Textlines(x, y int, s []string, size, spacing int, fill, align string)") + defrgb("rgb", w, h, 44, 77, 232, 1.0, "RGB(r, g, b int)") + defrgb("rgba", w, h, 44, 77, 232, 0.33, "RGBA(r, g, b int, opacity float64)") + canvas.DefEnd() +} + +// colordot makes a colored dot, with opacity +func colordot(x, y, r, red, green, blue int, a float64) { + // canvas.Circle(x,y,r+textsize/6,"fill:none;stroke:"+objcolor) + if a == 1.0 { + canvas.Circle(x, y, r, canvas.RGB(red, green, blue)) + } else { + canvas.Circle(x, y, r, canvas.RGBA(red, green, blue, a)) + } +} + +// placerow is a helper for placeobjects, placing to previously +// defined objects row-wise +func placerow(w int, s []string) { + for x, name := range s { + canvas.Use(x*w, 0, "#"+name) + } +} + +// placeobjects places a grid of objects on the canvas as specified +// by a string array. +func placeobjects(x, y, w, h int, data [][]string) { + canvas.Desc("Object Usage") + for _, object := range data { + canvas.Translate(x, y) + placerow(w, object) + canvas.Gend() + y += h + } +} + +var roworder = [][]string{ + {"rect", "crect", "roundrect", "square", "line", "polyline"}, + {"polygon", "circle", "ellipse", "arc", "qbez", "bezier"}, + {"trans", "scale", "scalexy", "skewx", "skewy", "skewxy"}, + {"rotate", "text", "textpath", "path", "image", "grid"}, + {"lgrad", "rgrad", "rgb", "rgba", "meta"}, +} + +func main() { + width := 4500 + height := (width * 3) / 4 + canvas.Start(width, height) + defobjects(250, 125) + canvas.Title("SVG Go Library Description") + canvas.Rect(0, 0, width, height, "fill:white;stroke:black;stroke-width:2") + canvas.Gstyle(gtextstyle) + canvas.Link("http://github.com/ajstarks/svgo", "SVGo Library") + canvas.Text(width/2, 150, "SVG Go Library", "font-size:125px") + canvas.Text(width/2, 200, "github.com/ajstarks/svgo", "font-size:50px;fill:gray") + canvas.LinkEnd() + placeobjects(400, 400, 700, 600, roworder) + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/svgopher/svgopher.go b/vendor/github.com/ajstarks/svgo/svgopher/svgopher.go new file mode 100644 index 0000000..084781c --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgopher/svgopher.go @@ -0,0 +1,76 @@ +// svgopher - Go mascot remix +// +build !appengine + +package main + +import ( + "os" + + "github.com/ajstarks/svgo" +) + +var ( + width = 500 + height = 300 + canvas = svg.New(os.Stdout) +) + +func background(v int) { canvas.Rect(0, 0, width, height, canvas.RGB(v, v, v)) } + +func gordon(x, y, w, h int) { + + w10 := w / 10 + w12 := w / 12 + w2 := w / 2 + w3 := w / 3 + w8 := w / 8 + w6 := w / 6 + xw := x + w + h23 := (h * 2) / 3 + + blf := "fill:black" + wf := "fill:white" + nf := "fill:brown" + brf := "fill:brown; fill-opacity:0.2" + brb := "fill:rgb(210,161,161)" + + canvas.Gstyle("fill:none; stroke:none") + canvas.Bezier(x, y+h, x, y+h, x+w2, y-h, x+w, y+h, brb) + canvas.Roundrect(x, y+(h-1), w, h, 10, 10, brb) + canvas.Circle(x, y+h, w12, brf) // left ear + canvas.Circle(x, y+h, w12-10, nf) + + canvas.Circle(x+w, y+h, w12, brf) // right ear + canvas.Circle(x+w, y+h, w12-10, nf) + + canvas.Circle(x+w3, y+h23, w/9, wf) // left eye + canvas.Circle(x+w3+10, y+h23, w10-10, blf) + canvas.Circle(x+w3+15, y+h23, 5, wf) + + canvas.Circle(xw-w3, y+h23, w/9, wf) // right eye + canvas.Circle(xw-w3+10, y+h23, w10-10, blf) + canvas.Circle(xw-(w3)+15, y+h23, 5, wf) + + canvas.Roundrect(x+w2-w8, y+h+30, w8, w6, 5, 5, wf) // left tooth + canvas.Roundrect(x+w2, y+h+30, w8, w6, 5, 5, wf) // right tooth + + canvas.Ellipse(x+(w2), y+h+30, w6, w12, nf) // snout + canvas.Ellipse(x+(w2), y+h+10, w10, w12, blf) // nose + + canvas.Gend() +} + +func main() { + canvas.Start(width, height) + canvas.Title("SVG Gopher") + background(255) + canvas.Gtransform("translate(100, 100)") + canvas.Gtransform("rotate(-30)") + gordon(48, 48, 240, 72) + canvas.Gend() + canvas.Gend() + canvas.Link("svgdef.svg", "SVG Spec & Usage") + canvas.Text(90, 145, "SVG", "font-family:Calibri,sans-serif;font-size:80;fill:brown") + canvas.LinkEnd() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/svgplay/svgplay.go b/vendor/github.com/ajstarks/svgo/svgplay/svgplay.go new file mode 100644 index 0000000..8b6f844 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgplay/svgplay.go @@ -0,0 +1,291 @@ +// svgplay: sketch with SVGo, (derived from the old misc/goplay), except: +// (1) only listen on localhost, (default port 1999) +// (2) always render html, +// (3) SVGo default code, +package main + +import ( + "bytes" + "flag" + "io/ioutil" + "log" + "net/http" + "os" + "os/exec" + "path/filepath" + "strconv" + "text/template" +) + +var ( + httpListen = flag.String("port", "1999", "port to listen on") +) + +var ( + // a source of numbers, for naming temporary files + uniq = make(chan int) +) + +func main() { + flag.Parse() + + // source of unique numbers + go func() { + for i := 0; ; i++ { + uniq <- i + } + }() + + http.HandleFunc("/", FrontPage) + http.HandleFunc("/compile", Compile) + log.Printf("☠ ☠ ☠ Warning: this server allows a client connecting to 127.0.0.1:%s to execute code on this computer ☠ ☠ ☠", *httpListen) + log.Fatal(http.ListenAndServe("127.0.0.1:"+*httpListen, nil)) +} + +// FrontPage is an HTTP handler that renders the svgoplay interface. +// If a filename is supplied in the path component of the URI, +// its contents will be put in the interface's text area. +// Otherwise, the default "hello, world" program is displayed. +func FrontPage(w http.ResponseWriter, req *http.Request) { + data, err := ioutil.ReadFile(req.URL.Path[1:]) + if err != nil { + data = helloWorld + } + frontPage.Execute(w, data) +} + +// Compile is an HTTP handler that reads Go source code from the request, +// runs the program (returning any errors), +// and sends the program's output as the HTTP response. +func Compile(w http.ResponseWriter, req *http.Request) { + out, err := compile(req) + if err != nil { + compileError(w, out, err) + return + } + + // write the output of target as the http response + w.Write(out) +} + +var ( + tmpdir, pkgdir, buildpid string +) + +func init() { + // find real temporary directory (for rewriting filename in output) + var err error + tmpdir, err = filepath.EvalSymlinks(os.TempDir()) + if err != nil { + log.Fatal(err) + } + + buildpid = strconv.Itoa(os.Getpid()) +} + +func compile(req *http.Request) (out []byte, err error) { + // target is the base name for .go, object, executable files + target := filepath.Join(tmpdir, "svgplay"+buildpid+strconv.Itoa(<-uniq)) + src := target + ".go" + + // write body to target.go + body := new(bytes.Buffer) + if _, err = body.ReadFrom(req.Body); err != nil { + return + } + defer os.Remove(src) + if err = ioutil.WriteFile(src, body.Bytes(), 0666); err != nil { + return + } + return run("", "go", "run", src) +} + +// error writes compile, link, or runtime errors to the HTTP connection. +// The JavaScript interface uses the 404 status code to identify the error. +func compileError(w http.ResponseWriter, out []byte, err error) { + w.WriteHeader(404) + if out != nil { + elines := bytes.Split(out, []byte{'\n'}) + for _, l := range elines { + i := bytes.Index(l, []byte{':'}) + output.Execute(w, l[i+1:]) + } + } else { + output.Execute(w, err.Error()) + } +} + +// run executes the specified command and returns its output and an error. +func run(dir string, args ...string) ([]byte, error) { + var buf bytes.Buffer + cmd := exec.Command(args[0], args[1:]...) + cmd.Dir = dir + cmd.Stdout = &buf + cmd.Stderr = cmd.Stdout + err := cmd.Run() + return buf.Bytes(), err +} + +var frontPage = template.Must(template.New("frontPage").Parse(frontPageText)) // HTML template +var output = template.Must(template.New("output").Parse(outputText)) // HTML template + +var outputText = `
{{printf "%s" . |html}}
` + +var frontPageText = ` + + +svgplay: SVGo sketching + + + + +
+ +
+(Shift-Enter to compile and run.)     + Compile and run after each keystroke +
+
+ +
+
+
+ + +` + +var helloWorld = []byte(`package main + +import ( + "math/rand" + "os" + "time" + "github.com/ajstarks/svgo" +) + +func ri(n int) int { return rand.Intn(n) } + +func main() { + canvas := svg.New(os.Stdout) + width := 500 + height := 500 + nstars := 250 + style := "font-size:48pt;fill:white;text-anchor:middle" + + rand.Seed(time.Now().Unix()) + canvas.Start(width, height) + canvas.Rect(0,0,width,height) + for i := 0; i < nstars; i++ { + canvas.Circle(ri(width), ri(height), ri(3), "fill:white") + } + canvas.Circle(width/2, height, width/2, "fill:rgb(77, 117, 232)") + canvas.Text(width/2, height*4/5, "hello, world", style) + canvas.End() +}`) diff --git a/vendor/github.com/ajstarks/svgo/svgplot/mksvgplotdef b/vendor/github.com/ajstarks/svgo/svgplot/mksvgplotdef new file mode 100644 index 0000000..e1dbc94 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgplot/mksvgplotdef @@ -0,0 +1,24 @@ +#!/bin/sh +rm f??*.svg +gopts="-bx=50 -by=20 -width=460 -height=130 -pw=400 -ph=90 -barsize=3 -fontsize=11" +data="test.d" +# opt +svgplot $gopts -showbg -connect=f -label=showbg $data > f00.svg +svgplot $gopts -connect -label=connect $data > f01.svg +svgplot $gopts -showbar -connect=f -label=showbar $data > f02.svg +svgplot $gopts -area -connect=f -label=area $data > f03.svg +svgplot $gopts -showdot -connect=f -label=showdot $data > f04.svg +svgplot $gopts -showx -label=showx $data > f05.svg +svgplot $gopts -showy -label=showy $data > f06.svg +svgplot $gopts -showfile -label=showfile $data > f07.svg +# attr +svgplot $gopts -bgcolor=lightsteelblue -label=bgcolor $data > f08.svg +svgplot $gopts -linecolor=red -label=linecolor $data > f09.svg +svgplot $gopts -barcolor=red -showbar -connect=f -label=barcolor $data > f10.svg +svgplot $gopts -areacolor=red -area -connect=f -label=hcolor $data > f11.svg +svgplot $gopts -showdot -dotcolor=red -connect=f -label=dotcolor $data > f12.svg +svgplot $gopts -label=labelcolor -labelcolor=red $data > f13.svg +svgplot $gopts -label=fontsize $data > f14.svg +svgplot $gopts -font=Courier -label="font" $data > f15.svg +svgrid -h 1200 -w 1024 -r=f -x=50 -y=50 -g 10 -c 8 f??.svg > svgplotdef.svg + diff --git a/vendor/github.com/ajstarks/svgo/svgplot/svgplot.go b/vendor/github.com/ajstarks/svgo/svgplot/svgplot.go new file mode 100644 index 0000000..06f54a3 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgplot/svgplot.go @@ -0,0 +1,314 @@ +//svgplot -- plot data (a stream of x,y coordinates) +// +build !appengine + +package main + +import ( + "flag" + "fmt" + "io" + "math" + "os" + + "github.com/ajstarks/svgo" +) + +// rawdata defines data as float64 x,y coordinates +type rawdata struct { + x float64 + y float64 +} + +type options map[string]bool +type attributes map[string]string +type measures map[string]int + +// plotset defines plot metadata +type plotset struct { + opt options + attr attributes + size measures +} + +var ( + canvas = svg.New(os.Stdout) + plotopt = options{} + plotattr = attributes{} + plotnum = measures{} + ps = plotset{plotopt, plotattr, plotnum} + plotw, ploth, plotc, gwidth, gheight, gutter, beginx, beginy int +) + +const ( + globalfmt = "font-family:%s;font-size:%dpt;stroke-width:%dpx" + linestyle = "fill:none;stroke:" + linefmt = "fill:none;stroke:%s" + barfmt = linefmt + ";stroke-width:%dpx" + ticfmt = "stroke:rgb(200,200,200);stroke-width:1px" + labelfmt = ticfmt + ";text-anchor:end;fill:black" + textfmt = "stroke:none;baseline-shift:-33.3%" + smallint = -(1 << 30) +) + +// init initializes command flags and sets default options +func init() { + + // boolean options + showx := flag.Bool("showx", false, "show the xaxis") + showy := flag.Bool("showy", false, "show the yaxis") + showbar := flag.Bool("showbar", false, "show data bars") + area := flag.Bool("area", false, "area chart") + connect := flag.Bool("connect", true, "connect data points") + showdot := flag.Bool("showdot", false, "show dots") + showbg := flag.Bool("showbg", true, "show the background color") + showfile := flag.Bool("showfile", false, "show the filename") + sameplot := flag.Bool("sameplot", false, "plot on the same frame") + + // attributes + bgcolor := flag.String("bgcolor", "rgb(240,240,240)", "plot background color") + barcolor := flag.String("barcolor", "gray", "bar color") + dotcolor := flag.String("dotcolor", "black", "dot color") + linecolor := flag.String("linecolor", "gray", "line color") + areacolor := flag.String("areacolor", "gray", "area color") + font := flag.String("font", "Calibri,sans", "font") + labelcolor := flag.String("labelcolor", "black", "label color") + plotlabel := flag.String("label", "", "plot label") + + // sizes + dotsize := flag.Int("dotsize", 2, "dot size") + linesize := flag.Int("linesize", 2, "line size") + barsize := flag.Int("barsize", 2, "bar size") + fontsize := flag.Int("fontsize", 11, "font size") + xinterval := flag.Int("xint", 10, "x axis interval") + yinterval := flag.Int("yint", 4, "y axis interval") + ymin := flag.Int("ymin", smallint, "y minimum") + ymax := flag.Int("ymax", smallint, "y maximum") + + // meta options + flag.IntVar(&beginx, "bx", 100, "initial x") + flag.IntVar(&beginy, "by", 50, "initial y") + flag.IntVar(&plotw, "pw", 500, "plot width") + flag.IntVar(&ploth, "ph", 500, "plot height") + flag.IntVar(&plotc, "pc", 2, "plot columns") + flag.IntVar(&gutter, "gutter", ploth/10, "gutter") + flag.IntVar(&gwidth, "width", 1024, "canvas width") + flag.IntVar(&gheight, "height", 768, "canvas height") + + flag.Parse() + + // fill in the plotset -- all options, attributes, and sizes + plotopt["showx"] = *showx + plotopt["showy"] = *showy + plotopt["showbar"] = *showbar + plotopt["area"] = *area + plotopt["connect"] = *connect + plotopt["showdot"] = *showdot + plotopt["showbg"] = *showbg + plotopt["showfile"] = *showfile + plotopt["sameplot"] = *sameplot + + plotattr["bgcolor"] = *bgcolor + plotattr["barcolor"] = *barcolor + plotattr["linecolor"] = *linecolor + plotattr["dotcolor"] = *dotcolor + plotattr["areacolor"] = *areacolor + plotattr["font"] = *font + plotattr["label"] = *plotlabel + plotattr["labelcolor"] = *labelcolor + + plotnum["dotsize"] = *dotsize + plotnum["linesize"] = *linesize + plotnum["fontsize"] = *fontsize + plotnum["xinterval"] = *xinterval + plotnum["yinterval"] = *yinterval + plotnum["barsize"] = *barsize + plotnum["ymin"] = *ymin + plotnum["ymax"] = *ymax +} + +// fmap maps world data to document coordinates +func fmap(value float64, low1 float64, high1 float64, low2 float64, high2 float64) float64 { + return low2 + (high2-low2)*(value-low1)/(high1-low1) +} + +// doplot opens a file and makes a plot +func doplot(x, y int, location string) { + var f *os.File + var err error + if len(location) > 0 { + if plotopt["showfile"] { + plotattr["label"] = location + } + f, err = os.Open(location) + } else { + f = os.Stdin + } + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + nd, data := readxy(f) + f.Close() + + if nd >= 2 { + plot(x, y, plotw, ploth, ps, data) + } +} + +// plot places a plot at the specified location with the specified dimemsions +// usinng the specified settings, using the specified data +func plot(x, y, w, h int, settings plotset, d []rawdata) { + nd := len(d) + if nd < 2 { + fmt.Fprintf(os.Stderr, "%d is not enough points to plot\n", len(d)) + return + } + // Compute the minima and maxima + maxx, minx := d[0].x, d[0].x + maxy, miny := d[0].y, d[0].y + for _, v := range d { + + if v.x > maxx { + maxx = v.x + } + if v.y > maxy { + maxy = v.y + } + if v.x < minx { + minx = v.x + } + if v.y < miny { + miny = v.y + } + } + + if settings.size["ymin"] != smallint { + miny = float64(settings.size["ymin"]) + } + if settings.size["ymax"] != smallint { + maxy = float64(settings.size["ymax"]) + } + // Prepare for a area or line chart by allocating + // polygon coordinates; for the hrizon plot, you need two extra coordinates + // for the extrema. + needpoly := settings.opt["area"] || settings.opt["connect"] + var xpoly, ypoly []int + if needpoly { + xpoly = make([]int, nd+2) + ypoly = make([]int, nd+2) + // preload the extrema of the polygon, + // the bottom left and bottom right of the plot's rectangle + xpoly[0] = x + ypoly[0] = y + h + xpoly[nd+1] = x + w + ypoly[nd+1] = y + h + } + // Draw the plot's bounding rectangle + if settings.opt["showbg"] && !settings.opt["sameplot"] { + canvas.Rect(x, y, w, h, "fill:"+settings.attr["bgcolor"]) + } + // Loop through the data, drawing items as specified + spacer := 10 + canvas.Gstyle(fmt.Sprintf(globalfmt, + settings.attr["font"], settings.size["fontsize"], settings.size["linesize"])) + + for i, v := range d { + xp := int(fmap(v.x, minx, maxx, float64(x), float64(x+w))) + yp := int(fmap(v.y, miny, maxy, float64(y), float64(y-h))) + + if needpoly { + xpoly[i+1] = xp + ypoly[i+1] = yp + h + } + if settings.opt["showbar"] { + canvas.Line(xp, yp+h, xp, y+h, + fmt.Sprintf(barfmt, settings.attr["barcolor"], settings.size["barsize"])) + } + if settings.opt["showdot"] { + canvas.Circle(xp, yp+h, settings.size["dotsize"], "fill:"+settings.attr["dotcolor"]) + } + if settings.opt["showx"] { + if i%settings.size["xinterval"] == 0 { + canvas.Text(xp, (y+h)+(spacer*2), fmt.Sprintf("%d", int(v.x)), "text-anchor:middle") + canvas.Line(xp, (y + h), xp, (y+h)+spacer, ticfmt) + } + } + } + // Done constructing the points for the area or line plots, display them in one shot + if settings.opt["area"] { + canvas.Polygon(xpoly, ypoly, "fill:"+settings.attr["areacolor"]) + } + + if settings.opt["connect"] { + canvas.Polyline(xpoly[1:nd+1], ypoly[1:nd+1], linestyle+settings.attr["linecolor"]) + } + // Put on the y axis labels, if specified + if settings.opt["showy"] { + bot := math.Floor(miny) + top := math.Ceil(maxy) + yrange := top - bot + interval := yrange / float64(settings.size["yinterval"]) + canvas.Gstyle(labelfmt) + for yax := bot; yax <= top; yax += interval { + yaxp := fmap(yax, bot, top, float64(y), float64(y-h)) + canvas.Text(x-spacer, int(yaxp)+h, fmt.Sprintf("%.1f", yax), textfmt) + canvas.Line(x-spacer, int(yaxp)+h, x, int(yaxp)+h) + } + canvas.Gend() + } + // Finally, tack on the label, if specified + if len(settings.attr["label"]) > 0 { + canvas.Text(x, y+spacer, settings.attr["label"], "font-size:120%;fill:"+settings.attr["labelcolor"]) + } + + canvas.Gend() +} + +// readxy reads coordinates (x,y float64 values) from a io.Reader +func readxy(f io.Reader) (int, []rawdata) { + var ( + r rawdata + err error + n, nf int + ) + data := make([]rawdata, 1) + for ; err == nil; n++ { + if n > 0 { + data = append(data, r) + } + nf, err = fmt.Fscan(f, &data[n].x, &data[n].y) + if nf != 2 { + continue + } + } + return n - 1, data[0 : n-1] +} + +// plotgrid places plots on a grid, governed by a number of columns. +func plotgrid(x, y int, files []string) { + px := x + for i, f := range files { + if i > 0 && i%plotc == 0 && !plotopt["sameplot"] { + px = x + y += (ploth + gutter) + } + doplot(px, y, f) + if !plotopt["sameplot"] { + px += (plotw + gutter) + } + } +} + +// main plots data from specified files or standard input in a +// grid where plotc specifies the number of columns. +func main() { + canvas.Start(gwidth, gheight) + canvas.Rect(0, 0, gwidth, gheight, "fill:white") + filenames := flag.Args() + if len(filenames) == 0 { + doplot(beginx, beginy, "") + } else { + plotgrid(beginx, beginy, filenames) + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/svgplot/test.d b/vendor/github.com/ajstarks/svgo/svgplot/test.d new file mode 100644 index 0000000..e79c144 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgplot/test.d @@ -0,0 +1,51 @@ +0 493.65 +1 497.57 +2 506.38 +3 521.03 +4 532.44 +5 535.36 +6 546.60 +7 531.99 +8 527.28 +9 534.01 +10 538.26 +11 528.94 +12 597.62 +13 594.94 +14 602.55 +15 595.35 +16 606.99 +17 618.23 +18 618.98 +19 622.52 +20 607.22 +21 610.94 +22 603.69 +23 606.77 +24 592.40 +25 601.17 +26 577.52 +27 579.04 +28 546.02 +29 573.41 +30 549.01 +31 562.13 +32 563.77 +33 557.23 +34 539.00 +35 533.15 +36 504.88 +37 490.92 +38 498.17 +39 518.82 +40 523.29 +41 520.04 +42 526.86 +43 539.08 +44 540.70 +45 540.96 +46 532.50 +47 524.84 +48 522.18 +49 534.03 +50 534.96 diff --git a/vendor/github.com/ajstarks/svgo/svgrid/svgrid.go b/vendor/github.com/ajstarks/svgo/svgrid/svgrid.go new file mode 100644 index 0000000..4d36b0e --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/svgrid/svgrid.go @@ -0,0 +1,107 @@ +// svgrid -- composite SVG files in a grid +// +build !appengine + +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "io" + "os" + + "github.com/ajstarks/svgo" +) + +// SVG is a SVG document +type SVG struct { + Width string `xml:"width,attr"` + Height string `xml:"height,attr"` + Doc string `xml:",innerxml"` +} + +var ( + byrow bool + startx, starty, count, gutter, gwidth, gheight int + canvas = svg.New(os.Stdout) +) + +// init sets up command line options +func init() { + flag.BoolVar(&byrow, "r", true, "order row wise") + flag.IntVar(&startx, "x", 0, "begin x") + flag.IntVar(&starty, "y", 0, "begin y") + flag.IntVar(&count, "c", 3, "columns or rows") + flag.IntVar(&gutter, "g", 100, "gutter") + flag.IntVar(&gwidth, "w", 1024, "width") + flag.IntVar(&gheight, "h", 768, "height") + flag.Parse() +} + +// placepic puts a SVG file at a location +func placepic(x, y int, filename string) (int, int) { + var ( + s SVG + width, height int + wunit, hunit string + ) + f, err := os.Open(filename) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return 0, 0 + } + defer f.Close() + if err := xml.NewDecoder(f).Decode(&s); err != nil { + fmt.Fprintf(os.Stderr, "Unable to parse (%v)\n", err) + return 0, 0 + } + + // read the width and height, including any units + // if there are errors use 10 as a default + nw, _ := fmt.Sscanf(s.Width, "%d%s", &width, &wunit) + if nw < 1 { + width = 10 + } + nh, _ := fmt.Sscanf(s.Height, "%d%s", &height, &hunit) + if nh < 1 { + height = 10 + } + canvas.Group(`clip-path="url(#pic)"`, fmt.Sprintf(`transform="translate(%d,%d)"`, x, y)) + canvas.ClipPath(`id="pic"`) + canvas.Rect(0, 0, width, height) + canvas.ClipEnd() + io.WriteString(canvas.Writer, s.Doc) + canvas.Gend() + return width, height +} + +// compose places files row or column-wise +func compose(x, y, n int, rflag bool, files []string) { + px := x + py := y + var pw, ph int + for i, f := range files { + if i > 0 && i%n == 0 { + if rflag { + px = x + py += gutter + ph + } else { + px += gutter + pw + py = y + } + } + pw, ph = placepic(px, py, f) + if rflag { + px += gutter + pw + } else { + py += gutter + ph + } + } +} + +// main lays out files as specified on the command line +func main() { + canvas.Start(gwidth, gheight) + compose(startx, starty, count, byrow, flag.Args()) + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/tsg/tsg.go b/vendor/github.com/ajstarks/svgo/tsg/tsg.go new file mode 100644 index 0000000..8605392 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/tsg/tsg.go @@ -0,0 +1,126 @@ +// tsg -- twitter search grid +// +build !appengine + +package main + +import ( + "encoding/xml" + "flag" + "fmt" + "io" + "net/http" + "net/url" + "os" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +// Feed is the Atom feed structure +type Feed struct { + XMLName xml.Name `xml:"http://www.w3.org/2005/Atom feed"` + Entry []Entry `xml:"entry"` +} + +// Entry defines an entry within an Aton feed +type Entry struct { + Link []Link `xml:"link"` + Title string `xml:"title"` + Author Person `xml:"author"` +} + +// Link defines a link within an Atom feed +type Link struct { + Rel string `xml:"rel,attr"` + Href string `xml:"href,attr"` +} + +// Person defines a person responsible for the tweet +type Person struct { + Name string `xml:"name"` +} + +// Text defines the text of the tweet +type Text struct { + Type string `xml:",attr"` + Body string `xml:",chardata"` +} + +var ( + nresults = flag.Int("n", 100, "Maximum results (up to 100)") + since = flag.String("d", "", "Search since this date (YYYY-MM-DD)") +) + +const ( + queryURI = "http://search.twitter.com/search.atom?q=%s&since=%s&rpp=%d" + textfmt = "font-family:Calibri,Lucida,sans;fill:gray;text-anchor:middle;font-size:48px" + imw = 48 + imh = 48 +) + +// ts dereferences the twitter search URL and reads the XML (Atom) response +func ts(s string, date string, n int) { + + r, err := http.Get(fmt.Sprintf(queryURI, url.QueryEscape(s), date, n)) + if err != nil { + fmt.Fprintf(os.Stderr, "%v\n", err) + return + } + if r.StatusCode == http.StatusOK { + readatom(r.Body) + } else { + fmt.Fprintf(os.Stderr, + "Twitter is unable to search for %s (%s)\n", s, r.Status) + } + r.Body.Close() +} + +// readatom unmarshals the twitter search response and formats the results into a grid +func readatom(r io.Reader) { + var twitter Feed + err := xml.NewDecoder(r).Decode(&twitter) + if err == nil { + tgrid(twitter, 25, 25, 50, 50, 10) + } else { + fmt.Fprintf(os.Stderr, "Unable to parse the Atom feed (%v)\n", err) + } +} + +// tgrid makes a clickable grid of tweets from the Atom feed +func tgrid(t Feed, x, y, w, h, nc int) { + 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 + } +} + +// for every non-flag argument, make a twitter search grid +func main() { + flag.Parse() + width := 550 + height := 700 + canvas.Start(width, height) + for _, s := range flag.Args() { + canvas.Title("Twitter search for " + s) + ts(s, *since, *nresults) + canvas.Text(width/2, height-50, s, textfmt) + } + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/tumblrgrid/tlist b/vendor/github.com/ajstarks/svgo/tumblrgrid/tlist new file mode 100644 index 0000000..c709df1 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/tumblrgrid/tlist @@ -0,0 +1,4 @@ +f0o0od.tumblr.com +ign0ranceisbliiiss.tumblr.com +agilaagira.tumblr.com +geek-art.tumblr.com diff --git a/vendor/github.com/ajstarks/svgo/tumblrgrid/tumblrgrid.go b/vendor/github.com/ajstarks/svgo/tumblrgrid/tumblrgrid.go new file mode 100644 index 0000000..82c20e8 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/tumblrgrid/tumblrgrid.go @@ -0,0 +1,218 @@ +// tumblrgrid: display a flexible grid of pictures from tumblr, filtered by tags +// +build !appengine + +package main + +import ( + "encoding/json" + "flag" + "fmt" + "io" + "io/ioutil" + "net/http" + "os" + + "github.com/ajstarks/svgo" +) + +var ( + localfile, postlink bool + ncols, gutter, thumbwidth, piclimit int + filtertag string +) + +const ( + apiKey = "APIKEY" + apifmt = "http://api.tumblr.com/v2/blog/%s/posts?api_key=%s&type=photo&limit=%d" +) + +// Tumblr is the JSON data descriptions +type Tumblr struct { + Meta meta + Response response +} + +type meta struct { + Msg string + Status int +} + +type response struct { + Blog blog + Posts []posts + Total_posts int +} + +type blog struct { + Name string + Posts int + Title string + Updated int + Description string + Url string +} + +type posts struct { + Photos []photos + Tags []string + Type string + Link_url string + Post_url string +} + +type photos struct { + Alt_sizes []altsizes +} + +type altsizes struct { + Height int + Url string + Width int +} + +// resource gives a ReadCloser given a local file or URL +func resource(name string) (io.ReadCloser, 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 +} + +// grid displays tumblr photos in a flexible grid +func grid(canvas *svg.SVG, location string, x, y, nc, gutter int) { + var ( + t Tumblr + r io.ReadCloser + err error + b []byte + ) + + //get data from the resource, put it into the data structure + if r, err = resource(location); err != nil { + fmt.Fprintln(os.Stderr, err) + return + } + + defer r.Close() + if b, err = ioutil.ReadAll(r); err != nil { + fmt.Fprintf(os.Stderr, "%s %v\n", location, err) + return + } + + if err = json.Unmarshal(b, &t); err != nil { + fmt.Fprintf(os.Stderr, "%s, %v\n", location, err) + return + } + + // create the linked blog title + fontsize := thumbwidth / 3 + title := t.Response.Blog.Title + + if len(title) == 0 { + title = t.Response.Blog.Name + } + canvas.Link(t.Response.Blog.Url, t.Response.Blog.Name) + if nc < 4 { // if the columns are too narrow, rotate the title text 90 degrees + canvas.TranslateRotate(x, y/2, 90) + canvas.Text(fontsize, fontsize, title, "fill:lightgray") + canvas.Gend() + } else { + canvas.Text(x, y/2, title, "fill:lightgray") + } + canvas.LinkEnd() + + // walk through the posts, displaying thumbnails, filtered by tags + np := 0 + xp := x + + for _, posts := range t.Response.Posts { + if np >= piclimit { + break + } + if !intag(filtertag, posts.Tags) { + continue + } + for _, photos := range posts.Photos { + for i, p := range photos.Alt_sizes { + if i == 0 { // link to the first image in the list + if postlink { + canvas.Link(posts.Post_url, "Photo") + } else { + canvas.Link(p.Url, "Photo") + } + } + if p.Width == thumbwidth { + np++ + canvas.Image(xp, y, p.Width, p.Width, p.Url) + xp += p.Width + gutter + if np%nc == 0 { + xp = x + y += p.Width + gutter + } + } + } + canvas.LinkEnd() + } + } +} + +// intag searches for tags in list +func intag(tag string, list []string) bool { + if len(tag) == 0 { + return true + } + for _, s := range list { + if s == tag { + return true + } + } + return false +} + +// init sets up command flags +func init() { + flag.BoolVar(&localfile, "f", false, "read from local files") + flag.BoolVar(&postlink, "p", false, "link to original post") + flag.IntVar(&ncols, "nc", 5, "number of columns") + flag.IntVar(&gutter, "g", 5, "gutter (pixels)") + flag.IntVar(&thumbwidth, "tw", 75, "thumbnail width") + flag.IntVar(&piclimit, "n", 30, "picture limit") + flag.StringVar(&filtertag, "tag", "", "filter tag") + flag.Parse() +} + +func main() { + + np := len(flag.Args()) + if np == 0 { + np = 1 + } + + thalf := thumbwidth / 2 + x := thalf + y := 50 + nrows := piclimit / ncols + colincr := (ncols * thumbwidth) + (ncols * gutter) + thalf + width := (colincr * np) + thalf + height := (thumbwidth * nrows) + (nrows * gutter) + y + thalf + gstyle := "font-family:Calibri,sans-serif;font-size:18px" + + canvas := svg.New(os.Stdout) + canvas.Start(width, height) + canvas.Rect(0, 0, width, height, "fill:rgb(43,62,87)") // tumblr blue + canvas.Gstyle(gstyle) + if len(flag.Args()) == 0 { + grid(canvas, "", x, y, ncols, gutter) + } else { + for _, f := range flag.Args() { + grid(canvas, f, x, y, ncols, gutter) + x += colincr + } + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/turbulence/turbulence.go b/vendor/github.com/ajstarks/svgo/turbulence/turbulence.go new file mode 100644 index 0000000..e247d4d --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/turbulence/turbulence.go @@ -0,0 +1,73 @@ +// turbulence example from http://www.w3.org/TR/2003/REC-SVG11-20030114/filters.html#feTurbulence +// +build !appengine + +package main + +import ( + "fmt" + "github.com/ajstarks/svgo" + "os" +) + +var ( + canvas = svg.New(os.Stdout) + width = 500 + height = 500 +) + +type perlin struct { + id string + ftype string + basefreqx float64 + basefreqy float64 + octave int + seed int64 + tile bool +} + +func (p perlin) defturbulence() { + x := svg.Filterspec{} + canvas.Filter(p.id) + canvas.FeTurbulence(x, p.ftype, p.basefreqx, p.basefreqy, p.octave, p.seed, p.tile) + canvas.Fend() +} + +func (p perlin) frect(x, y, w, h int) { + bot := y + h + canvas.Rect(x, y, w, h, fmt.Sprintf(`filter="url(#%s)"`, p.id)) + canvas.Text(x+w/2, bot+25, fmt.Sprintf("type=%s", p.ftype)) + canvas.Text(x+w/2, bot+40, fmt.Sprintf("baseFrequency=%.2f", p.basefreqx)) + canvas.Text(x+w/2, bot+55, fmt.Sprintf("numOctaves=%d", p.octave)) +} + +func main() { + var t1, t2, t3, t4, t5, t6 perlin + + t1 = perlin{"Turb1", "t", 0.05, 0.05, 2, 0, false} + t2 = perlin{"Turb2", "t", 0.10, 0.10, 2, 0, false} + t3 = perlin{"Turb3", "t", 0.05, 0.05, 8, 0, false} + t4 = perlin{"Turb4", "f", 0.10, 0.10, 4, 0, false} + t5 = perlin{"Turb5", "f", 0.40, 0.40, 4, 0, false} + t6 = perlin{"Turb6", "f", 0.10, 0.10, 1, 0, false} + + canvas.Start(width, height) + canvas.Title("Example of feTurbulence") + canvas.Def() + t1.defturbulence() + t2.defturbulence() + t3.defturbulence() + t4.defturbulence() + t5.defturbulence() + t6.defturbulence() + canvas.DefEnd() + + canvas.Gstyle("font-size:10;font-family:Verdana;text-anchor:middle") + t1.frect(25, 25, 100, 75) + t2.frect(175, 25, 100, 75) + t3.frect(325, 25, 100, 75) + t4.frect(25, 180, 100, 75) + t5.frect(175, 180, 100, 75) + t6.frect(325, 180, 100, 75) + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/vismem/vismem.go b/vendor/github.com/ajstarks/svgo/vismem/vismem.go new file mode 100644 index 0000000..f0d1b54 --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/vismem/vismem.go @@ -0,0 +1,51 @@ +// vismem visualizes memory locations +// +build !appengine + +package main + +import ( + "os" + + "github.com/ajstarks/svgo" +) + +var canvas = svg.New(os.Stdout) + +func main() { + width := 512 + height := 512 + n := 1024 + rowsize := 32 + diameter := 16 + var value int + var source string + + if len(os.Args) > 1 { + source = os.Args[1] + } else { + source = "/dev/urandom" + } + + f, _ := os.Open(source) + mem := make([]byte, n) + f.Read(mem) + f.Close() + + canvas.Start(width, height) + canvas.Title("Visualize Files") + canvas.Rect(0, 0, width, height, "fill:white") + dx := diameter / 2 + dy := diameter / 2 + canvas.Gstyle("fill-opacity:1.0") + for i := 0; i < n; i++ { + value = int(mem[i]) + if i%rowsize == 0 && i != 0 { + dx = diameter / 2 + dy += diameter + } + canvas.Circle(dx, dy, diameter/2, canvas.RGB(value, value, value)) + dx += diameter + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/webfonts/webfonts.go b/vendor/github.com/ajstarks/svgo/webfonts/webfonts.go new file mode 100644 index 0000000..6a6593e --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/webfonts/webfonts.go @@ -0,0 +1,62 @@ +// webfonts demo +// +build !appengine + +package main + +import ( + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "strings" + + "github.com/ajstarks/svgo" +) + +var ( + canvas = svg.New(os.Stdout) + width = 500 + height = 1100 + fontlist = "Sue Ellen Francisco|Over the Rainbow|Pacifico|Inconsolata|Miltonian|Megrim|Monofett|Permanent Marker|Homemade Apple|Ultra" +) + +const ( + gwfURI = "http://fonts.googleapis.com/css?family=" + fontfmt = "\n" + gfmt = "fill:white;font-size:36pt;text-anchor:middle" +) + +func googlefont(f string) []string { + empty := []string{} + r, err := http.Get(gwfURI + url.QueryEscape(f)) + if err != nil { + return empty + } + defer r.Body.Close() + b, rerr := ioutil.ReadAll(r.Body) + if rerr != nil || r.StatusCode != http.StatusOK { + return empty + } + canvas.Def() + fmt.Fprintf(canvas.Writer, fontfmt, b) + canvas.DefEnd() + return strings.Split(fontlist, "|") +} + +func main() { + canvas.Start(width, height) + canvas.Title("Webfonts") + if len(os.Args) > 1 { + fontlist = os.Args[1] + } + fl := googlefont(fontlist) + canvas.Rect(0, 0, width, height) + canvas.Ellipse(width/2, height+50, width/2, height/5, "fill:rgb(44,77,232)") + canvas.Gstyle(gfmt) + for i, f := range fl { + canvas.Text(width/2, (i+1)*100, "Hello, World", "font-family:"+f) + } + canvas.Gend() + canvas.End() +} diff --git a/vendor/github.com/ajstarks/svgo/websvg/websvg.go b/vendor/github.com/ajstarks/svgo/websvg/websvg.go new file mode 100644 index 0000000..cc8000b --- /dev/null +++ b/vendor/github.com/ajstarks/svgo/websvg/websvg.go @@ -0,0 +1,73 @@ +// websvg draws SVG in a web server +// +build !appengine + +package main + +import ( + "flag" + "log" + "net/http" + "strings" + + "github.com/ajstarks/svgo" +) + +const defaultstyle = "fill:rgb(127,0,0)" + +var port = flag.String("port", ":2003", "http service address") + +func main() { + flag.Parse() + http.Handle("/circle/", http.HandlerFunc(circle)) + http.Handle("/rect/", http.HandlerFunc(rect)) + http.Handle("/arc/", http.HandlerFunc(arc)) + http.Handle("/text/", http.HandlerFunc(text)) + err := http.ListenAndServe(*port, nil) + if err != nil { + log.Println("ListenAndServe:", err) + } +} + +func shapestyle(path string) string { + i := strings.LastIndex(path, "/") + 1 + if i > 0 && len(path[i:]) > 0 { + return "fill:" + path[i:] + } + return defaultstyle +} + +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 arc(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Content-Type", "image/svg+xml") + s := svg.New(w) + s.Start(500, 500) + s.Title("Arc") + s.Arc(250, 250, 100, 100, 0, false, false, 100, 125, shapestyle(req.URL.Path)) + s.End() +} + +func text(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Content-Type", "image/svg+xml") + s := svg.New(w) + s.Start(500, 500) + s.Title("Text") + s.Text(250, 250, "Hello, world", "text-anchor:middle;font-size:32px;"+shapestyle(req.URL.Path)) + s.End() +}