This closes #1786, support set fill color of the chart (#1788)

- Add a new field Fill in Chart, ChartPlotArea, and ChartMarker struct
- Support set solid color or transparent fill for chart area, plot area, and maker
This commit is contained in:
MELF晓宇 2024-01-22 09:41:57 +08:00 committed by GitHub
parent 4eb3486682
commit 5399572353
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 38 additions and 20 deletions

View File

@ -158,7 +158,12 @@ func TestAddChart(t *testing.T) {
{Name: "Sheet1!$A$34", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$34:$D$34"},
{Name: "Sheet1!$A$35", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$35:$D$35"},
{Name: "Sheet1!$A$36", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$36:$D$36"},
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37"},
{
Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37",
Marker: ChartMarker{
Fill: Fill{Type: "pattern", Color: []string{"FFFF00"}, Pattern: 1},
},
},
}
series2 := []ChartSeries{
{
@ -203,14 +208,15 @@ func TestAddChart(t *testing.T) {
ShowPercent: true,
ShowSerName: true,
ShowVal: true,
Fill: Fill{Type: "pattern", Pattern: 1},
}
for _, c := range []struct {
sheetName, cell string
opts *Chart
}{
{sheetName: "Sheet1", cell: "P1", opts: &Chart{Type: Col, Series: series, Format: format, Legend: ChartLegend{Position: "none", ShowLegendKey: true}, Title: []RichTextRun{{Text: "2D Column Chart"}}, PlotArea: plotArea, Border: ChartLine{Type: ChartLineNone}, ShowBlanksAs: "zero", XAxis: ChartAxis{Font: Font{Bold: true, Italic: true, Underline: "dbl", Color: "000000"}, Title: []RichTextRun{{Text: "Primary Horizontal Axis Title"}}}, YAxis: ChartAxis{Font: Font{Bold: false, Italic: false, Underline: "sng", Color: "777777"}, Title: []RichTextRun{{Text: "Primary Vertical Axis Title", Font: &Font{Color: "777777", Bold: true, Italic: true, Size: 12}}}}}},
{sheetName: "Sheet1", cell: "X1", opts: &Chart{Type: ColStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Stacked Column Chart"}}, PlotArea: plotArea, Border: ChartLine{Type: ChartLineAutomatic}, ShowBlanksAs: "zero"}},
{sheetName: "Sheet1", cell: "P16", opts: &Chart{Type: ColPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "100% Stacked Column Chart"}}, PlotArea: plotArea, Border: ChartLine{Type: ChartLineSolid, Width: 2}, ShowBlanksAs: "zero"}},
{sheetName: "Sheet1", cell: "X1", opts: &Chart{Type: ColStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Stacked Column Chart"}}, PlotArea: plotArea, Fill: Fill{Type: "pattern", Pattern: 1}, Border: ChartLine{Type: ChartLineAutomatic}, ShowBlanksAs: "zero"}},
{sheetName: "Sheet1", cell: "P16", opts: &Chart{Type: ColPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "100% Stacked Column Chart"}}, PlotArea: plotArea, Fill: Fill{Type: "pattern", Color: []string{"EEEEEE"}, Pattern: 1}, Border: ChartLine{Type: ChartLineSolid, Width: 2}, ShowBlanksAs: "zero"}},
{sheetName: "Sheet1", cell: "X16", opts: &Chart{Type: Col3DClustered, Series: series, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: []RichTextRun{{Text: "3D Clustered Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
{sheetName: "Sheet1", cell: "P30", opts: &Chart{Type: Col3DStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Stacked Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
{sheetName: "Sheet1", cell: "X30", opts: &Chart{Type: Col3DPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D 100% Stacked Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},

View File

@ -107,6 +107,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
},
},
}
xlsxChartSpace.SpPr = f.drawShapeFill(opts.Fill, xlsxChartSpace.SpPr)
plotAreaFunc := map[ChartType]func(*Chart) *cPlotArea{
Area: f.drawBaseChart,
AreaStacked: f.drawBaseChart,
@ -167,6 +168,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
if opts.Legend.Position == "none" {
xlsxChartSpace.Chart.Legend = nil
}
xlsxChartSpace.Chart.PlotArea.SpPr = f.drawShapeFill(opts.PlotArea.Fill, xlsxChartSpace.Chart.PlotArea.SpPr)
addChart := func(c, p *cPlotArea) {
immutable, mutable := reflect.ValueOf(c).Elem(), reflect.ValueOf(p).Elem()
for i := 0; i < mutable.NumField(); i++ {
@ -727,19 +729,28 @@ func (f *File) drawChartSeries(opts *Chart) *[]cSer {
return &ser
}
// drawShapeFill provides a function to draw the a:solidFill element by given
// fill format sets.
func (f *File) drawShapeFill(fill Fill, spPr *cSpPr) *cSpPr {
if fill.Type == "pattern" && fill.Pattern == 1 {
if spPr == nil {
spPr = &cSpPr{}
}
if len(fill.Color) == 1 {
spPr.SolidFill = &aSolidFill{SrgbClr: &attrValString{Val: stringPtr(strings.TrimPrefix(fill.Color[0], "#"))}}
return spPr
}
spPr.SolidFill = nil
spPr.NoFill = stringPtr("")
}
return spPr
}
// drawChartSeriesSpPr provides a function to draw the c:spPr element by given
// format sets.
func (f *File) drawChartSeriesSpPr(i int, opts *Chart) *cSpPr {
var srgbClr *attrValString
var schemeClr *aSchemeClr
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}}
spPr := &cSpPr{SolidFill: &aSolidFill{SchemeClr: &aSchemeClr{Val: "accent" + strconv.Itoa((opts.order+i)%6+1)}}}
spPr = f.drawShapeFill(opts.Series[i].Fill, spPr)
spPrScatter := &cSpPr{
Ln: &aLn{
W: 25400,
@ -748,12 +759,9 @@ func (f *File) drawChartSeriesSpPr(i int, opts *Chart) *cSpPr {
}
spPrLine := &cSpPr{
Ln: &aLn{
W: f.ptToEMUs(opts.Series[i].Line.Width),
Cap: "rnd", // rnd, sq, flat
SolidFill: &aSolidFill{
SchemeClr: schemeClr,
SrgbClr: srgbClr,
},
W: f.ptToEMUs(opts.Series[i].Line.Width),
Cap: "rnd", // rnd, sq, flat
SolidFill: spPr.SolidFill,
},
}
if chartSeriesSpPr, ok := map[ChartType]*cSpPr{
@ -761,7 +769,7 @@ func (f *File) drawChartSeriesSpPr(i int, opts *Chart) *cSpPr {
}[opts.Type]; ok {
return chartSeriesSpPr
}
if srgbClr != nil {
if spPr.SolidFill.SrgbClr != nil {
return spPr
}
return nil
@ -857,6 +865,7 @@ func (f *File) drawChartSeriesMarker(i int, opts *Chart) *cMarker {
},
}
}
marker.SpPr = f.drawShapeFill(opts.Series[i].Marker.Fill, marker.SpPr)
chartSeriesMarker := map[ChartType]*cMarker{Scatter: marker, Line: marker}
return chartSeriesMarker[opts.Type]
}

View File

@ -561,6 +561,7 @@ type ChartPlotArea struct {
ShowPercent bool
ShowSerName bool
ShowVal bool
Fill Fill
NumFmt ChartNumFmt
}
@ -576,6 +577,7 @@ type Chart struct {
XAxis ChartAxis
YAxis ChartAxis
PlotArea ChartPlotArea
Fill Fill
Border ChartLine
ShowBlanksAs string
BubbleSize int
@ -591,6 +593,7 @@ type ChartLegend struct {
// ChartMarker directly maps the format settings of the chart marker.
type ChartMarker struct {
Fill Fill
Symbol string
Size int
}