a color type that actually works.
This commit is contained in:
parent
0da2b41a9d
commit
1357950324
10 changed files with 181 additions and 69 deletions
2
chart.go
2
chart.go
|
@ -350,7 +350,7 @@ func (c Chart) drawSeries(r Renderer, canvasBox Box, index int, s Series, xrange
|
|||
var x, y int
|
||||
|
||||
fill := s.GetStyle().GetFillColor()
|
||||
if !ColorIsZero(fill) {
|
||||
if !fill.IsZero() {
|
||||
r.SetFillColor(fill)
|
||||
r.MoveTo(x0+cx, y0+cy)
|
||||
for i := 1; i < s.Len(); i++ {
|
||||
|
|
30
defaults.go
30
defaults.go
|
@ -1,10 +1,10 @@
|
|||
package chart
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"sync"
|
||||
|
||||
"github.com/golang/freetype/truetype"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -47,44 +47,44 @@ const (
|
|||
var (
|
||||
// DefaultBackgroundColor is the default chart background color.
|
||||
// It is equivalent to css color:white.
|
||||
DefaultBackgroundColor = color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
||||
DefaultBackgroundColor = drawing.Color{R: 255, G: 255, B: 255, A: 255}
|
||||
// DefaultBackgroundStrokeColor is the default chart border color.
|
||||
// It is equivalent to color:white.
|
||||
DefaultBackgroundStrokeColor = color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
||||
DefaultBackgroundStrokeColor = drawing.Color{R: 255, G: 255, B: 255, A: 255}
|
||||
// DefaultCanvasColor is the default chart canvas color.
|
||||
// It is equivalent to css color:white.
|
||||
DefaultCanvasColor = color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
||||
DefaultCanvasColor = drawing.Color{R: 255, G: 255, B: 255, A: 255}
|
||||
// DefaultCanvasStrokColor is the default chart canvas stroke color.
|
||||
// It is equivalent to css color:white.
|
||||
DefaultCanvasStrokColor = color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
||||
DefaultCanvasStrokColor = drawing.Color{R: 255, G: 255, B: 255, A: 255}
|
||||
// DefaultTextColor is the default chart text color.
|
||||
// It is equivalent to #333333.
|
||||
DefaultTextColor = color.RGBA{R: 51, G: 51, B: 51, A: 255}
|
||||
DefaultTextColor = drawing.Color{R: 51, G: 51, B: 51, A: 255}
|
||||
// DefaultAxisColor is the default chart axis line color.
|
||||
// It is equivalent to #333333.
|
||||
DefaultAxisColor = color.RGBA{R: 51, G: 51, B: 51, A: 255}
|
||||
DefaultAxisColor = drawing.Color{R: 51, G: 51, B: 51, A: 255}
|
||||
// DefaultStrokeColor is the default chart border color.
|
||||
// It is equivalent to #efefef.
|
||||
DefaultStrokeColor = color.RGBA{R: 239, G: 239, B: 239, A: 255}
|
||||
DefaultStrokeColor = drawing.Color{R: 239, G: 239, B: 239, A: 255}
|
||||
// DefaultFillColor is the default fill color.
|
||||
// It is equivalent to #0074d9.
|
||||
DefaultFillColor = color.RGBA{R: 0, G: 217, B: 116, A: 255}
|
||||
DefaultFillColor = drawing.Color{R: 0, G: 217, B: 116, A: 255}
|
||||
// DefaultFinalLabelBackgroundColor is the default final label background color.
|
||||
DefaultFinalLabelBackgroundColor = color.RGBA{R: 255, G: 255, B: 255, A: 255}
|
||||
DefaultFinalLabelBackgroundColor = drawing.Color{R: 255, G: 255, B: 255, A: 255}
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultSeriesStrokeColors are a couple default series colors.
|
||||
DefaultSeriesStrokeColors = []color.RGBA{
|
||||
color.RGBA{R: 0, G: 116, B: 217, A: 255},
|
||||
color.RGBA{R: 0, G: 217, B: 116, A: 255},
|
||||
color.RGBA{R: 217, G: 0, B: 116, A: 255},
|
||||
DefaultSeriesStrokeColors = []drawing.Color{
|
||||
drawing.Color{R: 0, G: 116, B: 217, A: 255},
|
||||
drawing.Color{R: 0, G: 217, B: 116, A: 255},
|
||||
drawing.Color{R: 217, G: 0, B: 116, A: 255},
|
||||
}
|
||||
)
|
||||
|
||||
// GetDefaultSeriesStrokeColor returns a color from the default list by index.
|
||||
// NOTE: the index will wrap around (using a modulo).g
|
||||
func GetDefaultSeriesStrokeColor(index int) color.RGBA {
|
||||
func GetDefaultSeriesStrokeColor(index int) drawing.Color {
|
||||
finalIndex := index % len(DefaultSeriesStrokeColors)
|
||||
return DefaultSeriesStrokeColors[finalIndex]
|
||||
}
|
||||
|
|
85
drawing/color.go
Normal file
85
drawing/color.go
Normal file
|
@ -0,0 +1,85 @@
|
|||
package drawing
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var (
|
||||
// ColorTransparent is a fully transparent color.
|
||||
ColorTransparent = Color{}
|
||||
|
||||
// ColorWhite is white.
|
||||
ColorWhite = Color{R: 255, G: 255, B: 255, A: 255}
|
||||
|
||||
// ColorBlack is black.
|
||||
ColorBlack = Color{R: 0, G: 0, B: 0, A: 255}
|
||||
|
||||
// ColorRed is red.
|
||||
ColorRed = Color{R: 255, G: 0, B: 0, A: 255}
|
||||
|
||||
// ColorGreen is green.
|
||||
ColorGreen = Color{R: 0, G: 255, B: 0, A: 255}
|
||||
|
||||
// ColorBlue is blue.
|
||||
ColorBlue = Color{R: 0, G: 0, B: 255, A: 255}
|
||||
)
|
||||
|
||||
func parseHex(hex string) uint8 {
|
||||
v, _ := strconv.ParseInt(hex, 16, 16)
|
||||
return uint8(v)
|
||||
}
|
||||
|
||||
// ColorFromHex returns a color from a css hex code.
|
||||
func ColorFromHex(hex string) Color {
|
||||
var c Color
|
||||
if len(hex) == 3 {
|
||||
c.R = parseHex(string(hex[0])) * 0x11
|
||||
c.G = parseHex(string(hex[1])) * 0x11
|
||||
c.B = parseHex(string(hex[2])) * 0x11
|
||||
} else {
|
||||
c.R = parseHex(string(hex[0:2]))
|
||||
c.G = parseHex(string(hex[2:4]))
|
||||
c.B = parseHex(string(hex[4:6]))
|
||||
}
|
||||
c.A = 255
|
||||
return c
|
||||
}
|
||||
|
||||
// Color is our internal color type because color.Color is bullshit.
|
||||
type Color struct {
|
||||
R uint8
|
||||
G uint8
|
||||
B uint8
|
||||
A uint8
|
||||
}
|
||||
|
||||
// RGBA returns the color as a pre-alpha mixed color set.
|
||||
func (c Color) RGBA() (r, g, b, a uint32) {
|
||||
fa := float64(c.A) / 255.0
|
||||
r = uint32(float64(uint32(c.R)) * fa)
|
||||
r |= r << 8
|
||||
g = uint32(float64(uint32(c.G)) * fa)
|
||||
g |= g << 8
|
||||
b = uint32(float64(uint32(c.B)) * fa)
|
||||
b |= b << 8
|
||||
a = uint32(c.A)
|
||||
a |= a << 8
|
||||
return
|
||||
}
|
||||
|
||||
// IsZero returns if the color has been set or not.
|
||||
func (c Color) IsZero() bool {
|
||||
return c.R == 0 && c.G == 0 && c.B == 0 && c.A == 0
|
||||
}
|
||||
|
||||
// IsTransparent returns if the colors alpha channel is zero.
|
||||
func (c Color) IsTransparent() bool {
|
||||
return c.A == 0
|
||||
}
|
||||
|
||||
// String returns a css string representation of the color.
|
||||
func (c Color) String() string {
|
||||
fa := float64(c.A) / float64(255)
|
||||
return fmt.Sprintf("rgba(%v,%v,%v,%.1f)", c.R, c.G, c.B, fa)
|
||||
}
|
41
drawing/color_test.go
Normal file
41
drawing/color_test.go
Normal file
|
@ -0,0 +1,41 @@
|
|||
package drawing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/blendlabs/go-assert"
|
||||
)
|
||||
|
||||
func TestColorFromHex(t *testing.T) {
|
||||
assert := assert.New(t)
|
||||
|
||||
white := ColorFromHex("FFFFFF")
|
||||
assert.Equal(ColorWhite, white)
|
||||
|
||||
shortWhite := ColorFromHex("FFF")
|
||||
assert.Equal(ColorWhite, shortWhite)
|
||||
|
||||
black := ColorFromHex("000000")
|
||||
assert.Equal(ColorBlack, black)
|
||||
|
||||
shortBlack := ColorFromHex("000")
|
||||
assert.Equal(ColorBlack, shortBlack)
|
||||
|
||||
red := ColorFromHex("FF0000")
|
||||
assert.Equal(ColorRed, red)
|
||||
|
||||
shortRed := ColorFromHex("F00")
|
||||
assert.Equal(ColorRed, shortRed)
|
||||
|
||||
green := ColorFromHex("00FF00")
|
||||
assert.Equal(ColorGreen, green)
|
||||
|
||||
shortGreen := ColorFromHex("0F0")
|
||||
assert.Equal(ColorGreen, shortGreen)
|
||||
|
||||
blue := ColorFromHex("0000FF")
|
||||
assert.Equal(ColorBlue, blue)
|
||||
|
||||
shortBlue := ColorFromHex("00F")
|
||||
assert.Equal(ColorBlue, shortBlue)
|
||||
}
|
|
@ -29,7 +29,7 @@ type rasterRenderer struct {
|
|||
gc *drawing.RasterGraphicContext
|
||||
|
||||
fontSize float64
|
||||
fontColor color.RGBA
|
||||
fontColor color.Color
|
||||
f *truetype.Font
|
||||
}
|
||||
|
||||
|
@ -39,12 +39,12 @@ func (rr *rasterRenderer) SetDPI(dpi float64) {
|
|||
}
|
||||
|
||||
// SetStrokeColor implements the interface method.
|
||||
func (rr *rasterRenderer) SetStrokeColor(c color.RGBA) {
|
||||
func (rr *rasterRenderer) SetStrokeColor(c drawing.Color) {
|
||||
rr.gc.SetStrokeColor(c)
|
||||
}
|
||||
|
||||
// SetFillColor implements the interface method.
|
||||
func (rr *rasterRenderer) SetFillColor(c color.RGBA) {
|
||||
func (rr *rasterRenderer) SetFillColor(c drawing.Color) {
|
||||
rr.gc.SetFillColor(c)
|
||||
}
|
||||
|
||||
|
@ -109,7 +109,7 @@ func (rr *rasterRenderer) SetFontSize(size float64) {
|
|||
}
|
||||
|
||||
// SetFontColor implements the interface method.
|
||||
func (rr *rasterRenderer) SetFontColor(c color.RGBA) {
|
||||
func (rr *rasterRenderer) SetFontColor(c drawing.Color) {
|
||||
rr.fontColor = c
|
||||
rr.gc.SetFillColor(c)
|
||||
rr.gc.SetStrokeColor(c)
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
package chart
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"io"
|
||||
|
||||
"github.com/golang/freetype/truetype"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
)
|
||||
|
||||
// RendererProvider is a function that returns a renderer.
|
||||
|
@ -16,10 +16,10 @@ type Renderer interface {
|
|||
SetDPI(dpi float64)
|
||||
|
||||
// SetStrokeColor sets the current stroke color.
|
||||
SetStrokeColor(color.RGBA)
|
||||
SetStrokeColor(drawing.Color)
|
||||
|
||||
// SetFillColor sets the current fill color.
|
||||
SetFillColor(color.RGBA)
|
||||
SetFillColor(drawing.Color)
|
||||
|
||||
// SetStrokeWidth sets the stroke width.
|
||||
SetStrokeWidth(width float64)
|
||||
|
@ -50,7 +50,7 @@ type Renderer interface {
|
|||
SetFont(*truetype.Font)
|
||||
|
||||
// SetFontColor sets a font's color
|
||||
SetFontColor(color.RGBA)
|
||||
SetFontColor(drawing.Color)
|
||||
|
||||
// SetFontSize sets the font size for a text field.
|
||||
SetFontSize(size float64)
|
||||
|
|
39
style.go
39
style.go
|
@ -2,7 +2,6 @@ package chart
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"strings"
|
||||
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
|
@ -11,37 +10,37 @@ import (
|
|||
// Style is a simple style set.
|
||||
type Style struct {
|
||||
Show bool
|
||||
StrokeColor color.RGBA
|
||||
FillColor color.RGBA
|
||||
StrokeColor drawing.Color
|
||||
FillColor drawing.Color
|
||||
StrokeWidth float64
|
||||
FontSize float64
|
||||
FontColor color.RGBA
|
||||
FontColor drawing.Color
|
||||
Padding Box
|
||||
}
|
||||
|
||||
// IsZero returns if the object is set or not.
|
||||
func (s Style) IsZero() bool {
|
||||
return ColorIsZero(s.StrokeColor) && ColorIsZero(s.FillColor) && s.StrokeWidth == 0 && s.FontSize == 0
|
||||
return s.StrokeColor.IsZero() && s.FillColor.IsZero() && s.StrokeWidth == 0 && s.FontSize == 0
|
||||
}
|
||||
|
||||
// GetStrokeColor returns the stroke color.
|
||||
func (s Style) GetStrokeColor(defaults ...color.RGBA) color.RGBA {
|
||||
if ColorIsZero(s.StrokeColor) {
|
||||
func (s Style) GetStrokeColor(defaults ...drawing.Color) drawing.Color {
|
||||
if s.StrokeColor.IsZero() {
|
||||
if len(defaults) > 0 {
|
||||
return defaults[0]
|
||||
}
|
||||
return color.RGBA{}
|
||||
return drawing.ColorTransparent
|
||||
}
|
||||
return s.StrokeColor
|
||||
}
|
||||
|
||||
// GetFillColor returns the fill color.
|
||||
func (s Style) GetFillColor(defaults ...color.RGBA) color.RGBA {
|
||||
if ColorIsZero(s.FillColor) {
|
||||
func (s Style) GetFillColor(defaults ...drawing.Color) drawing.Color {
|
||||
if s.FillColor.IsZero() {
|
||||
if len(defaults) > 0 {
|
||||
return defaults[0]
|
||||
}
|
||||
return color.RGBA{}
|
||||
return drawing.ColorTransparent
|
||||
}
|
||||
return s.FillColor
|
||||
}
|
||||
|
@ -69,12 +68,12 @@ func (s Style) GetFontSize(defaults ...float64) float64 {
|
|||
}
|
||||
|
||||
// GetFontColor gets the font size.
|
||||
func (s Style) GetFontColor(defaults ...color.RGBA) color.RGBA {
|
||||
if ColorIsZero(s.FontColor) {
|
||||
func (s Style) GetFontColor(defaults ...drawing.Color) drawing.Color {
|
||||
if s.FontColor.IsZero() {
|
||||
if len(defaults) > 0 {
|
||||
return defaults[0]
|
||||
}
|
||||
return color.RGBA{}
|
||||
return drawing.ColorTransparent
|
||||
}
|
||||
return s.FontColor
|
||||
}
|
||||
|
@ -93,13 +92,13 @@ func (s Style) SVG(dpi float64) string {
|
|||
}
|
||||
|
||||
strokeText := "stroke:none"
|
||||
if !ColorIsZero(sc) {
|
||||
strokeText = "stroke:" + ColorAsString(sc)
|
||||
if !sc.IsZero() {
|
||||
strokeText = "stroke:" + sc.String()
|
||||
}
|
||||
|
||||
fillText := "fill:none"
|
||||
if !ColorIsZero(fc) {
|
||||
fillText = "fill:" + ColorAsString(fc)
|
||||
if !fc.IsZero() {
|
||||
fillText = "fill:" + fc.String()
|
||||
}
|
||||
|
||||
fontSizeText := ""
|
||||
|
@ -107,8 +106,8 @@ func (s Style) SVG(dpi float64) string {
|
|||
fontSizeText = "font-size:" + fmt.Sprintf("%.1fpx", drawing.PointsToPixels(dpi, fs))
|
||||
}
|
||||
|
||||
if !ColorIsZero(fnc) {
|
||||
fillText = "fill:" + ColorAsString(fnc)
|
||||
if !fnc.IsZero() {
|
||||
fillText = "fill:" + fnc.String()
|
||||
}
|
||||
return strings.Join([]string{strokeWidthText, strokeText, fillText, fontSizeText}, ";")
|
||||
}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/wcharczuk/go-chart"
|
||||
"github.com/wcharczuk/go-chart/drawing"
|
||||
"github.com/wcharczuk/go-web"
|
||||
)
|
||||
|
||||
|
@ -46,7 +46,7 @@ func chartHandler(rc *web.RequestContext) web.ControllerResult {
|
|||
XValues: []float64{1.0, 2.0, 3.0, 4.0},
|
||||
YValues: []float64{2.5, 5.0, 2.0, 3.3},
|
||||
Style: chart.Style{
|
||||
FillColor: color.RGBA{R: 0, G: 116, B: 217, A: 255},
|
||||
FillColor: drawing.Color{R: 0, G: 116, B: 217, A: 128},
|
||||
},
|
||||
},
|
||||
chart.ContinuousSeries{
|
||||
|
|
12
util.go
12
util.go
|
@ -2,21 +2,9 @@ package chart
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"image/color"
|
||||
"time"
|
||||
)
|
||||
|
||||
// ColorIsZero returns if a color.RGBA is unset or not.
|
||||
func ColorIsZero(c color.RGBA) bool {
|
||||
return c.R == 0 && c.G == 0 && c.B == 0 && c.A == 0
|
||||
}
|
||||
|
||||
// ColorAsString returns if a color.RGBA is unset or not.
|
||||
func ColorAsString(c color.RGBA) string {
|
||||
a := float64(c.A) / float64(255)
|
||||
return fmt.Sprintf("rgba(%v,%v,%v,%.1f)", c.R, c.G, c.B, a)
|
||||
}
|
||||
|
||||
// MinAndMax returns both the min and max in one pass.
|
||||
func MinAndMax(values ...float64) (min float64, max float64) {
|
||||
if len(values) == 0 {
|
||||
|
|
|
@ -3,7 +3,6 @@ package chart
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"image/color"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
|
@ -43,12 +42,12 @@ func (vr *vectorRenderer) SetDPI(dpi float64) {
|
|||
}
|
||||
|
||||
// SetStrokeColor implements the interface method.
|
||||
func (vr *vectorRenderer) SetStrokeColor(c color.RGBA) {
|
||||
func (vr *vectorRenderer) SetStrokeColor(c drawing.Color) {
|
||||
vr.s.StrokeColor = c
|
||||
}
|
||||
|
||||
// SetFillColor implements the interface method.
|
||||
func (vr *vectorRenderer) SetFillColor(c color.RGBA) {
|
||||
func (vr *vectorRenderer) SetFillColor(c drawing.Color) {
|
||||
vr.s.FillColor = c
|
||||
}
|
||||
|
||||
|
@ -73,22 +72,22 @@ func (vr *vectorRenderer) Close() {
|
|||
|
||||
// Stroke draws the path with no fill.
|
||||
func (vr *vectorRenderer) Stroke() {
|
||||
vr.s.FillColor = color.RGBA{}
|
||||
vr.s.FontColor = color.RGBA{}
|
||||
vr.s.FillColor = drawing.ColorTransparent
|
||||
vr.s.FontColor = drawing.ColorTransparent
|
||||
vr.drawPath()
|
||||
}
|
||||
|
||||
// Fill draws the path with no stroke.
|
||||
func (vr *vectorRenderer) Fill() {
|
||||
vr.s.StrokeColor = color.RGBA{}
|
||||
vr.s.StrokeColor = drawing.ColorTransparent
|
||||
vr.s.StrokeWidth = 0
|
||||
vr.s.FontColor = color.RGBA{}
|
||||
vr.s.FontColor = drawing.ColorTransparent
|
||||
vr.drawPath()
|
||||
}
|
||||
|
||||
// FillStroke draws the path with both fill and stroke.
|
||||
func (vr *vectorRenderer) FillStroke() {
|
||||
vr.s.FontColor = color.RGBA{}
|
||||
vr.s.FontColor = drawing.ColorTransparent
|
||||
vr.drawPath()
|
||||
}
|
||||
|
||||
|
@ -108,7 +107,7 @@ func (vr *vectorRenderer) SetFont(f *truetype.Font) {
|
|||
}
|
||||
|
||||
// SetFontColor implements the interface method.
|
||||
func (vr *vectorRenderer) SetFontColor(c color.RGBA) {
|
||||
func (vr *vectorRenderer) SetFontColor(c drawing.Color) {
|
||||
vr.s.FontColor = c
|
||||
}
|
||||
|
||||
|
@ -130,8 +129,8 @@ func (vr *vectorRenderer) svgFontFace() string {
|
|||
|
||||
// Text draws a text blob.
|
||||
func (vr *vectorRenderer) Text(body string, x, y int) {
|
||||
vr.s.FillColor = color.RGBA{}
|
||||
vr.s.StrokeColor = color.RGBA{}
|
||||
vr.s.FillColor = drawing.ColorTransparent
|
||||
vr.s.StrokeColor = drawing.ColorTransparent
|
||||
vr.s.StrokeWidth = 0
|
||||
vr.c.Text(x, y, body, vr.s.SVG(vr.dpi)+";"+vr.svgFontFace())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue