diff --git a/svg.go b/svg.go index 03af677..34d0a7b 100644 --- a/svg.go +++ b/svg.go @@ -24,6 +24,7 @@ package svg // import ( + "bytes" "fmt" "io" @@ -48,6 +49,9 @@ type Filterspec struct { In, In2, Result string } +// A function which builds an SVG snippet on an SVG instance +type Snippetspec func(*SVG) + const ( svgtop = ` @@ -83,6 +87,14 @@ func (svg *SVG) genattr(ns []string) { svg.println(svgns) } +// Use a temporary SVG instance to create a snippet in a buffer, then write the snippet to our own writer +func (svg *SVG) genbuff(gen Snippetspec) { + var b bytes.Buffer + buffSvg := SVG{&b} + gen(&buffSvg) + b.WriteTo(svg.Writer) +} + // Structure, Metadata, Scripting, Style, Transformation, and Links // Start begins the SVG document with the width w and height h. @@ -93,6 +105,15 @@ func (svg *SVG) Start(w int, h int, ns ...string) { svg.genattr(ns) } +// StartFunc begins and ends the SVG document with the width w and height h with the +// contents provided by the gen function. +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) StartFunc(gen Snippetspec, w int, h int, ns ...string) { + svg.Start(w, h, ns...) + svg.genbuff(gen) + svg.End() +} + // 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) { @@ -100,6 +121,15 @@ func (svg *SVG) Startunit(w int, h int, unit string, ns ...string) { svg.genattr(ns) } +// StartunitFunc begins the SVG document, with width and height in the specified units +// with the contents provided by the gen function. +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) StartunitFunc(gen Snippetspec, w int, h int, unit string, ns ...string) { + svg.Startunit(w, h, unit, ns...) + svg.genbuff(gen) + svg.End() +} + // 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) { @@ -107,23 +137,58 @@ func (svg *SVG) Startpercent(w int, h int, ns ...string) { svg.genattr(ns) } +// StartpercentFunc begins the SVG document, with width and height as percentages +// with the contents provided by the gen function. +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) StartpercentFunc(gen Snippetspec, w int, h int, ns ...string) { + svg.Startpercent(w, h, ns...) + svg.genbuff(gen) + svg.End() +} + // 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)) } +// StartviewFunc begins the SVG document, with width, height, and viewbox with the +// contents provided by the gen function. +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) StartviewFunc(gen Snippetspec, w, h, minx, miny, vw, vh int) { + svg.Startview(w, h, minx, miny, vw, vh) + svg.genbuff(gen) + svg.End() +} + // StartviewUnit begins the SVG document with the specified width, height, and unit 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)) } +// StartviewUnitFunc begins the SVG document, with width, height, and viewbox with the +// contents provided by the gen function. +// Other attributes may be optionally added, for example viewbox or additional namespaces +func (svg *SVG) StartviewUnitFunc(gen Snippetspec, w, h int, unit string, minx, miny, vw, vh int) { + svg.StartviewUnit(w, h, unit, minx, miny, vw, vh) + svg.genbuff(gen) + svg.End() +} + // Startraw begins the SVG document, passing arbitrary attributes func (svg *SVG) Startraw(ns ...string) { svg.printf(svgtop) svg.genattr(ns) } +// StartrawFunc begins the SVG document, passing arbitrary attributes with the +// contents provided by the gen function. +func (svg *SVG) StartrawFunc(gen Snippetspec, ns ...string) { + svg.Startraw(ns...) + svg.genbuff(gen) + svg.End() +} + // End the SVG document func (svg *SVG) End() { svg.println("") } @@ -164,51 +229,147 @@ func (svg *SVG) Style(scriptype string, data ...string) { // Standard Reference: http://www.w3.org/TR/SVG11/struct.html#GElement func (svg *SVG) Gstyle(s string) { svg.println(group("style", s)) } +// GstyleFunc creates a group with the specified style with the contents generated by the +// gen function +func (svg *SVG) GstyleFunc(s string, gen Snippetspec) { + svg.Gstyle(s) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// GtransformFunc creates a group with the specified trnsform with the contents generated +// by the gen function +func (svg *SVG) GtransformFunc(s string, gen Snippetspec) { + svg.Gtransform(s) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// TranslateFunc creates a coordinate translation group with the specified translation +// containing the contents generated by the gen function +func (svg *SVG) TranslateFunc(x, y int, gen Snippetspec) { + svg.Translate(x, y) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// Scale scales the coordinate system by n for a group containing the contents generated +// by the gen function +func (svg *SVG) ScaleFunc(n float64, gen Snippetspec) { + svg.Scale(n) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// ScaleXY scales the coordinate system by dx and dy for a group containing the contents +// generated by the gen function +func (svg *SVG) ScaleXYFunc(dx, dy float64, gen Snippetspec) { + svg.ScaleXY(dx, dy) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// SkewXFunc skews the x coordinate system by angle a for a group containing the contents +// generated by the gen function +func (svg *SVG) SkewXFunc(a float64, gen Snippetspec) { + svg.SkewX(a) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// SkewYFunc skews the y coordinate system by angle a for a group containing the contents +// generated by the gen function +func (svg *SVG) SkewYFunc(a float64, gen Snippetspec) { + svg.SkewY(a) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// SkewXYFunc skews the x and y coordinates by angle ax, ay respectively for a group +// containing the contents generated by the gen function +func (svg *SVG) SkewXYFunc(ax, ay float64, gen Snippetspec) { + svg.SkewXY(ax, ay) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// Rotate rotates the coordinate system by r degrees for a group containing the contents generated by +// the gen function +func (svg *SVG) RotateFunc(r float64, gen Snippetspec) { + svg.Rotate(r) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// TranslateRotate translates the coordinate system to (x, y), then rotates to r degrees for a group +// containing the contents generated by the gen function +func (svg *SVG) TranslateRotateFunc(x, y int, r float64, gen Snippetspec) { + svg.TranslateRotate(x, y, r) + svg.genbuff(gen) + svg.Gend() +} + // 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)) } +// RotateTranslate rotates the coordinate system r degrees, then translate to (x, y) for a group +// containing the contents generated by the gen function +func (svg *SVG) RotateTranslateFunc(x, y int, r float64, gen Snippetspec) { + svg.RotateTranslate(x, y, r) + svg.genbuff(gen) + svg.Gend() +} + // Group begins a group with arbitrary attributes func (svg *SVG) Group(s ...string) { svg.printf("`)) } +// Group begins a group with arbitrary attributes for a group containing the contents generated by the +// gen function +func (svg *SVG) GroupFunc(gen Snippetspec, s ...string) { + svg.Group(s...) + svg.genbuff(gen) + svg.Gend() +} + // Gid begins a group, with the specified id func (svg *SVG) Gid(s string) { svg.print(``) } +// Gid begins a group with the specified id containing the contents generated by the gen function +func (svg *SVG) GidFunc(gen Snippetspec, s string) { + svg.Gid(s) + svg.genbuff(gen) + svg.Gend() +} + // 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(``)) } +// ClipPathFunc defines a clip path containing the contents generated by the gen function +func (svg *SVG) ClipPathFunc(gen Snippetspec, s ...string) { + svg.ClipPath(s...) + svg.genbuff(gen) + svg.ClipEnd() +} + // ClipEnd ends a ClipPath func (svg *SVG) ClipEnd() { svg.println(``) @@ -231,6 +406,13 @@ func (svg *SVG) ClipEnd() { // Standard Reference: http://www.w3.org/TR/SVG11/struct.html#DefsElement func (svg *SVG) Def() { svg.println(``) } +// DefFunc defines a definition block containing the contents generated by the gen function +func (svg *SVG) DefFunc(gen Snippetspec) { + svg.Def() + svg.genbuff(gen) + svg.DefEnd() +} + // DefEnd ends a defintion block. func (svg *SVG) DefEnd() { svg.println(``) } @@ -241,6 +423,13 @@ func (svg *SVG) Marker(id string, x, y, width, height int, s ...string) { id, x, y, width, height, endstyle(s, ">\n")) } +// MarkerFunc defines a marker containing the contents generated by the gen function +func (svg *SVG) MarkerFunc(id string, x, y, width, height int, gen Snippetspec, s ...string) { + svg.Marker(id, x, y, width, height, s...) + svg.genbuff(gen) + svg.MarkerEnd() +} + // MarkerEnd ends a marker func (svg *SVG) MarkerEnd() { svg.println(``) } @@ -257,6 +446,13 @@ func (svg *SVG) Pattern(id string, x, y, width, height int, putype string, s ... id, x, y, width, height, puattr, endstyle(s, ">\n")) } +// PatternFunc defines a pattern containing the contents generated by the gen function +func (svg *SVG) PatternFunc(id string, x, y, width, height int, putype string, gen Snippetspec, s ...string) { + svg.Pattern(id, x, y, width, height, putype, s...) + svg.genbuff(gen) + svg.PatternEnd() +} + // PatternEnd ends a marker func (svg *SVG) PatternEnd() { svg.println(``) } @@ -276,6 +472,13 @@ func (svg *SVG) Link(href string, title string) { svg.println("\">") } +// LinkFunc defines a link containing the contents generated by the gen function +func (svg *SVG) LinkFunc(href string, title string, gen Snippetspec) { + svg.Link(href, title) + svg.genbuff(gen) + svg.LinkEnd() +} + // LinkEnd ends a link. func (svg *SVG) LinkEnd() { svg.println(``) } @@ -290,6 +493,13 @@ func (svg *SVG) Mask(id string, x int, y int, w int, h int, s ...string) { svg.printf(``)) } +// LinkFunc defines a link containing the contents generated by the gen function +func (svg *SVG) MaskFunc(id string, x, y, w, h int, gen Snippetspec, s ...string) { + svg.Mask(id, x, y, w, y, s...) + svg.genbuff(gen) + svg.MaskEnd() +} + // MaskEnd ends a Mask. func (svg *SVG) MaskEnd() { svg.println(``) } @@ -301,6 +511,12 @@ func (svg *SVG) Circle(x int, y int, r int, s ...string) { svg.printf(``) } +// TextStart draws text using the style specified in s, end with TextEnd() +// Standard Reference: http://www.w3.org/TR/SVG11/text.html#TextElement +func (svg *SVG) TextStart(s ...string) { + svg.printf(`")) +} + +func (svg *SVG) TextRaw(t string) { + xml.Escape(svg.Writer, []byte(t)) +} + +func (svg *SVG) TextFunc(gen Snippetspec, s ...string) { + svg.TextStart(s...) + svg.genbuff(gen) + svg.TextEnd() +} + // Textspan begins text, assuming a tspan will be included, end with TextEnd() // Standard Reference: https://www.w3.org/TR/SVG11/text.html#TSpanElement func (svg *SVG) Textspan(x int, y int, t string, s ...string) { @@ -418,6 +650,14 @@ func (svg *SVG) Textspan(x int, y int, t string, s ...string) { xml.Escape(svg.Writer, []byte(t)) } +// TextspanFunc draws text at a specified location containing the contents generated by the gen function +// Standard Reference: https://www.w3.org/TR/SVG11/text.html#TSpanElement +func (svg *SVG) TextspanFunc(x int, y int, gen Snippetspec, s ...string) { + svg.TextStart(append(s, loc(x, y))...) + svg.genbuff(gen) + svg.TextEnd() +} + // Span makes styled spanned text, should be proceeded by Textspan // Standard Reference: https://www.w3.org/TR/SVG11/text.html#TSpanElement func (svg *SVG) Span(t string, s ...string) { @@ -430,6 +670,24 @@ func (svg *SVG) Span(t string, s ...string) { svg.printf(``) } +// Span makes styled spanned text, should be proceeded by Textspan +// Standard Reference: https://www.w3.org/TR/SVG11/text.html#TSpanElement +func (svg *SVG) SpanRaw(s ...string) { + svg.printf(`")) +} + +func (svg *SVG) SpanFunc(gen Snippetspec, s ...string) { + svg.SpanRaw(s...) + svg.genbuff(gen) + svg.SpanEnd() +} + +// SpanEnd ends a SpanRaw +// Standard Reference: https://www.w3.org/TR/SVG11/text.html#TSpanElement +func (svg *SVG) SpanEnd() { + svg.printf(``) +} + // TextEnd ends spanned text // Standard Reference: https://www.w3.org/TR/SVG11/text.html#TSpanElement func (svg *SVG) TextEnd() { @@ -444,6 +702,22 @@ func (svg *SVG) Textpath(t string, pathid string, s ...string) { 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) TextpathRaw(pathid string, s ...string) { + svg.printf("")) +} + +func (svg *SVG) TextpathFunc(pathid string, gen Snippetspec, s ...string) { + svg.TextpathRaw(pathid, s...) + svg.genbuff(gen) + svg.TextPathEnd() +} + +func (svg *SVG) TextPathEnd() { + 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) { @@ -511,6 +785,13 @@ func (svg *SVG) Filter(id string, s ...string) { svg.printf(`\n")) } +// FilterFunc creates a filter containing the contents generated by the gen function +func (svg *SVG) FilterFunc(id string, gen Snippetspec, s ...string) { + svg.Filter(id, s...) + svg.genbuff(gen) + svg.Fend() +} + // Fend ends a filter set // Standard reference: http://www.w3.org/TR/SVG11/filters.html#FilterElement func (svg *SVG) Fend() { @@ -573,6 +854,13 @@ func (svg *SVG) FeComponentTransfer() { svg.println(``) } +// FeComponentTransferEnd creates a feComponent filter with the contents generated by the gen function +func (svg *SVG) FeComponentTransferFunc(gen Snippetspec) { + svg.FeComponentTransfer() + svg.genbuff(gen) + svg.FeCompEnd() +} + // FeCompEnd ends a feComponent filter element // Standard reference: http://www.w3.org/TR/SVG11/filters.html#feComponentTransferElement func (svg *SVG) FeCompEnd() { @@ -610,6 +898,13 @@ func (svg *SVG) FeDiffuseLighting(fs Filterspec, scale, constant float64, s ...s fsattr(fs), scale, constant, endstyle(s, `>`)) } +// FeDiffuseLightingFunc creates a diffulse lighting filter with the contents generated by the gen function +func (svg *SVG) FeDiffuseLightingFunc(fs Filterspec, scale, constant float64, gen Snippetspec, s ...string) { + svg.FeDiffuseLighting(fs, scale, constant, s...) + svg.genbuff(gen) + svg.FeDiffEnd() +} + // FeDiffEnd ends a diffuse lighting filter primitive container // Standard reference: http://www.w3.org/TR/SVG11/filters.html#feDiffuseLightingElement func (svg *SVG) FeDiffEnd() { @@ -733,6 +1028,13 @@ func (svg *SVG) FeSpecularLighting(fs Filterspec, scale, constant float64, expon fsattr(fs), scale, constant, exponent, color, endstyle(s, ">\n")) } +// FeSpecularLightingFunc creates a specular lighting filter with the contents generated by the gen function +func (svg *SVG) FeSpecularLightingFunc(fs Filterspec, scale, constant float64, exponent int, color string, gen Snippetspec, s ...string) { + svg.FeSpecularLighting(fs, scale, constant, exponent, color, s...) + svg.genbuff(gen) + svg.FeSpecEnd() +} + // FeSpecEnd ends a specular lighting filter primitive container // Standard reference: http://www.w3.org/TR/SVG11/filters.html#feSpecularLightingElement func (svg *SVG) FeSpecEnd() {