diff --git a/bar_chart.go b/bar_chart.go
index f291d78..e008baf 100644
--- a/bar_chart.go
+++ b/bar_chart.go
@@ -54,7 +54,10 @@ func barChartRender(opt barChartOption, result *basicRenderResult) ([]markPointR
margin := 10
// 每一个bar之间的margin
barMargin := 5
- if width < 50 {
+ if width < 20 {
+ margin = 2
+ barMargin = 2
+ } else if width < 50 {
margin = 5
barMargin = 3
}
@@ -95,6 +98,9 @@ func barChartRender(opt barChartOption, result *basicRenderResult) ([]markPointR
})
divideValues := xRange.AutoDivide()
for j, item := range series.Data {
+ if j >= len(divideValues) {
+ continue
+ }
x := divideValues[j]
x += margin
if i != 0 {
diff --git a/bar_chart_test.go b/bar_chart_test.go
index 2351e1a..f10a1bc 100644
--- a/bar_chart_test.go
+++ b/bar_chart_test.go
@@ -23,7 +23,6 @@
package charts
import (
- "fmt"
"testing"
"github.com/stretchr/testify/assert"
@@ -128,6 +127,5 @@ func TestBarChartRender(t *testing.T) {
data, err := d.Bytes()
assert.Nil(err)
- fmt.Println(string(data))
assert.Equal("", string(data))
}
diff --git a/chart.go b/chart.go
index c211a6d..5178b04 100644
--- a/chart.go
+++ b/chart.go
@@ -38,6 +38,11 @@ const (
ChartTypePie = "pie"
)
+const (
+ ChartOutputSVG = "svg"
+ ChartOutputPNG = "png"
+)
+
type Point struct {
X int
Y int
diff --git a/chart_test.go b/chart_test.go
index ee768ec..4fc3d20 100644
--- a/chart_test.go
+++ b/chart_test.go
@@ -23,6 +23,7 @@
package charts
import (
+ "errors"
"testing"
"github.com/stretchr/testify/assert"
@@ -276,3 +277,228 @@ func TestChartRender(t *testing.T) {
assert.Nil(err)
assert.Equal("", string(data))
}
+
+func BenchmarkMultiChartPNGRender(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ opt := ChartOption{
+ Type: ChartOutputPNG,
+ Legend: LegendOption{
+ Top: "-90",
+ Data: []string{
+ "Milk Tea",
+ "Matcha Latte",
+ "Cheese Cocoa",
+ "Walnut Brownie",
+ },
+ },
+ Padding: chart.Box{
+ Top: 100,
+ Right: 10,
+ Bottom: 10,
+ Left: 10,
+ },
+ XAxis: NewXAxisOption([]string{
+ "2012",
+ "2013",
+ "2014",
+ "2015",
+ "2016",
+ "2017",
+ }),
+ YAxisList: []YAxisOption{
+ {
+
+ Min: NewFloatPoint(0),
+ Max: NewFloatPoint(90),
+ },
+ },
+ SeriesList: []Series{
+ NewSeriesFromValues([]float64{
+ 56.5,
+ 82.1,
+ 88.7,
+ 70.1,
+ 53.4,
+ 85.1,
+ }),
+ NewSeriesFromValues([]float64{
+ 51.1,
+ 51.4,
+ 55.1,
+ 53.3,
+ 73.8,
+ 68.7,
+ }),
+ NewSeriesFromValues([]float64{
+ 40.1,
+ 62.2,
+ 69.5,
+ 36.4,
+ 45.2,
+ 32.5,
+ }, ChartTypeBar),
+ NewSeriesFromValues([]float64{
+ 25.2,
+ 37.1,
+ 41.2,
+ 18,
+ 33.9,
+ 49.1,
+ }, ChartTypeBar),
+ },
+ Children: []ChartOption{
+ {
+ Legend: LegendOption{
+ Show: FalseFlag(),
+ Data: []string{
+ "Milk Tea",
+ "Matcha Latte",
+ "Cheese Cocoa",
+ "Walnut Brownie",
+ },
+ },
+ Box: chart.Box{
+ Top: 20,
+ Left: 400,
+ Right: 500,
+ Bottom: 120,
+ },
+ SeriesList: NewPieSeriesList([]float64{
+ 435.9,
+ 354.3,
+ 285.9,
+ 204.5,
+ }, PieSeriesOption{
+ Label: SeriesLabel{
+ Show: true,
+ },
+ Radius: "35%",
+ }),
+ },
+ },
+ }
+ d, err := Render(opt)
+ if err != nil {
+ panic(err)
+ }
+ buf, err := d.Bytes()
+ if err != nil {
+ panic(err)
+ }
+ if len(buf) == 0 {
+ panic(errors.New("data is nil"))
+ }
+ }
+}
+
+func BenchmarkMultiChartSVGRender(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ opt := ChartOption{
+ Legend: LegendOption{
+ Top: "-90",
+ Data: []string{
+ "Milk Tea",
+ "Matcha Latte",
+ "Cheese Cocoa",
+ "Walnut Brownie",
+ },
+ },
+ Padding: chart.Box{
+ Top: 100,
+ Right: 10,
+ Bottom: 10,
+ Left: 10,
+ },
+ XAxis: NewXAxisOption([]string{
+ "2012",
+ "2013",
+ "2014",
+ "2015",
+ "2016",
+ "2017",
+ }),
+ YAxisList: []YAxisOption{
+ {
+
+ Min: NewFloatPoint(0),
+ Max: NewFloatPoint(90),
+ },
+ },
+ SeriesList: []Series{
+ NewSeriesFromValues([]float64{
+ 56.5,
+ 82.1,
+ 88.7,
+ 70.1,
+ 53.4,
+ 85.1,
+ }),
+ NewSeriesFromValues([]float64{
+ 51.1,
+ 51.4,
+ 55.1,
+ 53.3,
+ 73.8,
+ 68.7,
+ }),
+ NewSeriesFromValues([]float64{
+ 40.1,
+ 62.2,
+ 69.5,
+ 36.4,
+ 45.2,
+ 32.5,
+ }, ChartTypeBar),
+ NewSeriesFromValues([]float64{
+ 25.2,
+ 37.1,
+ 41.2,
+ 18,
+ 33.9,
+ 49.1,
+ }, ChartTypeBar),
+ },
+ Children: []ChartOption{
+ {
+ Legend: LegendOption{
+ Show: FalseFlag(),
+ Data: []string{
+ "Milk Tea",
+ "Matcha Latte",
+ "Cheese Cocoa",
+ "Walnut Brownie",
+ },
+ },
+ Box: chart.Box{
+ Top: 20,
+ Left: 400,
+ Right: 500,
+ Bottom: 120,
+ },
+ SeriesList: NewPieSeriesList([]float64{
+ 435.9,
+ 354.3,
+ 285.9,
+ 204.5,
+ }, PieSeriesOption{
+ Label: SeriesLabel{
+ Show: true,
+ },
+ Radius: "35%",
+ }),
+ },
+ },
+ }
+ d, err := Render(opt)
+ if err != nil {
+ panic(err)
+ }
+ buf, err := d.Bytes()
+ if err != nil {
+ panic(err)
+ }
+ if len(buf) == 0 {
+ panic(errors.New("data is nil"))
+ }
+ }
+}
diff --git a/draw.go b/draw.go
index 228f622..bc3d9e8 100644
--- a/draw.go
+++ b/draw.go
@@ -114,7 +114,7 @@ func NewDraw(opt DrawOption, opts ...Option) (*Draw, error) {
// 创建render
if d.parent == nil {
fn := chart.SVG
- if opt.Type == "png" {
+ if opt.Type == ChartOutputPNG {
fn = chart.PNG
}
r, err := fn(d.Box.Right, d.Box.Bottom)
diff --git a/echarts.go b/echarts.go
index 9232ed7..dc2e761 100644
--- a/echarts.go
+++ b/echarts.go
@@ -76,12 +76,14 @@ type EChartsSeriesData struct {
}
type _EChartsSeriesData EChartsSeriesData
+var numericRep = regexp.MustCompile("^[-+]?[0-9]+(?:\\.[0-9]+)?$")
+
func (es *EChartsSeriesData) UnmarshalJSON(data []byte) error {
data = bytes.TrimSpace(data)
if len(data) == 0 {
return nil
}
- if regexp.MustCompile(`^\d+`).Match(data) {
+ if numericRep.Match(data) {
v, err := strconv.ParseFloat(string(data), 64)
if err != nil {
return err
@@ -215,16 +217,20 @@ type EChartsMarkPoint struct {
}
func (emp *EChartsMarkPoint) ToSeriesMarkPoint() SeriesMarkPoint {
+ sp := SeriesMarkPoint{
+ SymbolSize: emp.SymbolSize,
+ }
+ if len(emp.Data) == 0 {
+ return sp
+ }
data := make([]SeriesMarkData, len(emp.Data))
for index, item := range emp.Data {
data[index] = SeriesMarkData{
Type: item.Type,
}
}
- return SeriesMarkPoint{
- Data: data,
- SymbolSize: emp.SymbolSize,
- }
+ sp.Data = data
+ return sp
}
type EChartsMarkLine struct {
@@ -234,15 +240,18 @@ type EChartsMarkLine struct {
}
func (eml *EChartsMarkLine) ToSeriesMarkLine() SeriesMarkLine {
+ sl := SeriesMarkLine{}
+ if len(eml.Data) == 0 {
+ return sl
+ }
data := make([]SeriesMarkData, len(eml.Data))
for index, item := range eml.Data {
data[index] = SeriesMarkData{
Type: item.Type,
}
}
- return SeriesMarkLine{
- Data: data,
- }
+ sl.Data = data
+ return sl
}
type EChartsSeries struct {
@@ -260,8 +269,27 @@ type EChartsSeries struct {
type EChartsSeriesList []EChartsSeries
func (esList EChartsSeriesList) ToSeriesList() SeriesList {
- seriesList := make(SeriesList, len(esList))
- for index, item := range esList {
+ seriesList := make(SeriesList, 0, len(esList))
+ for _, item := range esList {
+ // 如果是pie,则每个子荐生成一个series
+ if item.Type == ChartTypePie {
+ for _, dataItem := range item.Data {
+ seriesList = append(seriesList, Series{
+ Type: ChartTypePie,
+ Name: dataItem.Name,
+ Label: SeriesLabel{
+ Show: true,
+ },
+ Radius: item.Radius,
+ Data: []SeriesData{
+ {
+ Value: dataItem.Value,
+ },
+ },
+ })
+ }
+ continue
+ }
data := make([]SeriesData, len(item.Data))
for j, dataItem := range item.Data {
data[j] = SeriesData{
@@ -269,7 +297,7 @@ func (esList EChartsSeriesList) ToSeriesList() SeriesList {
Style: dataItem.ItemStyle.ToStyle(),
}
}
- seriesList[index] = Series{
+ seriesList = append(seriesList, Series{
Type: item.Type,
Data: data,
YAxisIndex: item.YAxisIndex,
@@ -280,10 +308,9 @@ func (esList EChartsSeriesList) ToSeriesList() SeriesList {
Distance: item.Label.Distance,
},
Name: item.Name,
- Radius: item.Radius,
MarkPoint: item.MarkPoint.ToSeriesMarkPoint(),
MarkLine: item.MarkLine.ToSeriesMarkLine(),
- }
+ })
}
return seriesList
}
@@ -295,10 +322,14 @@ type EChartsTextStyle struct {
}
func (et *EChartsTextStyle) ToStyle() chart.Style {
- return chart.Style{
+ s := chart.Style{
FontSize: et.FontSize,
FontColor: parseColor(et.Color),
}
+ if et.FontFamily != "" {
+ s.Font, _ = GetFont(et.FontFamily)
+ }
+ return s
}
type EChartsOption struct {
@@ -373,6 +404,7 @@ func (eo *EChartsOption) ToOption() ChartOption {
Color: parseColor(item.AxisLine.LineStyle.Color),
}
}
+ o.YAxisList = yAxisOptions
if len(eo.Children) != 0 {
o.Children = make([]ChartOption, len(eo.Children))
diff --git a/echarts_test.go b/echarts_test.go
index 3cefb5a..d80ecbb 100644
--- a/echarts_test.go
+++ b/echarts_test.go
@@ -28,6 +28,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/wcharczuk/go-chart/v2"
+ "github.com/wcharczuk/go-chart/v2/drawing"
)
func TestEChartsPosition(t *testing.T) {
@@ -42,6 +43,24 @@ func TestEChartsPosition(t *testing.T) {
assert.Nil(err)
assert.Equal("12%", string(p))
}
+func TestEChartStyle(t *testing.T) {
+ assert := assert.New(t)
+
+ s := EChartStyle{
+ Color: "#aaa",
+ }
+ r := drawing.Color{
+ R: 170,
+ G: 170,
+ B: 170,
+ A: 255,
+ }
+ assert.Equal(chart.Style{
+ FillColor: r,
+ FontColor: r,
+ StrokeColor: r,
+ }, s.ToStyle())
+}
func TestEChartsXAxis(t *testing.T) {
assert := assert.New(t)
@@ -299,3 +318,242 @@ func TestEChartsSeries(t *testing.T) {
},
}, esList)
}
+
+func TestEChartsMarkPoint(t *testing.T) {
+ assert := assert.New(t)
+
+ p := EChartsMarkPoint{}
+
+ err := json.Unmarshal([]byte(`{
+ "symbolSize": 30,
+ "data": [
+ {
+ "type": "max"
+ },
+ {
+ "type": "min"
+ }
+ ]
+ }`), &p)
+ assert.Nil(err)
+ assert.Equal(SeriesMarkPoint{
+ SymbolSize: 30,
+ Data: []SeriesMarkData{
+ {
+ Type: "max",
+ },
+ {
+ Type: "min",
+ },
+ },
+ }, p.ToSeriesMarkPoint())
+}
+
+func TestEChartsMarkLine(t *testing.T) {
+ assert := assert.New(t)
+ l := EChartsMarkLine{}
+
+ err := json.Unmarshal([]byte(`{
+ "data": [
+ {
+ "type": "max"
+ },
+ {
+ "type": "min"
+ }
+ ]
+ }`), &l)
+ assert.Nil(err)
+ assert.Equal(SeriesMarkLine{
+ Data: []SeriesMarkData{
+ {
+ Type: "max",
+ },
+ {
+ Type: "min",
+ },
+ },
+ }, l.ToSeriesMarkLine())
+}
+
+func TestEChartsTextStyle(t *testing.T) {
+ assert := assert.New(t)
+
+ s := EChartsTextStyle{
+ Color: "#aaa",
+ FontFamily: "test",
+ FontSize: 14,
+ }
+ assert.Equal(chart.Style{
+ FontColor: drawing.Color{
+ R: 170,
+ G: 170,
+ B: 170,
+ A: 255,
+ },
+ FontSize: 14,
+ }, s.ToStyle())
+}
+
+func TestEChartsSeriesList(t *testing.T) {
+ assert := assert.New(t)
+
+ // pie
+ es := EChartsSeriesList{
+ {
+ Type: ChartTypePie,
+ Radius: "30%",
+ Data: []EChartsSeriesData{
+ {
+ Name: "1",
+ Value: 1,
+ },
+ {
+ Name: "2",
+ Value: 2,
+ },
+ },
+ },
+ }
+ assert.Equal(SeriesList{
+ {
+ Type: ChartTypePie,
+ Name: "1",
+ Label: SeriesLabel{
+ Show: true,
+ },
+ Radius: "30%",
+ Data: []SeriesData{
+ {
+ Value: 1,
+ },
+ },
+ },
+ {
+ Type: ChartTypePie,
+ Name: "2",
+ Label: SeriesLabel{
+ Show: true,
+ },
+ Radius: "30%",
+ Data: []SeriesData{
+ {
+ Value: 2,
+ },
+ },
+ },
+ }, es.ToSeriesList())
+
+ es = EChartsSeriesList{
+ {
+ Type: ChartTypeBar,
+ Data: []EChartsSeriesData{
+ {
+ Value: 1,
+ ItemStyle: EChartStyle{
+ Color: "#aaa",
+ },
+ },
+ {
+ Value: 2,
+ },
+ },
+ YAxisIndex: 1,
+ },
+ {
+ Data: []EChartsSeriesData{
+ {
+ Value: 3,
+ },
+ {
+ Value: 4,
+ },
+ },
+ ItemStyle: EChartStyle{
+ Color: "#ccc",
+ },
+ Label: EChartsLabelOption{
+ Color: "#ddd",
+ Show: true,
+ Distance: 5,
+ },
+ },
+ }
+ assert.Equal(SeriesList{
+ {
+ Type: ChartTypeBar,
+ Data: []SeriesData{
+ {
+ Value: 1,
+ Style: chart.Style{
+ FontColor: drawing.Color{
+ R: 170,
+ G: 170,
+ B: 170,
+ A: 255,
+ },
+ StrokeColor: drawing.Color{
+ R: 170,
+ G: 170,
+ B: 170,
+ A: 255,
+ },
+ FillColor: drawing.Color{
+ R: 170,
+ G: 170,
+ B: 170,
+ A: 255,
+ },
+ },
+ },
+ {
+ Value: 2,
+ },
+ },
+ YAxisIndex: 1,
+ },
+ {
+ Data: []SeriesData{
+ {
+ Value: 3,
+ },
+ {
+ Value: 4,
+ },
+ },
+ Style: chart.Style{
+ FontColor: drawing.Color{
+ R: 204,
+ G: 204,
+ B: 204,
+ A: 255,
+ },
+ StrokeColor: drawing.Color{
+ R: 204,
+ G: 204,
+ B: 204,
+ A: 255,
+ },
+ FillColor: drawing.Color{
+ R: 204,
+ G: 204,
+ B: 204,
+ A: 255,
+ },
+ },
+ Label: SeriesLabel{
+ Color: drawing.Color{
+ R: 221,
+ G: 221,
+ B: 221,
+ A: 255,
+ },
+ Show: true,
+ Distance: 5,
+ },
+ MarkPoint: SeriesMarkPoint{},
+ MarkLine: SeriesMarkLine{},
+ },
+ }, es.ToSeriesList())
+
+}
diff --git a/examples/demo/main.go b/examples/demo/main.go
index 7916b4d..4ab6b04 100644
--- a/examples/demo/main.go
+++ b/examples/demo/main.go
@@ -62,8 +62,9 @@ var html = `