Skip to content

Commit 249b593

Browse files
authored
This closes qax-os#2169, support to set font for chart legends (qax-os#2171)
- Add Font field in the ChartLegend data type - Add Legend field in the ChartSeries data type - Update documentation for legend font support - Update unit tests
1 parent f47b3df commit 249b593

File tree

4 files changed

+69
-19
lines changed

4 files changed

+69
-19
lines changed

chart.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,6 +765,7 @@ func (opts *Chart) parseTitle() {
765765
// Categories
766766
// Values
767767
// Fill
768+
// Legend
768769
// Line
769770
// Marker
770771
// DataLabel
@@ -787,7 +788,10 @@ func (opts *Chart) parseTitle() {
787788
// optional and the default value was same with 'Values'.
788789
//
789790
// Fill: This set the format for the data series fill. The 'Fill' property is
790-
// optional
791+
// optional.
792+
//
793+
// Legend: This set the font of legend text for a data series. The 'Legend'
794+
// property is optional.
791795
//
792796
// Line: This sets the line format of the line chart. The 'Line' property is
793797
// optional and if it isn't supplied it will default style. The options that
@@ -819,6 +823,7 @@ func (opts *Chart) parseTitle() {
819823
//
820824
// Position
821825
// ShowLegendKey
826+
// Font
822827
//
823828
// Position: Set the position of the chart legend. The default legend position
824829
// is bottom. The available positions are:
@@ -833,6 +838,11 @@ func (opts *Chart) parseTitle() {
833838
// ShowLegendKey: Set the legend keys shall be shown in data labels. The default
834839
// value is false.
835840
//
841+
// Font: Set the font properties of the chart legend text. The properties that
842+
// can be set are the same as the font object that is used for cell formatting.
843+
// The font family, size, color, bold, italic, underline, and strike properties
844+
// can be set.
845+
//
836846
// Set properties of the chart title. The properties that can be set are:
837847
//
838848
// Title
@@ -1008,6 +1018,9 @@ func (opts *Chart) parseTitle() {
10081018
// Set chart size by 'Dimension' property. The 'Dimension' property is optional.
10091019
// The default width is 480, and height is 260.
10101020
//
1021+
// Set chart legend for all data series by 'Legend' property. The 'Legend'
1022+
// property is optional.
1023+
//
10111024
// Set the bubble size in all data series for the bubble chart or 3D bubble
10121025
// chart by 'BubbleSizes' property. The 'BubbleSizes' property is optional. The
10131026
// default width is 100, and the value should be great than 0 and less or equal

chart_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ func TestAddChart(t *testing.T) {
171171
Width: 1,
172172
},
173173
},
174+
Legend: ChartLegend{Font: &Font{Family: "Arial", Size: 11, Strike: true, Color: "777777"}},
174175
},
175176
}
176177
series2 := []ChartSeries{
@@ -225,7 +226,7 @@ func TestAddChart(t *testing.T) {
225226
{sheetName: "Sheet1", cell: "P1", opts: &Chart{Type: Col, Series: series, Format: format, Legend: ChartLegend{Position: "none", ShowLegendKey: true}, Title: []RichTextRun{{Text: "2D Column Chart", Font: &Font{Size: 11, Family: "Calibri"}}}, PlotArea: plotArea, Border: ChartLine{Type: ChartLineNone}, ShowBlanksAs: "zero", XAxis: ChartAxis{Font: Font{Bold: true, Italic: true, Underline: "dbl", Family: "Times New Roman", Size: 15, Strike: true, 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}}}}}},
226227
{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", GapWidth: uintPtr(10), Overlap: intPtr(100)}},
227228
{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", XAxis: ChartAxis{Alignment: Alignment{Vertical: "wordArtVertRtl", TextRotation: 0}}}},
228-
{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"}},
229+
{sheetName: "Sheet1", cell: "X16", opts: &Chart{Type: Col3DClustered, Series: series, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false, Font: &Font{Size: 10}}, Title: []RichTextRun{{Text: "3D Clustered Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
229230
{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", XAxis: ChartAxis{Alignment: Alignment{Vertical: "vert", TextRotation: 0}}}},
230231
{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"}},
231232
{sheetName: "Sheet1", cell: "X45", opts: &Chart{Type: Radar, Series: series, Format: format, Legend: ChartLegend{Position: "top_right", ShowLegendKey: false}, Title: []RichTextRun{{Text: "Radar Chart"}}, PlotArea: plotArea, ShowBlanksAs: "span"}},

drawing.go

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
8080
BackWall: &cThicknessSpPr{
8181
Thickness: &attrValInt{Val: intPtr(0)},
8282
},
83-
PlotArea: &cPlotArea{},
84-
Legend: &cLegend{
85-
LegendPos: &attrValString{Val: stringPtr(chartLegendPosition[opts.Legend.Position])},
86-
Overlay: &attrValBool{Val: boolPtr(false)},
87-
},
88-
83+
PlotArea: &cPlotArea{},
8984
PlotVisOnly: &attrValBool{Val: boolPtr(false)},
9085
DispBlanksAs: &attrValString{Val: stringPtr(opts.ShowBlanksAs)},
9186
ShowDLblsOverMax: &attrValBool{Val: boolPtr(false)},
@@ -165,9 +160,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
165160
Bubble: f.drawBubbleChart,
166161
Bubble3D: f.drawBubbleChart,
167162
}
168-
if opts.Legend.Position == "none" {
169-
xlsxChartSpace.Chart.Legend = nil
170-
}
163+
xlsxChartSpace.Chart.drawChartLegend(opts)
171164
xlsxChartSpace.Chart.PlotArea.SpPr = f.drawShapeFill(opts.PlotArea.Fill, xlsxChartSpace.Chart.PlotArea.SpPr)
172165
xlsxChartSpace.Chart.PlotArea.DTable = f.drawPlotAreaDTable(opts)
173166
addChart := func(c, p *cPlotArea) {
@@ -881,7 +874,8 @@ func (f *File) drawChartSeriesCat(v ChartSeries, opts *Chart) *cCat {
881874
func (f *File) drawChartSeriesVal(v ChartSeries, opts *Chart) *cVal {
882875
val := &cVal{
883876
NumRef: &cNumRef{
884-
F: v.Values,
877+
F: v.Values,
878+
NumCache: &cNumCache{},
885879
},
886880
}
887881
chartSeriesVal := map[ChartType]*cVal{Scatter: nil, Bubble: nil, Bubble3D: nil}
@@ -935,7 +929,8 @@ func (f *File) drawChartSeriesXVal(v ChartSeries, opts *Chart) *cCat {
935929
func (f *File) drawChartSeriesYVal(v ChartSeries, opts *Chart) *cVal {
936930
val := &cVal{
937931
NumRef: &cNumRef{
938-
F: v.Values,
932+
F: v.Values,
933+
NumCache: &cNumCache{},
939934
},
940935
}
941936
chartSeriesYVal := map[ChartType]*cVal{Scatter: val, Bubble: val, Bubble3D: val}
@@ -954,7 +949,8 @@ func (f *File) drawCharSeriesBubbleSize(v ChartSeries, opts *Chart) *cVal {
954949
}
955950
return &cVal{
956951
NumRef: &cNumRef{
957-
F: fVal,
952+
F: fVal,
953+
NumCache: &cNumCache{},
958954
},
959955
}
960956
}
@@ -1343,6 +1339,36 @@ func (f *File) drawChartLn(opts *ChartLine) *aLn {
13431339
}
13441340
}
13451341

1342+
// drawChartLegend provides a function to draw the c:legend element.
1343+
func (c *cChart) drawChartLegend(opts *Chart) {
1344+
if opts.Legend.Position == "none" {
1345+
c.Legend = nil
1346+
return
1347+
}
1348+
if c.Legend == nil {
1349+
c.Legend = &cLegend{
1350+
LegendPos: &attrValString{Val: stringPtr(chartLegendPosition[opts.Legend.Position])},
1351+
Overlay: &attrValBool{Val: boolPtr(false)},
1352+
}
1353+
}
1354+
if opts.Legend.Font != nil {
1355+
c.Legend.TxPr = &cTxPr{P: aP{PPr: &aPPr{}}}
1356+
drawChartFont(opts.Legend.Font, &c.Legend.TxPr.P.PPr.DefRPr)
1357+
}
1358+
for k := range opts.Series {
1359+
font := opts.Series[k].Legend.Font
1360+
if font == nil {
1361+
continue
1362+
}
1363+
legendEntry := cLegendEntry{
1364+
IDx: &attrValInt{Val: intPtr(k + opts.order)},
1365+
TxPr: &cTxPr{P: aP{PPr: &aPPr{}}},
1366+
}
1367+
drawChartFont(font, &legendEntry.TxPr.P.PPr.DefRPr)
1368+
c.Legend.LegendEntry = append(c.Legend.LegendEntry, legendEntry)
1369+
}
1370+
}
1371+
13461372
// drawingParser provides a function to parse drawingXML. In order to solve
13471373
// the problem that the label structure is changed after serialization and
13481374
// deserialization, two different structures: decodeWsDr and encodeWsDr are

xmlChart.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -509,14 +509,22 @@ type cDLbls struct {
509509
ShowLeaderLines *attrValBool `xml:"showLeaderLines"`
510510
}
511511

512+
// cLegendEntry (Legend Entry) directly maps the legendEntry element. This
513+
// element specifies the legend entry.
514+
type cLegendEntry struct {
515+
IDx *attrValInt `xml:"idx"`
516+
TxPr *cTxPr `xml:"txPr"`
517+
}
518+
512519
// cLegend (Legend) directly maps the legend element. This element specifies
513520
// the legend.
514521
type cLegend struct {
515-
Layout *string `xml:"layout"`
516-
LegendPos *attrValString `xml:"legendPos"`
517-
Overlay *attrValBool `xml:"overlay"`
518-
SpPr *cSpPr `xml:"spPr"`
519-
TxPr *cTxPr `xml:"txPr"`
522+
Layout *string `xml:"layout"`
523+
LegendPos *attrValString `xml:"legendPos"`
524+
LegendEntry []cLegendEntry `xml:"legendEntry"`
525+
Overlay *attrValBool `xml:"overlay"`
526+
SpPr *cSpPr `xml:"spPr"`
527+
TxPr *cTxPr `xml:"txPr"`
520528
}
521529

522530
// cPrintSettings directly maps the printSettings element. This element
@@ -611,6 +619,7 @@ type Chart struct {
611619
type ChartLegend struct {
612620
Position string
613621
ShowLegendKey bool
622+
Font *Font
614623
}
615624

616625
// ChartMarker directly maps the format settings of the chart marker.
@@ -644,6 +653,7 @@ type ChartSeries struct {
644653
Values string
645654
Sizes string
646655
Fill Fill
656+
Legend ChartLegend
647657
Line ChartLine
648658
Marker ChartMarker
649659
DataLabel ChartDataLabel

0 commit comments

Comments
 (0)