Skip to content

Commit 4e936da

Browse files
committed
This closes qax-os#1706 and closes qax-os#1708
- Add export ChartLineType enumeration to specify the chart line type - Add new Border field in the Chart type to set the chart area border - Add new Type field in the ChartLine type to set the line type - Fix some format missing on get style definition - Update the unit tests
1 parent 7291e78 commit 4e936da

7 files changed

+84
-47
lines changed

chart.go

+25-7
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,16 @@ const (
8080
Bubble3D
8181
)
8282

83+
// ChartLineType is the type of supported chart line types.
84+
type ChartLineType byte
85+
86+
// This section defines the currently supported chart line types enumeration.
87+
const (
88+
ChartLineSolid ChartLineType = iota
89+
ChartLineNone
90+
ChartLineAutomatic
91+
)
92+
8393
// This section defines the default value of chart properties.
8494
var (
8595
chartView3DRotX = map[ChartType]int{
@@ -507,6 +517,21 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
507517
if opts.Legend.Position == "" {
508518
opts.Legend.Position = defaultChartLegendPosition
509519
}
520+
opts.parseTitle()
521+
if opts.VaryColors == nil {
522+
opts.VaryColors = boolPtr(true)
523+
}
524+
if opts.Border.Width == 0 {
525+
opts.Border.Width = 0.75
526+
}
527+
if opts.ShowBlanksAs == "" {
528+
opts.ShowBlanksAs = defaultChartShowBlanksAs
529+
}
530+
return opts, nil
531+
}
532+
533+
// parseTitle parse the title settings of the chart with default value.
534+
func (opts *Chart) parseTitle() {
510535
for i := range opts.Title {
511536
if opts.Title[i].Font == nil {
512537
opts.Title[i].Font = &Font{}
@@ -518,13 +543,6 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
518543
opts.Title[i].Font.Size = 14
519544
}
520545
}
521-
if opts.VaryColors == nil {
522-
opts.VaryColors = boolPtr(true)
523-
}
524-
if opts.ShowBlanksAs == "" {
525-
opts.ShowBlanksAs = defaultChartShowBlanksAs
526-
}
527-
return opts, nil
528546
}
529547

530548
// AddChart provides the method to add chart in a sheet by given chart format

chart_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -208,9 +208,9 @@ func TestAddChart(t *testing.T) {
208208
sheetName, cell string
209209
opts *Chart
210210
}{
211-
{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, 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}}}}}},
212-
{sheetName: "Sheet1", cell: "X1", opts: &Chart{Type: ColStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Stacked Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
213-
{sheetName: "Sheet1", cell: "P16", opts: &Chart{Type: ColPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "100% Stacked Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
211+
{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}}}}}},
212+
{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"}},
213+
{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"}},
214214
{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"}},
215215
{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"}},
216216
{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"}},

drawing.go

+32-18
Original file line numberDiff line numberDiff line change
@@ -94,23 +94,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
9494
SolidFill: &aSolidFill{
9595
SchemeClr: &aSchemeClr{Val: "bg1"},
9696
},
97-
Ln: &aLn{
98-
W: 9525,
99-
Cap: "flat",
100-
Cmpd: "sng",
101-
Algn: "ctr",
102-
SolidFill: &aSolidFill{
103-
SchemeClr: &aSchemeClr{
104-
Val: "tx1",
105-
LumMod: &attrValInt{
106-
Val: intPtr(15000),
107-
},
108-
LumOff: &attrValInt{
109-
Val: intPtr(85000),
110-
},
111-
},
112-
},
113-
},
97+
Ln: f.drawChartLn(&opts.Border),
11498
},
11599
PrintSettings: &cPrintSettings{
116100
PageMargins: &cPageMargins{
@@ -756,7 +740,7 @@ func (f *File) drawChartSeriesSpPr(i int, opts *Chart) *cSpPr {
756740
spPrScatter := &cSpPr{
757741
Ln: &aLn{
758742
W: 25400,
759-
NoFill: " ",
743+
NoFill: &attrValString{},
760744
},
761745
}
762746
spPrLine := &cSpPr{
@@ -1237,6 +1221,36 @@ func (f *File) drawPlotAreaTxPr(opts *ChartAxis) *cTxPr {
12371221
return cTxPr
12381222
}
12391223

1224+
// drawChartLn provides a function to draw the a:ln element.
1225+
func (f *File) drawChartLn(opts *ChartLine) *aLn {
1226+
ln := &aLn{
1227+
W: f.ptToEMUs(opts.Width),
1228+
Cap: "flat",
1229+
Cmpd: "sng",
1230+
Algn: "ctr",
1231+
}
1232+
switch opts.Type {
1233+
case ChartLineSolid:
1234+
ln.SolidFill = &aSolidFill{
1235+
SchemeClr: &aSchemeClr{
1236+
Val: "tx1",
1237+
LumMod: &attrValInt{
1238+
Val: intPtr(15000),
1239+
},
1240+
LumOff: &attrValInt{
1241+
Val: intPtr(85000),
1242+
},
1243+
},
1244+
}
1245+
return ln
1246+
case ChartLineNone:
1247+
ln.NoFill = &attrValString{}
1248+
return ln
1249+
default:
1250+
return nil
1251+
}
1252+
}
1253+
12401254
// drawingParser provides a function to parse drawingXML. In order to solve
12411255
// the problem that the label structure is changed after serialization and
12421256
// deserialization, two different structures: decodeWsDr and encodeWsDr are

styles.go

+8-6
Original file line numberDiff line numberDiff line change
@@ -1201,25 +1201,25 @@ var (
12011201
// extract style definition by given style.
12021202
extractStyleCondFuncs = map[string]func(xlsxXf, *xlsxStyleSheet) bool{
12031203
"fill": func(xf xlsxXf, s *xlsxStyleSheet) bool {
1204-
return xf.ApplyFill != nil && *xf.ApplyFill &&
1204+
return (xf.ApplyFill == nil || (xf.ApplyFill != nil && *xf.ApplyFill)) &&
12051205
xf.FillID != nil && s.Fills != nil &&
12061206
*xf.FillID < len(s.Fills.Fill)
12071207
},
12081208
"border": func(xf xlsxXf, s *xlsxStyleSheet) bool {
1209-
return xf.ApplyBorder != nil && *xf.ApplyBorder &&
1209+
return (xf.ApplyBorder == nil || (xf.ApplyBorder != nil && *xf.ApplyBorder)) &&
12101210
xf.BorderID != nil && s.Borders != nil &&
12111211
*xf.BorderID < len(s.Borders.Border)
12121212
},
12131213
"font": func(xf xlsxXf, s *xlsxStyleSheet) bool {
1214-
return xf.ApplyFont != nil && *xf.ApplyFont &&
1214+
return (xf.ApplyFont == nil || (xf.ApplyFont != nil && *xf.ApplyFont)) &&
12151215
xf.FontID != nil && s.Fonts != nil &&
12161216
*xf.FontID < len(s.Fonts.Font)
12171217
},
12181218
"alignment": func(xf xlsxXf, s *xlsxStyleSheet) bool {
1219-
return xf.ApplyAlignment != nil && *xf.ApplyAlignment
1219+
return xf.ApplyAlignment == nil || (xf.ApplyAlignment != nil && *xf.ApplyAlignment)
12201220
},
12211221
"protection": func(xf xlsxXf, s *xlsxStyleSheet) bool {
1222-
return xf.ApplyProtection != nil && *xf.ApplyProtection
1222+
return xf.ApplyProtection == nil || (xf.ApplyProtection != nil && *xf.ApplyProtection)
12231223
},
12241224
}
12251225
// drawContFmtFunc defines functions to create conditional formats.
@@ -1366,7 +1366,9 @@ func (f *File) extractFont(fnt *xlsxFont, s *xlsxStyleSheet, style *Style) {
13661366
font.Italic = fnt.I.Value()
13671367
}
13681368
if fnt.U != nil {
1369-
font.Underline = fnt.U.Value()
1369+
if font.Underline = fnt.U.Value(); font.Underline == "" {
1370+
font.Underline = "single"
1371+
}
13701372
}
13711373
if fnt.Name != nil {
13721374
font.Family = fnt.Name.Value()

styles_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,12 @@ func TestGetStyle(t *testing.T) {
606606
}
607607
assert.Equal(t, "012345", f.getThemeColor(&xlsxColor{Indexed: 0}))
608608

609+
f.Styles.Fonts.Font[0].U = &attrValString{}
610+
f.Styles.CellXfs.Xf[0].FontID = intPtr(0)
611+
style, err = f.GetStyle(styleID)
612+
assert.NoError(t, err)
613+
assert.Equal(t, "single", style.Font.Underline)
614+
609615
// Test get style with invalid style index
610616
style, err = f.GetStyle(-1)
611617
assert.Nil(t, style)

xmlCalcChain.go

+1-6
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,11 @@
1111

1212
package excelize
1313

14-
import (
15-
"encoding/xml"
16-
"sync"
17-
)
14+
import "encoding/xml"
1815

1916
// xlsxCalcChain directly maps the calcChain element. This element represents
2017
// the root of the calculation chain.
2118
type xlsxCalcChain struct {
22-
mu sync.Mutex
2319
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main calcChain"`
2420
C []xlsxCalcChainC `xml:"c"`
2521
}
@@ -91,7 +87,6 @@ type xlsxCalcChainC struct {
9187
// xlsxVolTypes maps the volatileDependencies part provides a cache of data that
9288
// supports Real Time Data (RTD) and CUBE functions in the workbook.
9389
type xlsxVolTypes struct {
94-
mu sync.Mutex
9590
XMLName xml.Name `xml:"http://schemas.openxmlformats.org/spreadsheetml/2006/main volTypes"`
9691
VolType []xlsxVolType `xml:"volType"`
9792
ExtLst *xlsxExtLst `xml:"extLst"`

xmlChart.go

+9-7
Original file line numberDiff line numberDiff line change
@@ -248,13 +248,13 @@ type aContourClr struct {
248248
// shapes and text. The line allows for the specifying of many different types
249249
// of outlines including even line dashes and bevels.
250250
type aLn struct {
251-
Algn string `xml:"algn,attr,omitempty"`
252-
Cap string `xml:"cap,attr,omitempty"`
253-
Cmpd string `xml:"cmpd,attr,omitempty"`
254-
W int `xml:"w,attr,omitempty"`
255-
NoFill string `xml:"a:noFill,omitempty"`
256-
Round string `xml:"a:round,omitempty"`
257-
SolidFill *aSolidFill `xml:"a:solidFill"`
251+
Algn string `xml:"algn,attr,omitempty"`
252+
Cap string `xml:"cap,attr,omitempty"`
253+
Cmpd string `xml:"cmpd,attr,omitempty"`
254+
W int `xml:"w,attr,omitempty"`
255+
NoFill *attrValString `xml:"a:noFill"`
256+
Round string `xml:"a:round,omitempty"`
257+
SolidFill *aSolidFill `xml:"a:solidFill"`
258258
}
259259

260260
// cTxPr (Text Properties) directly maps the txPr element. This element
@@ -575,6 +575,7 @@ type Chart struct {
575575
XAxis ChartAxis
576576
YAxis ChartAxis
577577
PlotArea ChartPlotArea
578+
Border ChartLine
578579
ShowBlanksAs string
579580
HoleSize int
580581
order int
@@ -594,6 +595,7 @@ type ChartMarker struct {
594595

595596
// ChartLine directly maps the format settings of the chart line.
596597
type ChartLine struct {
598+
Type ChartLineType
597599
Smooth bool
598600
Width float64
599601
}

0 commit comments

Comments
 (0)