From c39306034c90a000608bcc4ff549ca59b5e44ccf Mon Sep 17 00:00:00 2001 From: vicanso Date: Sat, 19 Feb 2022 10:23:13 +0800 Subject: [PATCH] docs: update readme --- .gitignore | 3 +- README.md | 129 ++++++++++++++++++++++++------ assets/go-line-chart.png | Bin 40531 -> 0 bytes echarts.go | 6 +- examples/basic/main.go | 91 +++++++++++++++++++++ examples/{demo => charts}/main.go | 0 6 files changed, 199 insertions(+), 30 deletions(-) delete mode 100644 assets/go-line-chart.png create mode 100644 examples/basic/main.go rename examples/{demo => charts}/main.go (100%) diff --git a/.gitignore b/.gitignore index 2ac8a25..2e33342 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ *.png -*.svg \ No newline at end of file +*.svg +tmp diff --git a/README.md b/README.md index b349d5b..c6be480 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ [![license](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/vicanso/go-charts/blob/master/LICENSE) [![Build Status](https://github.com/vicanso/go-charts/workflows/Test/badge.svg)](https://github.com/vicanso/go-charts/actions) -`go-charts`基于[go-chart](https://github.com/wcharczuk/go-chart)生成数据图表,无其它模块的依赖纯golang的实现,支持`svg`与`png`的输出,`Apache ECharts`在前端开发中得到众多开发者的认可,`go-charts`兼容`Apache ECharts`的配置参数,简单快捷的生成相似的图表(`svg`或`png`),方便插入至Email或分享使用。下面为常用的几种图表截图(两种模式): +`go-charts`基于[go-chart](https://github.com/wcharczuk/go-chart)生成数据图表,支持`svg`与`png`两种方式的输出,支持三种主题`light`, `dark`以及`grafana`。 +`Apache ECharts`在前端开发中得到众多开发者的认可,因此`go-charts`提供了兼容`Apache ECharts`的配置参数,简单快捷的生成相似的图表(`svg`或`png`),方便插入至Email或分享使用。下面为常用的图表截图(主题为light与grafana): + ![go-charts](./assets/go-charts.png) @@ -14,24 +16,74 @@ ## 示例 -`go-charts`兼容了`echarts`的参数配置,可简单的使用json形式的配置字符串则可快速生成图表。 + +下面的示例为`go-charts`两种方式的参数配置:golang的参数配置、echarts的JSON配置,输出相同的折线图。 +更多的示例参考:`./examples/`目录 ```go package main import ( "os" + "path/filepath" charts "github.com/vicanso/go-charts" ) -func main() { - buf, err := charts.RenderEChartsToPNG(`{ +func writeFile(file string, buf []byte) error { + tmpPath := "./tmp" + err := os.MkdirAll(tmpPath, 0700) + if err != nil { + return err + } + + file = filepath.Join(tmpPath, file) + err = os.WriteFile(file, buf, 0600) + if err != nil { + return err + } + return nil +} + +func chartsRender() ([]byte, error) { + d, err := charts.Render(charts.ChartOption{ + Type: charts.ChartOutputPNG, + Title: charts.TitleOption{ + Text: "Line", + }, + XAxis: charts.NewXAxisOption([]string{ + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun", + }), + SeriesList: charts.SeriesList{ + charts.NewSeriesFromValues([]float64{ + 150, + 230, + 224, + 218, + 135, + 147, + 260, + }), + }, + }) + if err != nil { + return nil, err + } + return d.Bytes() +} + +func echartsRender() ([]byte, error) { + return charts.RenderEChartsToPNG(`{ "title": { "text": "Line" }, "xAxis": { - "type": "category", "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] }, "series": [ @@ -40,27 +92,50 @@ func main() { } ] }`) - if err != nil { - panic(err) - } - os.WriteFile("output.png", buf, 0600) } + +type Render func() ([]byte, error) + +func main() { + m := map[string]Render{ + "charts-line.png": chartsRender, + "echarts-line.png": echartsRender, + } + for name, fn := range m { + buf, err := fn() + if err != nil { + panic(err) + } + err = writeFile(name, buf) + if err != nil { + panic(err) + } + } +} + ``` -## 参数说明 +## ECharts参数说明 -- `theme` 颜色主题,支持`dark`与`light`模式,默认为`light` -- `padding` 图表的内边距,单位px。支持以下几种模式的设置 +标记为[非echarts配置]的参数为新增参数,可根据实际使用场景添加。 + +- `type` 画布类型,支持`svg`与`png`,默认为`svg` +- `theme` 颜色主题,支持`dark`、`light`以及`grafana`模式,默认为`light` +- `fontFamily` 字体,全局的字体设置[非echarts配置] +- `padding` 图表的内边距,单位px。支持以下几种模式的设置[非echarts配置] - `padding: 5` 设置内边距为5 - `padding: [5, 10]` 设置上下的内边距为 5,左右的内边距为 10 - `padding:[5, 10, 5, 10]` 分别设置`上右下左`边距 +- `box` 图表的区域,以{"left": Int, "right": Int, "top": Int, "bottom": Int}的形式配置,[非echarts配置] +- `width` 画布宽度,默认为600[非echarts配置] +- `height` 画布高度,默认为400[非echarts配置] - `title` 图表标题,包括标题内容、高度、颜色等 - - `title.text` 标题内容 + - `title.text` 标题文本,支持以`\n`的形式换行 + - `title.subtext` 副标题文本,支持以`\n`的形式换行 - `title.left` 标题与容器左侧的距离,可设置为`left`, `right`, `center`, `20%` 以及 `20` 这样的具体数值 - `title.top` 标题与容器顶部的距离,暂仅支持具体数值,如`20` - `title.textStyle.color` 标题文字颜色 - `title.textStyle.fontSize` 标题文字字体大小 - - `title.textStyle.height` 标题高度 - `title.textStyle.fontFamily` 标题文字的字体系列,需要注意此配置是会影响整个图表的字体 - `xAxis` 直角坐标系grid中的x轴,由于go-charts仅支持单一个x轴,因此若参数为数组多个x轴,只使用第一个配置 - `xAxis.boundaryGap` 坐标轴两边留白策略,仅支持三种设置方式`null`, `true`或者`false`。`null`或`true`时则数据点展示在两个刻度中间 @@ -70,21 +145,27 @@ func main() { - `yAxis.min` 坐标轴刻度最小值,若不设置则自动计算 - `yAxis.max` 坐标轴刻度最大值,若不设置则自动计算 - `yAxis.axisLabel.formatter` 刻度标签的内容格式器,如`"formatter": "{value} kg"` + - `yAxis.axisLine.lineStyle.color` 坐标轴颜色 - `legend` 图表中不同系列的标记 + - `legend.show` 图例是否显示,如果不需要展示需要设置为`false` - `legend.data` 图例的数据数组,为字符串数组,如["Email", "Video Ads"] - - `legend.align` 图例标记和文本的对齐,默认为标记靠左`left` + - `legend.align` 图例标记和文本的对齐,可设置为`left`或者`right`,默认为标记靠左`left` - `legend.padding` legend的padding,配置方式与图表的`padding`一致 - - `legend.left` legend离容器左侧的距离,其值可以为具体的像素值(20)或百分比(20%) - - `legend.right` legend离容器右侧的距离,其值可以为具体的像素值(20)或百分比(20%) + - `legend.left` legend离容器左侧的距离,其值可以为具体的像素值(20)或百分比(20%)、`left`或者`right` + - `legend.top` legend离容器顶部的距离,暂仅支持数值形式 - `series` 图表的数据项列表 + - `series.name` 图表的名称,与`legend.data`对应,两者只只设置其一 - `series.type` 图表的展示类型,暂支持`line`, `bar`以及`pie`,需要注意`pie`只能单独使用 + - `series.radius` 饼图的半径值,如`50%`,默认为`40%` + - `series.yAxisIndex` 该数据项使用的y轴,默认为0,对yAxis的配置对应 - `series.label.show` 是否显示文本标签(默认为对应的值) - `series.label.distance` 距离图形元素的距离 - - `series.yAxisIndex` 该数据项使用的y轴,默认为0,对yAxis的配置对应 - - `series.itemStyle.color` 该数据项展示时使用的颜色 + - `series.label.color` 文本标签的颜色 + - `series.itemStyle.color` 该数据项展示时使用的颜色 - `series.data` 数据项对应的数据数组,支持以下形式的数据: - `数值` 常用形式,数组数据为浮点数组,如[1.1, 2,3, 5.2] - `结构体` pie图表或bar图表中指定样式使用,如[{"value": 1048, "name": "Search Engine"},{"value": 735,"name": "Direct"}] +- `children` 嵌套的子图表参数列表,图表支持嵌套的形式非echarts配置] ## 性能 @@ -92,15 +173,11 @@ func main() { 简单的图表生成PNG在20ms左右,而SVG的性能则更快,性能上比起使用`chrome headless`加载`echarts`图表展示页面再截图生成的方式大幅度提升,满足简单的图表生成需求。 ```bash -goos: darwin -goarch: amd64 -pkg: github.com/vicanso/go-charts -cpu: Intel(R) Core(TM) i5-8257U CPU @ 1.40GHz -BenchmarkEChartsRenderPNG-8 60 17765045 ns/op 2492854 B/op 1007 allocs/op -BenchmarkEChartsRenderSVG-8 282 4303042 ns/op 32622688 B/op 2983 allocs/op +BenchmarkMultiChartPNGRender-8 78 15216336 ns/op 2298308 B/op 1148 allocs/op +BenchmarkMultiChartSVGRender-8 367 3356325 ns/op 20597282 B/op 3088 allocs/op ``` ## 中文字符 -默认使用的字符为`Roboto`为英文字体库,因此如果需要显示中文字符需要增加中文字体库,`InstallFont`函数可添加对应的字体库,成功添加之后则指定`title.textStyle.fontFamily`即可。 +默认使用的字符为`roboto`为英文字体库,因此如果需要显示中文字符需要增加中文字体库,`InstallFont`函数可添加对应的字体库,成功添加之后则指定`title.textStyle.fontFamily`即可。 在浏览器中使用`svg`时,如果指定的`fontFamily`不支持中文字符,展示的中文并不会乱码,但是会导致在计算字符宽度等错误。 diff --git a/assets/go-line-chart.png b/assets/go-line-chart.png deleted file mode 100644 index 71c9eb14d6197450572322797e4852159f557f8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40531 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

aFJ*EYoL84W!lN566D&buvAoFMUlr zH|fBiEPhf}KT-v`>P`1bg80YnOOWOUPrR_GvuNooFiD-{Ac^yXrGMlk;Rq)78;`Hl z-BE>vT+s#SM&U9=(8ODjU*^M6VNM(IiKxOC`&&nqS1S-a>gtEhVnR?FqM$RB_R;u; zDM9MN);Io)1^#LBpVt1fpSZ~-KFFN_1%Y8*&PzHSlplIR!)_k)&b}_$>SoEjd@5e> zHM%tuVmfdjRpMsUele;fM5~1K({qid_ngPA4ABQmx8HdH4#&_3-aa`dDw-3yKVoD@ z0^9+05D=C*j6aLB{v6BHeyV^vf&mrF76R1EVJv7*q7b5(3d65hFSD+pFtBW1a;lXg z(S<=#R;C}_9~WhY=Sca~;_^y$4dAiRrHc*XaU+~3u82S<1F=N3?*%$MtqFlJ7Ywde zMZy?Z$hrA;fJ$>(M6d|w}OBxzeRSWy$nJN7d7T#9Gr)JwhH8_Cvg zD>fCTfwJ_z*K-SY(fdLVlj7*VQOOX=gE0hxkqWOqB!WVb!2g6suBqk@Ex0U4vGs`+ zgX+}j3zKqym)23}SG|qSvs)MNvpiYf2V*!@iJ9J2H&%P?kTPo3 z;RrO4^gMYIv6@a}m1{PPq&-kqkqpq1DJ&=xh}eDtYM>}IoQ~OWa;M; zoCLxmnUfYu^%}qB(|#c=zo&eIjjTqRZ_kwIBfcuj z1c&<(Wr>N=-+V^yw4}7Qxt^CABqbVNA&~KG+S$H~(HGXCDm)Lf(22^((4$o9SBPnQ z!P!ZiGW)DhczRY=5t!_4AL^x{e)$4YR#ip*t3Z{?rKTpp2c8|{^ zK?XrBD=`um54!p@d;a&A7(j`enHE6D%`h#(AN2XZV9{NZ3c(OV5Dx+G$g~99`c$I) zKP^@@y22!OwZGf=uZ0ncRG9QHmHwyItqfM`uriole_OHyfWJ5fW90v~=*9ngkY&{W zeNrI`ju=8|g*~vfa8Wr2J2X>AA$r*MWtHT(#-s zh{H&&K1f&g!A*kc0&t|PX)0l{9%hm9`hJ zwwItwIE{3ha>diw>Kjl0y?c*$yWVvzocmF};HE&or-U#mF!mCO!KZr!h6 z$1Kc`JKA~_b~Imdf)HOB{51S-#m`l0+AO{pyVQ|1sv?uT_g@+CTm5}%Vpj4CH5da# z?-;MHAC(j+OFRLP3WOQBi3&;c1;E>rNcTjsX|QT?l7{saZeBlIV&T;vCT(eHx(cI5 zQS0x@*2xPb#7xAQZp=`A^>|h0UrRa}pwf&!ae3Uk)$c;yjN)lKxwJ1i!```%UsQ{h zt={)r7fOp&LNhn&u924)N(kX|ijErJHVPr`Y2Nm+X;Ti^ACXw}E<~syRPN(}I{XGR zn=r~woEXkej_Jx@EGBNX)FhahGQcHskCMy+wom+N#OMBKgiu)U<9AUoJ;4wxqbWZ% zNl622g@P~_Xo>e8Zh<$dZ3zs!;iW-&@q+I!Buj|>TLs*1k^0uwK0UnnVll%%O8hQq z^}C25<>mQC3xbn8bkkD0o}Tz=XE(EUlWoJMaO3P~_-=f}JnPGZ;Ef0Rs#M@HLxU3j z&0u@}4!)aYh@q58IO$^%=?6^)$a+~QtFKQ&QPkgX!=1&Suk14k$}vN}Zc^VL%P&bq z`=Grc*G@``=AvqTL)J0bk1dtu=z-dA>0U43qKDPYNUFm8Au49JTWTYp zQbOp>iA_d2+_{3KTyz z2LZujpYAi1q>nQbIyfu?;AUg?n<*w%bisBY+-GWm9znKxalh!Prr3u*(QWqFK{Z))9hJ8)Ni~QD%3!Kj`lwp z^89*-J9b%Ye3L8qOp`1p0+iw|CX}9r+t&zF10z9sS0i37Y6$bU2)%*IA|xvK2Rjj` zr*;pXuN#Kb6aE-Qm3)yjHElyG#omH)m+dQk|u5joVaK3MnOXtgliognw10VM+y23p$UI!4{9X zs5l9fct^5g5#CbE;WyU=Eqs1fq?()({AesU@!mLCv{=-1jh*ld^{^U4R$zUbIcrKN zykUb42XiN~$m#ayvy8Eauiy$_tSj*q`O3Z9wvm^Zw6)~CvxUiE_XW}G7XuTWZ_HH( zP%g#_ecyWp_59h`g>iz;@KL`yvg;Icp0t5%%IhcTRV;tB)j+h_zM1vuy=Ir$QkgC2 zwp`WR?Rr0wU#$Hrs(2Yh$djfIUlcX?XIaFgL{5oOmlk+*i#aP2Z-=gEv#_{k%Q#x~ zvaUH^2fAS3u_w5y9wZPvF{b)<*}vx=@$0YT6hU5m@$hB4mkML&1m)T0lbbs+xNsJH z`+iEM{~Y<|gsyyEvzyTf5o-4i*6Z*$mj^8NU=m3!PTgPi%f%>m0{k%r2THQ^uG|@}3K6<0vQlz1 zaGo5}bYR;sEm)vZE!+e_xd}?p*G4r$e|v-#R-;7dK6QY>?TyXSO;Rq{Pp`1x7+Kf= z82i-U-vs1>9sNmPy-=Xb_XR0GJ)H)jzn(6-P?NGx6GQ3EBU_>Gw3B#w{$`9wI)~I3 zq?X$7pJaApK_*YYWngl0JQp7i3ev+Hd zOWCVIDM9K<|LLC&*h@Qv^yik;?}NdMs1Gx9bc&CY9EKuLVXHUse)HJz&YsEmxT%p~ z%l=OvjRGIS--XC~8t&-8$Erh3I`P7q8qC-5hX*)(U2JEkOHl+%AzjAi$OJ6<73Oz= zb&~i1bl=wuh4z=TljV(su=XG+vX|Vo#Em_X$F_DwdRvnAlNEKA53OA6_;G3Nd0XF5 zlFQ3&Mzb36-JR~80Bb&v#?d4qI7i$z^J!mM9r+Q+E1=p$hW9;?xvBPo>bUU%>yJ17 zTN)it9Jox27a{AYo(Hbw21Ie{3^#`TS2zxiPW=~!0@v;aZAsHp`q|PX??T#Ca_@47 zuI7m0O-qP{+@Q8-54anStlkm6b?h|RKzp6-ow{`5NsqQC>aWqyOkYXEaGV4pMMT1A1s(djMBhA zZ4Y$JCE)n4i!vrFdv0AT?L24v-ZXjX<~EDKAMgegUNte3I64|q-N+QADU7Xzf@+6c z&cvuiI;w}1ORK7+<6ZQr$eVNO~{JQaFhxLUL!RJ|}3=|x69{1>H@H<^YgTwZI&l*4ZTMYMZu*26pkvbm7 z)-#?M{Y6BALqgXm=?ldvynk;dwmFs7RXR(F;(*d)XqAl=1fFoo$j-J1#DeS-npw zboZL@q;kK1M`A(sRi7`C?K(r*K43!d*_lz>!4e@O*Lo%&I1TLe}&8V%{PkrFM0W zd+qyrZT}#wXK25&ODacya&{W2s&v($aelxA6@{g3c7Dj-|fH#=4;gyQDdzu|}3%q%fq z%;~T5m-fw})@kni@b)K4;$3t6e`EP&aeH%G;(el6WN6BBya}|i^^~{Zzo7k`5I1Y6 z%leVg%UBAWvL=DN7pI00A0L9ZraS3SPM1sXSN>)MoYDo10;y4Kh`1&xa{+JJ!z^iY z+F1AzNhm{59_w_O^JODA0~bR`knCD6@QIFAlJK(R`kRJ;P1jFKc9@h8ZGX}m%|{xF z-?}Zi)nN2&fj-fHD)>8@a0A}LErQrXV%wie`_vR$rMEoe2TwhIkCAGEt}-HcZ8!0t zhqNKg5eley`h<(G9UA{mB_qu+CC!(hhxSjO!}sIpmr^Of;iUIuX*xfI-b6Q;I|_

