refactor: support more echarts options
This commit is contained in:
parent
23e2eca0c6
commit
c0170bf250
5 changed files with 176 additions and 43 deletions
39
axis.go
39
axis.go
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,9 @@ type (
|
|||
Style chart.Style
|
||||
}
|
||||
Legend struct {
|
||||
Data []string
|
||||
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,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
144
echarts.go
144
echarts.go
|
|
@ -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,11 +77,57 @@ 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"`
|
||||
Interval int `json:"interval"`
|
||||
Min *float64 `json:"min"`
|
||||
Max *float64 `json:"max"`
|
||||
Interval int `json:"interval"`
|
||||
AxisLabel struct {
|
||||
Formatter string `json:"formatter"`
|
||||
} `json:"axisLabel"`
|
||||
|
|
@ -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"`
|
||||
Text string `json:"text"`
|
||||
// 暂不支持(go-chart默认title只能居中)
|
||||
TextAlign string `json:"textAlign"`
|
||||
TextStyle struct {
|
||||
Color string `json:"color"`
|
||||
FontFamily string `json:"fontFamily"`
|
||||
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"`
|
||||
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,
|
||||
},
|
||||
}
|
||||
|
||||
o.XAxis = XAxis{
|
||||
Type: e.XAxis.Type,
|
||||
Data: e.XAxis.Data,
|
||||
SplitNumber: e.XAxis.SplitNumber,
|
||||
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: xAxis.Type,
|
||||
Data: xAxis.Data,
|
||||
SplitNumber: xAxis.SplitNumber,
|
||||
}
|
||||
if xAxis.BoundaryGap == nil || *xAxis.BoundaryGap {
|
||||
boundaryGap = true
|
||||
}
|
||||
}
|
||||
|
||||
o.Legend = Legend{
|
||||
Data: e.Legend.Data,
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
12
legend.go
12
legend.go
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue