diff --git a/chart.go b/chart.go
index 9748a95..6f4740f 100644
--- a/chart.go
+++ b/chart.go
@@ -283,7 +283,10 @@ func (r *basicRenderResult) getYRange(index int) *Range {
}
// Render renders the chart by option
-func Render(opt ChartOption) (*Draw, error) {
+func Render(opt ChartOption, optFuncs ...OptionFunc) (*Draw, error) {
+ for _, optFunc := range optFuncs {
+ optFunc(&opt)
+ }
if len(opt.SeriesList) == 0 {
return nil, errors.New("series can not be nil")
}
diff --git a/chart_option.go b/chart_option.go
new file mode 100644
index 0000000..1bbf4cf
--- /dev/null
+++ b/chart_option.go
@@ -0,0 +1,185 @@
+// MIT License
+
+// Copyright (c) 2022 Tree Xie
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package charts
+
+import (
+ "github.com/wcharczuk/go-chart/v2"
+ "github.com/wcharczuk/go-chart/v2/drawing"
+)
+
+// OptionFunc option function
+type OptionFunc func(opt *ChartOption)
+
+// TypeOptionFunc set type of chart's output
+func TypeOptionFunc(t string) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Type = t
+ }
+}
+
+// FontFamilyOptionFunc set font family of chart
+func FontFamilyOptionFunc(fontFamily string) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.FontFamily = fontFamily
+ }
+}
+
+// ThemeOptionFunc set them of chart
+func ThemeOptionFunc(theme string) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Theme = theme
+ }
+}
+
+// TitleOptionFunc set title of chart
+func TitleOptionFunc(title TitleOption) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Title = title
+ }
+}
+
+// LegendOptionFunc set legend of chart
+func LegendOptionFunc(legend LegendOption) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Legend = legend
+ }
+}
+
+// XAxisOptionFunc set x axis of chart
+func XAxisOptionFunc(xAxisOption XAxisOption) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.XAxis = xAxisOption
+ }
+}
+
+// YAxisOptionFunc set y axis of chart, support two y axis
+func YAxisOptionFunc(yAxisOption ...YAxisOption) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.YAxisList = yAxisOption
+ }
+}
+
+// WidthOptionFunc set width of chart
+func WidthOptionFunc(width int) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Width = width
+ }
+}
+
+// HeightOptionFunc set height of chart
+func HeightOptionFunc(height int) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Height = height
+ }
+}
+
+// PaddingOptionFunc set padding of chart
+func PaddingOptionFunc(padding chart.Box) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Padding = padding
+ }
+}
+
+// BoxOptionFunc set box of chart
+func BoxOptionFunc(box chart.Box) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.Box = box
+ }
+}
+
+// ChildOptionFunc add child chart
+func ChildOptionFunc(child ...ChartOption) OptionFunc {
+ return func(opt *ChartOption) {
+ if opt.Children == nil {
+ opt.Children = make([]ChartOption, 0)
+ }
+ opt.Children = append(opt.Children, child...)
+ }
+}
+
+// RadarIndicatorOptionFunc set radar indicator of chart
+func RadarIndicatorOptionFunc(radarIndicator ...RadarIndicator) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.RadarIndicators = radarIndicator
+ }
+}
+
+// BackgroundColorOptionFunc set background color of chart
+func BackgroundColorOptionFunc(color drawing.Color) OptionFunc {
+ return func(opt *ChartOption) {
+ opt.BackgroundColor = color
+ }
+}
+
+// LineRender line chart render
+func LineRender(values [][]float64, opts ...OptionFunc) (*Draw, error) {
+ seriesList := make(SeriesList, len(values))
+ for index, value := range values {
+ seriesList[index] = NewSeriesFromValues(value, ChartTypeLine)
+ }
+ return Render(ChartOption{
+ SeriesList: seriesList,
+ }, opts...)
+}
+
+// BarRender bar chart render
+func BarRender(values [][]float64, opts ...OptionFunc) (*Draw, error) {
+ seriesList := make(SeriesList, len(values))
+ for index, value := range values {
+ seriesList[index] = NewSeriesFromValues(value, ChartTypeBar)
+ }
+ return Render(ChartOption{
+ SeriesList: seriesList,
+ }, opts...)
+}
+
+// PieRender pie chart render
+func PieRender(values []float64, opts ...OptionFunc) (*Draw, error) {
+ return Render(ChartOption{
+ SeriesList: NewPieSeriesList(values),
+ }, opts...)
+}
+
+// RadarRender radar chart render
+func RadarRender(values [][]float64, opts ...OptionFunc) (*Draw, error) {
+ seriesList := make(SeriesList, len(values))
+ for index, value := range values {
+ seriesList[index] = NewSeriesFromValues(value, ChartTypeRadar)
+ }
+ return Render(ChartOption{
+ SeriesList: seriesList,
+ }, opts...)
+}
+
+// FunnelRender funnel chart render
+func FunnelRender(values []float64, opts ...OptionFunc) (*Draw, error) {
+ seriesList := make(SeriesList, len(values))
+ for index, value := range values {
+ seriesList[index] = NewSeriesFromValues([]float64{
+ value,
+ }, ChartTypeFunnel)
+ }
+ return Render(ChartOption{
+ SeriesList: seriesList,
+ }, opts...)
+}
diff --git a/chart_option_test.go b/chart_option_test.go
new file mode 100644
index 0000000..41e8d50
--- /dev/null
+++ b/chart_option_test.go
@@ -0,0 +1,238 @@
+// MIT License
+
+// Copyright (c) 2022 Tree Xie
+
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+// SOFTWARE.
+
+package charts
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/wcharczuk/go-chart/v2"
+ "github.com/wcharczuk/go-chart/v2/drawing"
+)
+
+func TestOptionFunc(t *testing.T) {
+ assert := assert.New(t)
+
+ fns := []OptionFunc{
+ TypeOptionFunc(ChartOutputPNG),
+ FontFamilyOptionFunc("fontFamily"),
+ ThemeOptionFunc("black"),
+ TitleOptionFunc(TitleOption{
+ Text: "title",
+ }),
+ LegendOptionFunc(LegendOption{
+ Data: []string{
+ "a",
+ "b",
+ },
+ }),
+ XAxisOptionFunc(NewXAxisOption([]string{
+ "Mon",
+ "Tue",
+ })),
+ YAxisOptionFunc(YAxisOption{
+ Min: NewFloatPoint(0),
+ Max: NewFloatPoint(100),
+ }),
+ WidthOptionFunc(400),
+ HeightOptionFunc(300),
+ PaddingOptionFunc(chart.Box{
+ Top: 10,
+ }),
+ BoxOptionFunc(chart.Box{
+ Left: 0,
+ Right: 300,
+ }),
+ ChildOptionFunc(ChartOption{}),
+ RadarIndicatorOptionFunc(RadarIndicator{
+ Min: 0,
+ Max: 10,
+ }),
+ BackgroundColorOptionFunc(drawing.ColorBlack),
+ }
+
+ opt := ChartOption{}
+ for _, fn := range fns {
+ fn(&opt)
+ }
+
+ assert.Equal("png", opt.Type)
+ assert.Equal("fontFamily", opt.FontFamily)
+ assert.Equal("black", opt.Theme)
+ assert.Equal(TitleOption{
+ Text: "title",
+ }, opt.Title)
+ assert.Equal(LegendOption{
+ Data: []string{
+ "a",
+ "b",
+ },
+ }, opt.Legend)
+ assert.Equal(NewXAxisOption([]string{
+ "Mon",
+ "Tue",
+ }), opt.XAxis)
+ assert.Equal([]YAxisOption{
+ {
+ Min: NewFloatPoint(0),
+ Max: NewFloatPoint(100),
+ },
+ }, opt.YAxisList)
+ assert.Equal(400, opt.Width)
+ assert.Equal(300, opt.Height)
+ assert.Equal(chart.Box{
+ Top: 10,
+ }, opt.Padding)
+ assert.Equal(chart.Box{
+ Left: 0,
+ Right: 300,
+ }, opt.Box)
+ assert.Equal(1, len(opt.Children))
+ assert.Equal([]RadarIndicator{
+ {
+ Min: 0,
+ Max: 10,
+ },
+ }, opt.RadarIndicators)
+ assert.Equal(drawing.ColorBlack, opt.BackgroundColor)
+}
+
+func TestLineRender(t *testing.T) {
+ assert := assert.New(t)
+
+ d, err := LineRender([][]float64{
+ {
+ 1,
+ 2,
+ 3,
+ },
+ {
+ 1,
+ 5,
+ 2,
+ },
+ },
+ XAxisOptionFunc(NewXAxisOption([]string{
+ "01",
+ "02",
+ "03",
+ })),
+ )
+ assert.Nil(err)
+ data, err := d.Bytes()
+ assert.Nil(err)
+ assert.Equal("", string(data))
+}
+
+func TestBarRender(t *testing.T) {
+ assert := assert.New(t)
+
+ d, err := BarRender([][]float64{
+ {
+ 1,
+ 2,
+ 3,
+ },
+ {
+ 1,
+ 5,
+ 2,
+ },
+ },
+ XAxisOptionFunc(NewXAxisOption([]string{
+ "01",
+ "02",
+ "03",
+ })),
+ )
+ assert.Nil(err)
+ data, err := d.Bytes()
+ assert.Nil(err)
+ assert.Equal("", string(data))
+}
+
+func TestPieRender(t *testing.T) {
+ assert := assert.New(t)
+
+ d, err := PieRender([]float64{
+ 1,
+ 3,
+ 5,
+ })
+ assert.Nil(err)
+ data, err := d.Bytes()
+ assert.Nil(err)
+ assert.Equal("", string(data))
+}
+
+func TestRadarRender(t *testing.T) {
+ assert := assert.New(t)
+ d, err := RadarRender([][]float64{
+ {
+ 1,
+ 2,
+ 3,
+ },
+ {
+ 1,
+ 5,
+ 2,
+ },
+ },
+ RadarIndicatorOptionFunc([]RadarIndicator{
+ {
+ Name: "A",
+ Min: 0,
+ Max: 10,
+ },
+ {
+ Name: "B",
+ Min: 0,
+ Max: 10,
+ },
+ {
+ Name: "C",
+ Min: 0,
+ Max: 10,
+ },
+ }...),
+ )
+ assert.Nil(err)
+ data, err := d.Bytes()
+ assert.Nil(err)
+ assert.Equal("", string(data))
+}
+
+func TestFunnelRender(t *testing.T) {
+ assert := assert.New(t)
+
+ d, err := FunnelRender([]float64{
+ 5,
+ 3,
+ 1,
+ })
+ assert.Nil(err)
+ data, err := d.Bytes()
+ assert.Nil(err)
+ assert.Equal("", string(data))
+}
diff --git a/series.go b/series.go
index a1b7486..14227d1 100644
--- a/series.go
+++ b/series.go
@@ -128,7 +128,7 @@ type PieSeriesOption struct {
Names []string
}
-func NewPieSeriesList(values []float64, opts ...PieSeriesOption) []Series {
+func NewPieSeriesList(values []float64, opts ...PieSeriesOption) SeriesList {
result := make([]Series, len(values))
var opt PieSeriesOption
if len(opts) != 0 {
diff --git a/series_test.go b/series_test.go
index aae83de..1460180 100644
--- a/series_test.go
+++ b/series_test.go
@@ -66,7 +66,7 @@ func TestNewSeriesDataFromValues(t *testing.T) {
func TestNewPieSeriesList(t *testing.T) {
assert := assert.New(t)
- assert.Equal([]Series{
+ assert.Equal(SeriesList{
{
Type: ChartTypePie,
Name: "a",