This closes #1921, fix set axis format doesn't work in combo chart (#1924)

- Fix incorrect primary axis titles position
This commit is contained in:
联盟少侠 2024-06-17 21:54:15 +08:00 committed by GitHub
parent c349313850
commit 1a99dd4a23
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 99 additions and 130 deletions

View File

@ -108,7 +108,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
},
}
xlsxChartSpace.SpPr = f.drawShapeFill(opts.Fill, xlsxChartSpace.SpPr)
plotAreaFunc := map[ChartType]func(*Chart) *cPlotArea{
plotAreaFunc := map[ChartType]func(pa *cPlotArea, opts *Chart) *cPlotArea{
Area: f.drawBaseChart,
AreaStacked: f.drawBaseChart,
AreaPercentStacked: f.drawBaseChart,
@ -179,11 +179,11 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
immutable.FieldByName(mutable.Type().Field(i).Name).Set(field)
}
}
addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[opts.Type](opts))
addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[opts.Type](xlsxChartSpace.Chart.PlotArea, opts))
order := len(opts.Series)
for idx := range comboCharts {
comboCharts[idx].order = order
addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[comboCharts[idx].Type](comboCharts[idx]))
addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[comboCharts[idx].Type](xlsxChartSpace.Chart.PlotArea, comboCharts[idx]))
order += len(comboCharts[idx].Series)
}
chart, _ := xml.Marshal(xlsxChartSpace)
@ -193,7 +193,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
// drawBaseChart provides a function to draw the c:plotArea element for bar,
// and column series charts by given format sets.
func (f *File) drawBaseChart(opts *Chart) *cPlotArea {
func (f *File) drawBaseChart(pa *cPlotArea, opts *Chart) *cPlotArea {
c := cCharts{
BarDir: &attrValString{
Val: stringPtr("col"),
@ -217,8 +217,8 @@ func (f *File) drawBaseChart(opts *Chart) *cPlotArea {
if *c.Overlap.Val, ok = plotAreaChartOverlap[opts.Type]; !ok {
c.Overlap = nil
}
catAx := f.drawPlotAreaCatAx(opts)
valAx := f.drawPlotAreaValAx(opts)
catAx := f.drawPlotAreaCatAx(pa, opts)
valAx := f.drawPlotAreaValAx(pa, opts)
charts := map[ChartType]*cPlotArea{
Area: {
AreaChart: &c,
@ -436,7 +436,7 @@ func (f *File) drawBaseChart(opts *Chart) *cPlotArea {
// drawDoughnutChart provides a function to draw the c:plotArea element for
// doughnut chart by given format sets.
func (f *File) drawDoughnutChart(opts *Chart) *cPlotArea {
func (f *File) drawDoughnutChart(pa *cPlotArea, opts *Chart) *cPlotArea {
holeSize := 75
if opts.HoleSize > 0 && opts.HoleSize <= 90 {
holeSize = opts.HoleSize
@ -455,7 +455,7 @@ func (f *File) drawDoughnutChart(opts *Chart) *cPlotArea {
// drawLineChart provides a function to draw the c:plotArea element for line
// chart by given format sets.
func (f *File) drawLineChart(opts *Chart) *cPlotArea {
func (f *File) drawLineChart(pa *cPlotArea, opts *Chart) *cPlotArea {
return &cPlotArea{
LineChart: &cCharts{
Grouping: &attrValString{
@ -468,14 +468,14 @@ func (f *File) drawLineChart(opts *Chart) *cPlotArea {
DLbls: f.drawChartDLbls(opts),
AxID: f.genAxID(opts),
},
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
CatAx: f.drawPlotAreaCatAx(pa, opts),
ValAx: f.drawPlotAreaValAx(pa, opts),
}
}
// drawLine3DChart provides a function to draw the c:plotArea element for line
// chart by given format sets.
func (f *File) drawLine3DChart(opts *Chart) *cPlotArea {
func (f *File) drawLine3DChart(pa *cPlotArea, opts *Chart) *cPlotArea {
return &cPlotArea{
Line3DChart: &cCharts{
Grouping: &attrValString{
@ -488,14 +488,14 @@ func (f *File) drawLine3DChart(opts *Chart) *cPlotArea {
DLbls: f.drawChartDLbls(opts),
AxID: f.genAxID(opts),
},
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
CatAx: f.drawPlotAreaCatAx(pa, opts),
ValAx: f.drawPlotAreaValAx(pa, opts),
}
}
// drawPieChart provides a function to draw the c:plotArea element for pie
// chart by given format sets.
func (f *File) drawPieChart(opts *Chart) *cPlotArea {
func (f *File) drawPieChart(pa *cPlotArea, opts *Chart) *cPlotArea {
return &cPlotArea{
PieChart: &cCharts{
VaryColors: &attrValBool{
@ -508,7 +508,7 @@ func (f *File) drawPieChart(opts *Chart) *cPlotArea {
// drawPie3DChart provides a function to draw the c:plotArea element for 3D
// pie chart by given format sets.
func (f *File) drawPie3DChart(opts *Chart) *cPlotArea {
func (f *File) drawPie3DChart(pa *cPlotArea, opts *Chart) *cPlotArea {
return &cPlotArea{
Pie3DChart: &cCharts{
VaryColors: &attrValBool{
@ -521,7 +521,7 @@ func (f *File) drawPie3DChart(opts *Chart) *cPlotArea {
// drawPieOfPieChart provides a function to draw the c:plotArea element for
// pie chart by given format sets.
func (f *File) drawPieOfPieChart(opts *Chart) *cPlotArea {
func (f *File) drawPieOfPieChart(pa *cPlotArea, opts *Chart) *cPlotArea {
var splitPos *attrValInt
if opts.PlotArea.SecondPlotValues > 0 {
splitPos = &attrValInt{Val: intPtr(opts.PlotArea.SecondPlotValues)}
@ -543,7 +543,7 @@ func (f *File) drawPieOfPieChart(opts *Chart) *cPlotArea {
// drawBarOfPieChart provides a function to draw the c:plotArea element for
// pie chart by given format sets.
func (f *File) drawBarOfPieChart(opts *Chart) *cPlotArea {
func (f *File) drawBarOfPieChart(pa *cPlotArea, opts *Chart) *cPlotArea {
var splitPos *attrValInt
if opts.PlotArea.SecondPlotValues > 0 {
splitPos = &attrValInt{Val: intPtr(opts.PlotArea.SecondPlotValues)}
@ -565,7 +565,7 @@ func (f *File) drawBarOfPieChart(opts *Chart) *cPlotArea {
// drawRadarChart provides a function to draw the c:plotArea element for radar
// chart by given format sets.
func (f *File) drawRadarChart(opts *Chart) *cPlotArea {
func (f *File) drawRadarChart(pa *cPlotArea, opts *Chart) *cPlotArea {
return &cPlotArea{
RadarChart: &cCharts{
RadarStyle: &attrValString{
@ -578,14 +578,14 @@ func (f *File) drawRadarChart(opts *Chart) *cPlotArea {
DLbls: f.drawChartDLbls(opts),
AxID: f.genAxID(opts),
},
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
CatAx: f.drawPlotAreaCatAx(pa, opts),
ValAx: f.drawPlotAreaValAx(pa, opts),
}
}
// drawScatterChart provides a function to draw the c:plotArea element for
// scatter chart by given format sets.
func (f *File) drawScatterChart(opts *Chart) *cPlotArea {
func (f *File) drawScatterChart(pa *cPlotArea, opts *Chart) *cPlotArea {
return &cPlotArea{
ScatterChart: &cCharts{
ScatterStyle: &attrValString{
@ -598,14 +598,14 @@ func (f *File) drawScatterChart(opts *Chart) *cPlotArea {
DLbls: f.drawChartDLbls(opts),
AxID: f.genAxID(opts),
},
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
CatAx: f.drawPlotAreaCatAx(pa, opts),
ValAx: f.drawPlotAreaValAx(pa, opts),
}
}
// drawSurface3DChart provides a function to draw the c:surface3DChart element by
// given format sets.
func (f *File) drawSurface3DChart(opts *Chart) *cPlotArea {
func (f *File) drawSurface3DChart(pa *cPlotArea, opts *Chart) *cPlotArea {
plotArea := &cPlotArea{
Surface3DChart: &cCharts{
Ser: f.drawChartSeries(opts),
@ -615,8 +615,8 @@ func (f *File) drawSurface3DChart(opts *Chart) *cPlotArea {
{Val: intPtr(100000005)},
},
},
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
CatAx: f.drawPlotAreaCatAx(pa, opts),
ValAx: f.drawPlotAreaValAx(pa, opts),
SerAx: f.drawPlotAreaSerAx(opts),
}
if opts.Type == WireframeSurface3D {
@ -627,7 +627,7 @@ func (f *File) drawSurface3DChart(opts *Chart) *cPlotArea {
// drawSurfaceChart provides a function to draw the c:surfaceChart element by
// given format sets.
func (f *File) drawSurfaceChart(opts *Chart) *cPlotArea {
func (f *File) drawSurfaceChart(pa *cPlotArea, opts *Chart) *cPlotArea {
plotArea := &cPlotArea{
SurfaceChart: &cCharts{
Ser: f.drawChartSeries(opts),
@ -637,8 +637,8 @@ func (f *File) drawSurfaceChart(opts *Chart) *cPlotArea {
{Val: intPtr(100000005)},
},
},
CatAx: f.drawPlotAreaCatAx(opts),
ValAx: f.drawPlotAreaValAx(opts),
CatAx: f.drawPlotAreaCatAx(pa, opts),
ValAx: f.drawPlotAreaValAx(pa, opts),
SerAx: f.drawPlotAreaSerAx(opts),
}
if opts.Type == WireframeContour {
@ -649,7 +649,7 @@ func (f *File) drawSurfaceChart(opts *Chart) *cPlotArea {
// drawBubbleChart provides a function to draw the c:bubbleChart element by
// given format sets.
func (f *File) drawBubbleChart(opts *Chart) *cPlotArea {
func (f *File) drawBubbleChart(pa *cPlotArea, opts *Chart) *cPlotArea {
plotArea := &cPlotArea{
BubbleChart: &cCharts{
VaryColors: &attrValBool{
@ -659,7 +659,7 @@ func (f *File) drawBubbleChart(opts *Chart) *cPlotArea {
DLbls: f.drawChartDLbls(opts),
AxID: f.genAxID(opts),
},
ValAx: []*cAxs{f.drawPlotAreaCatAx(opts)[0], f.drawPlotAreaValAx(opts)[0]},
ValAx: []*cAxs{f.drawPlotAreaCatAx(pa, opts)[0], f.drawPlotAreaValAx(pa, opts)[0]},
}
if opts.BubbleSize > 0 && opts.BubbleSize <= 300 {
plotArea.BubbleChart.BubbleScale = &attrValFloat{Val: float64Ptr(float64(opts.BubbleSize))}
@ -979,7 +979,7 @@ func (f *File) drawChartSeriesDLbls(i int, opts *Chart) *cDLbls {
}
// drawPlotAreaCatAx provides a function to draw the c:catAx element.
func (f *File) drawPlotAreaCatAx(opts *Chart) []*cAxs {
func (f *File) drawPlotAreaCatAx(pa *cPlotArea, opts *Chart) []*cAxs {
maxVal := &attrValFloat{Val: opts.XAxis.Maximum}
minVal := &attrValFloat{Val: opts.XAxis.Minimum}
if opts.XAxis.Maximum == nil {
@ -988,70 +988,53 @@ func (f *File) drawPlotAreaCatAx(opts *Chart) []*cAxs {
if opts.XAxis.Minimum == nil {
minVal = nil
}
axs := []*cAxs{
{
AxID: &attrValInt{Val: intPtr(100000000)},
Scaling: &cScaling{
Orientation: &attrValString{Val: stringPtr(orientation[opts.XAxis.ReverseOrder])},
Max: maxVal,
Min: minVal,
},
Delete: &attrValBool{Val: boolPtr(opts.XAxis.None)},
AxPos: &attrValString{Val: stringPtr(catAxPos[opts.XAxis.ReverseOrder])},
NumFmt: &cNumFmt{FormatCode: "General"},
MajorTickMark: &attrValString{Val: stringPtr("none")},
MinorTickMark: &attrValString{Val: stringPtr("none")},
Title: f.drawPlotAreaTitles(opts.XAxis.Title, ""),
TickLblPos: &attrValString{Val: stringPtr("nextTo")},
SpPr: f.drawPlotAreaSpPr(),
TxPr: f.drawPlotAreaTxPr(&opts.YAxis),
CrossAx: &attrValInt{Val: intPtr(100000001)},
Crosses: &attrValString{Val: stringPtr("autoZero")},
Auto: &attrValBool{Val: boolPtr(true)},
LblAlgn: &attrValString{Val: stringPtr("ctr")},
LblOffset: &attrValInt{Val: intPtr(100)},
NoMultiLvlLbl: &attrValBool{Val: boolPtr(false)},
ax := &cAxs{
AxID: &attrValInt{Val: intPtr(100000000)},
Scaling: &cScaling{
Orientation: &attrValString{Val: stringPtr(orientation[opts.XAxis.ReverseOrder])},
Max: maxVal,
Min: minVal,
},
Delete: &attrValBool{Val: boolPtr(opts.XAxis.None)},
AxPos: &attrValString{Val: stringPtr(catAxPos[opts.XAxis.ReverseOrder])},
NumFmt: &cNumFmt{FormatCode: "General"},
MajorTickMark: &attrValString{Val: stringPtr("none")},
MinorTickMark: &attrValString{Val: stringPtr("none")},
Title: f.drawPlotAreaTitles(opts.XAxis.Title, ""),
TickLblPos: &attrValString{Val: stringPtr("nextTo")},
SpPr: f.drawPlotAreaSpPr(),
TxPr: f.drawPlotAreaTxPr(&opts.XAxis),
CrossAx: &attrValInt{Val: intPtr(100000001)},
Crosses: &attrValString{Val: stringPtr("autoZero")},
Auto: &attrValBool{Val: boolPtr(true)},
LblAlgn: &attrValString{Val: stringPtr("ctr")},
LblOffset: &attrValInt{Val: intPtr(100)},
NoMultiLvlLbl: &attrValBool{Val: boolPtr(false)},
}
if numFmt := f.drawChartNumFmt(opts.XAxis.NumFmt); numFmt != nil {
axs[0].NumFmt = numFmt
ax.NumFmt = numFmt
}
if opts.XAxis.MajorGridLines {
axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
ax.MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if opts.XAxis.MinorGridLines {
axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
ax.MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if opts.XAxis.TickLabelSkip != 0 {
axs[0].TickLblSkip = &attrValInt{Val: intPtr(opts.XAxis.TickLabelSkip)}
ax.TickLblSkip = &attrValInt{Val: intPtr(opts.XAxis.TickLabelSkip)}
}
if opts.order > 0 && opts.YAxis.Secondary {
axs = append(axs, &cAxs{
AxID: &attrValInt{Val: intPtr(opts.XAxis.axID)},
Scaling: &cScaling{
Orientation: &attrValString{Val: stringPtr(orientation[opts.XAxis.ReverseOrder])},
Max: maxVal,
Min: minVal,
},
Delete: &attrValBool{Val: boolPtr(true)},
AxPos: &attrValString{Val: stringPtr("b")},
MajorTickMark: &attrValString{Val: stringPtr("none")},
MinorTickMark: &attrValString{Val: stringPtr("none")},
TickLblPos: &attrValString{Val: stringPtr("nextTo")},
SpPr: f.drawPlotAreaSpPr(),
TxPr: f.drawPlotAreaTxPr(&opts.YAxis),
CrossAx: &attrValInt{Val: intPtr(opts.YAxis.axID)},
Auto: &attrValBool{Val: boolPtr(true)},
LblAlgn: &attrValString{Val: stringPtr("ctr")},
LblOffset: &attrValInt{Val: intPtr(100)},
NoMultiLvlLbl: &attrValBool{Val: boolPtr(false)},
})
if opts.order > 0 && opts.YAxis.Secondary && pa.CatAx != nil {
ax.AxID = &attrValInt{Val: intPtr(opts.XAxis.axID)}
ax.Delete = &attrValBool{Val: boolPtr(true)}
ax.Crosses = nil
ax.CrossAx = &attrValInt{Val: intPtr(opts.YAxis.axID)}
return []*cAxs{pa.CatAx[0], ax}
}
return axs
return []*cAxs{ax}
}
// drawPlotAreaValAx provides a function to draw the c:valAx element.
func (f *File) drawPlotAreaValAx(opts *Chart) []*cAxs {
func (f *File) drawPlotAreaValAx(pa *cPlotArea, opts *Chart) []*cAxs {
maxVal := &attrValFloat{Val: opts.YAxis.Maximum}
minVal := &attrValFloat{Val: opts.YAxis.Minimum}
if opts.YAxis.Maximum == nil {
@ -1064,67 +1047,53 @@ func (f *File) drawPlotAreaValAx(opts *Chart) []*cAxs {
if opts.YAxis.LogBase >= 2 && opts.YAxis.LogBase <= 1000 {
logBase = &attrValFloat{Val: float64Ptr(opts.YAxis.LogBase)}
}
axs := []*cAxs{
{
AxID: &attrValInt{Val: intPtr(100000001)},
Scaling: &cScaling{
LogBase: logBase,
Orientation: &attrValString{Val: stringPtr(orientation[opts.YAxis.ReverseOrder])},
Max: maxVal,
Min: minVal,
},
Delete: &attrValBool{Val: boolPtr(opts.YAxis.None)},
AxPos: &attrValString{Val: stringPtr(valAxPos[opts.YAxis.ReverseOrder])},
Title: f.drawPlotAreaTitles(opts.YAxis.Title, "horz"),
NumFmt: &cNumFmt{
FormatCode: chartValAxNumFmtFormatCode[opts.Type],
},
MajorTickMark: &attrValString{Val: stringPtr("none")},
MinorTickMark: &attrValString{Val: stringPtr("none")},
TickLblPos: &attrValString{Val: stringPtr("nextTo")},
SpPr: f.drawPlotAreaSpPr(),
TxPr: f.drawPlotAreaTxPr(&opts.XAxis),
CrossAx: &attrValInt{Val: intPtr(100000000)},
Crosses: &attrValString{Val: stringPtr("autoZero")},
CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[opts.Type])},
ax := &cAxs{
AxID: &attrValInt{Val: intPtr(100000001)},
Scaling: &cScaling{
LogBase: logBase,
Orientation: &attrValString{Val: stringPtr(orientation[opts.YAxis.ReverseOrder])},
Max: maxVal,
Min: minVal,
},
Delete: &attrValBool{Val: boolPtr(opts.YAxis.None)},
AxPos: &attrValString{Val: stringPtr(valAxPos[opts.YAxis.ReverseOrder])},
Title: f.drawPlotAreaTitles(opts.YAxis.Title, "horz"),
NumFmt: &cNumFmt{
FormatCode: chartValAxNumFmtFormatCode[opts.Type],
},
MajorTickMark: &attrValString{Val: stringPtr("none")},
MinorTickMark: &attrValString{Val: stringPtr("none")},
TickLblPos: &attrValString{Val: stringPtr("nextTo")},
SpPr: f.drawPlotAreaSpPr(),
TxPr: f.drawPlotAreaTxPr(&opts.YAxis),
CrossAx: &attrValInt{Val: intPtr(100000000)},
Crosses: &attrValString{Val: stringPtr("autoZero")},
CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[opts.Type])},
}
if numFmt := f.drawChartNumFmt(opts.YAxis.NumFmt); numFmt != nil {
axs[0].NumFmt = numFmt
ax.NumFmt = numFmt
}
if opts.YAxis.MajorGridLines {
axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
ax.MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if opts.YAxis.MinorGridLines {
axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
ax.MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
}
if pos, ok := valTickLblPos[opts.Type]; ok {
axs[0].TickLblPos.Val = stringPtr(pos)
ax.TickLblPos.Val = stringPtr(pos)
}
if opts.YAxis.MajorUnit != 0 {
axs[0].MajorUnit = &attrValFloat{Val: float64Ptr(opts.YAxis.MajorUnit)}
ax.MajorUnit = &attrValFloat{Val: float64Ptr(opts.YAxis.MajorUnit)}
}
if opts.order > 0 && opts.YAxis.Secondary {
axs = append(axs, &cAxs{
AxID: &attrValInt{Val: intPtr(opts.YAxis.axID)},
Scaling: &cScaling{
Orientation: &attrValString{Val: stringPtr(orientation[opts.YAxis.ReverseOrder])},
Max: maxVal,
Min: minVal,
},
Delete: &attrValBool{Val: boolPtr(false)},
AxPos: &attrValString{Val: stringPtr("r")},
MajorTickMark: &attrValString{Val: stringPtr("none")},
MinorTickMark: &attrValString{Val: stringPtr("none")},
TickLblPos: &attrValString{Val: stringPtr("nextTo")},
SpPr: f.drawPlotAreaSpPr(),
TxPr: f.drawPlotAreaTxPr(&opts.XAxis),
CrossAx: &attrValInt{Val: intPtr(opts.XAxis.axID)},
Crosses: &attrValString{Val: stringPtr("max")},
CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[opts.Type])},
})
if opts.order > 0 && opts.YAxis.Secondary && pa.ValAx != nil {
ax.AxID = &attrValInt{Val: intPtr(opts.YAxis.axID)}
ax.AxPos = &attrValString{Val: stringPtr("r")}
ax.Title = nil
ax.Crosses = &attrValString{Val: stringPtr("max")}
ax.CrossAx = &attrValInt{Val: intPtr(opts.XAxis.axID)}
return []*cAxs{pa.ValAx[0], ax}
}
return axs
return []*cAxs{ax}
}
// drawPlotAreaSerAx provides a function to draw the c:serAx element.