This closes # 1704, support set the data labels position for the chart (#1755)
- Breaking change: remove the Sizes field in the ChartSeries data type
- Add new field DataLabelPosition in the ChartSeries data type, support to sets the position of the chart series data label
- Add new field BubbleSize in the Chart data type, support set the bubble size in all data series for the bubble chart or 3D bubble chart
- Add new exported ChartDataLabelPositionType data type
- Update docs and unit test for the AddChart function
- Fix a v2.7.1 regression bug, the bubble is hidden in the bubble or 3D bubble chart, commit ID: c2d6707a85
This commit is contained in:
parent
284345e471
commit
dfaf418f34
21
chart.go
21
chart.go
|
@ -688,11 +688,11 @@ func (opts *Chart) parseTitle() {
|
|||
//
|
||||
// Name
|
||||
// Categories
|
||||
// Sizes
|
||||
// Values
|
||||
// Fill
|
||||
// Line
|
||||
// Marker
|
||||
// DataLabelPosition
|
||||
//
|
||||
// Name: Set the name for the series. The name is displayed in the chart legend
|
||||
// and in the formula bar. The 'Name' property is optional and if it isn't
|
||||
|
@ -703,8 +703,6 @@ func (opts *Chart) parseTitle() {
|
|||
// 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.
|
||||
|
@ -733,6 +731,8 @@ func (opts *Chart) parseTitle() {
|
|||
// x
|
||||
// auto
|
||||
//
|
||||
// DataLabelPosition: This sets the position of the chart series data label.
|
||||
//
|
||||
// Set properties of the chart legend. The options that can be set are:
|
||||
//
|
||||
// Position
|
||||
|
@ -776,11 +776,11 @@ func (opts *Chart) parseTitle() {
|
|||
// Specifies that each data marker in the series has a different color by
|
||||
// 'VaryColors'. The default value is true.
|
||||
//
|
||||
// Set chart offset, scale, aspect ratio setting and print settings by format,
|
||||
// Set chart offset, scale, aspect ratio setting and print settings by 'Format',
|
||||
// same as function 'AddPicture'.
|
||||
//
|
||||
// Set the position of the chart plot area by PlotArea. The properties that can
|
||||
// be set are:
|
||||
// Set the position of the chart plot area by 'PlotArea'. The properties that
|
||||
// can be set are:
|
||||
//
|
||||
// SecondPlotValues
|
||||
// ShowBubbleSize
|
||||
|
@ -891,6 +891,15 @@ func (opts *Chart) parseTitle() {
|
|||
// Set chart size by 'Dimension' property. The 'Dimension' property is optional.
|
||||
// The default width is 480, and height is 260.
|
||||
//
|
||||
// Set the bubble size in all data series for the bubble chart or 3D bubble
|
||||
// chart by 'BubbleSizes' property. The 'BubbleSizes' property is optional.
|
||||
// The default width is 100, and the value should be great than 0 and less or
|
||||
// equal than 300.
|
||||
//
|
||||
// Set the doughnut hole size in all data series for the doughnut chart by
|
||||
// 'HoleSize' property. The 'HoleSize' property is optional. The default width
|
||||
// is 75, and the value should be great than 0 and less or equal than 90.
|
||||
//
|
||||
// combo: Specifies the create a chart that combines two or more chart types in
|
||||
// a single chart. For example, create a clustered column - line chart with
|
||||
// data Sheet1!$E$1:$L$15:
|
||||
|
|
|
@ -176,14 +176,14 @@ func TestAddChart(t *testing.T) {
|
|||
}
|
||||
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"},
|
||||
{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30", DataLabelPosition: ChartDataLabelsPositionAbove},
|
||||
{Name: "Sheet1!$A$31", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$31:$D$31", DataLabelPosition: ChartDataLabelsPositionLeft},
|
||||
{Name: "Sheet1!$A$32", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$32:$D$32", DataLabelPosition: ChartDataLabelsPositionBestFit},
|
||||
{Name: "Sheet1!$A$33", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$33:$D$33", DataLabelPosition: ChartDataLabelsPositionCenter},
|
||||
{Name: "Sheet1!$A$34", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$34:$D$34", DataLabelPosition: ChartDataLabelsPositionInsideBase},
|
||||
{Name: "Sheet1!$A$35", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$35:$D$35", DataLabelPosition: ChartDataLabelsPositionInsideEnd},
|
||||
{Name: "Sheet1!$A$36", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$36:$D$36", DataLabelPosition: ChartDataLabelsPositionOutsideEnd},
|
||||
{Name: "Sheet1!$A$37", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$37:$D$37", DataLabelPosition: ChartDataLabelsPositionRight},
|
||||
}
|
||||
format := GraphicOptions{
|
||||
ScaleX: defaultDrawingScale,
|
||||
|
@ -265,7 +265,7 @@ func TestAddChart(t *testing.T) {
|
|||
{sheetName: "Sheet2", cell: "AV32", opts: &Chart{Type: Contour, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Contour Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||
{sheetName: "Sheet2", cell: "BD1", opts: &Chart{Type: WireframeContour, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Wireframe Contour Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||
// bubble chart
|
||||
{sheetName: "Sheet2", cell: "BD16", opts: &Chart{Type: Bubble, Series: series4, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Bubble Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||
{sheetName: "Sheet2", cell: "BD16", opts: &Chart{Type: Bubble, Series: series4, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Bubble Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", BubbleSize: 75}},
|
||||
{sheetName: "Sheet2", cell: "BD32", opts: &Chart{Type: Bubble3D, Series: series4, Format: format, Legend: legend, Title: []RichTextRun{{Text: "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: []RichTextRun{{Text: "Pie of Pie Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
||||
|
|
30
drawing.go
30
drawing.go
|
@ -659,6 +659,9 @@ func (f *File) drawBubbleChart(opts *Chart) *cPlotArea {
|
|||
},
|
||||
ValAx: []*cAxs{f.drawPlotAreaCatAx(opts)[0], f.drawPlotAreaValAx(opts)[0]},
|
||||
}
|
||||
if opts.BubbleSize > 0 && opts.BubbleSize <= 300 {
|
||||
plotArea.BubbleChart.BubbleScale = &attrValFloat{Val: float64Ptr(float64(opts.BubbleSize))}
|
||||
}
|
||||
return plotArea
|
||||
}
|
||||
|
||||
|
@ -710,7 +713,7 @@ func (f *File) drawChartSeries(opts *Chart) *[]cSer {
|
|||
SpPr: f.drawChartSeriesSpPr(k, opts),
|
||||
Marker: f.drawChartSeriesMarker(k, opts),
|
||||
DPt: f.drawChartSeriesDPt(k, opts),
|
||||
DLbls: f.drawChartSeriesDLbls(opts),
|
||||
DLbls: f.drawChartSeriesDLbls(k, opts),
|
||||
InvertIfNegative: &attrValBool{Val: boolPtr(false)},
|
||||
Cat: f.drawChartSeriesCat(opts.Series[k], opts),
|
||||
Smooth: &attrValBool{Val: boolPtr(opts.Series[k].Line.Smooth)},
|
||||
|
@ -885,12 +888,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[ChartType]bool{Bubble: true, Bubble3D: true}[opts.Type]; !ok || v.Sizes == "" {
|
||||
if _, ok := map[ChartType]bool{Bubble: true, Bubble3D: true}[opts.Type]; !ok {
|
||||
return nil
|
||||
}
|
||||
return &cVal{
|
||||
NumRef: &cNumRef{
|
||||
F: v.Sizes,
|
||||
F: v.Values,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -932,16 +935,33 @@ func (f *File) drawChartDLbls(opts *Chart) *cDLbls {
|
|||
}
|
||||
}
|
||||
|
||||
// inSupportedChartDataLabelsPositionType provides a method to check if an
|
||||
// element is present in an array, and return the index of its location,
|
||||
// otherwise return -1.
|
||||
func inSupportedChartDataLabelsPositionType(a []ChartDataLabelPositionType, x ChartDataLabelPositionType) int {
|
||||
for idx, n := range a {
|
||||
if x == n {
|
||||
return idx
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
// drawChartSeriesDLbls provides a function to draw the c:dLbls element by
|
||||
// given format sets.
|
||||
func (f *File) drawChartSeriesDLbls(opts *Chart) *cDLbls {
|
||||
func (f *File) drawChartSeriesDLbls(i int, opts *Chart) *cDLbls {
|
||||
dLbls := f.drawChartDLbls(opts)
|
||||
chartSeriesDLbls := map[ChartType]*cDLbls{
|
||||
Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil,
|
||||
Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil,
|
||||
}
|
||||
if _, ok := chartSeriesDLbls[opts.Type]; ok {
|
||||
return nil
|
||||
}
|
||||
if types, ok := supportedChartDataLabelsPosition[opts.Type]; ok && opts.Series[i].DataLabelPosition != ChartDataLabelsPositionUnset {
|
||||
if inSupportedChartDataLabelsPositionType(types, opts.Series[i].DataLabelPosition) != -1 {
|
||||
dLbls.DLblPos = &attrValString{Val: stringPtr(chartDataLabelsPositionTypes[opts.Series[i].DataLabelPosition])}
|
||||
}
|
||||
}
|
||||
return dLbls
|
||||
}
|
||||
|
||||
|
|
48
templates.go
48
templates.go
|
@ -217,6 +217,54 @@ const (
|
|||
ColorMappingTypeUnset int = -1
|
||||
)
|
||||
|
||||
// ChartDataLabelPositionType is the type of chart data labels position.
|
||||
type ChartDataLabelPositionType byte
|
||||
|
||||
// Chart data labels positions types enumeration.
|
||||
const (
|
||||
ChartDataLabelsPositionUnset ChartDataLabelPositionType = iota
|
||||
ChartDataLabelsPositionBestFit
|
||||
ChartDataLabelsPositionBelow
|
||||
ChartDataLabelsPositionCenter
|
||||
ChartDataLabelsPositionInsideBase
|
||||
ChartDataLabelsPositionInsideEnd
|
||||
ChartDataLabelsPositionLeft
|
||||
ChartDataLabelsPositionOutsideEnd
|
||||
ChartDataLabelsPositionRight
|
||||
ChartDataLabelsPositionAbove
|
||||
)
|
||||
|
||||
// chartDataLabelsPositionTypes defined supported chart data labels position
|
||||
// types.
|
||||
var chartDataLabelsPositionTypes = map[ChartDataLabelPositionType]string{
|
||||
ChartDataLabelsPositionBestFit: "bestFit",
|
||||
ChartDataLabelsPositionBelow: "b",
|
||||
ChartDataLabelsPositionCenter: "ctr",
|
||||
ChartDataLabelsPositionInsideBase: "inBase",
|
||||
ChartDataLabelsPositionInsideEnd: "inEnd",
|
||||
ChartDataLabelsPositionLeft: "l",
|
||||
ChartDataLabelsPositionOutsideEnd: "outEnd",
|
||||
ChartDataLabelsPositionRight: "r",
|
||||
ChartDataLabelsPositionAbove: "t",
|
||||
}
|
||||
|
||||
// supportedChartDataLabelsPosition defined supported chart data labels position
|
||||
// types for each type of chart.
|
||||
var supportedChartDataLabelsPosition = map[ChartType][]ChartDataLabelPositionType{
|
||||
Bar: {ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideBase, ChartDataLabelsPositionInsideEnd, ChartDataLabelsPositionOutsideEnd},
|
||||
BarStacked: {ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideBase, ChartDataLabelsPositionInsideEnd},
|
||||
BarPercentStacked: {ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideBase, ChartDataLabelsPositionInsideEnd},
|
||||
Col: {ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideBase, ChartDataLabelsPositionInsideEnd, ChartDataLabelsPositionOutsideEnd},
|
||||
ColStacked: {ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideBase, ChartDataLabelsPositionInsideEnd},
|
||||
ColPercentStacked: {ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideBase, ChartDataLabelsPositionInsideEnd},
|
||||
Line: {ChartDataLabelsPositionBelow, ChartDataLabelsPositionCenter, ChartDataLabelsPositionLeft, ChartDataLabelsPositionRight, ChartDataLabelsPositionAbove},
|
||||
Pie: {ChartDataLabelsPositionBestFit, ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideEnd, ChartDataLabelsPositionOutsideEnd},
|
||||
Pie3D: {ChartDataLabelsPositionBestFit, ChartDataLabelsPositionCenter, ChartDataLabelsPositionInsideEnd, ChartDataLabelsPositionOutsideEnd},
|
||||
Scatter: {ChartDataLabelsPositionBelow, ChartDataLabelsPositionCenter, ChartDataLabelsPositionLeft, ChartDataLabelsPositionRight, ChartDataLabelsPositionAbove},
|
||||
Bubble: {ChartDataLabelsPositionBelow, ChartDataLabelsPositionCenter, ChartDataLabelsPositionLeft, ChartDataLabelsPositionRight, ChartDataLabelsPositionAbove},
|
||||
Bubble3D: {ChartDataLabelsPositionBelow, ChartDataLabelsPositionCenter, ChartDataLabelsPositionLeft, ChartDataLabelsPositionRight, ChartDataLabelsPositionAbove},
|
||||
}
|
||||
|
||||
const (
|
||||
defaultTempFileSST = "sharedStrings"
|
||||
defaultXMLPathCalcChain = "xl/calcChain.xml"
|
||||
|
|
32
xmlChart.go
32
xmlChart.go
|
@ -482,14 +482,15 @@ type cNumCache struct {
|
|||
// entire series or the entire chart. It contains child elements that specify
|
||||
// the specific formatting and positioning settings.
|
||||
type cDLbls struct {
|
||||
NumFmt *cNumFmt `xml:"numFmt"`
|
||||
ShowLegendKey *attrValBool `xml:"showLegendKey"`
|
||||
ShowVal *attrValBool `xml:"showVal"`
|
||||
ShowCatName *attrValBool `xml:"showCatName"`
|
||||
ShowSerName *attrValBool `xml:"showSerName"`
|
||||
ShowPercent *attrValBool `xml:"showPercent"`
|
||||
ShowBubbleSize *attrValBool `xml:"showBubbleSize"`
|
||||
ShowLeaderLines *attrValBool `xml:"showLeaderLines"`
|
||||
NumFmt *cNumFmt `xml:"numFmt"`
|
||||
DLblPos *attrValString `xml:"dLblPos"`
|
||||
ShowLegendKey *attrValBool `xml:"showLegendKey"`
|
||||
ShowVal *attrValBool `xml:"showVal"`
|
||||
ShowCatName *attrValBool `xml:"showCatName"`
|
||||
ShowSerName *attrValBool `xml:"showSerName"`
|
||||
ShowPercent *attrValBool `xml:"showPercent"`
|
||||
ShowBubbleSize *attrValBool `xml:"showBubbleSize"`
|
||||
ShowLeaderLines *attrValBool `xml:"showLeaderLines"`
|
||||
}
|
||||
|
||||
// cLegend (Legend) directly maps the legend element. This element specifies
|
||||
|
@ -577,6 +578,7 @@ type Chart struct {
|
|||
PlotArea ChartPlotArea
|
||||
Border ChartLine
|
||||
ShowBlanksAs string
|
||||
BubbleSize int
|
||||
HoleSize int
|
||||
order int
|
||||
}
|
||||
|
@ -602,11 +604,11 @@ type ChartLine struct {
|
|||
|
||||
// ChartSeries directly maps the format settings of the chart series.
|
||||
type ChartSeries struct {
|
||||
Name string
|
||||
Categories string
|
||||
Sizes string
|
||||
Values string
|
||||
Fill Fill
|
||||
Line ChartLine
|
||||
Marker ChartMarker
|
||||
Name string
|
||||
Categories string
|
||||
Values string
|
||||
Fill Fill
|
||||
Line ChartLine
|
||||
Marker ChartMarker
|
||||
DataLabelPosition ChartDataLabelPositionType
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue