refactor: support more echarts options

This commit is contained in:
vicanso 2021-12-18 11:22:53 +08:00
parent 23e2eca0c6
commit c0170bf250
5 changed files with 176 additions and 43 deletions

39
axis.go
View file

@ -43,6 +43,8 @@ type (
type YAxisOption struct {
Formater chart.ValueFormatter
Disabled bool
Min *float64
Max *float64
}
const axisStrokeWidth = 1
@ -113,14 +115,9 @@ func defaultFloatFormater(v interface{}) string {
func GetSecondaryYAxis(theme string, option *YAxisOption) chart.YAxis {
strokeColor := getGridColor(theme)
formater := defaultFloatFormater
if option != nil {
if option.Formater != nil {
formater = option.Formater
}
}
return chart.YAxis{
ValueFormatter: formater,
yAxis := chart.YAxis{
Range: &chart.ContinuousRange{},
ValueFormatter: defaultFloatFormater,
AxisType: chart.YAxisSecondary,
GridMajorStyle: chart.Style{
StrokeColor: strokeColor,
@ -137,22 +134,35 @@ func GetSecondaryYAxis(theme string, option *YAxisOption) chart.YAxis {
StrokeWidth: axisStrokeWidth,
},
}
setYAxis(&yAxis, option)
return yAxis
}
func setYAxis(yAxis *chart.YAxis, option *YAxisOption) {
if option == nil {
return
}
if option.Formater != nil {
yAxis.ValueFormatter = option.Formater
}
if option.Max != nil {
yAxis.Range.SetMax(*option.Max)
}
if option.Min != nil {
yAxis.Range.SetMin(*option.Min)
}
}
func GetYAxis(theme string, option *YAxisOption) chart.YAxis {
// strokeColor := getGridColor(theme)
formater := defaultFloatFormater
disabled := false
if option != nil {
if option.Formater != nil {
formater = option.Formater
}
disabled = option.Disabled
}
hidden := chart.Hidden()
yAxis := chart.YAxis{
ValueFormatter: formater,
Range: &chart.ContinuousRange{},
ValueFormatter: defaultFloatFormater,
AxisType: chart.YAxisPrimary,
GridMajorStyle: hidden,
GridMinorStyle: hidden,
@ -167,5 +177,6 @@ func GetYAxis(theme string, option *YAxisOption) chart.YAxis {
yAxis.Range = &HiddenRange{}
yAxis.Style.Hidden = true
}
setYAxis(&yAxis, option)
return yAxis
}

View file

@ -47,6 +47,8 @@ type (
}
Legend struct {
Data []string
Align string
Padding chart.Box
}
Options struct {
Width int
@ -177,6 +179,8 @@ func New(opt Options) (Graph, error) {
Theme: opt.Theme,
TextPosition: LegendTextPositionRight,
IconDraw: DefaultLegendIconDraw,
Align: opt.Legend.Align,
Padding: opt.Legend.Padding,
}),
}
}

View file

@ -42,6 +42,17 @@ type ECharsSeriesData struct {
}
type _ECharsSeriesData ECharsSeriesData
func convertToArray(data []byte) []byte {
data = bytes.TrimSpace(data)
if len(data) == 0 {
return nil
}
if data[0] != '[' {
data = []byte("[" + string(data) + "]")
}
return data
}
func (es *ECharsSeriesData) UnmarshalJSON(data []byte) error {
data = bytes.TrimSpace(data)
if len(data) == 0 {
@ -66,10 +77,56 @@ func (es *ECharsSeriesData) UnmarshalJSON(data []byte) error {
return nil
}
type EChartsPadding struct {
box chart.Box
}
func (ep *EChartsPadding) UnmarshalJSON(data []byte) error {
data = convertToArray(data)
if len(data) == 0 {
return nil
}
arr := make([]int, 0)
err := json.Unmarshal(data, &arr)
if err != nil {
return err
}
if len(arr) == 0 {
return nil
}
switch len(arr) {
case 1:
ep.box = chart.Box{
Left: arr[0],
Top: arr[0],
Bottom: arr[0],
Right: arr[0],
}
case 2:
ep.box = chart.Box{
Top: arr[0],
Bottom: arr[0],
Left: arr[1],
Right: arr[1],
}
default:
result := make([]int, 4)
copy(result, arr)
// 上右下左
ep.box = chart.Box{
Top: arr[0],
Right: arr[1],
Bottom: arr[2],
Left: arr[3],
}
}
return nil
}
type EChartsYAxis struct {
Data []struct {
Min int `json:"min"`
Max int `json:"max"`
Min *float64 `json:"min"`
Max *float64 `json:"max"`
Interval int `json:"interval"`
AxisLabel struct {
Formatter string `json:"formatter"`
@ -78,34 +135,50 @@ type EChartsYAxis struct {
}
func (ey *EChartsYAxis) UnmarshalJSON(data []byte) error {
data = bytes.TrimSpace(data)
data = convertToArray(data)
if len(data) == 0 {
return nil
}
if data[0] != '[' {
data = []byte("[" + string(data) + "]")
}
return json.Unmarshal(data, &ey.Data)
}
type EChartsXAxis struct {
Data []struct {
Type string `json:"type"`
BoundaryGap *bool `json:"boundaryGap"`
SplitNumber int `json:"splitNumber"`
Data []string `json:"data"`
}
}
func (ex *EChartsXAxis) UnmarshalJSON(data []byte) error {
data = convertToArray(data)
if len(data) == 0 {
return nil
}
return json.Unmarshal(data, &ex.Data)
}
type ECharsOptions struct {
Theme string `json:"theme"`
Title struct {
Text string `json:"text"`
// 暂不支持(go-chart默认title只能居中)
TextAlign string `json:"textAlign"`
TextStyle struct {
Color string `json:"color"`
// TODO 字体支持
FontFamily string `json:"fontFamily"`
FontSize float64 `json:"fontSize"`
Height float64 `json:"height"`
} `json:"textStyle"`
} `json:"title"`
XAxis struct {
Type string `json:"type"`
BoundaryGap *bool `json:"boundaryGap"`
SplitNumber int `json:"splitNumber"`
Data []string `json:"data"`
} `json:"xAxis"`
XAxis EChartsXAxis `json:"xAxis"`
YAxis EChartsYAxis `json:"yAxis"`
Legend struct {
Data []string `json:"data"`
Align string `json:"align"`
Padding EChartsPadding `json:"padding"`
} `json:"legend"`
Series []struct {
Data []ECharsSeriesData `json:"data"`
@ -167,23 +240,46 @@ func (e *ECharsOptions) ToOptions() Options {
o := Options{
Theme: e.Theme,
}
titleTextStyle := e.Title.TextStyle
o.Title = Title{
Text: e.Title.Text,
Style: chart.Style{
FontColor: parseColor(titleTextStyle.Color),
FontSize: titleTextStyle.FontSize,
},
}
if titleTextStyle.FontSize != 0 && titleTextStyle.Height > titleTextStyle.FontSize {
padding := int(titleTextStyle.Height-titleTextStyle.FontSize) / 2
o.Title.Style.Padding.Top = padding
o.Title.Style.Padding.Bottom = padding
}
boundaryGap := false
if len(e.XAxis.Data) != 0 {
xAxis := e.XAxis.Data[0]
o.XAxis = XAxis{
Type: e.XAxis.Type,
Data: e.XAxis.Data,
SplitNumber: e.XAxis.SplitNumber,
Type: xAxis.Type,
Data: xAxis.Data,
SplitNumber: xAxis.SplitNumber,
}
if xAxis.BoundaryGap == nil || *xAxis.BoundaryGap {
boundaryGap = true
}
}
o.Legend = Legend{
Data: e.Legend.Data,
Align: e.Legend.Align,
Padding: e.Legend.Padding.box,
}
if len(e.YAxis.Data) != 0 {
yAxisOptions := make([]*YAxisOption, len(e.YAxis.Data))
for index, item := range e.YAxis.Data {
opt := &YAxisOption{}
opt := &YAxisOption{
Max: item.Max,
Min: item.Min,
}
template := item.AxisLabel.Formatter
if template != "" {
opt.Formater = func(v interface{}) string {
@ -200,7 +296,7 @@ func (e *ECharsOptions) ToOptions() Options {
o.Series = series
if e.XAxis.BoundaryGap == nil || *e.XAxis.BoundaryGap {
if boundaryGap {
tickPosition = chart.TickPositionBetweenTicks
}
o.TickPosition = tickPosition

View file

@ -42,6 +42,19 @@ var chartOptions = []map[string]string{
{
"title": "折线图",
"option": `{
"title": {
"text": "line",
"textAlign": "left",
"textStyle": {
"color": "#333",
"fontSize": 24,
"height": 40
}
},
"yAxis": {
"min": 0,
"max": 300
},
"xAxis": {
"type": "category",
"data": ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
@ -61,6 +74,8 @@ var chartOptions = []map[string]string{
"text": "Multi Line"
},
"legend": {
"align": "left",
"padding": [5, 0, 0, 50],
"data": ["Email", "Union Ads", "Video Ads", "Direct", "Search Engine"]
},
"xAxis": {
@ -288,6 +303,9 @@ var chartOptions = []map[string]string{
func render(theme string) ([]byte, error) {
data := bytes.Buffer{}
for _, m := range chartOptions {
// if m["title"] != "多柱状图" {
// continue
// }
chartHTML := []byte(`<div>
<h1>{{title}}</h1>
<pre>{{option}}</pre>

View file

@ -28,6 +28,7 @@ import (
type LegendOption struct {
Style chart.Style
Padding chart.Box
Align string
TextPosition string
Theme string
@ -61,7 +62,7 @@ func DefaultLegendIconDraw(r chart.Renderer, opt LegendIconDrawOption) {
stokeWidth := opt.Style.GetStrokeWidth()
r.SetStrokeWidth(stokeWidth)
height := opt.Box.Bottom - opt.Box.Top
ly := (height / 2) + 1
ly := opt.Box.Top - (height / 2) + 2
r.MoveTo(opt.Box.Left, ly)
r.LineTo(opt.Box.Right, ly)
r.Stroke()
@ -126,11 +127,14 @@ func LegendCustomize(c *chart.Chart, opt LegendOption) chart.Renderable {
left = (cb.Width() - labelWidth) / 2
}
left += opt.Padding.Left
top := opt.Padding.Top
legendBox := chart.Box{
Left: left,
Right: left + labelWidth,
Top: 0,
Bottom: 0 + legendBoxHeight,
Top: top,
Bottom: top + legendBoxHeight,
}
chart.Draw.Box(r, legendBox, legendDefaults)
@ -142,7 +146,7 @@ func LegendCustomize(c *chart.Chart, opt LegendOption) chart.Renderable {
lineTextGap := 5
startX := legendBox.Left + legendStyle.Padding.Left
ty := legendYMargin + legendStyle.Padding.Top + textHeight
ty := top + legendYMargin + legendStyle.Padding.Top + textHeight
var label string
var x int
iconDraw := opt.IconDraw