forked from p30928647/excelize
This closes #1474, support set the format for the data series fill (solid fill)
- Breaking changes: remove the `Color` field in the `ChartLine` structure - This support set the bubble size in a data series - Unit test update and correct the docs of the function `GetSheetDimension`
This commit is contained in:
parent
ad90cea78b
commit
c2d6707a85
8
chart.go
8
chart.go
|
@ -657,7 +657,9 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
|
|||
//
|
||||
// Name
|
||||
// Categories
|
||||
// Sizes
|
||||
// Values
|
||||
// Fill
|
||||
// Line
|
||||
// Marker
|
||||
//
|
||||
|
@ -670,16 +672,18 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
|
|||
// the same as the X axis. In most chart types the 'Categories' property is
|
||||
// optional and the chart will just assume a sequential series from 1..n.
|
||||
//
|
||||
// Sizes: This sets the bubble size in a data series.
|
||||
//
|
||||
// Values: This is the most important property of a series and is the only
|
||||
// mandatory option for every chart object. This option links the chart with
|
||||
// the worksheet data that it displays.
|
||||
//
|
||||
// Fill: This set the format for the data series fill.
|
||||
//
|
||||
// Line: This sets the line format of the line chart. The 'Line' property is
|
||||
// optional and if it isn't supplied it will default style. The options that
|
||||
// can be set are width and color. The range of width is 0.25pt - 999pt. If the
|
||||
// value of width is outside the range, the default width of the line is 2pt.
|
||||
// The value for color should be represented in hex format
|
||||
// (e.g., #000000 - #FFFFFF)
|
||||
//
|
||||
// Marker: This sets the marker of the line chart and scatter chart. The range
|
||||
// of optional field 'Size' is 2-72 (default value is 5). The enumeration value
|
||||
|
|
|
@ -153,7 +153,9 @@ func TestAddChart(t *testing.T) {
|
|||
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37"},
|
||||
}
|
||||
series2 := []ChartSeries{
|
||||
{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30", Marker: ChartMarker{Symbol: "none", Size: 10}, Line: ChartLine{Color: "#000000"}},
|
||||
{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30",
|
||||
Fill: Fill{Type: "pattern", Color: []string{"000000"}, Pattern: 1},
|
||||
Marker: ChartMarker{Symbol: "none", Size: 10}},
|
||||
{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"},
|
||||
{Name: "Sheet1!$A$33", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$33:$D$33"},
|
||||
|
@ -163,6 +165,16 @@ func TestAddChart(t *testing.T) {
|
|||
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37", Line: ChartLine{Width: 0.25}},
|
||||
}
|
||||
series3 := []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$A$30:$D$37", Values: "Sheet1!$B$30:$B$37"}}
|
||||
series4 := []ChartSeries{
|
||||
{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30", Sizes: "Sheet1!$B$30:$D$30"},
|
||||
{Name: "Sheet1!$A$31", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$31:$D$31", Sizes: "Sheet1!$B$31:$D$31"},
|
||||
{Name: "Sheet1!$A$32", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$32:$D$32", Sizes: "Sheet1!$B$32:$D$32"},
|
||||
{Name: "Sheet1!$A$33", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$33:$D$33", Sizes: "Sheet1!$B$33:$D$33"},
|
||||
{Name: "Sheet1!$A$34", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$34:$D$34", Sizes: "Sheet1!$B$34:$D$34"},
|
||||
{Name: "Sheet1!$A$35", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$35:$D$35", Sizes: "Sheet1!$B$35:$D$35"},
|
||||
{Name: "Sheet1!$A$36", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$36:$D$36", Sizes: "Sheet1!$B$36:$D$36"},
|
||||
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37", Sizes: "Sheet1!$B$37:$D$37"},
|
||||
}
|
||||
format := GraphicOptions{
|
||||
ScaleX: defaultPictureScale,
|
||||
ScaleY: defaultPictureScale,
|
||||
|
@ -242,8 +254,8 @@ func TestAddChart(t *testing.T) {
|
|||
{sheetName: "Sheet2", cell: "AV32", opts: &Chart{Type: "contour", Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "Contour Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||
{sheetName: "Sheet2", cell: "BD1", opts: &Chart{Type: "wireframeContour", Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "Wireframe Contour Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||
// bubble chart
|
||||
{sheetName: "Sheet2", cell: "BD16", opts: &Chart{Type: "bubble", Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "Bubble Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||
{sheetName: "Sheet2", cell: "BD32", opts: &Chart{Type: "bubble3D", Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "Bubble 3D Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
||||
{sheetName: "Sheet2", cell: "BD16", opts: &Chart{Type: "bubble", Series: series4, Format: format, Legend: legend, Title: ChartTitle{Name: "Bubble Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||
{sheetName: "Sheet2", cell: "BD32", opts: &Chart{Type: "bubble3D", Series: series4, Format: format, Legend: legend, Title: ChartTitle{Name: "Bubble 3D Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
||||
// pie of pie chart
|
||||
{sheetName: "Sheet2", cell: "BD48", opts: &Chart{Type: "pieOfPie", Series: series3, Format: format, Legend: legend, Title: ChartTitle{Name: "Pie of Pie Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
||||
// bar of pie chart
|
||||
|
@ -256,18 +268,14 @@ func TestAddChart(t *testing.T) {
|
|||
assert.NoError(t, err)
|
||||
clusteredColumnCombo := [][]string{
|
||||
{"A1", "line", "Clustered Column - Line Chart"},
|
||||
{"I1", "bubble", "Clustered Column - Bubble Chart"},
|
||||
{"Q1", "bubble3D", "Clustered Column - Bubble 3D Chart"},
|
||||
{"Y1", "doughnut", "Clustered Column - Doughnut Chart"},
|
||||
{"I1", "doughnut", "Clustered Column - Doughnut Chart"},
|
||||
}
|
||||
for _, props := range clusteredColumnCombo {
|
||||
assert.NoError(t, f.AddChart("Combo Charts", props[0], &Chart{Type: "col", Series: series[:4], Format: format, Legend: legend, Title: ChartTitle{Name: props[2]}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[1], Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}))
|
||||
}
|
||||
stackedAreaCombo := map[string][]string{
|
||||
"A16": {"line", "Stacked Area - Line Chart"},
|
||||
"I16": {"bubble", "Stacked Area - Bubble Chart"},
|
||||
"Q16": {"bubble3D", "Stacked Area - Bubble 3D Chart"},
|
||||
"Y16": {"doughnut", "Stacked Area - Doughnut Chart"},
|
||||
"I16": {"doughnut", "Stacked Area - Doughnut Chart"},
|
||||
}
|
||||
for axis, props := range stackedAreaCombo {
|
||||
assert.NoError(t, f.AddChart("Combo Charts", axis, &Chart{Type: "areaStacked", Series: series[:4], Format: format, Legend: legend, Title: ChartTitle{Name: props[1]}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[0], Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}))
|
||||
|
|
52
drawing.go
52
drawing.go
|
@ -234,8 +234,8 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
|
|||
WireframeSurface3D: f.drawSurface3DChart,
|
||||
Contour: f.drawSurfaceChart,
|
||||
WireframeContour: f.drawSurfaceChart,
|
||||
Bubble: f.drawBaseChart,
|
||||
Bubble3D: f.drawBaseChart,
|
||||
Bubble: f.drawBubbleChart,
|
||||
Bubble3D: f.drawBubbleChart,
|
||||
}
|
||||
if opts.Legend.Position == "none" {
|
||||
xlsxChartSpace.Chart.Legend = nil
|
||||
|
@ -270,7 +270,7 @@ func (f *File) drawBaseChart(opts *Chart) *cPlotArea {
|
|||
Val: stringPtr("col"),
|
||||
},
|
||||
Grouping: &attrValString{
|
||||
Val: stringPtr("clustered"),
|
||||
Val: stringPtr(plotAreaChartGrouping[opts.Type]),
|
||||
},
|
||||
VaryColors: &attrValBool{
|
||||
Val: opts.VaryColors,
|
||||
|
@ -288,9 +288,6 @@ func (f *File) drawBaseChart(opts *Chart) *cPlotArea {
|
|||
if *c.BarDir.Val, ok = plotAreaChartBarDir[opts.Type]; !ok {
|
||||
c.BarDir = nil
|
||||
}
|
||||
if *c.Grouping.Val, ok = plotAreaChartGrouping[opts.Type]; !ok {
|
||||
c.Grouping = nil
|
||||
}
|
||||
if *c.Overlap.Val, ok = plotAreaChartOverlap[opts.Type]; !ok {
|
||||
c.Overlap = nil
|
||||
}
|
||||
|
@ -726,6 +723,26 @@ func (f *File) drawSurfaceChart(opts *Chart) *cPlotArea {
|
|||
return plotArea
|
||||
}
|
||||
|
||||
// drawBubbleChart provides a function to draw the c:bubbleChart element by
|
||||
// given format sets.
|
||||
func (f *File) drawBubbleChart(opts *Chart) *cPlotArea {
|
||||
plotArea := &cPlotArea{
|
||||
BubbleChart: &cCharts{
|
||||
VaryColors: &attrValBool{
|
||||
Val: opts.VaryColors,
|
||||
},
|
||||
Ser: f.drawChartSeries(opts),
|
||||
DLbls: f.drawChartDLbls(opts),
|
||||
AxID: []*attrValInt{
|
||||
{Val: intPtr(754001152)},
|
||||
{Val: intPtr(753999904)},
|
||||
},
|
||||
},
|
||||
ValAx: []*cAxs{f.drawPlotAreaCatAx(opts)[0], f.drawPlotAreaValAx(opts)[0]},
|
||||
}
|
||||
return plotArea
|
||||
}
|
||||
|
||||
// drawChartShape provides a function to draw the c:shape element by given
|
||||
// format sets.
|
||||
func (f *File) drawChartShape(opts *Chart) *attrValString {
|
||||
|
@ -794,13 +811,13 @@ func (f *File) drawChartSeriesSpPr(i int, opts *Chart) *cSpPr {
|
|||
var srgbClr *attrValString
|
||||
var schemeClr *aSchemeClr
|
||||
|
||||
if color := stringPtr(opts.Series[i].Line.Color); *color != "" {
|
||||
*color = strings.TrimPrefix(*color, "#")
|
||||
srgbClr = &attrValString{Val: color}
|
||||
if color := opts.Series[i].Fill.Color; len(color) == 1 {
|
||||
srgbClr = &attrValString{Val: stringPtr(strings.TrimPrefix(color[0], "#"))}
|
||||
} else {
|
||||
schemeClr = &aSchemeClr{Val: "accent" + strconv.Itoa((opts.order+i)%6+1)}
|
||||
}
|
||||
|
||||
spPr := &cSpPr{SolidFill: &aSolidFill{SchemeClr: schemeClr, SrgbClr: srgbClr}}
|
||||
spPrScatter := &cSpPr{
|
||||
Ln: &aLn{
|
||||
W: 25400,
|
||||
|
@ -817,8 +834,15 @@ func (f *File) drawChartSeriesSpPr(i int, opts *Chart) *cSpPr {
|
|||
},
|
||||
},
|
||||
}
|
||||
chartSeriesSpPr := map[string]*cSpPr{Line: spPrLine, Scatter: spPrScatter}
|
||||
return chartSeriesSpPr[opts.Type]
|
||||
if chartSeriesSpPr, ok := map[string]*cSpPr{
|
||||
Line: spPrLine, Scatter: spPrScatter,
|
||||
}[opts.Type]; ok {
|
||||
return chartSeriesSpPr
|
||||
}
|
||||
if srgbClr != nil {
|
||||
return spPr
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// drawChartSeriesDPt provides a function to draw the c:dPt element by given
|
||||
|
@ -923,7 +947,7 @@ func (f *File) drawChartSeriesXVal(v ChartSeries, opts *Chart) *cCat {
|
|||
F: v.Categories,
|
||||
},
|
||||
}
|
||||
chartSeriesXVal := map[string]*cCat{Scatter: cat}
|
||||
chartSeriesXVal := map[string]*cCat{Scatter: cat, Bubble: cat, Bubble3D: cat}
|
||||
return chartSeriesXVal[opts.Type]
|
||||
}
|
||||
|
||||
|
@ -942,12 +966,12 @@ func (f *File) drawChartSeriesYVal(v ChartSeries, opts *Chart) *cVal {
|
|||
// drawCharSeriesBubbleSize provides a function to draw the c:bubbleSize
|
||||
// element by given chart series and format sets.
|
||||
func (f *File) drawCharSeriesBubbleSize(v ChartSeries, opts *Chart) *cVal {
|
||||
if _, ok := map[string]bool{Bubble: true, Bubble3D: true}[opts.Type]; !ok {
|
||||
if _, ok := map[string]bool{Bubble: true, Bubble3D: true}[opts.Type]; !ok || v.Sizes == "" {
|
||||
return nil
|
||||
}
|
||||
return &cVal{
|
||||
NumRef: &cNumRef{
|
||||
F: v.Values,
|
||||
F: v.Sizes,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
2
sheet.go
2
sheet.go
|
@ -1920,7 +1920,7 @@ func (f *File) SetSheetDimension(sheet string, rangeRef string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
// SetSheetDimension provides the method to get the used range of the worksheet.
|
||||
// GetSheetDimension provides the method to get the used range of the worksheet.
|
||||
func (f *File) GetSheetDimension(sheet string) (string, error) {
|
||||
var ref string
|
||||
ws, err := f.workSheetReader(sheet)
|
||||
|
|
|
@ -579,7 +579,6 @@ type ChartMarker struct {
|
|||
|
||||
// ChartLine directly maps the format settings of the chart line.
|
||||
type ChartLine struct {
|
||||
Color string
|
||||
Smooth bool
|
||||
Width float64
|
||||
}
|
||||
|
@ -588,7 +587,9 @@ type ChartLine struct {
|
|||
type ChartSeries struct {
|
||||
Name string
|
||||
Categories string
|
||||
Sizes string
|
||||
Values string
|
||||
Fill Fill
|
||||
Line ChartLine
|
||||
Marker ChartMarker
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue