diff --git a/defaults.go b/defaults.go index 52cbc55..03eefdd 100644 --- a/defaults.go +++ b/defaults.go @@ -91,7 +91,7 @@ func GetDefaultSeriesStrokeColor(index int) color.RGBA { var ( // DefaultFinalLabelPadding is the padding around the final label. - DefaultFinalLabelPadding = Box{Top: 5, Left: 0, Right: 5, Bottom: 5} + DefaultFinalLabelPadding = Box{Top: 5, Left: 0, Right: 7, Bottom: 5} // DefaultBackgroundPadding is the default canvas padding config. DefaultBackgroundPadding = Box{Top: 5, Left: 5, Right: 5, Bottom: 5} ) diff --git a/drawing/constants.go b/drawing/constants.go index 7639b29..2fb154e 100644 --- a/drawing/constants.go +++ b/drawing/constants.go @@ -3,7 +3,4 @@ package drawing const ( // DefaultDPI is the default image DPI. DefaultDPI = 96.0 - - // EMRatio is the ratio of something to something else. - EMRatio = 64.0 / 72.0 ) diff --git a/drawing/raster_graphic_context.go b/drawing/raster_graphic_context.go index a967775..33f11dc 100644 --- a/drawing/raster_graphic_context.go +++ b/drawing/raster_graphic_context.go @@ -149,9 +149,8 @@ func (rgc *RasterGraphicContext) CreateStringPath(s string, x, y float64) (curso return } -// GetStringBounds returns the approximate pixel bounds of a string. -// The the left edge of the em square of the first character of s -// and the baseline intersect at 0, 0 in the returned coordinates. +// GetStringBounds returns the approximate points bounds of a string. +// It will be required to convert points to pixels for measurement. func (rgc *RasterGraphicContext) GetStringBounds(s string) (left, top, right, bottom float64, err error) { f := rgc.GetFont() if f == nil { @@ -192,7 +191,7 @@ func (rgc *RasterGraphicContext) GetStringBounds(s string) (left, top, right, bo // recalc recalculates scale and bounds values from the font size, screen // resolution and font metrics, and invalidates the glyph cache. func (rgc *RasterGraphicContext) recalc() { - rgc.current.Scale = rgc.current.FontSize * float64(rgc.DPI) * EMRatio + rgc.current.Scale = rgc.current.FontSizePoints * float64(rgc.DPI) } // SetFont sets the font used to draw text. @@ -206,8 +205,8 @@ func (rgc *RasterGraphicContext) GetFont() *truetype.Font { } // SetFontSize sets the font size in points (as in ``a 12 point font''). -func (rgc *RasterGraphicContext) SetFontSize(fontSize float64) { - rgc.current.FontSize = fontSize +func (rgc *RasterGraphicContext) SetFontSize(fontSizePoints float64) { + rgc.current.FontSizePoints = fontSizePoints rgc.recalc() } diff --git a/drawing/stack_graphic_context.go b/drawing/stack_graphic_context.go index b03a37d..d353438 100644 --- a/drawing/stack_graphic_context.go +++ b/drawing/stack_graphic_context.go @@ -25,8 +25,8 @@ type ContextStack struct { Cap LineCap Join LineJoin - FontSize float64 - Font *truetype.Font + FontSizePoints float64 + Font *truetype.Font Scale float64 @@ -45,118 +45,145 @@ func NewStackGraphicContext() *StackGraphicContext { gc.current.Cap = RoundCap gc.current.FillRule = FillRuleEvenOdd gc.current.Join = RoundJoin - gc.current.FontSize = 10 + gc.current.FontSizePoints = 10 return gc } +// GetMatrixTransform returns the matrix transform. func (gc *StackGraphicContext) GetMatrixTransform() Matrix { return gc.current.Tr } -func (gc *StackGraphicContext) SetMatrixTransform(Tr Matrix) { - gc.current.Tr = Tr +// SetMatrixTransform sets the matrix transform. +func (gc *StackGraphicContext) SetMatrixTransform(tr Matrix) { + gc.current.Tr = tr } -func (gc *StackGraphicContext) ComposeMatrixTransform(Tr Matrix) { - gc.current.Tr.Compose(Tr) +// ComposeMatrixTransform composes a transform into the current transform. +func (gc *StackGraphicContext) ComposeMatrixTransform(tr Matrix) { + gc.current.Tr.Compose(tr) } +// Rotate rotates the matrix transform by an angle in degrees. func (gc *StackGraphicContext) Rotate(angle float64) { gc.current.Tr.Rotate(angle) } +// Translate translates a transform. func (gc *StackGraphicContext) Translate(tx, ty float64) { gc.current.Tr.Translate(tx, ty) } +// Scale scales a transform. func (gc *StackGraphicContext) Scale(sx, sy float64) { gc.current.Tr.Scale(sx, sy) } +// SetStrokeColor sets the stroke color. func (gc *StackGraphicContext) SetStrokeColor(c color.Color) { gc.current.StrokeColor = c } +// SetFillColor sets the fill color. func (gc *StackGraphicContext) SetFillColor(c color.Color) { gc.current.FillColor = c } +// SetFillRule sets the fill rule. func (gc *StackGraphicContext) SetFillRule(f FillRule) { gc.current.FillRule = f } +// SetLineWidth sets the line width. func (gc *StackGraphicContext) SetLineWidth(lineWidth float64) { gc.current.LineWidth = lineWidth } +// SetLineCap sets the line cap. func (gc *StackGraphicContext) SetLineCap(cap LineCap) { gc.current.Cap = cap } +// SetLineJoin sets the line join. func (gc *StackGraphicContext) SetLineJoin(join LineJoin) { gc.current.Join = join } +// SetLineDash sets the line dash. func (gc *StackGraphicContext) SetLineDash(dash []float64, dashOffset float64) { gc.current.Dash = dash gc.current.DashOffset = dashOffset } -func (gc *StackGraphicContext) SetFontSize(fontSize float64) { - gc.current.FontSize = fontSize +// SetFontSize sets the font size. +func (gc *StackGraphicContext) SetFontSize(fontSizePoints float64) { + gc.current.FontSizePoints = fontSizePoints } +// GetFontSize gets the font size. func (gc *StackGraphicContext) GetFontSize() float64 { - return gc.current.FontSize + return gc.current.FontSizePoints } +// SetFont sets the current font. func (gc *StackGraphicContext) SetFont(f *truetype.Font) { gc.current.Font = f } +// GetFont returns the font. func (gc *StackGraphicContext) GetFont() *truetype.Font { return gc.current.Font } +// BeginPath starts a new path. func (gc *StackGraphicContext) BeginPath() { gc.current.Path.Clear() } +// IsEmpty returns if the path is empty. func (gc *StackGraphicContext) IsEmpty() bool { return gc.current.Path.IsEmpty() } -func (gc *StackGraphicContext) LastPoint() (float64, float64) { +// LastPoint returns the last point on the path. +func (gc *StackGraphicContext) LastPoint() (x float64, y float64) { return gc.current.Path.LastPoint() } +// MoveTo moves the cursor for a path. func (gc *StackGraphicContext) MoveTo(x, y float64) { gc.current.Path.MoveTo(x, y) } +// LineTo draws a line. func (gc *StackGraphicContext) LineTo(x, y float64) { gc.current.Path.LineTo(x, y) } +// QuadCurveTo draws a quad curve. func (gc *StackGraphicContext) QuadCurveTo(cx, cy, x, y float64) { gc.current.Path.QuadCurveTo(cx, cy, x, y) } +// CubicCurveTo draws a cubic curve. func (gc *StackGraphicContext) CubicCurveTo(cx1, cy1, cx2, cy2, x, y float64) { gc.current.Path.CubicCurveTo(cx1, cy1, cx2, cy2, x, y) } +// ArcTo draws an arc. func (gc *StackGraphicContext) ArcTo(cx, cy, rx, ry, startAngle, angle float64) { gc.current.Path.ArcTo(cx, cy, rx, ry, startAngle, angle) } +// Close closes a path. func (gc *StackGraphicContext) Close() { gc.current.Path.Close() } +// Save pushes a context onto the stack. func (gc *StackGraphicContext) Save() { context := new(ContextStack) - context.FontSize = gc.current.FontSize + context.FontSizePoints = gc.current.FontSizePoints context.Font = gc.current.Font context.LineWidth = gc.current.LineWidth context.StrokeColor = gc.current.StrokeColor @@ -174,6 +201,7 @@ func (gc *StackGraphicContext) Save() { gc.current = context } +// Restore restores the previous context. func (gc *StackGraphicContext) Restore() { if gc.current.Previous != nil { oldContext := gc.current diff --git a/drawing/util.go b/drawing/util.go index c4c49c1..1eba3ff 100644 --- a/drawing/util.go +++ b/drawing/util.go @@ -9,6 +9,18 @@ import ( "github.com/golang/freetype/truetype" ) +// PixelsToPoints returns the points for a given number of pixels at a DPI. +func PixelsToPoints(dpi, pixels float64) (points float64) { + points = (pixels * 72.0) / dpi + return +} + +// PointsToPixels returns the pixels for a given number of points at a DPI. +func PointsToPixels(dpi, points float64) (pixels float64) { + pixels = (points * dpi) / 72.0 + return +} + func abs(i int) int { if i < 0 { return -i diff --git a/raster_renderer.go b/raster_renderer.go index 97af3f8..8114fac 100644 --- a/raster_renderer.go +++ b/raster_renderer.go @@ -5,7 +5,6 @@ import ( "image/color" "image/png" "io" - "math" "github.com/golang/freetype/truetype" "github.com/wcharczuk/go-chart/drawing" @@ -130,8 +129,8 @@ func (rr *rasterRenderer) MeasureText(body string) (width int, height int) { } dw := r - l dh := b - t - width = int(math.Ceil(dw * (4.0 / 3.0))) - height = int(math.Ceil(dh * (4.0 / 3.0))) + width = int(drawing.PointsToPixels(rr.gc.GetDPI(), dw)) + height = int(drawing.PointsToPixels(rr.gc.GetDPI(), dh)) return }