diff --git a/README.md b/README.md index 55e5760..270a338 100644 --- a/README.md +++ b/README.md @@ -1 +1,47 @@ -# go-chart \ No newline at end of file +# go-echarts + + + +[go-chart](https://github.com/wcharczuk/go-chart)是golang常用的可视化图表库,支持`svg`与`png`的输出,`Apache ECharts`在前端开发中得到众多开发者的认可。go-echarts则是结合两者的方式,兼容`Apache ECharts`的配置参数,简单快捷的生成相似的图表(`svg`或`png`),方便插入至Email或分享使用。下面为常用的几种图表截图: + + + +## 支持图表类型 + +暂仅支持三种的图表类型:`line`, `bar` 以及 `pie` + + +## 示例 + +`go-echarts`兼容了`echarts`的参数配置,可简单的使用json形式的配置字符串则可快速生成图表。 + +```go +package main + +import ( + "os" + + charts "github.com/vicanso/echarts" +) + +func main() { + buf, err := charts.RenderEChartsToPNG(`{ + "title": { + "text": "Line" + }, + "xAxis": { + "type": "category", + "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + }, + "series": [ + { + "data": [150, 230, 224, 218, 135, 147, 260] + } + ] + }`) + if err != nil { + panic(err) + } + os.WriteFile("output.png", buf, 0600) +} +``` \ No newline at end of file diff --git a/assets/go-echarts.jpg b/assets/go-echarts.jpg new file mode 100644 index 0000000..85032e5 Binary files /dev/null and b/assets/go-echarts.jpg differ diff --git a/axis.go b/axis.go index 5b2be9e..42569a3 100644 --- a/axis.go +++ b/axis.go @@ -50,6 +50,16 @@ type YAxisOption struct { const axisStrokeWidth = 1 +func maxInt(values ...int) int { + result := 0 + for _, v := range values { + if v > result { + result = v + } + } + return result +} + // GetXAxisAndValues returns x axis by theme, and the values of axis. func GetXAxisAndValues(xAxis XAxis, tickPosition chart.TickPosition, theme string) (chart.XAxis, []float64) { data := xAxis.Data @@ -66,10 +76,8 @@ func GetXAxisAndValues(xAxis XAxis, tickPosition chart.TickPosition, theme strin xValues := make([]float64, size) ticks := make([]chart.Tick, 0) - maxTicks := xAxis.SplitNumber - if maxTicks == 0 { - maxTicks = 10 - } + // tick width + maxTicks := maxInt(xAxis.SplitNumber, 10) // 计息最多每个unit至少放多个 minUnitSize := originalSize / maxTicks diff --git a/echarts.go b/echarts.go index 02cede2..672a21a 100644 --- a/echarts.go +++ b/echarts.go @@ -188,6 +188,7 @@ type ECharsOptions struct { Data []ECharsSeriesData `json:"data"` Type string `json:"type"` YAxisIndex int `json:"yAxisIndex"` + ItemStyle EChartStyle `json:"itemStyle"` } `json:"series"` } @@ -201,7 +202,15 @@ func convertEChartsSeries(e *ECharsOptions) ([]Series, chart.TickPosition) { if seriesType == SeriesPie { series := make([]Series, len(e.Series[0].Data)) for index, item := range e.Series[0].Data { + style := chart.Style{} + if item.ItemStyle.Color != "" { + c := parseColor(item.ItemStyle.Color) + style.FillColor = c + style.StrokeColor = c + } + series[index] = Series{ + Style: style, Data: []SeriesData{ { Value: item.Value, @@ -219,6 +228,12 @@ func convertEChartsSeries(e *ECharsOptions) ([]Series, chart.TickPosition) { if item.Type == SeriesBar { tickPosition = chart.TickPositionBetweenTicks } + style := chart.Style{} + if item.ItemStyle.Color != "" { + c := parseColor(item.ItemStyle.Color) + style.FillColor = c + style.StrokeColor = c + } data := make([]SeriesData, len(item.Data)) for j, itemData := range item.Data { sd := SeriesData{ @@ -232,6 +247,7 @@ func convertEChartsSeries(e *ECharsOptions) ([]Series, chart.TickPosition) { data[j] = sd } series[index] = Series{ + Style: style, YAxisIndex: item.YAxisIndex, Data: data, Type: item.Type, @@ -317,3 +333,23 @@ func ParseECharsOptions(options string) (Options, error) { return e.ToOptions(), nil } + +func echartsRender(options string, rp chart.RendererProvider) ([]byte, error) { + o, err := ParseECharsOptions(options) + if err != nil { + return nil, err + } + g, err := New(o) + if err != nil { + return nil, err + } + return render(g, rp) +} + +func RenderEChartsToPNG(options string) ([]byte, error) { + return echartsRender(options, chart.PNG) +} + +func RenderEChartsToSVG(options string) ([]byte, error) { + return echartsRender(options, chart.SVG) +} diff --git a/echarts_test.go b/echarts_test.go index 99bf414..b06da53 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 TestConvertToArray(t *testing.T) { @@ -288,6 +289,9 @@ func TestParseECharsOptions(t *testing.T) { { "name": "Precipitation", "type": "bar", + "itemStyle": { + "color": "#0052d9" + }, "data": [2.6, 5.9, 9, 26.4, 28.7, 70.7, 175.6] }, { @@ -368,6 +372,20 @@ func TestParseECharsOptions(t *testing.T) { 2.6, 5.9, 9, 26.4, 28.7, 70.7, 175.6, }), Type: SeriesBar, + Style: chart.Style{ + StrokeColor: drawing.Color{ + R: 0, + G: 82, + B: 217, + A: 255, + }, + FillColor: drawing.Color{ + R: 0, + G: 82, + B: 217, + A: 255, + }, + }, }, { Data: NewSeriesDataListFromFloat([]float64{ diff --git a/examples/basic/main.go b/examples/basic/main.go new file mode 100644 index 0000000..906f32c --- /dev/null +++ b/examples/basic/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "os" + + charts "github.com/vicanso/echarts" +) + +func main() { + buf, err := charts.RenderEChartsToPNG(`{ + "title": { + "text": "Line" + }, + "xAxis": { + "type": "category", + "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + }, + "series": [ + { + "data": [150, 230, 224, 218, 135, 147, 260] + } + ] + }`) + if err != nil { + panic(err) + } + os.WriteFile("output.png", buf, 0600) +} diff --git a/examples/main.go b/examples/charts/main.go similarity index 79% rename from examples/main.go rename to examples/charts/main.go index c07b49d..4cf72e2 100644 --- a/examples/main.go +++ b/examples/charts/main.go @@ -9,32 +9,44 @@ import ( var html = ` -
- - - - - -{{option}}
{{svg}}