g+d(6A`a&8oFq2_&T=smuw&4SDRD{c`d* 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 XZ~-$O07xkY00000NkvXXu0mjf=gwEf diff --git a/echarts.go b/echarts.go index db50e5d..6de8dc4 100644 --- a/echarts.go +++ b/echarts.go @@ -128,9 +128,9 @@ type EChartsYAxisData struct { AxisLabel EChartsAxisLabel `json:"axisLabel"` AxisLine struct { LineStyle struct { - Color string - } - } + Color string `json:"color"` + } `json:"lineStyle"` + } `json:"axisLine"` } type EChartsYAxis struct { Data []EChartsYAxisData `json:"data"` diff --git a/examples/basic/main.go b/examples/basic/main.go new file mode 100644 index 0000000..035a7b4 --- /dev/null +++ b/examples/basic/main.go @@ -0,0 +1,91 @@ +package main + +import ( + "os" + "path/filepath" + + charts "github.com/vicanso/go-charts" +) + +func writeFile(file string, buf []byte) error { + tmpPath := "./tmp" + err := os.MkdirAll(tmpPath, 0700) + if err != nil { + return err + } + + file = filepath.Join(tmpPath, file) + err = os.WriteFile(file, buf, 0600) + if err != nil { + return err + } + return nil +} + +func chartsRender() ([]byte, error) { + d, err := charts.Render(charts.ChartOption{ + Type: charts.ChartOutputPNG, + Title: charts.TitleOption{ + Text: "Line", + }, + XAxis: charts.NewXAxisOption([]string{ + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun", + }), + SeriesList: charts.SeriesList{ + charts.NewSeriesFromValues([]float64{ + 150, + 230, + 224, + 218, + 135, + 147, + 260, + }), + }, + }) + if err != nil { + return nil, err + } + return d.Bytes() +} + +func echartsRender() ([]byte, error) { + return charts.RenderEChartsToPNG(`{ + "title": { + "text": "Line" + }, + "xAxis": { + "data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + }, + "series": [ + { + "data": [150, 230, 224, 218, 135, 147, 260] + } + ] + }`) +} + +type Render func() ([]byte, error) + +func main() { + m := map[string]Render{ + "charts-line.png": chartsRender, + "echarts-line.png": echartsRender, + } + for name, fn := range m { + buf, err := fn() + if err != nil { + panic(err) + } + err = writeFile(name, buf) + if err != nil { + panic(err) + } + } +} diff --git a/examples/demo/main.go b/examples/charts/main.go similarity index 100% rename from examples/demo/main.go rename to examples/charts/main.go