From 90f962641f712a4f9c72c31a109f02815732f671 Mon Sep 17 00:00:00 2001 From: Drahoslav Date: Tue, 26 Dec 2017 19:38:19 +0100 Subject: [PATCH] Implement basic text drawing in svg context fonts, bounds and string paths not yet implemented --- draw2dsvg/gc.go | 156 ++++++++++++++++++++++++------------------ draw2dsvg/svg.go | 16 +++-- draw2dsvg/xml_test.go | 20 +++--- 3 files changed, 109 insertions(+), 83 deletions(-) diff --git a/draw2dsvg/gc.go b/draw2dsvg/gc.go index 1daa5fe..94d9abe 100644 --- a/draw2dsvg/gc.go +++ b/draw2dsvg/gc.go @@ -46,9 +46,6 @@ func NewGraphicContext(svg *Svg) *GraphicContext { // Clear fills the current canvas with a default transparent color func (gc *GraphicContext) Clear() { gc.svg.Groups = nil - gc.svg.Groups = append(gc.svg.Groups, Group{ - // TODO add background color? - }) } // Stroke strokes the paths with the color specified by SetStrokeColor @@ -69,47 +66,102 @@ func (gc *GraphicContext) FillStroke(paths ...*draw2d.Path) { gc.Current.Path.Clear() } +// FillString draws the text at point (0, 0) +func (gc *GraphicContext) FillString(text string) (cursor float64) { + return gc.FillStringAt(text, 0, 0) +} + +// FillStringAt draws the text at the specified point (x, y) +func (gc *GraphicContext) FillStringAt(text string, x, y float64) (cursor float64) { + return gc.drawString(text, filled, x, y) +} + +// StrokeString draws the contour of the text at point (0, 0) +func (gc *GraphicContext) StrokeString(text string) (cursor float64) { + return gc.StrokeStringAt(text, 0, 0) +} + +// StrokeStringAt draws the contour of the text at point (x, y) +func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (cursor float64) { + return gc.drawString(text, stroked, x, y) +} + +// Save the context and push it to the context stack +func (gc *GraphicContext) Save() { + gc.StackGraphicContext.Save() + // TODO use common transformation group for multiple elements +} + +// Restore remove the current context and restore the last one +func (gc *GraphicContext) Restore() { + gc.StackGraphicContext.Restore() + // TODO use common transformation group for multiple elements +} + +// private funcitons + func (gc *GraphicContext) drawPaths(drawType drawType, paths ...*draw2d.Path) { // create elements svgPath := Path{} + group := gc.newGroup(drawType) + + // set attrs to path element + paths = append(paths, gc.Current.Path) + svgPathsDesc := make([]string, len(paths)) + // multiple pathes has to be joined to single svg path description + // because fill-rule wont work for whole group as excepted + for i, path := range paths { + svgPathsDesc[i] = toSvgPathDesc(path) + } + svgPath.Desc = strings.Join(svgPathsDesc, " ") + + // link to group + group.Paths = []*Path{&svgPath} +} + +func (gc *GraphicContext) drawString(text string, drawType drawType, x, y float64) float64 { + // create elements + svgText := Text{} + group := gc.newGroup(drawType) + + // set attrs to text element + svgText.Text = text + svgText.X = x + svgText.Y = y + // TODO set font + + // link to group + (*group).Texts = []*Text{&svgText} + return 0 +} + +// Creates new group from current context +// append it to svg and return +func (gc *GraphicContext) newGroup(drawType drawType) *Group { group := Group{} - - // set attrs to path - { - paths = append(paths, gc.Current.Path) - svgPathsDesc := make([]string, len(paths)) - // multiple pathes has to be joined to single svg path description - // because fill-rule wont work for whole group as excepted - for i, path := range paths { - svgPathsDesc[i] = toSvgPathDesc(path) - } - svgPath.Desc = strings.Join(svgPathsDesc, " ") - } - // set attrs to group - { - if drawType&stroked == stroked { - group.Stroke = toSvgRGBA(gc.Current.StrokeColor) - group.StrokeWidth = toSvgLength(gc.Current.LineWidth) - group.StrokeLinecap = gc.Current.Cap.String() - group.StrokeLinejoin = gc.Current.Join.String() - if len(gc.Current.Dash) > 0 { - group.StrokeDasharray = toSvgArray(gc.Current.Dash) - group.StrokeDashoffset = toSvgLength(gc.Current.DashOffset) - } + if drawType&stroked == stroked { + group.Stroke = toSvgRGBA(gc.Current.StrokeColor) + group.StrokeWidth = toSvgLength(gc.Current.LineWidth) + group.StrokeLinecap = gc.Current.Cap.String() + group.StrokeLinejoin = gc.Current.Join.String() + if len(gc.Current.Dash) > 0 { + group.StrokeDasharray = toSvgArray(gc.Current.Dash) + group.StrokeDashoffset = toSvgLength(gc.Current.DashOffset) } - - if drawType&filled == filled { - group.Fill = toSvgRGBA(gc.Current.FillColor) - group.FillRule = toSvgFillRule(gc.Current.FillRule) - } - - group.Transform = toSvgTransform(gc.Current.Tr) } - // link elements - group.Paths = []Path{svgPath} - gc.svg.Groups = append(gc.svg.Groups, group) + if drawType&filled == filled { + group.Fill = toSvgRGBA(gc.Current.FillColor) + group.FillRule = toSvgFillRule(gc.Current.FillRule) + } + + group.Transform = toSvgTransform(gc.Current.Tr) + + // link + gc.svg.Groups = append(gc.svg.Groups, &group) + + return &group } /////////////////////////////////////// @@ -135,18 +187,6 @@ func (gc *GraphicContext) DrawImage(image image.Image) { } -// Save the context and push it to the context stack -func (gc *GraphicContext) Save() { - gc.StackGraphicContext.Save() - // TODO use common transformation group for multiple elements -} - -// Restore remove the current context and restore the last one -func (gc *GraphicContext) Restore() { - gc.StackGraphicContext.Restore() - // TODO use common transformation group for multiple elements -} - // ClearRect fills the specified rectangle with a default transparent color func (gc *GraphicContext) ClearRect(x1, y1, x2, y2 int) { @@ -171,23 +211,3 @@ func (gc *GraphicContext) GetStringBounds(s string) (left, top, right, bottom fl func (gc *GraphicContext) CreateStringPath(text string, x, y float64) (cursor float64) { return 0 } - -// FillString draws the text at point (0, 0) -func (gc *GraphicContext) FillString(text string) (cursor float64) { - return 0 -} - -// FillStringAt draws the text at the specified point (x, y) -func (gc *GraphicContext) FillStringAt(text string, x, y float64) (cursor float64) { - return 0 -} - -// StrokeString draws the contour of the text at point (0, 0) -func (gc *GraphicContext) StrokeString(text string) (cursor float64) { - return 0 -} - -// StrokeStringAt draws the contour of the text at point (x, y) -func (gc *GraphicContext) StrokeStringAt(text string, x, y float64) (cursor float64) { - return 0 -} diff --git a/draw2dsvg/svg.go b/draw2dsvg/svg.go index e9a414a..4a22cc6 100644 --- a/draw2dsvg/svg.go +++ b/draw2dsvg/svg.go @@ -12,16 +12,16 @@ import ( type Svg struct { XMLName xml.Name `xml:"svg"` Xmlns string `xml:"xmlns,attr"` - Groups []Group `xml:"g"` + Groups []*Group `xml:"g"` FillStroke } type Group struct { FillStroke - Transform string `xml:"transform,attr,omitempty"` - Groups []Group `xml:"g"` - Paths []Path `xml:"path"` - Texts []Text `xml:"text"` + Transform string `xml:"transform,attr,omitempty"` + Groups []*Group `xml:"g"` + Paths []*Path `xml:"path"` + Texts []*Text `xml:"text"` } type Path struct { @@ -31,12 +31,18 @@ type Path struct { type Text struct { FillStroke + Position Text string `xml:",innerxml"` Style string `xml:"style,attr,omitempty"` } /* shared attrs */ +type Position struct { + X float64 `xml:"x,attr,omitempty"` + Y float64 `xml:"y,attr,omitempty"` +} + type FillStroke struct { Fill string `xml:"fill,attr,omitempty"` FillRule string `xml:"fill-rule,attr,omitempty"` diff --git a/draw2dsvg/xml_test.go b/draw2dsvg/xml_test.go index db22895..b0760e7 100644 --- a/draw2dsvg/xml_test.go +++ b/draw2dsvg/xml_test.go @@ -15,18 +15,18 @@ import ( func TestXml(t *testing.T) { svg := NewSvg() - svg.Groups = []Group{Group{ - Groups: []Group{ - Group{}, // nested groups - Group{}, + svg.Groups = []*Group{&Group{ + Groups: []*Group{ + &Group{}, // nested groups + &Group{}, }, - Texts: []Text{ - Text{Text: "Hello"}, // text - Text{Text: "world", Style: "opacity: 0.5"}, // text with style + Texts: []*Text{ + &Text{Text: "Hello"}, // text + &Text{Text: "world", Style: "opacity: 0.5"}, // text with style }, - Paths: []Path{ - Path{Desc: "M100,200 C100,100 250,100 250,200 S400,300 400,200"}, // simple path - Path{}, // empty path + Paths: []*Path{ + &Path{Desc: "M100,200 C100,100 250,100 250,200 S400,300 400,200"}, // simple path + &Path{}, // empty path }, }}