diff --git a/chart.go b/chart.go index b8f9069..1f68505 100644 --- a/chart.go +++ b/chart.go @@ -9,62 +9,73 @@ import ( // This section defines the currently supported chart types. const ( - Bar = "bar" - BarStacked = "barStacked" - Bar3D = "bar3D" - Doughnut = "doughnut" - Line = "line" - Pie = "pie" - Pie3D = "pie3D" - Radar = "radar" - Scatter = "scatter" + Bar = "bar" + BarStacked = "barStacked" + Bar3D = "bar3D" + Bar3DColumn = "bar3DColumn" + Bar3DPercentStacked = "bar3DPercentStacked" + Doughnut = "doughnut" + Line = "line" + Pie = "pie" + Pie3D = "pie3D" + Radar = "radar" + Scatter = "scatter" ) // This section defines the default value of chart properties. var ( chartView3DRotX = map[string]int{ - Bar: 0, - BarStacked: 0, - Bar3D: 15, - Doughnut: 0, - Line: 0, - Pie: 0, - Pie3D: 30, - Radar: 0, - Scatter: 0, + Bar: 0, + BarStacked: 0, + Bar3D: 15, + Bar3DColumn: 15, + Bar3DPercentStacked: 15, + Doughnut: 0, + Line: 0, + Pie: 0, + Pie3D: 30, + Radar: 0, + Scatter: 0, } chartView3DRotY = map[string]int{ - Bar: 0, - BarStacked: 0, - Bar3D: 20, - Doughnut: 0, - Line: 0, - Pie: 0, - Pie3D: 0, - Radar: 0, - Scatter: 0, + Bar: 0, + BarStacked: 0, + Bar3D: 20, + Bar3DColumn: 20, + Bar3DPercentStacked: 20, + Doughnut: 0, + Line: 0, + Pie: 0, + Pie3D: 0, + Radar: 0, + Scatter: 0, } chartView3DDepthPercent = map[string]int{ - Bar: 100, - BarStacked: 100, - Bar3D: 100, - Doughnut: 100, - Line: 100, - Pie: 100, - Pie3D: 100, - Radar: 100, - Scatter: 100, + Bar: 100, + BarStacked: 100, + Bar3D: 100, + Bar3DColumn: 100, + Bar3DPercentStacked: 100, + Doughnut: 100, + Line: 100, + Pie: 100, + Pie3D: 100, + Radar: 100, + Scatter: 100, } chartView3DRAngAx = map[string]int{ - Bar: 0, - BarStacked: 0, - Bar3D: 1, - Doughnut: 0, - Line: 0, - Pie: 0, - Pie3D: 0, - Radar: 0, - Scatter: 0} + Bar: 0, + BarStacked: 0, + Bar3D: 1, + Bar3DColumn: 1, + Bar3DPercentStacked: 1, + Doughnut: 0, + Line: 0, + Pie: 0, + Pie3D: 0, + Radar: 0, + Scatter: 0, + } chartLegendPosition = map[string]string{ "bottom": "b", "left": "l", @@ -72,6 +83,27 @@ var ( "top": "t", "top_right": "tr", } + chartValAxNumFmtFormatCode = map[string]string{ + Bar: "General", + BarStacked: "General", + Bar3D: "General", + Bar3DColumn: "General", + Bar3DPercentStacked: "0%", + Doughnut: "General", + Line: "General", + Pie: "General", + Pie3D: "General", + Radar: "General", + Scatter: "General", + } + plotAreaChartGrouping = map[string]string{ + Bar: "clustered", + BarStacked: "stacked", + Bar3D: "clustered", + Bar3DColumn: "standard", + Bar3DPercentStacked: "percentStacked", + Line: "standard", + } ) // parseFormatChartSet provides function to parse the format settings of the @@ -133,17 +165,19 @@ func parseFormatChartSet(formatSet string) *formatChart { // // The following shows the type of chart supported by excelize: // -// Type | Chart -// ------------+---------------- -// bar | bar chart -// barStacked | stacked bar chart -// bar3D | 3D bar chart -// doughnut | doughnut chart -// line | line chart -// pie | pie chart -// pie3D | 3D pie chart -// radar | radar chart -// scatter | scatter chart +// Type | Chart +// ---------------------+--------------------------- +// bar | bar chart +// barStacked | stacked bar chart +// bar3D | 3D bar chart +// bar3DColumn | 3D column bar chart +// bar3DPercentStacked | 3D 100% stacked bar chart +// doughnut | doughnut chart +// line | line chart +// pie | pie chart +// pie3D | 3D pie chart +// radar | radar chart +// scatter | scatter chart // // In Excel a chart series is a collection of information that defines which data is plotted such as values, axis labels and formatting. // @@ -389,15 +423,17 @@ func (f *File) addChart(formatSet *formatChart) { }, } plotAreaFunc := map[string]func(*formatChart) *cPlotArea{ - Bar: f.drawBarChart, - BarStacked: f.drawBarChart, - Bar3D: f.drawBarChart, - Doughnut: f.drawDoughnutChart, - Line: f.drawLineChart, - Pie3D: f.drawPie3DChart, - Pie: f.drawPieChart, - Radar: f.drawRadarChart, - Scatter: f.drawScatterChart, + Bar: f.drawBarChart, + BarStacked: f.drawBarChart, + Bar3D: f.drawBarChart, + Bar3DColumn: f.drawBarChart, + Bar3DPercentStacked: f.drawBarChart, + Doughnut: f.drawDoughnutChart, + Line: f.drawLineChart, + Pie3D: f.drawPie3DChart, + Pie: f.drawPieChart, + Radar: f.drawRadarChart, + Scatter: f.drawScatterChart, } xlsxChartSpace.Chart.PlotArea = plotAreaFunc[formatSet.Type](formatSet) @@ -426,12 +462,12 @@ func (f *File) drawBarChart(formatSet *formatChart) *cPlotArea { {Val: 753999904}, }, } + c.Grouping.Val = plotAreaChartGrouping[formatSet.Type] if formatSet.Type == "barStacked" { - c.Grouping.Val = "stacked" c.Overlap = &attrValInt{Val: 100} } - catAx := f.drawPlotAreaCatAx() - valAx := f.drawPlotAreaValAx() + catAx := f.drawPlotAreaCatAx(formatSet) + valAx := f.drawPlotAreaValAx(formatSet) charts := map[string]*cPlotArea{ "bar": { BarChart: &c, @@ -448,6 +484,16 @@ func (f *File) drawBarChart(formatSet *formatChart) *cPlotArea { CatAx: catAx, ValAx: valAx, }, + "bar3DColumn": { + Bar3DChart: &c, + CatAx: catAx, + ValAx: valAx, + }, + "bar3DPercentStacked": { + Bar3DChart: &c, + CatAx: catAx, + ValAx: valAx, + }, } return charts[formatSet.Type] } @@ -472,7 +518,7 @@ func (f *File) drawLineChart(formatSet *formatChart) *cPlotArea { return &cPlotArea{ LineChart: &cCharts{ Grouping: &attrValString{ - Val: "standard", + Val: plotAreaChartGrouping[formatSet.Type], }, VaryColors: &attrValBool{ Val: false, @@ -487,8 +533,8 @@ func (f *File) drawLineChart(formatSet *formatChart) *cPlotArea { {Val: 753999904}, }, }, - CatAx: f.drawPlotAreaCatAx(), - ValAx: f.drawPlotAreaValAx(), + CatAx: f.drawPlotAreaCatAx(formatSet), + ValAx: f.drawPlotAreaValAx(formatSet), } } @@ -536,8 +582,8 @@ func (f *File) drawRadarChart(formatSet *formatChart) *cPlotArea { {Val: 753999904}, }, }, - CatAx: f.drawPlotAreaCatAx(), - ValAx: f.drawPlotAreaValAx(), + CatAx: f.drawPlotAreaCatAx(formatSet), + ValAx: f.drawPlotAreaValAx(formatSet), } } @@ -559,8 +605,8 @@ func (f *File) drawScatterChart(formatSet *formatChart) *cPlotArea { {Val: 753999904}, }, }, - CatAx: f.drawPlotAreaCatAx(), - ValAx: f.drawPlotAreaValAx(), + CatAx: f.drawPlotAreaCatAx(formatSet), + ValAx: f.drawPlotAreaValAx(formatSet), } } @@ -608,7 +654,7 @@ func (f *File) drawChartSeriesSpPr(i int, formatSet *formatChart) *cSpPr { }, }, } - chartSeriesSpPr := map[string]*cSpPr{Bar: nil, BarStacked: nil, Bar3D: nil, Doughnut: nil, Line: spPrLine, Pie: nil, Pie3D: nil, Radar: nil, Scatter: spPrScatter} + chartSeriesSpPr := map[string]*cSpPr{Bar: nil, BarStacked: nil, Bar3D: nil, Bar3DColumn: nil, Bar3DPercentStacked: nil, Doughnut: nil, Line: spPrLine, Pie: nil, Pie3D: nil, Radar: nil, Scatter: spPrScatter} return chartSeriesSpPr[formatSet.Type] } @@ -637,7 +683,7 @@ func (f *File) drawChartSeriesDPt(i int, formatSet *formatChart) []*cDPt { }, }, }} - chartSeriesDPt := map[string][]*cDPt{Bar: nil, BarStacked: nil, Bar3D: nil, Doughnut: nil, Line: nil, Pie: dpt, Pie3D: dpt, Radar: nil, Scatter: nil} + chartSeriesDPt := map[string][]*cDPt{Bar: nil, BarStacked: nil, Bar3D: nil, Bar3DColumn: nil, Bar3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: dpt, Pie3D: dpt, Radar: nil, Scatter: nil} return chartSeriesDPt[formatSet.Type] } @@ -649,7 +695,7 @@ func (f *File) drawChartSeriesCat(v formatChartSeries, formatSet *formatChart) * F: v.Categories, }, } - chartSeriesCat := map[string]*cCat{Bar: cat, BarStacked: cat, Bar3D: cat, Doughnut: cat, Line: cat, Pie: cat, Pie3D: cat, Radar: cat, Scatter: nil} + chartSeriesCat := map[string]*cCat{Bar: cat, BarStacked: cat, Bar3D: cat, Bar3DColumn: cat, Bar3DPercentStacked: cat, Doughnut: cat, Line: cat, Pie: cat, Pie3D: cat, Radar: cat, Scatter: nil} return chartSeriesCat[formatSet.Type] } @@ -661,7 +707,7 @@ func (f *File) drawChartSeriesVal(v formatChartSeries, formatSet *formatChart) * F: v.Values, }, } - chartSeriesVal := map[string]*cVal{Bar: val, BarStacked: val, Bar3D: val, Doughnut: val, Line: val, Pie: val, Pie3D: val, Radar: val, Scatter: nil} + chartSeriesVal := map[string]*cVal{Bar: val, BarStacked: val, Bar3D: val, Bar3DColumn: val, Bar3DPercentStacked: val, Doughnut: val, Line: val, Pie: val, Pie3D: val, Radar: val, Scatter: nil} return chartSeriesVal[formatSet.Type] } @@ -687,7 +733,7 @@ func (f *File) drawChartSeriesMarker(i int, formatSet *formatChart) *cMarker { }, }, } - chartSeriesMarker := map[string]*cMarker{Bar: nil, BarStacked: nil, Bar3D: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: marker} + chartSeriesMarker := map[string]*cMarker{Bar: nil, BarStacked: nil, Bar3D: nil, Bar3DColumn: nil, Bar3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: marker} return chartSeriesMarker[formatSet.Type] } @@ -699,7 +745,7 @@ func (f *File) drawChartSeriesXVal(v formatChartSeries, formatSet *formatChart) F: v.Categories, }, } - chartSeriesXVal := map[string]*cCat{Bar: nil, BarStacked: nil, Bar3D: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: cat} + chartSeriesXVal := map[string]*cCat{Bar: nil, BarStacked: nil, Bar3D: nil, Bar3DColumn: nil, Bar3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: cat} return chartSeriesXVal[formatSet.Type] } @@ -711,7 +757,7 @@ func (f *File) drawChartSeriesYVal(v formatChartSeries, formatSet *formatChart) F: v.Values, }, } - chartSeriesYVal := map[string]*cVal{Bar: nil, BarStacked: nil, Bar3D: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: val} + chartSeriesYVal := map[string]*cVal{Bar: nil, BarStacked: nil, Bar3D: nil, Bar3DColumn: nil, Bar3DPercentStacked: nil, Doughnut: nil, Line: nil, Pie: nil, Pie3D: nil, Radar: nil, Scatter: val} return chartSeriesYVal[formatSet.Type] } @@ -733,12 +779,12 @@ func (f *File) drawChartDLbls(formatSet *formatChart) *cDLbls { // format sets. func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls { dLbls := f.drawChartDLbls(formatSet) - chartSeriesDLbls := map[string]*cDLbls{Bar: dLbls, BarStacked: dLbls, Bar3D: dLbls, Doughnut: dLbls, Line: dLbls, Pie: dLbls, Pie3D: dLbls, Radar: dLbls, Scatter: nil} + chartSeriesDLbls := map[string]*cDLbls{Bar: dLbls, BarStacked: dLbls, Bar3D: dLbls, Bar3DColumn: dLbls, Bar3DPercentStacked: dLbls, Doughnut: dLbls, Line: dLbls, Pie: dLbls, Pie3D: dLbls, Radar: dLbls, Scatter: nil} return chartSeriesDLbls[formatSet.Type] } // drawPlotAreaCatAx provides function to draw the c:catAx element. -func (f *File) drawPlotAreaCatAx() []*cAxs { +func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs { return []*cAxs{ { AxID: &attrValInt{Val: 754001152}, @@ -766,8 +812,8 @@ func (f *File) drawPlotAreaCatAx() []*cAxs { } } -// drawPlotAreaCatAx provides function to draw the c:valAx element. -func (f *File) drawPlotAreaValAx() []*cAxs { +// drawPlotAreaValAx provides function to draw the c:valAx element. +func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs { return []*cAxs{ { AxID: &attrValInt{Val: 753999904}, @@ -777,7 +823,7 @@ func (f *File) drawPlotAreaValAx() []*cAxs { Delete: &attrValBool{Val: false}, AxPos: &attrValString{Val: "l"}, NumFmt: &cNumFmt{ - FormatCode: "General", + FormatCode: chartValAxNumFmtFormatCode[formatSet.Type], SourceLinked: true, }, MajorTickMark: &attrValString{Val: "none"}, diff --git a/excelize_test.go b/excelize_test.go index 34dac8d..a4dc287 100644 --- a/excelize_test.go +++ b/excelize_test.go @@ -819,7 +819,9 @@ func TestAddChart(t *testing.T) { xlsx.AddChart("Sheet1", "X30", `{"type":"pie","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit Pie Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":false,"show_val":false},"show_blanks_as":"gap"}`) xlsx.AddChart("Sheet2", "P1", `{"type":"radar","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"top_right","show_legend_key":false},"title":{"name":"Fruit Radar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"span"}`) xlsx.AddChart("Sheet2", "X1", `{"type":"scatter","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"bottom","show_legend_key":false},"title":{"name":"Fruit Scatter Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) - xlsx.AddChart("Sheet2", "P16", `{"type":"barStacked","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit Bar Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) + xlsx.AddChart("Sheet2", "P16", `{"type":"barStacked","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) + xlsx.AddChart("Sheet2", "X17", `{"type":"bar3DColumn","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) + xlsx.AddChart("Sheet2", "P32", `{"type":"bar3DPercentStacked","series":[{"name":"=Sheet1!$A$30","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$30:$D$30"},{"name":"=Sheet1!$A$31","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$31:$D$31"},{"name":"=Sheet1!$A$32","categories":"=Sheet1!$B$29:$D$29","values":"=Sheet1!$B$32:$D$32"}],"format":{"x_scale":1.0,"y_scale":1.0,"x_offset":15,"y_offset":10,"print_obj":true,"lock_aspect_ratio":false,"locked":false},"legend":{"position":"left","show_legend_key":false},"title":{"name":"Fruit 3D 100% Stacked Column Chart"},"plotarea":{"show_bubble_size":true,"show_cat_name":false,"show_leader_lines":false,"show_percent":true,"show_series_name":true,"show_val":true},"show_blanks_as":"zero"}`) // Save xlsx file by the given path. err = xlsx.SaveAs("./test/Workbook_addchart.xlsx") if err != nil {