refactor: enhance chart render function
This commit is contained in:
parent
65a1cb11ad
commit
38c4978e44
20 changed files with 665 additions and 462 deletions
32
README.md
32
README.md
|
|
@ -49,25 +49,21 @@ func writeFile(file string, buf []byte) error {
|
|||
}
|
||||
|
||||
func chartsRender() ([]byte, error) {
|
||||
d, err := charts.LineRender([][]float64{
|
||||
values := [][]float64{
|
||||
{
|
||||
150,
|
||||
120,
|
||||
132,
|
||||
101,
|
||||
134,
|
||||
90,
|
||||
230,
|
||||
224,
|
||||
218,
|
||||
135,
|
||||
147,
|
||||
260,
|
||||
210,
|
||||
},
|
||||
},
|
||||
// output type
|
||||
charts.PNGTypeOption(),
|
||||
// title
|
||||
charts.TitleOptionFunc(charts.TitleOption{
|
||||
Text: "Line",
|
||||
}),
|
||||
// x axis
|
||||
charts.XAxisOptionFunc(charts.NewXAxisOption([]string{
|
||||
}
|
||||
p, err := charts.LineRender(
|
||||
values,
|
||||
charts.TitleTextOptionFunc("Line"),
|
||||
charts.XAxisDataOptionFunc([]string{
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
|
|
@ -75,12 +71,12 @@ func chartsRender() ([]byte, error) {
|
|||
"Fri",
|
||||
"Sat",
|
||||
"Sun",
|
||||
})),
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return d.Bytes()
|
||||
return p.Bytes()
|
||||
}
|
||||
|
||||
func echartsRender() ([]byte, error) {
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ type barChart struct {
|
|||
|
||||
func NewBarChart(p *Painter, opt BarChartOption) *barChart {
|
||||
if opt.Theme == nil {
|
||||
opt.Theme = NewTheme("")
|
||||
opt.Theme = defaultTheme
|
||||
}
|
||||
return &barChart{
|
||||
p: p,
|
||||
|
|
|
|||
238
chart_option.go
238
chart_option.go
|
|
@ -66,6 +66,182 @@ type ChartOption struct {
|
|||
Children []ChartOption
|
||||
}
|
||||
|
||||
// OptionFunc option function
|
||||
type OptionFunc func(opt *ChartOption)
|
||||
|
||||
// PNGTypeOption set png type of chart's output
|
||||
func PNGTypeOption() OptionFunc {
|
||||
return TypeOptionFunc(ChartOutputPNG)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
}
|
||||
|
||||
// TitleTextOptionFunc set title text of chart
|
||||
func TitleTextOptionFunc(text string) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.Title.Text = text
|
||||
}
|
||||
}
|
||||
|
||||
// LegendOptionFunc set legend of chart
|
||||
func LegendOptionFunc(legend LegendOption) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.Legend = legend
|
||||
}
|
||||
}
|
||||
|
||||
// LegendLabelsOptionFunc set legend labels of chart
|
||||
func LegendLabelsOptionFunc(labels []string, left ...string) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.Legend = NewLegendOption(labels, left...)
|
||||
}
|
||||
}
|
||||
|
||||
// XAxisOptionFunc set x axis of chart
|
||||
func XAxisOptionFunc(xAxisOption XAxisOption) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.XAxis = xAxisOption
|
||||
}
|
||||
}
|
||||
|
||||
// XAxisDataOptionFunc set x axis data of chart
|
||||
func XAxisDataOptionFunc(data []string, boundaryGap ...*bool) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.XAxis = NewXAxisOption(data, boundaryGap...)
|
||||
}
|
||||
}
|
||||
|
||||
// YAxisOptionFunc set y axis of chart, support two y axis
|
||||
func YAxisOptionFunc(yAxisOption ...YAxisOption) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.YAxisOptions = yAxisOption
|
||||
}
|
||||
}
|
||||
|
||||
// YAxisDataOptionFunc set y axis data of chart
|
||||
func YAxisDataOptionFunc(data []string) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.YAxisOptions = NewYAxisOptions(data)
|
||||
}
|
||||
}
|
||||
|
||||
// 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 Box) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.Padding = padding
|
||||
}
|
||||
}
|
||||
|
||||
// BoxOptionFunc set box of chart
|
||||
func BoxOptionFunc(box Box) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.Box = box
|
||||
}
|
||||
}
|
||||
|
||||
// PieSeriesShowLabel set pie series show label
|
||||
func PieSeriesShowLabel() OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
for index := range opt.SeriesList {
|
||||
opt.SeriesList[index].Label.Show = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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(names []string, values []float64) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
if len(names) != len(values) {
|
||||
return
|
||||
}
|
||||
indicators := make([]RadarIndicator, len(names))
|
||||
for index, name := range names {
|
||||
indicators[index] = RadarIndicator{
|
||||
Name: name,
|
||||
Max: values[index],
|
||||
}
|
||||
}
|
||||
opt.RadarIndicators = indicators
|
||||
}
|
||||
}
|
||||
|
||||
// BackgroundColorOptionFunc set background color of chart
|
||||
func BackgroundColorOptionFunc(color Color) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
opt.BackgroundColor = color
|
||||
}
|
||||
}
|
||||
|
||||
// MarkLineOptionFunc set mark line for series of chart
|
||||
func MarkLineOptionFunc(seriesIndex int, markLineTypes ...string) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
if len(opt.SeriesList) <= seriesIndex {
|
||||
return
|
||||
}
|
||||
opt.SeriesList[seriesIndex].MarkLine = NewMarkLine(markLineTypes...)
|
||||
}
|
||||
}
|
||||
|
||||
// MarkPointOptionFunc set mark point for series of chart
|
||||
func MarkPointOptionFunc(seriesIndex int, markPointTypes ...string) OptionFunc {
|
||||
return func(opt *ChartOption) {
|
||||
if len(opt.SeriesList) <= seriesIndex {
|
||||
return
|
||||
}
|
||||
opt.SeriesList[seriesIndex].MarkPoint = NewMarkPoint(markPointTypes...)
|
||||
}
|
||||
}
|
||||
|
||||
func (o *ChartOption) fillDefault() {
|
||||
t := NewTheme(o.Theme)
|
||||
o.theme = t
|
||||
|
|
@ -90,11 +266,11 @@ func (o *ChartOption) fillDefault() {
|
|||
o.BackgroundColor = t.GetBackgroundColor()
|
||||
}
|
||||
if o.Padding.IsZero() {
|
||||
o.Padding = chart.Box{
|
||||
Top: 10,
|
||||
Right: 10,
|
||||
Bottom: 10,
|
||||
Left: 10,
|
||||
o.Padding = Box{
|
||||
Top: 20,
|
||||
Right: 20,
|
||||
Bottom: 20,
|
||||
Left: 20,
|
||||
}
|
||||
}
|
||||
// legend与series name的关联
|
||||
|
|
@ -118,3 +294,55 @@ func (o *ChartOption) fillDefault() {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
// LineRender line chart render
|
||||
func LineRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
|
||||
seriesList := NewSeriesListDataFromValues(values, ChartTypeLine)
|
||||
return Render(ChartOption{
|
||||
SeriesList: seriesList,
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// BarRender bar chart render
|
||||
func BarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
|
||||
seriesList := NewSeriesListDataFromValues(values, ChartTypeBar)
|
||||
return Render(ChartOption{
|
||||
SeriesList: seriesList,
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// HorizontalBarRender horizontal bar chart render
|
||||
func HorizontalBarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
|
||||
seriesList := NewSeriesListDataFromValues(values, ChartTypeHorizontalBar)
|
||||
return Render(ChartOption{
|
||||
SeriesList: seriesList,
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// PieRender pie chart render
|
||||
func PieRender(values []float64, opts ...OptionFunc) (*Painter, error) {
|
||||
return Render(ChartOption{
|
||||
SeriesList: NewPieSeriesList(values),
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// RadarRender radar chart render
|
||||
func RadarRender(values [][]float64, opts ...OptionFunc) (*Painter, error) {
|
||||
seriesList := NewSeriesListDataFromValues(values, ChartTypeRadar)
|
||||
return Render(ChartOption{
|
||||
SeriesList: seriesList,
|
||||
}, opts...)
|
||||
}
|
||||
|
||||
// FunnelRender funnel chart render
|
||||
func FunnelRender(values []float64, opts ...OptionFunc) (*Painter, error) {
|
||||
seriesList := make(SeriesList, len(values))
|
||||
for index, value := range values {
|
||||
seriesList[index] = NewSeriesFromValues([]float64{
|
||||
value,
|
||||
}, ChartTypeFunnel)
|
||||
}
|
||||
return Render(ChartOption{
|
||||
SeriesList: seriesList,
|
||||
}, opts...)
|
||||
}
|
||||
|
|
|
|||
11
charts.go
11
charts.go
|
|
@ -239,7 +239,10 @@ func doRender(renderers ...Renderer) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func Render(opt ChartOption) (*Painter, error) {
|
||||
func Render(opt ChartOption, opts ...OptionFunc) (*Painter, error) {
|
||||
for _, fn := range opts {
|
||||
fn(&opt)
|
||||
}
|
||||
opt.fillDefault()
|
||||
|
||||
isChild := true
|
||||
|
|
@ -398,6 +401,12 @@ func Render(opt ChartOption) (*Painter, error) {
|
|||
}
|
||||
for _, item := range opt.Children {
|
||||
item.Parent = p
|
||||
if item.Theme == "" {
|
||||
item.Theme = opt.Theme
|
||||
}
|
||||
if item.FontFamily == "" {
|
||||
item.FontFamily = opt.FontFamily
|
||||
}
|
||||
_, err = Render(item)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
18
echarts.go
18
echarts.go
|
|
@ -130,6 +130,7 @@ type EChartsXAxisData struct {
|
|||
BoundaryGap *bool `json:"boundaryGap"`
|
||||
SplitNumber int `json:"splitNumber"`
|
||||
Data []string `json:"data"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type EChartsXAxis struct {
|
||||
Data []EChartsXAxisData
|
||||
|
|
@ -155,6 +156,7 @@ type EChartsYAxisData struct {
|
|||
Color string `json:"color"`
|
||||
} `json:"lineStyle"`
|
||||
} `json:"axisLine"`
|
||||
Data []string `json:"data"`
|
||||
}
|
||||
type EChartsYAxis struct {
|
||||
Data []EChartsYAxisData `json:"data"`
|
||||
|
|
@ -453,6 +455,21 @@ func (eo *EChartsOption) ToOption() ChartOption {
|
|||
Box: eo.Box,
|
||||
SeriesList: eo.Series.ToSeriesList(),
|
||||
}
|
||||
isHorizontalChart := false
|
||||
for _, item := range eo.XAxis.Data {
|
||||
if item.Type == "value" {
|
||||
isHorizontalChart = true
|
||||
}
|
||||
}
|
||||
if isHorizontalChart {
|
||||
for index := range o.SeriesList {
|
||||
series := o.SeriesList[index]
|
||||
if series.Type == ChartTypeBar {
|
||||
o.SeriesList[index].Type = ChartTypeHorizontalBar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(eo.XAxis.Data) != 0 {
|
||||
xAxisData := eo.XAxis.Data[0]
|
||||
o.XAxis = XAxisOption{
|
||||
|
|
@ -468,6 +485,7 @@ func (eo *EChartsOption) ToOption() ChartOption {
|
|||
Max: item.Max,
|
||||
Formatter: item.AxisLabel.Formatter,
|
||||
Color: parseColor(item.AxisLine.LineStyle.Color),
|
||||
Data: item.Data,
|
||||
}
|
||||
}
|
||||
o.YAxisOptions = yAxisOptions
|
||||
|
|
|
|||
|
|
@ -24,26 +24,39 @@ func writeFile(buf []byte) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
p, err := charts.NewPainter(charts.PainterOptions{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Type: charts.ChartOutputPNG,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
values := [][]float64{
|
||||
{
|
||||
2.0,
|
||||
4.9,
|
||||
7.0,
|
||||
23.2,
|
||||
25.6,
|
||||
76.7,
|
||||
135.6,
|
||||
162.2,
|
||||
32.6,
|
||||
20.0,
|
||||
6.4,
|
||||
3.3,
|
||||
},
|
||||
{
|
||||
2.6,
|
||||
5.9,
|
||||
9.0,
|
||||
26.4,
|
||||
28.7,
|
||||
70.7,
|
||||
175.6,
|
||||
182.2,
|
||||
48.7,
|
||||
18.8,
|
||||
6.0,
|
||||
2.3,
|
||||
},
|
||||
}
|
||||
_, err = charts.NewBarChart(p, charts.BarChartOption{
|
||||
Title: charts.TitleOption{
|
||||
Text: "Rainfall vs Evaporation",
|
||||
Subtext: "Fake Data",
|
||||
},
|
||||
Padding: charts.Box{
|
||||
Top: 20,
|
||||
Right: 20,
|
||||
Bottom: 20,
|
||||
Left: 20,
|
||||
},
|
||||
XAxis: charts.NewXAxisOption([]string{
|
||||
p, err := charts.BarRender(
|
||||
values,
|
||||
charts.XAxisDataOptionFunc([]string{
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
|
|
@ -57,61 +70,24 @@ func main() {
|
|||
"Nov",
|
||||
"Dec",
|
||||
}),
|
||||
Legend: charts.NewLegendOption([]string{
|
||||
charts.LegendLabelsOptionFunc([]string{
|
||||
"Rainfall",
|
||||
"Evaporation",
|
||||
}, charts.PositionRight),
|
||||
SeriesList: []charts.Series{
|
||||
{
|
||||
Type: charts.ChartTypeBar,
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
2.0,
|
||||
4.9,
|
||||
7.0,
|
||||
23.2,
|
||||
25.6,
|
||||
76.7,
|
||||
135.6,
|
||||
162.2,
|
||||
32.6,
|
||||
20.0,
|
||||
6.4,
|
||||
3.3,
|
||||
}),
|
||||
MarkPoint: charts.NewMarkPoint(
|
||||
charts.SeriesMarkDataTypeMax,
|
||||
charts.SeriesMarkDataTypeMin,
|
||||
),
|
||||
MarkLine: charts.NewMarkLine(
|
||||
charts.SeriesMarkDataTypeAverage,
|
||||
),
|
||||
},
|
||||
{
|
||||
Type: charts.ChartTypeBar,
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
2.6,
|
||||
5.9,
|
||||
9.0,
|
||||
26.4,
|
||||
28.7,
|
||||
70.7,
|
||||
175.6,
|
||||
182.2,
|
||||
48.7,
|
||||
18.8,
|
||||
6.0,
|
||||
2.3,
|
||||
}),
|
||||
MarkPoint: charts.NewMarkPoint(
|
||||
charts.SeriesMarkDataTypeMax,
|
||||
charts.SeriesMarkDataTypeMin,
|
||||
),
|
||||
MarkLine: charts.NewMarkLine(
|
||||
charts.SeriesMarkDataTypeAverage,
|
||||
),
|
||||
},
|
||||
charts.MarkLineOptionFunc(0, charts.SeriesMarkDataTypeAverage),
|
||||
charts.MarkPointOptionFunc(0, charts.SeriesMarkDataTypeMax,
|
||||
charts.SeriesMarkDataTypeMin),
|
||||
// custom option func
|
||||
func(opt *charts.ChartOption) {
|
||||
opt.SeriesList[1].MarkPoint = charts.NewMarkPoint(
|
||||
charts.SeriesMarkDataTypeMax,
|
||||
charts.SeriesMarkDataTypeMin,
|
||||
)
|
||||
opt.SeriesList[1].MarkLine = charts.NewMarkLine(
|
||||
charts.SeriesMarkDataTypeAverage,
|
||||
)
|
||||
},
|
||||
}).Render()
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,7 @@ func handler(w http.ResponseWriter, req *http.Request, chartOptions []charts.Cha
|
|||
bytesList := make([][]byte, 0)
|
||||
for _, opt := range chartOptions {
|
||||
opt.Theme = theme
|
||||
opt.Type = charts.ChartOutputSVG
|
||||
d, err := charts.Render(opt)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
|
@ -1055,6 +1056,64 @@ func echartsHandler(w http.ResponseWriter, req *http.Request) {
|
|||
}
|
||||
]
|
||||
}`,
|
||||
`{
|
||||
"title": {
|
||||
"text": "World Population"
|
||||
},
|
||||
"tooltip": {
|
||||
"trigger": "axis",
|
||||
"axisPointer": {
|
||||
"type": "shadow"
|
||||
}
|
||||
},
|
||||
"legend": {},
|
||||
"grid": {
|
||||
"left": "3%",
|
||||
"right": "4%",
|
||||
"bottom": "3%",
|
||||
"containLabel": true
|
||||
},
|
||||
"xAxis": {
|
||||
"type": "value"
|
||||
},
|
||||
"yAxis": {
|
||||
"type": "category",
|
||||
"data": [
|
||||
"Brazil",
|
||||
"Indonesia",
|
||||
"USA",
|
||||
"India",
|
||||
"China",
|
||||
"World"
|
||||
]
|
||||
},
|
||||
"series": [
|
||||
{
|
||||
"name": "2011",
|
||||
"type": "bar",
|
||||
"data": [
|
||||
18203,
|
||||
23489,
|
||||
29034,
|
||||
104970,
|
||||
131744,
|
||||
630230
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "2012",
|
||||
"type": "bar",
|
||||
"data": [
|
||||
19325,
|
||||
23438,
|
||||
31000,
|
||||
121594,
|
||||
134141,
|
||||
681807
|
||||
]
|
||||
}
|
||||
]
|
||||
}`,
|
||||
`{
|
||||
"title": {
|
||||
"text": "Rainfall vs Evaporation",
|
||||
|
|
|
|||
|
|
@ -24,64 +24,24 @@ func writeFile(buf []byte) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
p, err := charts.NewPainter(charts.PainterOptions{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Type: charts.ChartOutputPNG,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
values := []float64{
|
||||
100,
|
||||
80,
|
||||
60,
|
||||
40,
|
||||
20,
|
||||
}
|
||||
_, err = charts.NewFunnelChart(p, charts.FunnelChartOption{
|
||||
Title: charts.TitleOption{
|
||||
Text: "Funnel",
|
||||
},
|
||||
Legend: charts.NewLegendOption([]string{
|
||||
p, err := charts.FunnelRender(
|
||||
values,
|
||||
charts.TitleTextOptionFunc("Funnel"),
|
||||
charts.LegendLabelsOptionFunc([]string{
|
||||
"Show",
|
||||
"Click",
|
||||
"Visit",
|
||||
"Inquiry",
|
||||
"Order",
|
||||
}),
|
||||
SeriesList: []charts.Series{
|
||||
|
||||
{
|
||||
Type: charts.ChartTypeFunnel,
|
||||
Name: "Show",
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
100,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Type: charts.ChartTypeFunnel,
|
||||
Name: "Click",
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
80,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Type: charts.ChartTypeFunnel,
|
||||
Name: "Visit",
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
60,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Type: charts.ChartTypeFunnel,
|
||||
Name: "Inquiry",
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
40,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Type: charts.ChartTypeFunnel,
|
||||
Name: "Order",
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
20,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).Render()
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,29 +24,38 @@ func writeFile(buf []byte) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
p, err := charts.NewPainter(charts.PainterOptions{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Type: charts.ChartOutputPNG,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
_, err = charts.NewHorizontalBarChart(p, charts.HorizontalBarChartOption{
|
||||
Title: charts.TitleOption{
|
||||
Text: "World Population",
|
||||
values := [][]float64{
|
||||
{
|
||||
18203,
|
||||
23489,
|
||||
29034,
|
||||
104970,
|
||||
131744,
|
||||
630230,
|
||||
},
|
||||
Padding: charts.Box{
|
||||
{
|
||||
19325,
|
||||
23438,
|
||||
31000,
|
||||
121594,
|
||||
134141,
|
||||
681807,
|
||||
},
|
||||
}
|
||||
p, err := charts.HorizontalBarRender(
|
||||
values,
|
||||
charts.TitleTextOptionFunc("World Population"),
|
||||
charts.PaddingOptionFunc(charts.Box{
|
||||
Top: 20,
|
||||
Right: 40,
|
||||
Bottom: 20,
|
||||
Left: 20,
|
||||
},
|
||||
Legend: charts.NewLegendOption([]string{
|
||||
}),
|
||||
charts.LegendLabelsOptionFunc([]string{
|
||||
"2011",
|
||||
"2012",
|
||||
}),
|
||||
YAxisOptions: charts.NewYAxisOptions([]string{
|
||||
charts.YAxisDataOptionFunc([]string{
|
||||
"Brazil",
|
||||
"Indonesia",
|
||||
"USA",
|
||||
|
|
@ -54,31 +63,7 @@ func main() {
|
|||
"China",
|
||||
"World",
|
||||
}),
|
||||
SeriesList: []charts.Series{
|
||||
{
|
||||
Type: charts.ChartTypeHorizontalBar,
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
18203,
|
||||
23489,
|
||||
29034,
|
||||
104970,
|
||||
131744,
|
||||
630230,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Type: charts.ChartTypeHorizontalBar,
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
19325,
|
||||
23438,
|
||||
31000,
|
||||
121594,
|
||||
134141,
|
||||
681807,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).Render()
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,35 +24,57 @@ func writeFile(buf []byte) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
p, err := charts.NewPainter(charts.PainterOptions{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Type: charts.ChartOutputPNG,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
values := [][]float64{
|
||||
{
|
||||
120,
|
||||
132,
|
||||
101,
|
||||
134,
|
||||
90,
|
||||
230,
|
||||
210,
|
||||
},
|
||||
{
|
||||
220,
|
||||
182,
|
||||
191,
|
||||
234,
|
||||
290,
|
||||
330,
|
||||
310,
|
||||
},
|
||||
{
|
||||
150,
|
||||
232,
|
||||
201,
|
||||
154,
|
||||
190,
|
||||
330,
|
||||
410,
|
||||
},
|
||||
{
|
||||
320,
|
||||
332,
|
||||
301,
|
||||
334,
|
||||
390,
|
||||
330,
|
||||
320,
|
||||
},
|
||||
{
|
||||
820,
|
||||
932,
|
||||
901,
|
||||
934,
|
||||
1290,
|
||||
1330,
|
||||
1320,
|
||||
},
|
||||
}
|
||||
_, err = charts.NewLineChart(p, charts.LineChartOption{
|
||||
Padding: charts.Box{
|
||||
Left: 10,
|
||||
Top: 10,
|
||||
Right: 10,
|
||||
Bottom: 10,
|
||||
},
|
||||
Title: charts.TitleOption{
|
||||
Text: "Line",
|
||||
},
|
||||
Legend: charts.LegendOption{
|
||||
Data: []string{
|
||||
"Email",
|
||||
"Union Ads",
|
||||
"Video Ads",
|
||||
"Direct",
|
||||
"Search Engine",
|
||||
},
|
||||
Left: charts.PositionCenter,
|
||||
},
|
||||
XAxis: charts.NewXAxisOption([]string{
|
||||
p, err := charts.LineRender(
|
||||
values,
|
||||
charts.TitleTextOptionFunc("Line"),
|
||||
charts.XAxisDataOptionFunc([]string{
|
||||
"Mon",
|
||||
"Tue",
|
||||
"Wed",
|
||||
|
|
@ -61,54 +83,15 @@ func main() {
|
|||
"Sat",
|
||||
"Sun",
|
||||
}),
|
||||
SeriesList: charts.SeriesList{
|
||||
charts.NewSeriesFromValues([]float64{
|
||||
120,
|
||||
132,
|
||||
101,
|
||||
134,
|
||||
90,
|
||||
230,
|
||||
210,
|
||||
}),
|
||||
charts.NewSeriesFromValues([]float64{
|
||||
220,
|
||||
182,
|
||||
191,
|
||||
234,
|
||||
290,
|
||||
330,
|
||||
310,
|
||||
}),
|
||||
charts.NewSeriesFromValues([]float64{
|
||||
150,
|
||||
232,
|
||||
201,
|
||||
154,
|
||||
190,
|
||||
330,
|
||||
410,
|
||||
}),
|
||||
charts.NewSeriesFromValues([]float64{
|
||||
320,
|
||||
332,
|
||||
301,
|
||||
334,
|
||||
390,
|
||||
330,
|
||||
320,
|
||||
}),
|
||||
charts.NewSeriesFromValues([]float64{
|
||||
820,
|
||||
932,
|
||||
901,
|
||||
934,
|
||||
1290,
|
||||
1330,
|
||||
1320,
|
||||
}),
|
||||
},
|
||||
}).Render()
|
||||
charts.LegendLabelsOptionFunc([]string{
|
||||
"Email",
|
||||
"Union Ads",
|
||||
"Video Ads",
|
||||
"Direct",
|
||||
"Search Engine",
|
||||
}, charts.PositionCenter),
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,27 +24,27 @@ func writeFile(buf []byte) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
p, err := charts.NewPainter(charts.PainterOptions{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Type: charts.ChartOutputPNG,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
values := []float64{
|
||||
1048,
|
||||
735,
|
||||
580,
|
||||
484,
|
||||
300,
|
||||
}
|
||||
_, err = charts.NewPieChart(p, charts.PieChartOption{
|
||||
Title: charts.TitleOption{
|
||||
p, err := charts.PieRender(
|
||||
values,
|
||||
charts.TitleOptionFunc(charts.TitleOption{
|
||||
Text: "Rainfall vs Evaporation",
|
||||
Subtext: "Fake Data",
|
||||
Left: charts.PositionCenter,
|
||||
},
|
||||
Padding: charts.Box{
|
||||
}),
|
||||
charts.PaddingOptionFunc(charts.Box{
|
||||
Top: 20,
|
||||
Right: 20,
|
||||
Bottom: 20,
|
||||
Left: 20,
|
||||
},
|
||||
Legend: charts.LegendOption{
|
||||
}),
|
||||
charts.LegendOptionFunc(charts.LegendOption{
|
||||
Orient: charts.OrientVertical,
|
||||
Data: []string{
|
||||
"Search Engine",
|
||||
|
|
@ -54,20 +54,9 @@ func main() {
|
|||
"Video Ads",
|
||||
},
|
||||
Left: charts.PositionLeft,
|
||||
},
|
||||
SeriesList: charts.NewPieSeriesList([]float64{
|
||||
1048,
|
||||
735,
|
||||
580,
|
||||
484,
|
||||
300,
|
||||
}, charts.PieSeriesOption{
|
||||
Label: charts.SeriesLabel{
|
||||
Show: true,
|
||||
},
|
||||
Radius: "35%",
|
||||
}),
|
||||
}).Render()
|
||||
charts.PieSeriesShowLabel(),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,79 +24,47 @@ func writeFile(buf []byte) error {
|
|||
}
|
||||
|
||||
func main() {
|
||||
p, err := charts.NewPainter(charts.PainterOptions{
|
||||
Width: 800,
|
||||
Height: 600,
|
||||
Type: charts.ChartOutputPNG,
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
values := [][]float64{
|
||||
{
|
||||
4200,
|
||||
3000,
|
||||
20000,
|
||||
35000,
|
||||
50000,
|
||||
18000,
|
||||
},
|
||||
{
|
||||
5000,
|
||||
14000,
|
||||
28000,
|
||||
26000,
|
||||
42000,
|
||||
21000,
|
||||
},
|
||||
}
|
||||
_, err = charts.NewRadarChart(p, charts.RadarChartOption{
|
||||
Padding: charts.Box{
|
||||
Left: 10,
|
||||
Top: 10,
|
||||
Right: 10,
|
||||
Bottom: 10,
|
||||
},
|
||||
Title: charts.TitleOption{
|
||||
Text: "Basic Radar Chart",
|
||||
},
|
||||
Legend: charts.NewLegendOption([]string{
|
||||
p, err := charts.RadarRender(
|
||||
values,
|
||||
charts.TitleTextOptionFunc("Basic Radar Chart"),
|
||||
charts.LegendLabelsOptionFunc([]string{
|
||||
"Allocated Budget",
|
||||
"Actual Spending",
|
||||
}),
|
||||
RadarIndicators: []charts.RadarIndicator{
|
||||
{
|
||||
Name: "Sales",
|
||||
Max: 6500,
|
||||
},
|
||||
{
|
||||
Name: "Administration",
|
||||
Max: 16000,
|
||||
},
|
||||
{
|
||||
Name: "Information Technology",
|
||||
Max: 30000,
|
||||
},
|
||||
{
|
||||
Name: "Customer Support",
|
||||
Max: 38000,
|
||||
},
|
||||
{
|
||||
Name: "Development",
|
||||
Max: 52000,
|
||||
},
|
||||
{
|
||||
Name: "Marketing",
|
||||
Max: 25000,
|
||||
},
|
||||
},
|
||||
SeriesList: charts.SeriesList{
|
||||
{
|
||||
Type: charts.ChartTypeRadar,
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
4200,
|
||||
3000,
|
||||
20000,
|
||||
35000,
|
||||
50000,
|
||||
18000,
|
||||
}),
|
||||
},
|
||||
{
|
||||
Type: charts.ChartTypeRadar,
|
||||
Data: charts.NewSeriesDataFromValues([]float64{
|
||||
5000,
|
||||
14000,
|
||||
28000,
|
||||
26000,
|
||||
42000,
|
||||
21000,
|
||||
}),
|
||||
},
|
||||
},
|
||||
}).Render()
|
||||
charts.RadarIndicatorOptionFunc([]string{
|
||||
"Sales",
|
||||
"Administration",
|
||||
"Information Technology",
|
||||
"Customer Support",
|
||||
"Development",
|
||||
"Marketing",
|
||||
}, []float64{
|
||||
6500,
|
||||
16000,
|
||||
30000,
|
||||
38000,
|
||||
52000,
|
||||
25000,
|
||||
}),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ type funnelChart struct {
|
|||
|
||||
func NewFunnelChart(p *Painter, opt FunnelChartOption) *funnelChart {
|
||||
if opt.Theme == nil {
|
||||
opt.Theme = NewTheme("")
|
||||
opt.Theme = defaultTheme
|
||||
}
|
||||
return &funnelChart{
|
||||
p: p,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ type HorizontalBarChartOption struct {
|
|||
|
||||
func NewHorizontalBarChart(p *Painter, opt HorizontalBarChartOption) *horizontalBarChart {
|
||||
if opt.Theme == nil {
|
||||
opt.Theme = NewTheme("")
|
||||
opt.Theme = defaultTheme
|
||||
}
|
||||
return &horizontalBarChart{
|
||||
p: p,
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ type lineChart struct {
|
|||
|
||||
func NewLineChart(p *Painter, opt LineChartOption) *lineChart {
|
||||
if opt.Theme == nil {
|
||||
opt.Theme = NewTheme("")
|
||||
opt.Theme = defaultTheme
|
||||
}
|
||||
return &lineChart{
|
||||
p: p,
|
||||
|
|
|
|||
|
|
@ -149,9 +149,9 @@ func NewPainter(opts PainterOptions, opt ...PainterOption) (*Painter, error) {
|
|||
}
|
||||
font = f
|
||||
}
|
||||
fn := chart.SVG
|
||||
if opts.Type == ChartOutputPNG {
|
||||
fn = chart.PNG
|
||||
fn := chart.PNG
|
||||
if opts.Type == ChartOutputSVG {
|
||||
fn = chart.SVG
|
||||
}
|
||||
width := opts.Width
|
||||
height := opts.Height
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ type PieChartOption struct {
|
|||
|
||||
func NewPieChart(p *Painter, opt PieChartOption) *pieChart {
|
||||
if opt.Theme == nil {
|
||||
opt.Theme = NewTheme("")
|
||||
opt.Theme = defaultTheme
|
||||
}
|
||||
return &pieChart{
|
||||
p: p,
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ type RadarChartOption struct {
|
|||
|
||||
func NewRadarChart(p *Painter, opt RadarChartOption) *radarChart {
|
||||
if opt.Theme == nil {
|
||||
opt.Theme = NewTheme("")
|
||||
opt.Theme = defaultTheme
|
||||
}
|
||||
return &radarChart{
|
||||
p: p,
|
||||
|
|
|
|||
|
|
@ -36,6 +36,14 @@ type SeriesData struct {
|
|||
Style Style
|
||||
}
|
||||
|
||||
func NewSeriesListDataFromValues(values [][]float64, chartType ...string) SeriesList {
|
||||
seriesList := make(SeriesList, len(values))
|
||||
for index, value := range values {
|
||||
seriesList[index] = NewSeriesFromValues(value, chartType...)
|
||||
}
|
||||
return seriesList
|
||||
}
|
||||
|
||||
func NewSeriesFromValues(values []float64, chartType ...string) Series {
|
||||
s := Series{
|
||||
Data: NewSeriesDataFromValues(values),
|
||||
|
|
|
|||
218
theme.go
218
theme.go
|
|
@ -55,10 +55,21 @@ type themeColorPalette struct {
|
|||
font *truetype.Font
|
||||
}
|
||||
|
||||
type ThemeOption struct {
|
||||
IsDarkMode bool
|
||||
AxisStrokeColor Color
|
||||
AxisSplitLineColor Color
|
||||
BackgroundColor Color
|
||||
TextColor Color
|
||||
SeriesColors []Color
|
||||
}
|
||||
|
||||
var palettes = map[string]ColorPalette{}
|
||||
|
||||
const defaultFontSize = 12.0
|
||||
|
||||
var defaultTheme ColorPalette
|
||||
|
||||
func init() {
|
||||
echartSeriesColors := []Color{
|
||||
parseColor("#5470c6"),
|
||||
|
|
@ -93,121 +104,134 @@ func init() {
|
|||
}
|
||||
AddTheme(
|
||||
ThemeDark,
|
||||
true,
|
||||
Color{
|
||||
R: 185,
|
||||
G: 184,
|
||||
B: 206,
|
||||
A: 255,
|
||||
ThemeOption{
|
||||
IsDarkMode: true,
|
||||
AxisStrokeColor: Color{
|
||||
R: 185,
|
||||
G: 184,
|
||||
B: 206,
|
||||
A: 255,
|
||||
},
|
||||
AxisSplitLineColor: Color{
|
||||
R: 72,
|
||||
G: 71,
|
||||
B: 83,
|
||||
A: 255,
|
||||
},
|
||||
BackgroundColor: Color{
|
||||
R: 16,
|
||||
G: 12,
|
||||
B: 42,
|
||||
A: 255,
|
||||
},
|
||||
TextColor: Color{
|
||||
R: 238,
|
||||
G: 238,
|
||||
B: 238,
|
||||
A: 255,
|
||||
},
|
||||
SeriesColors: echartSeriesColors,
|
||||
},
|
||||
Color{
|
||||
R: 72,
|
||||
G: 71,
|
||||
B: 83,
|
||||
A: 255,
|
||||
},
|
||||
Color{
|
||||
R: 16,
|
||||
G: 12,
|
||||
B: 42,
|
||||
A: 255,
|
||||
},
|
||||
Color{
|
||||
R: 238,
|
||||
G: 238,
|
||||
B: 238,
|
||||
A: 255,
|
||||
},
|
||||
echartSeriesColors,
|
||||
)
|
||||
|
||||
AddTheme(
|
||||
ThemeLight,
|
||||
false,
|
||||
Color{
|
||||
R: 110,
|
||||
G: 112,
|
||||
B: 121,
|
||||
A: 255,
|
||||
ThemeOption{
|
||||
IsDarkMode: false,
|
||||
AxisStrokeColor: Color{
|
||||
R: 110,
|
||||
G: 112,
|
||||
B: 121,
|
||||
A: 255,
|
||||
},
|
||||
AxisSplitLineColor: Color{
|
||||
R: 224,
|
||||
G: 230,
|
||||
B: 242,
|
||||
A: 255,
|
||||
},
|
||||
BackgroundColor: drawing.ColorWhite,
|
||||
TextColor: Color{
|
||||
R: 70,
|
||||
G: 70,
|
||||
B: 70,
|
||||
A: 255,
|
||||
},
|
||||
SeriesColors: echartSeriesColors,
|
||||
},
|
||||
Color{
|
||||
R: 224,
|
||||
G: 230,
|
||||
B: 242,
|
||||
A: 255,
|
||||
},
|
||||
drawing.ColorWhite,
|
||||
drawing.Color{
|
||||
R: 70,
|
||||
G: 70,
|
||||
B: 70,
|
||||
A: 255,
|
||||
},
|
||||
echartSeriesColors,
|
||||
)
|
||||
AddTheme(
|
||||
ThemeAnt,
|
||||
false,
|
||||
Color{
|
||||
R: 110,
|
||||
G: 112,
|
||||
B: 121,
|
||||
A: 255,
|
||||
ThemeOption{
|
||||
IsDarkMode: false,
|
||||
AxisStrokeColor: Color{
|
||||
R: 110,
|
||||
G: 112,
|
||||
B: 121,
|
||||
A: 255,
|
||||
},
|
||||
AxisSplitLineColor: Color{
|
||||
R: 224,
|
||||
G: 230,
|
||||
B: 242,
|
||||
A: 255,
|
||||
},
|
||||
BackgroundColor: drawing.ColorWhite,
|
||||
TextColor: drawing.Color{
|
||||
R: 70,
|
||||
G: 70,
|
||||
B: 70,
|
||||
A: 255,
|
||||
},
|
||||
SeriesColors: antSeriesColors,
|
||||
},
|
||||
Color{
|
||||
R: 224,
|
||||
G: 230,
|
||||
B: 242,
|
||||
A: 255,
|
||||
},
|
||||
drawing.ColorWhite,
|
||||
drawing.Color{
|
||||
R: 70,
|
||||
G: 70,
|
||||
B: 70,
|
||||
A: 255,
|
||||
},
|
||||
antSeriesColors,
|
||||
)
|
||||
AddTheme(
|
||||
ThemeGrafana,
|
||||
true,
|
||||
drawing.Color{
|
||||
R: 185,
|
||||
G: 184,
|
||||
B: 206,
|
||||
A: 255,
|
||||
ThemeOption{
|
||||
IsDarkMode: true,
|
||||
AxisStrokeColor: Color{
|
||||
R: 185,
|
||||
G: 184,
|
||||
B: 206,
|
||||
A: 255,
|
||||
},
|
||||
AxisSplitLineColor: Color{
|
||||
R: 68,
|
||||
G: 67,
|
||||
B: 67,
|
||||
A: 255,
|
||||
},
|
||||
BackgroundColor: drawing.Color{
|
||||
R: 31,
|
||||
G: 29,
|
||||
B: 29,
|
||||
A: 255,
|
||||
},
|
||||
TextColor: Color{
|
||||
R: 216,
|
||||
G: 217,
|
||||
B: 218,
|
||||
A: 255,
|
||||
},
|
||||
SeriesColors: grafanaSeriesColors,
|
||||
},
|
||||
drawing.Color{
|
||||
R: 68,
|
||||
G: 67,
|
||||
B: 67,
|
||||
A: 255,
|
||||
},
|
||||
drawing.Color{
|
||||
R: 31,
|
||||
G: 29,
|
||||
B: 29,
|
||||
A: 255,
|
||||
},
|
||||
drawing.Color{
|
||||
R: 216,
|
||||
G: 217,
|
||||
B: 218,
|
||||
A: 255,
|
||||
},
|
||||
grafanaSeriesColors,
|
||||
)
|
||||
SetDefaultTheme(ThemeLight)
|
||||
}
|
||||
|
||||
func AddTheme(name string, isDarkMode bool, axisStrokeColor, axisSplitLineColor, backgroundColor, textColor drawing.Color, seriesColors []drawing.Color) {
|
||||
func SetDefaultTheme(name string) {
|
||||
defaultTheme = NewTheme(name)
|
||||
}
|
||||
|
||||
func AddTheme(name string, opt ThemeOption) {
|
||||
palettes[name] = &themeColorPalette{
|
||||
isDarkMode: isDarkMode,
|
||||
axisStrokeColor: axisStrokeColor,
|
||||
axisSplitLineColor: axisSplitLineColor,
|
||||
backgroundColor: backgroundColor,
|
||||
textColor: textColor,
|
||||
seriesColors: seriesColors,
|
||||
isDarkMode: opt.IsDarkMode,
|
||||
axisStrokeColor: opt.AxisStrokeColor,
|
||||
axisSplitLineColor: opt.AxisSplitLineColor,
|
||||
backgroundColor: opt.BackgroundColor,
|
||||
textColor: opt.TextColor,
|
||||
seriesColors: opt.SeriesColors,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue