go-chart/raster_renderer.go

177 lines
3.9 KiB
Go
Raw Normal View History

2016-07-06 21:54:00 -04:00
package chart
import (
"image"
"image/png"
"io"
2016-07-11 21:48:51 -04:00
"math"
2016-07-06 21:54:00 -04:00
"github.com/golang/freetype/truetype"
2016-07-08 20:57:14 -04:00
"github.com/wcharczuk/go-chart/drawing"
2016-07-06 21:54:00 -04:00
)
// PNG returns a new png/raster renderer.
2016-07-08 20:57:14 -04:00
func PNG(width, height int) (Renderer, error) {
2016-07-06 21:54:00 -04:00
i := image.NewRGBA(image.Rect(0, 0, width, height))
2016-07-08 20:57:14 -04:00
gc, err := drawing.NewRasterGraphicContext(i)
if err == nil {
return &rasterRenderer{
i: i,
gc: gc,
}, nil
2016-07-06 21:54:00 -04:00
}
2016-07-08 20:57:14 -04:00
return nil, err
2016-07-06 21:54:00 -04:00
}
2016-07-08 01:18:53 -04:00
// rasterRenderer renders chart commands to a bitmap.
2016-07-06 21:54:00 -04:00
type rasterRenderer struct {
i *image.RGBA
2016-07-08 20:57:14 -04:00
gc *drawing.RasterGraphicContext
2016-07-06 21:54:00 -04:00
s Style
2016-07-08 20:57:14 -04:00
}
2016-07-10 04:11:47 -04:00
// GetDPI returns the dpi.
func (rr *rasterRenderer) GetDPI() float64 {
return rr.gc.GetDPI()
}
2016-07-08 20:57:14 -04:00
// SetDPI implements the interface method.
func (rr *rasterRenderer) SetDPI(dpi float64) {
rr.gc.SetDPI(dpi)
2016-07-06 21:54:00 -04:00
}
// SetStrokeColor implements the interface method.
2016-07-09 14:23:35 -04:00
func (rr *rasterRenderer) SetStrokeColor(c drawing.Color) {
rr.s.StrokeColor = c
2016-07-06 21:54:00 -04:00
}
// SetLineWidth implements the interface method.
2016-07-08 01:18:53 -04:00
func (rr *rasterRenderer) SetStrokeWidth(width float64) {
rr.s.StrokeWidth = width
2016-07-06 21:54:00 -04:00
}
2016-07-11 21:48:51 -04:00
// StrokeDashArray sets the stroke dash array.
func (rr *rasterRenderer) SetStrokeDashArray(dashArray []float64) {
rr.s.StrokeDashArray = dashArray
2016-07-11 21:48:51 -04:00
}
// SetFillColor implements the interface method.
func (rr *rasterRenderer) SetFillColor(c drawing.Color) {
rr.s.FillColor = c
2016-07-11 21:48:51 -04:00
}
2016-07-06 21:54:00 -04:00
// MoveTo implements the interface method.
func (rr *rasterRenderer) MoveTo(x, y int) {
rr.gc.MoveTo(float64(x), float64(y))
}
// LineTo implements the interface method.
func (rr *rasterRenderer) LineTo(x, y int) {
rr.gc.LineTo(float64(x), float64(y))
}
// Close implements the interface method.
func (rr *rasterRenderer) Close() {
rr.gc.Close()
}
// Stroke implements the interface method.
func (rr *rasterRenderer) Stroke() {
rr.gc.SetStrokeColor(rr.s.StrokeColor)
rr.gc.SetLineWidth(rr.s.StrokeWidth)
2016-07-06 21:54:00 -04:00
rr.gc.Stroke()
}
2016-07-07 17:44:03 -04:00
// Fill implements the interface method.
func (rr *rasterRenderer) Fill() {
rr.gc.SetFillColor(rr.s.FillColor)
2016-07-07 17:44:03 -04:00
rr.gc.Fill()
}
2016-07-06 21:54:00 -04:00
// FillStroke implements the interface method.
func (rr *rasterRenderer) FillStroke() {
rr.gc.SetFillColor(rr.s.FillColor)
rr.gc.SetStrokeColor(rr.s.StrokeColor)
rr.gc.SetLineWidth(rr.s.StrokeWidth)
2016-07-06 21:54:00 -04:00
rr.gc.FillStroke()
}
// Circle implements the interface method.
func (rr *rasterRenderer) Circle(radius float64, x, y int) {
xf := float64(x)
yf := float64(y)
rr.gc.MoveTo(xf-radius, yf) //9
rr.gc.QuadCurveTo(xf, yf, xf, yf-radius) //12
rr.gc.QuadCurveTo(xf, yf, xf+radius, yf) //3
rr.gc.QuadCurveTo(xf, yf, xf, yf+radius) //6
rr.gc.QuadCurveTo(xf, yf, xf-radius, yf) //9
rr.gc.Close()
rr.gc.FillStroke()
}
// SetFont implements the interface method.
func (rr *rasterRenderer) SetFont(f *truetype.Font) {
rr.s.Font = f
2016-07-06 21:54:00 -04:00
}
// SetFontSize implements the interface method.
func (rr *rasterRenderer) SetFontSize(size float64) {
rr.s.FontSize = size
2016-07-06 21:54:00 -04:00
}
// SetFontColor implements the interface method.
2016-07-09 14:23:35 -04:00
func (rr *rasterRenderer) SetFontColor(c drawing.Color) {
rr.s.FontColor = c
2016-07-06 21:54:00 -04:00
}
// Text implements the interface method.
func (rr *rasterRenderer) Text(body string, x, y int) {
rr.gc.SetFont(rr.s.Font)
rr.gc.SetFontSize(rr.s.FontSize)
rr.gc.SetFillColor(rr.s.FontColor)
2016-07-06 21:54:00 -04:00
rr.gc.CreateStringPath(body, float64(x), float64(y))
2016-07-07 17:46:52 -04:00
rr.gc.Fill()
2016-07-06 21:54:00 -04:00
}
2016-07-08 20:57:14 -04:00
// MeasureText returns the height and width in pixels of a string.
2016-07-11 21:48:51 -04:00
func (rr *rasterRenderer) MeasureText(body string) Box {
rr.gc.SetFont(rr.s.Font)
rr.gc.SetFontSize(rr.s.FontSize)
rr.gc.SetFillColor(rr.s.FontColor)
2016-07-08 20:57:14 -04:00
l, t, r, b, err := rr.gc.GetStringBounds(body)
if err != nil {
2016-07-11 21:48:51 -04:00
return Box{}
}
if l < 0 {
r = r - l // equivalent to r+(-1*l)
l = 0
}
if t < 0 {
b = b - t
t = 0
}
if l > 0 {
r = r + l
l = 0
}
if t > 0 {
b = b + t
t = 0
}
return Box{
Top: int(math.Ceil(t)),
Left: int(math.Ceil(l)),
Right: int(math.Ceil(r)),
Bottom: int(math.Ceil(b)),
2016-07-06 21:54:00 -04:00
}
}
// Save implements the interface method.
func (rr *rasterRenderer) Save(w io.Writer) error {
return png.Encode(w, rr.i)
}