From 3bcf9e0320bec460def49707af2ac444d4b94bb0 Mon Sep 17 00:00:00 2001 From: Michael Fogleman Date: Wed, 20 Feb 2019 16:47:39 -0500 Subject: [PATCH] Add SetDashOffset. Close #64. --- README.md | 1 + context.go | 9 ++++++++- path.go | 29 ++++++++++++++++++++++++++--- 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6cef251..575f0ec 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,7 @@ SetLineWidth(lineWidth float64) SetLineCap(lineCap LineCap) SetLineJoin(lineJoin LineJoin) SetDash(dashes ...float64) +SetDashOffset(offset float64) SetFillRule(fillRule FillRule) ``` diff --git a/context.go b/context.go index 65d04ca..427406e 100644 --- a/context.go +++ b/context.go @@ -67,6 +67,7 @@ type Context struct { current Point hasCurrent bool dashes []float64 + dashOffset float64 lineWidth float64 lineCap LineCap lineJoin LineJoin @@ -151,6 +152,12 @@ func (dc *Context) SetDash(dashes ...float64) { dc.dashes = dashes } +// SetDashOffset sets the initial offset into the dash pattern to use when +// stroking dashed paths. +func (dc *Context) SetDashOffset(offset float64) { + dc.dashOffset = offset +} + func (dc *Context) SetLineWidth(lineWidth float64) { dc.lineWidth = lineWidth } @@ -389,7 +396,7 @@ func (dc *Context) joiner() raster.Joiner { func (dc *Context) stroke(painter raster.Painter) { path := dc.strokePath if len(dc.dashes) > 0 { - path = dashed(path, dc.dashes) + path = dashed(path, dc.dashes, dc.dashOffset) } else { // TODO: this is a temporary workaround to remove tiny segments // that result in rendering issues diff --git a/path.go b/path.go index 74785b6..dfd3f81 100644 --- a/path.go +++ b/path.go @@ -1,6 +1,8 @@ package gg import ( + "math" + "github.com/golang/freetype/raster" "golang.org/x/image/math/fixed" ) @@ -57,7 +59,7 @@ func flattenPath(p raster.Path) [][]Point { return result } -func dashPath(paths [][]Point, dashes []float64) [][]Point { +func dashPath(paths [][]Point, dashes []float64, offset float64) [][]Point { var result [][]Point if len(dashes) == 0 { return paths @@ -73,6 +75,27 @@ func dashPath(paths [][]Point, dashes []float64) [][]Point { pathIndex := 1 dashIndex := 0 segmentLength := 0.0 + + // offset + if offset != 0 { + var totalLength float64 + for _, dashLength := range dashes { + totalLength += dashLength + } + offset = math.Mod(offset, totalLength) + if offset < 0 { + offset += totalLength + } + for i, dashLength := range dashes { + offset -= dashLength + if offset < 0 { + dashIndex = i + segmentLength = dashLength + offset + break + } + } + } + var segment []Point segment = append(segment, previous) for pathIndex < len(path) { @@ -135,6 +158,6 @@ func rasterPath(paths [][]Point) raster.Path { return result } -func dashed(path raster.Path, dashes []float64) raster.Path { - return rasterPath(dashPath(flattenPath(path), dashes)) +func dashed(path raster.Path, dashes []float64, offset float64) raster.Path { + return rasterPath(dashPath(flattenPath(path), dashes, offset)) }