- Removed exported `ChartTitle` data type - The `AddChart` function now supports formatting and setting rich text titles for the chart - New exported function `GetFormControl` for getting form control - Made case in-sensitive for internal worksheet XML path to improve compatibility - Update the unit tests - Update the documentation and internal comments on the codes
This commit is contained in:
parent
2e9c2904f2
commit
a07c8cd0b4
|
@ -165,8 +165,10 @@ func main() {
|
||||||
Categories: "Sheet1!$B$1:$D$1",
|
Categories: "Sheet1!$B$1:$D$1",
|
||||||
Values: "Sheet1!$B$4:$D$4",
|
Values: "Sheet1!$B$4:$D$4",
|
||||||
}},
|
}},
|
||||||
Title: excelize.ChartTitle{
|
Title: []excelize.RichTextRun{
|
||||||
Name: "Fruit 3D Clustered Column Chart",
|
{
|
||||||
|
Text: "Fruit 3D Clustered Column Chart",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|
|
@ -165,8 +165,10 @@ func main() {
|
||||||
Categories: "Sheet1!$B$1:$D$1",
|
Categories: "Sheet1!$B$1:$D$1",
|
||||||
Values: "Sheet1!$B$4:$D$4",
|
Values: "Sheet1!$B$4:$D$4",
|
||||||
}},
|
}},
|
||||||
Title: excelize.ChartTitle{
|
Title: []excelize.RichTextRun{
|
||||||
Name: "Fruit 3D Clustered Column Chart",
|
{
|
||||||
|
Text: "Fruit 3D Clustered Column Chart",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
|
|
26
chart.go
26
chart.go
|
@ -507,8 +507,16 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
|
||||||
if opts.Legend.Position == "" {
|
if opts.Legend.Position == "" {
|
||||||
opts.Legend.Position = defaultChartLegendPosition
|
opts.Legend.Position = defaultChartLegendPosition
|
||||||
}
|
}
|
||||||
if opts.Title.Name == "" {
|
for i := range opts.Title {
|
||||||
opts.Title.Name = " "
|
if opts.Title[i].Font == nil {
|
||||||
|
opts.Title[i].Font = &Font{}
|
||||||
|
}
|
||||||
|
if opts.Title[i].Font.Color == "" {
|
||||||
|
opts.Title[i].Font.Color = "595959"
|
||||||
|
}
|
||||||
|
if opts.Title[i].Font.Size == 0 {
|
||||||
|
opts.Title[i].Font.Size = 14
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if opts.VaryColors == nil {
|
if opts.VaryColors == nil {
|
||||||
opts.VaryColors = boolPtr(true)
|
opts.VaryColors = boolPtr(true)
|
||||||
|
@ -569,8 +577,10 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
|
||||||
// Values: "Sheet1!$B$4:$D$4",
|
// Values: "Sheet1!$B$4:$D$4",
|
||||||
// },
|
// },
|
||||||
// },
|
// },
|
||||||
// Title: excelize.ChartTitle{
|
// Title: []excelize.RichTextRun{
|
||||||
// Name: "Fruit 3D Clustered Column Chart",
|
// {
|
||||||
|
// Text: "Fruit 3D Clustered Column Chart",
|
||||||
|
// },
|
||||||
// },
|
// },
|
||||||
// Legend: excelize.ChartLegend{
|
// Legend: excelize.ChartLegend{
|
||||||
// ShowLegendKey: false,
|
// ShowLegendKey: false,
|
||||||
|
@ -727,7 +737,7 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
|
||||||
//
|
//
|
||||||
// Title
|
// Title
|
||||||
//
|
//
|
||||||
// Name: Set the name (title) for the chart. The name is displayed above the
|
// Title: Set the name (title) for the chart. The name is displayed above the
|
||||||
// chart. The name can also be a formula such as Sheet1!$A$1 or a list with a
|
// chart. The name can also be a formula such as Sheet1!$A$1 or a list with a
|
||||||
// sheet name. The name property is optional. The default is to have no chart
|
// sheet name. The name property is optional. The default is to have no chart
|
||||||
// title.
|
// title.
|
||||||
|
@ -912,8 +922,10 @@ func parseChartOptions(opts *Chart) (*Chart, error) {
|
||||||
// LockAspectRatio: false,
|
// LockAspectRatio: false,
|
||||||
// Locked: &disable,
|
// Locked: &disable,
|
||||||
// },
|
// },
|
||||||
// Title: excelize.ChartTitle{
|
// Title: []excelize.RichTextRun{
|
||||||
// Name: "Clustered Column - Line Chart",
|
// {
|
||||||
|
// Text: "Clustered Column - Line Chart",
|
||||||
|
// },
|
||||||
// },
|
// },
|
||||||
// Legend: excelize.ChartLegend{
|
// Legend: excelize.ChartLegend{
|
||||||
// Position: "left",
|
// Position: "left",
|
||||||
|
|
150
chart_test.go
150
chart_test.go
|
@ -52,7 +52,7 @@ func TestChartSize(t *testing.T) {
|
||||||
{Name: "Sheet1!$A$3", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$3:$D$3"},
|
{Name: "Sheet1!$A$3", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$3:$D$3"},
|
||||||
{Name: "Sheet1!$A$4", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$4:$D$4"},
|
{Name: "Sheet1!$A$4", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$4:$D$4"},
|
||||||
},
|
},
|
||||||
Title: ChartTitle{Name: "3D Clustered Column Chart"},
|
Title: []RichTextRun{{Text: "3D Clustered Column Chart"}},
|
||||||
}))
|
}))
|
||||||
|
|
||||||
var buffer bytes.Buffer
|
var buffer bytes.Buffer
|
||||||
|
@ -206,69 +206,69 @@ func TestAddChart(t *testing.T) {
|
||||||
sheetName, cell string
|
sheetName, cell string
|
||||||
opts *Chart
|
opts *Chart
|
||||||
}{
|
}{
|
||||||
{sheetName: "Sheet1", cell: "P1", opts: &Chart{Type: Col, Series: series, Format: format, Legend: ChartLegend{Position: "none", ShowLegendKey: true}, Title: ChartTitle{Name: "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}}}}}},
|
{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}}}}}},
|
||||||
{sheetName: "Sheet1", cell: "X1", opts: &Chart{Type: ColStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Stacked Column Chart"}, PlotArea: plotArea, 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, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "P16", opts: &Chart{Type: ColPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "100% Stacked Column Chart"}, PlotArea: plotArea, 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, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "X16", opts: &Chart{Type: Col3DClustered, Series: series, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: ChartTitle{Name: "3D Clustered Column Chart"}, PlotArea: plotArea, 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: ChartTitle{Name: "3D Stacked 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: ChartTitle{Name: "3D 100% 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"}},
|
||||||
{sheetName: "Sheet1", cell: "X45", opts: &Chart{Type: Radar, Series: series, Format: format, Legend: ChartLegend{Position: "top_right", ShowLegendKey: false}, Title: ChartTitle{Name: "Radar Chart"}, PlotArea: plotArea, ShowBlanksAs: "span"}},
|
{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"}},
|
||||||
{sheetName: "Sheet1", cell: "AF1", opts: &Chart{Type: Col3DConeStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cone Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AF1", opts: &Chart{Type: Col3DConeStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cone Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AF16", opts: &Chart{Type: Col3DConeClustered, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cone Clustered Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AF16", opts: &Chart{Type: Col3DConeClustered, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cone Clustered Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AF30", opts: &Chart{Type: Col3DConePercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cone Percent Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AF30", opts: &Chart{Type: Col3DConePercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cone Percent Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AF45", opts: &Chart{Type: Col3DCone, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cone Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AF45", opts: &Chart{Type: Col3DCone, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cone Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AN1", opts: &Chart{Type: Col3DPyramidStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Pyramid Percent Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AN1", opts: &Chart{Type: Col3DPyramidStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Pyramid Percent Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AN16", opts: &Chart{Type: Col3DPyramidClustered, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Pyramid Clustered Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AN16", opts: &Chart{Type: Col3DPyramidClustered, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Pyramid Clustered Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AN30", opts: &Chart{Type: Col3DPyramidPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Pyramid Percent Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AN30", opts: &Chart{Type: Col3DPyramidPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Pyramid Percent Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AN45", opts: &Chart{Type: Col3DPyramid, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Pyramid Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AN45", opts: &Chart{Type: Col3DPyramid, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Pyramid Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AV1", opts: &Chart{Type: Col3DCylinderStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cylinder Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AV1", opts: &Chart{Type: Col3DCylinderStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cylinder Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AV16", opts: &Chart{Type: Col3DCylinderClustered, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cylinder Clustered Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AV16", opts: &Chart{Type: Col3DCylinderClustered, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cylinder Clustered Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AV30", opts: &Chart{Type: Col3DCylinderPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cylinder Percent Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AV30", opts: &Chart{Type: Col3DCylinderPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cylinder Percent Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "AV45", opts: &Chart{Type: Col3DCylinder, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Cylinder Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "AV45", opts: &Chart{Type: Col3DCylinder, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Cylinder Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet1", cell: "P45", opts: &Chart{Type: Col3D, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Column Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet1", cell: "P45", opts: &Chart{Type: Col3D, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "P1", opts: &Chart{Type: Line3D, Series: series2, Format: format, Legend: ChartLegend{Position: "top", ShowLegendKey: false}, Title: ChartTitle{Name: "3D Line Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, TickLabelSkip: 1, NumFmt: ChartNumFmt{CustomNumFmt: "General"}}, YAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, MajorUnit: 1, NumFmt: ChartNumFmt{CustomNumFmt: "General"}}}},
|
{sheetName: "Sheet2", cell: "P1", opts: &Chart{Type: Line3D, Series: series2, Format: format, Legend: ChartLegend{Position: "top", ShowLegendKey: false}, Title: []RichTextRun{{Text: "3D Line Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, TickLabelSkip: 1, NumFmt: ChartNumFmt{CustomNumFmt: "General"}}, YAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, MajorUnit: 1, NumFmt: ChartNumFmt{CustomNumFmt: "General"}}}},
|
||||||
{sheetName: "Sheet2", cell: "X1", opts: &Chart{Type: Scatter, Series: series, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: ChartTitle{Name: "Scatter Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "X1", opts: &Chart{Type: Scatter, Series: series, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: []RichTextRun{{Text: "Scatter Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "P16", opts: &Chart{Type: Doughnut, Series: series3, Format: format, Legend: ChartLegend{Position: "right", ShowLegendKey: false}, Title: ChartTitle{Name: "Doughnut Chart"}, PlotArea: ChartPlotArea{ShowBubbleSize: false, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: false, ShowVal: false}, ShowBlanksAs: "zero", HoleSize: 30}},
|
{sheetName: "Sheet2", cell: "P16", opts: &Chart{Type: Doughnut, Series: series3, Format: format, Legend: ChartLegend{Position: "right", ShowLegendKey: false}, Title: []RichTextRun{{Text: "Doughnut Chart"}}, PlotArea: ChartPlotArea{ShowBubbleSize: false, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: false, ShowVal: false}, ShowBlanksAs: "zero", HoleSize: 30}},
|
||||||
{sheetName: "Sheet2", cell: "X16", opts: &Chart{Type: Line, Series: series2, Format: format, Legend: ChartLegend{Position: "top", ShowLegendKey: false}, Title: ChartTitle{Name: "Line Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, TickLabelSkip: 1}, YAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, MajorUnit: 1}}},
|
{sheetName: "Sheet2", cell: "X16", opts: &Chart{Type: Line, Series: series2, Format: format, Legend: ChartLegend{Position: "top", ShowLegendKey: false}, Title: []RichTextRun{{Text: "Line Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, TickLabelSkip: 1}, YAxis: ChartAxis{MajorGridLines: true, MinorGridLines: true, MajorUnit: 1}}},
|
||||||
{sheetName: "Sheet2", cell: "P32", opts: &Chart{Type: Pie3D, Series: series3, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: ChartTitle{Name: "3D Column Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "P32", opts: &Chart{Type: Pie3D, Series: series3, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: []RichTextRun{{Text: "3D Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "X32", opts: &Chart{Type: Pie, Series: series3, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: ChartTitle{Name: "Pie Chart"}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: false, ShowVal: false, NumFmt: ChartNumFmt{CustomNumFmt: "0.00%;0;;"}}, ShowBlanksAs: "gap"}},
|
{sheetName: "Sheet2", cell: "X32", opts: &Chart{Type: Pie, Series: series3, Format: format, Legend: ChartLegend{Position: "bottom", ShowLegendKey: false}, Title: []RichTextRun{{Text: "Pie Chart"}}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: false, ShowVal: false, NumFmt: ChartNumFmt{CustomNumFmt: "0.00%;0;;"}}, ShowBlanksAs: "gap"}},
|
||||||
// bar series chart
|
// bar series chart
|
||||||
{sheetName: "Sheet2", cell: "P48", opts: &Chart{Type: Bar, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Clustered Bar Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "P48", opts: &Chart{Type: Bar, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Clustered Bar Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "X48", opts: &Chart{Type: BarStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Stacked Bar Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "X48", opts: &Chart{Type: BarStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Stacked Bar Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "P64", opts: &Chart{Type: BarPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Stacked 100% Bar Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "P64", opts: &Chart{Type: BarPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Stacked 100% Bar Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "X64", opts: &Chart{Type: Bar3DClustered, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Clustered Bar Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "X64", opts: &Chart{Type: Bar3DClustered, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Clustered Bar Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "P80", opts: &Chart{Type: Bar3DStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Stacked Bar Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", YAxis: ChartAxis{Maximum: &maximum, Minimum: &minimum}}},
|
{sheetName: "Sheet2", cell: "P80", opts: &Chart{Type: Bar3DStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Stacked Bar Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", YAxis: ChartAxis{Maximum: &maximum, Minimum: &minimum}}},
|
||||||
{sheetName: "Sheet2", cell: "X80", opts: &Chart{Type: Bar3DPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D 100% Stacked Bar Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{ReverseOrder: true, Secondary: true, Minimum: &zero}, YAxis: ChartAxis{ReverseOrder: true, Minimum: &zero}}},
|
{sheetName: "Sheet2", cell: "X80", opts: &Chart{Type: Bar3DPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D 100% Stacked Bar Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{ReverseOrder: true, Secondary: true, Minimum: &zero}, YAxis: ChartAxis{ReverseOrder: true, Minimum: &zero}}},
|
||||||
// area series chart
|
// area series chart
|
||||||
{sheetName: "Sheet2", cell: "AF1", opts: &Chart{Type: Area, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Area Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AF1", opts: &Chart{Type: Area, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Area Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AN1", opts: &Chart{Type: AreaStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Stacked Area Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AN1", opts: &Chart{Type: AreaStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Stacked Area Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AF16", opts: &Chart{Type: AreaPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D 100% Stacked Area Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AF16", opts: &Chart{Type: AreaPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D 100% Stacked Area Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AN16", opts: &Chart{Type: Area3D, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Area Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AN16", opts: &Chart{Type: Area3D, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Area Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AF32", opts: &Chart{Type: Area3DStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Stacked Area Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AF32", opts: &Chart{Type: Area3DStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Stacked Area Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AN32", opts: &Chart{Type: Area3DPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D 100% Stacked Area Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AN32", opts: &Chart{Type: Area3DPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D 100% Stacked Area Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
// cylinder series chart
|
// cylinder series chart
|
||||||
{sheetName: "Sheet2", cell: "AF48", opts: &Chart{Type: Bar3DCylinderStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Cylinder Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AF48", opts: &Chart{Type: Bar3DCylinderStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Cylinder Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AF64", opts: &Chart{Type: Bar3DCylinderClustered, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Cylinder Clustered Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AF64", opts: &Chart{Type: Bar3DCylinderClustered, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Cylinder Clustered Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AF80", opts: &Chart{Type: Bar3DCylinderPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Cylinder Percent Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AF80", opts: &Chart{Type: Bar3DCylinderPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Cylinder Percent Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
// cone series chart
|
// cone series chart
|
||||||
{sheetName: "Sheet2", cell: "AN48", opts: &Chart{Type: Bar3DConeStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Cone Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AN48", opts: &Chart{Type: Bar3DConeStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Cone Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AN64", opts: &Chart{Type: Bar3DConeClustered, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Cone Clustered Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AN64", opts: &Chart{Type: Bar3DConeClustered, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Cone Clustered Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AN80", opts: &Chart{Type: Bar3DConePercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Cone Percent Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AN80", opts: &Chart{Type: Bar3DConePercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Cone Percent Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AV48", opts: &Chart{Type: Bar3DPyramidStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Pyramid Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AV48", opts: &Chart{Type: Bar3DPyramidStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Pyramid Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AV64", opts: &Chart{Type: Bar3DPyramidClustered, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Pyramid Clustered Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AV64", opts: &Chart{Type: Bar3DPyramidClustered, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Pyramid Clustered Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
{sheetName: "Sheet2", cell: "AV80", opts: &Chart{Type: Bar3DPyramidPercentStacked, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Bar Pyramid Percent Stacked Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{sheetName: "Sheet2", cell: "AV80", opts: &Chart{Type: Bar3DPyramidPercentStacked, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Bar Pyramid Percent Stacked Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
||||||
// surface series chart
|
// surface series chart
|
||||||
{sheetName: "Sheet2", cell: "AV1", opts: &Chart{Type: Surface3D, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Surface Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", YAxis: ChartAxis{MajorGridLines: true}}},
|
{sheetName: "Sheet2", cell: "AV1", opts: &Chart{Type: Surface3D, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Surface Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", YAxis: ChartAxis{MajorGridLines: true}}},
|
||||||
{sheetName: "Sheet2", cell: "AV16", opts: &Chart{Type: WireframeSurface3D, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "3D Wireframe Surface Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", YAxis: ChartAxis{MajorGridLines: true}}},
|
{sheetName: "Sheet2", cell: "AV16", opts: &Chart{Type: WireframeSurface3D, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "3D Wireframe Surface Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", YAxis: ChartAxis{MajorGridLines: true}}},
|
||||||
{sheetName: "Sheet2", cell: "AV32", opts: &Chart{Type: Contour, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "Contour Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}},
|
{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: ChartTitle{Name: "Wireframe 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
|
// bubble chart
|
||||||
{sheetName: "Sheet2", cell: "BD16", opts: &Chart{Type: Bubble, Series: series4, Format: format, Legend: legend, Title: ChartTitle{Name: "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"}},
|
||||||
{sheetName: "Sheet2", cell: "BD32", opts: &Chart{Type: Bubble3D, Series: series4, Format: format, Legend: legend, Title: ChartTitle{Name: "Bubble 3D Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
{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
|
// pie of pie chart
|
||||||
{sheetName: "Sheet2", cell: "BD48", opts: &Chart{Type: PieOfPie, Series: series3, Format: format, Legend: legend, Title: ChartTitle{Name: "Pie of Pie Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
{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}}},
|
||||||
// bar of pie chart
|
// bar of pie chart
|
||||||
{sheetName: "Sheet2", cell: "BD64", opts: &Chart{Type: BarOfPie, Series: series3, Format: format, Legend: legend, Title: ChartTitle{Name: "Bar of Pie Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
{sheetName: "Sheet2", cell: "BD64", opts: &Chart{Type: BarOfPie, Series: series3, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Bar of Pie Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}},
|
||||||
} {
|
} {
|
||||||
assert.NoError(t, f.AddChart(c.sheetName, c.cell, c.opts))
|
assert.NoError(t, f.AddChart(c.sheetName, c.cell, c.opts))
|
||||||
}
|
}
|
||||||
|
@ -280,32 +280,32 @@ func TestAddChart(t *testing.T) {
|
||||||
{"I1", Doughnut, "Clustered Column - Doughnut Chart"},
|
{"I1", Doughnut, "Clustered Column - Doughnut Chart"},
|
||||||
}
|
}
|
||||||
for _, props := range clusteredColumnCombo {
|
for _, props := range clusteredColumnCombo {
|
||||||
assert.NoError(t, f.AddChart("Combo Charts", props[0].(string), &Chart{Type: Col, Series: series[:4], Format: format, Legend: legend, Title: ChartTitle{Name: props[2].(string)}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[1].(ChartType), Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}, YAxis: ChartAxis{Secondary: true}}))
|
assert.NoError(t, f.AddChart("Combo Charts", props[0].(string), &Chart{Type: Col, Series: series[:4], Format: format, Legend: legend, Title: []RichTextRun{{Text: props[2].(string)}}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[1].(ChartType), Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}, YAxis: ChartAxis{Secondary: true}}))
|
||||||
}
|
}
|
||||||
stackedAreaCombo := map[string][]interface{}{
|
stackedAreaCombo := map[string][]interface{}{
|
||||||
"A16": {Line, "Stacked Area - Line Chart"},
|
"A16": {Line, "Stacked Area - Line Chart"},
|
||||||
"I16": {Doughnut, "Stacked Area - Doughnut Chart"},
|
"I16": {Doughnut, "Stacked Area - Doughnut Chart"},
|
||||||
}
|
}
|
||||||
for axis, props := range stackedAreaCombo {
|
for axis, props := range stackedAreaCombo {
|
||||||
assert.NoError(t, f.AddChart("Combo Charts", axis, &Chart{Type: AreaStacked, Series: series[:4], Format: format, Legend: legend, Title: ChartTitle{Name: props[1].(string)}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[0].(ChartType), Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}))
|
assert.NoError(t, f.AddChart("Combo Charts", axis, &Chart{Type: AreaStacked, Series: series[:4], Format: format, Legend: legend, Title: []RichTextRun{{Text: props[1].(string)}}, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}, &Chart{Type: props[0].(ChartType), Series: series[4:], Format: format, Legend: legend, PlotArea: ChartPlotArea{ShowBubbleSize: true, ShowCatName: false, ShowLeaderLines: false, ShowPercent: true, ShowSerName: true, ShowVal: true}}))
|
||||||
}
|
}
|
||||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChart.xlsx")))
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestAddChart.xlsx")))
|
||||||
// Test with invalid sheet name
|
// Test with invalid sheet name
|
||||||
assert.EqualError(t, f.AddChart("Sheet:1", "A1", &Chart{Type: Col, Series: series[:1]}), ErrSheetNameInvalid.Error())
|
assert.EqualError(t, f.AddChart("Sheet:1", "A1", &Chart{Type: Col, Series: series[:1]}), ErrSheetNameInvalid.Error())
|
||||||
// Test with illegal cell reference
|
// Test with illegal cell reference
|
||||||
assert.EqualError(t, f.AddChart("Sheet2", "A", &Chart{Type: Col, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Column Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
assert.EqualError(t, f.AddChart("Sheet2", "A", &Chart{Type: Col, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")).Error())
|
||||||
// Test with unsupported chart type
|
// Test with unsupported chart type
|
||||||
assert.EqualError(t, f.AddChart("Sheet2", "BD32", &Chart{Type: 0x37, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "Bubble 3D Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}), newUnsupportedChartType(0x37).Error())
|
assert.EqualError(t, f.AddChart("Sheet2", "BD32", &Chart{Type: 0x37, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Bubble 3D Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}), newUnsupportedChartType(0x37).Error())
|
||||||
// Test add combo chart with invalid format set
|
// Test add combo chart with invalid format set
|
||||||
assert.EqualError(t, f.AddChart("Sheet2", "BD32", &Chart{Type: Col, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Column Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}, nil), ErrParameterInvalid.Error())
|
assert.EqualError(t, f.AddChart("Sheet2", "BD32", &Chart{Type: Col, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}, nil), ErrParameterInvalid.Error())
|
||||||
// Test add combo chart with unsupported chart type
|
// Test add combo chart with unsupported chart type
|
||||||
assert.EqualError(t, f.AddChart("Sheet2", "BD64", &Chart{Type: BarOfPie, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$A$30:$D$37", Values: "Sheet1!$B$30:$B$37"}}, Format: format, Legend: legend, Title: ChartTitle{Name: "Bar of Pie Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}, &Chart{Type: 0x37, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$A$30:$D$37", Values: "Sheet1!$B$30:$B$37"}}, Format: format, Legend: legend, Title: ChartTitle{Name: "Bar of Pie Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}), newUnsupportedChartType(0x37).Error())
|
assert.EqualError(t, f.AddChart("Sheet2", "BD64", &Chart{Type: BarOfPie, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$A$30:$D$37", Values: "Sheet1!$B$30:$B$37"}}, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Bar of Pie Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}, &Chart{Type: 0x37, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$A$30:$D$37", Values: "Sheet1!$B$30:$B$37"}}, Format: format, Legend: legend, Title: []RichTextRun{{Text: "Bar of Pie Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero", XAxis: ChartAxis{MajorGridLines: true}, YAxis: ChartAxis{MajorGridLines: true}}), newUnsupportedChartType(0x37).Error())
|
||||||
assert.NoError(t, f.Close())
|
assert.NoError(t, f.Close())
|
||||||
|
|
||||||
// Test add chart with unsupported charset content types.
|
// Test add chart with unsupported charset content types.
|
||||||
f.ContentTypes = nil
|
f.ContentTypes = nil
|
||||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||||
assert.EqualError(t, f.AddChart("Sheet1", "P1", &Chart{Type: Col, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30"}}, Title: ChartTitle{Name: "2D Column Chart"}}), "XML syntax error on line 1: invalid UTF-8")
|
assert.EqualError(t, f.AddChart("Sheet1", "P1", &Chart{Type: Col, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30"}}, Title: []RichTextRun{{Text: "2D Column Chart"}}}), "XML syntax error on line 1: invalid UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddChartSheet(t *testing.T) {
|
func TestAddChartSheet(t *testing.T) {
|
||||||
|
@ -323,7 +323,7 @@ func TestAddChartSheet(t *testing.T) {
|
||||||
{Name: "Sheet1!$A$3", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$3:$D$3"},
|
{Name: "Sheet1!$A$3", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$3:$D$3"},
|
||||||
{Name: "Sheet1!$A$4", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$4:$D$4"},
|
{Name: "Sheet1!$A$4", Categories: "Sheet1!$B$1:$D$1", Values: "Sheet1!$B$4:$D$4"},
|
||||||
}
|
}
|
||||||
assert.NoError(t, f.AddChartSheet("Chart1", &Chart{Type: Col3DClustered, Series: series, Title: ChartTitle{Name: "Fruit 3D Clustered Column Chart"}}))
|
assert.NoError(t, f.AddChartSheet("Chart1", &Chart{Type: Col3DClustered, Series: series, Title: []RichTextRun{{Text: "Fruit 3D Clustered Column Chart"}}}))
|
||||||
// Test set the chartsheet as active sheet
|
// Test set the chartsheet as active sheet
|
||||||
var sheetIdx int
|
var sheetIdx int
|
||||||
for idx, sheetName := range f.GetSheetList() {
|
for idx, sheetName := range f.GetSheetList() {
|
||||||
|
@ -338,11 +338,11 @@ func TestAddChartSheet(t *testing.T) {
|
||||||
assert.EqualError(t, f.SetCellValue("Chart1", "A1", true), "sheet Chart1 is not a worksheet")
|
assert.EqualError(t, f.SetCellValue("Chart1", "A1", true), "sheet Chart1 is not a worksheet")
|
||||||
// Test add chartsheet on already existing name sheet
|
// Test add chartsheet on already existing name sheet
|
||||||
|
|
||||||
assert.EqualError(t, f.AddChartSheet("Sheet1", &Chart{Type: Col3DClustered, Series: series, Title: ChartTitle{Name: "Fruit 3D Clustered Column Chart"}}), ErrExistsSheet.Error())
|
assert.EqualError(t, f.AddChartSheet("Sheet1", &Chart{Type: Col3DClustered, Series: series, Title: []RichTextRun{{Text: "Fruit 3D Clustered Column Chart"}}}), ErrExistsSheet.Error())
|
||||||
// Test add chartsheet with invalid sheet name
|
// Test add chartsheet with invalid sheet name
|
||||||
assert.EqualError(t, f.AddChartSheet("Sheet:1", nil, &Chart{Type: Col3DClustered, Series: series, Title: ChartTitle{Name: "Fruit 3D Clustered Column Chart"}}), ErrSheetNameInvalid.Error())
|
assert.EqualError(t, f.AddChartSheet("Sheet:1", nil, &Chart{Type: Col3DClustered, Series: series, Title: []RichTextRun{{Text: "Fruit 3D Clustered Column Chart"}}}), ErrSheetNameInvalid.Error())
|
||||||
// Test with unsupported chart type
|
// Test with unsupported chart type
|
||||||
assert.EqualError(t, f.AddChartSheet("Chart2", &Chart{Type: 0x37, Series: series, Title: ChartTitle{Name: "Fruit 3D Clustered Column Chart"}}), newUnsupportedChartType(0x37).Error())
|
assert.EqualError(t, f.AddChartSheet("Chart2", &Chart{Type: 0x37, Series: series, Title: []RichTextRun{{Text: "Fruit 3D Clustered Column Chart"}}}), newUnsupportedChartType(0x37).Error())
|
||||||
|
|
||||||
assert.NoError(t, f.UpdateLinkedValue())
|
assert.NoError(t, f.UpdateLinkedValue())
|
||||||
|
|
||||||
|
@ -351,7 +351,7 @@ func TestAddChartSheet(t *testing.T) {
|
||||||
f = NewFile()
|
f = NewFile()
|
||||||
f.ContentTypes = nil
|
f.ContentTypes = nil
|
||||||
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
f.Pkg.Store(defaultXMLPathContentTypes, MacintoshCyrillicCharset)
|
||||||
assert.EqualError(t, f.AddChartSheet("Chart4", &Chart{Type: Col, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30"}}, Title: ChartTitle{Name: "2D Column Chart"}}), "XML syntax error on line 1: invalid UTF-8")
|
assert.EqualError(t, f.AddChartSheet("Chart4", &Chart{Type: Col, Series: []ChartSeries{{Name: "Sheet1!$A$30", Categories: "Sheet1!$B$29:$D$29", Values: "Sheet1!$B$30:$D$30"}}, Title: []RichTextRun{{Text: "2D Column Chart"}}}), "XML syntax error on line 1: invalid UTF-8")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDeleteChart(t *testing.T) {
|
func TestDeleteChart(t *testing.T) {
|
||||||
|
@ -386,7 +386,7 @@ func TestDeleteChart(t *testing.T) {
|
||||||
ShowSerName: true,
|
ShowSerName: true,
|
||||||
ShowVal: true,
|
ShowVal: true,
|
||||||
}
|
}
|
||||||
assert.NoError(t, f.AddChart("Sheet1", "P1", &Chart{Type: Col, Series: series, Format: format, Legend: legend, Title: ChartTitle{Name: "2D Column Chart"}, PlotArea: plotArea, ShowBlanksAs: "zero"}))
|
assert.NoError(t, f.AddChart("Sheet1", "P1", &Chart{Type: Col, Series: series, Format: format, Legend: legend, Title: []RichTextRun{{Text: "2D Column Chart"}}, PlotArea: plotArea, ShowBlanksAs: "zero"}))
|
||||||
assert.NoError(t, f.DeleteChart("Sheet1", "P1"))
|
assert.NoError(t, f.DeleteChart("Sheet1", "P1"))
|
||||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteChart.xlsx")))
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteChart.xlsx")))
|
||||||
// Test delete chart with invalid sheet name
|
// Test delete chart with invalid sheet name
|
||||||
|
@ -435,12 +435,12 @@ func TestChartWithLogarithmicBase(t *testing.T) {
|
||||||
cell string
|
cell string
|
||||||
opts *Chart
|
opts *Chart
|
||||||
}{
|
}{
|
||||||
{cell: "C1", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[0], Height: dimension[1]}, Series: series, Title: ChartTitle{Name: "Line chart without log scaling"}}},
|
{cell: "C1", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[0], Height: dimension[1]}, Series: series, Title: []RichTextRun{{Text: "Line chart without log scaling"}}}},
|
||||||
{cell: "M1", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[0], Height: dimension[1]}, Series: series, Title: ChartTitle{Name: "Line chart with log 10.5 scaling"}, YAxis: ChartAxis{LogBase: 10.5}}},
|
{cell: "M1", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[0], Height: dimension[1]}, Series: series, Title: []RichTextRun{{Text: "Line chart with log 10.5 scaling"}}, YAxis: ChartAxis{LogBase: 10.5}}},
|
||||||
{cell: "A25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: ChartTitle{Name: "Line chart with log 1.9 scaling"}, YAxis: ChartAxis{LogBase: 1.9}}},
|
{cell: "A25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: []RichTextRun{{Text: "Line chart with log 1.9 scaling"}}, YAxis: ChartAxis{LogBase: 1.9}}},
|
||||||
{cell: "F25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: ChartTitle{Name: "Line chart with log 2 scaling"}, YAxis: ChartAxis{LogBase: 2}}},
|
{cell: "F25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: []RichTextRun{{Text: "Line chart with log 2 scaling"}}, YAxis: ChartAxis{LogBase: 2}}},
|
||||||
{cell: "K25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: ChartTitle{Name: "Line chart with log 1000.1 scaling"}, YAxis: ChartAxis{LogBase: 1000.1}}},
|
{cell: "K25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: []RichTextRun{{Text: "Line chart with log 1000.1 scaling"}}, YAxis: ChartAxis{LogBase: 1000.1}}},
|
||||||
{cell: "P25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: ChartTitle{Name: "Line chart with log 1000 scaling"}, YAxis: ChartAxis{LogBase: 1000}}},
|
{cell: "P25", opts: &Chart{Type: Line, Dimension: ChartDimension{Width: dimension[2], Height: dimension[3]}, Series: series, Title: []RichTextRun{{Text: "Line chart with log 1000 scaling"}}, YAxis: ChartAxis{LogBase: 1000}}},
|
||||||
} {
|
} {
|
||||||
// Add two chart, one without and one with log scaling
|
// Add two chart, one without and one with log scaling
|
||||||
assert.NoError(t, f.AddChart(sheet1, c.cell, c.opts))
|
assert.NoError(t, f.AddChart(sheet1, c.cell, c.opts))
|
||||||
|
|
62
drawing.go
62
drawing.go
|
@ -63,67 +63,7 @@ func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
|
||||||
Lang: &attrValString{Val: stringPtr("en-US")},
|
Lang: &attrValString{Val: stringPtr("en-US")},
|
||||||
RoundedCorners: &attrValBool{Val: boolPtr(false)},
|
RoundedCorners: &attrValBool{Val: boolPtr(false)},
|
||||||
Chart: cChart{
|
Chart: cChart{
|
||||||
Title: &cTitle{
|
Title: f.drawPlotAreaTitles(opts.Title, ""),
|
||||||
Tx: cTx{
|
|
||||||
Rich: &cRich{
|
|
||||||
P: []aP{
|
|
||||||
{
|
|
||||||
PPr: &aPPr{
|
|
||||||
DefRPr: aRPr{
|
|
||||||
Kern: 1200,
|
|
||||||
Strike: "noStrike",
|
|
||||||
U: "none",
|
|
||||||
Sz: 1400,
|
|
||||||
SolidFill: &aSolidFill{
|
|
||||||
SchemeClr: &aSchemeClr{
|
|
||||||
Val: "tx1",
|
|
||||||
LumMod: &attrValInt{
|
|
||||||
Val: intPtr(65000),
|
|
||||||
},
|
|
||||||
LumOff: &attrValInt{
|
|
||||||
Val: intPtr(35000),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Ea: &aEa{
|
|
||||||
Typeface: "+mn-ea",
|
|
||||||
},
|
|
||||||
Cs: &aCs{
|
|
||||||
Typeface: "+mn-cs",
|
|
||||||
},
|
|
||||||
Latin: &xlsxCTTextFont{
|
|
||||||
Typeface: "+mn-lt",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
R: &aR{
|
|
||||||
RPr: aRPr{
|
|
||||||
Lang: "en-US",
|
|
||||||
AltLang: "en-US",
|
|
||||||
},
|
|
||||||
T: opts.Title.Name,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TxPr: cTxPr{
|
|
||||||
P: aP{
|
|
||||||
PPr: &aPPr{
|
|
||||||
DefRPr: aRPr{
|
|
||||||
Kern: 1200,
|
|
||||||
U: "none",
|
|
||||||
Sz: 14000,
|
|
||||||
Strike: "noStrike",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
EndParaRPr: &aEndParaRPr{
|
|
||||||
Lang: "en-US",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Overlay: &attrValBool{Val: boolPtr(false)},
|
|
||||||
},
|
|
||||||
View3D: &cView3D{
|
View3D: &cView3D{
|
||||||
RotX: &attrValInt{Val: intPtr(chartView3DRotX[opts.Type])},
|
RotX: &attrValInt{Val: intPtr(chartView3DRotX[opts.Type])},
|
||||||
RotY: &attrValInt{Val: intPtr(chartView3DRotY[opts.Type])},
|
RotY: &attrValInt{Val: intPtr(chartView3DRotY[opts.Type])},
|
||||||
|
|
2
lib.go
2
lib.go
|
@ -53,7 +53,7 @@ func (f *File) ReadZipReader(r *zip.Reader) (map[string][]byte, int, error) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(fileName, "xl/worksheets/sheet") {
|
if strings.HasPrefix(strings.ToLower(fileName), "xl/worksheets/sheet") {
|
||||||
worksheets++
|
worksheets++
|
||||||
if fileSize > f.options.UnzipXMLSizeLimit && !v.FileInfo().IsDir() {
|
if fileSize > f.options.UnzipXMLSizeLimit && !v.FileInfo().IsDir() {
|
||||||
if tempFile, err := f.unzipToTemp(v); err == nil {
|
if tempFile, err := f.unzipToTemp(v); err == nil {
|
||||||
|
|
|
@ -216,7 +216,7 @@ func (f *File) AddPictureFromBytes(sheet, cell string, pic *Picture) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Read sheet data.
|
// Read sheet data
|
||||||
f.mu.Lock()
|
f.mu.Lock()
|
||||||
ws, err := f.workSheetReader(sheet)
|
ws, err := f.workSheetReader(sheet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
2
shape.go
2
shape.go
|
@ -293,7 +293,7 @@ func (f *File) AddShape(sheet string, opts *Shape) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
// Read sheet data.
|
// Read sheet data
|
||||||
ws, err := f.workSheetReader(sheet)
|
ws, err := f.workSheetReader(sheet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
90
vml.go
90
vml.go
|
@ -390,7 +390,7 @@ func (f *File) DeleteFormControl(sheet, cell string) error {
|
||||||
VPath: &vPath{GradientShapeOK: "t", ConnectType: "rect"},
|
VPath: &vPath{GradientShapeOK: "t", ConnectType: "rect"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// load exist VML shapes from xl/drawings/vmlDrawing%d.vml
|
// Load exist VML shapes from xl/drawings/vmlDrawing%d.vml
|
||||||
d, err := f.decodeVMLDrawingReader(drawingVML)
|
d, err := f.decodeVMLDrawingReader(drawingVML)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -477,7 +477,7 @@ func (f *File) vmlDrawingWriter() {
|
||||||
// addVMLObject provides a function to create VML drawing parts and
|
// addVMLObject provides a function to create VML drawing parts and
|
||||||
// relationships for comments and form controls.
|
// relationships for comments and form controls.
|
||||||
func (f *File) addVMLObject(opts vmlOptions) error {
|
func (f *File) addVMLObject(opts vmlOptions) error {
|
||||||
// Read sheet data.
|
// Read sheet data
|
||||||
ws, err := f.workSheetReader(opts.sheet)
|
ws, err := f.workSheetReader(opts.sheet)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -836,7 +836,7 @@ func (f *File) addDrawingVML(dataID int, drawingVML string, opts *vmlOptions) er
|
||||||
VPath: &vPath{GradientShapeOK: "t", ConnectType: "rect"},
|
VPath: &vPath{GradientShapeOK: "t", ConnectType: "rect"},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
// load exist VML shapes from xl/drawings/vmlDrawing%d.vml
|
// Load exist VML shapes from xl/drawings/vmlDrawing%d.vml
|
||||||
d, err := f.decodeVMLDrawingReader(drawingVML)
|
d, err := f.decodeVMLDrawingReader(drawingVML)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -883,3 +883,87 @@ func (f *File) addDrawingVML(dataID int, drawingVML string, opts *vmlOptions) er
|
||||||
f.VMLDrawing[drawingVML] = vml
|
f.VMLDrawing[drawingVML] = vml
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetFormControls retrieves all form controls in a worksheet by a given
|
||||||
|
// worksheet name. Note that, this function does not support getting the width,
|
||||||
|
// height, text, rich text, and format currently.
|
||||||
|
func (f *File) GetFormControls(sheet string) ([]FormControl, error) {
|
||||||
|
var formControls []FormControl
|
||||||
|
// Read sheet data
|
||||||
|
ws, err := f.workSheetReader(sheet)
|
||||||
|
if err != nil {
|
||||||
|
return formControls, err
|
||||||
|
}
|
||||||
|
if ws.LegacyDrawing == nil {
|
||||||
|
return formControls, err
|
||||||
|
}
|
||||||
|
target := f.getSheetRelationshipsTargetByID(sheet, ws.LegacyDrawing.RID)
|
||||||
|
drawingVML := strings.ReplaceAll(target, "..", "xl")
|
||||||
|
vml := f.VMLDrawing[drawingVML]
|
||||||
|
if vml == nil {
|
||||||
|
// Load exist VML shapes from xl/drawings/vmlDrawing%d.vml
|
||||||
|
d, err := f.decodeVMLDrawingReader(drawingVML)
|
||||||
|
if err != nil {
|
||||||
|
return formControls, err
|
||||||
|
}
|
||||||
|
for _, sp := range d.Shape {
|
||||||
|
if sp.Type != "#_x0000_t201" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
formControl, err := extractFormControl(sp.Val)
|
||||||
|
if err != nil {
|
||||||
|
return formControls, err
|
||||||
|
}
|
||||||
|
if formControl.Type == FormControlNote || formControl.Cell == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
formControls = append(formControls, formControl)
|
||||||
|
}
|
||||||
|
return formControls, err
|
||||||
|
}
|
||||||
|
for _, sp := range vml.Shape {
|
||||||
|
if sp.Type != "#_x0000_t201" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
formControl, err := extractFormControl(sp.Val)
|
||||||
|
if err != nil {
|
||||||
|
return formControls, err
|
||||||
|
}
|
||||||
|
if formControl.Type == FormControlNote || formControl.Cell == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
formControls = append(formControls, formControl)
|
||||||
|
}
|
||||||
|
return formControls, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// extractFormControl provides a function to extract form controls for a
|
||||||
|
// worksheets by given client data.
|
||||||
|
func extractFormControl(clientData string) (FormControl, error) {
|
||||||
|
var (
|
||||||
|
err error
|
||||||
|
formControl FormControl
|
||||||
|
shapeVal decodeShapeVal
|
||||||
|
)
|
||||||
|
if err = xml.Unmarshal([]byte(fmt.Sprintf("<shape>%s</shape>", clientData)), &shapeVal); err != nil {
|
||||||
|
return formControl, err
|
||||||
|
}
|
||||||
|
for formCtrlType, preset := range formCtrlPresets {
|
||||||
|
if shapeVal.ClientData.ObjectType == preset.objectType {
|
||||||
|
formControl.Type = formCtrlType
|
||||||
|
if formControl.Cell, err = CoordinatesToCellName(shapeVal.ClientData.Column+1, shapeVal.ClientData.Row+1); err != nil {
|
||||||
|
return formControl, err
|
||||||
|
}
|
||||||
|
formControl.Macro = shapeVal.ClientData.FmlaMacro
|
||||||
|
formControl.Checked = shapeVal.ClientData.Checked != 0
|
||||||
|
formControl.CellLink = shapeVal.ClientData.FmlaLink
|
||||||
|
formControl.CurrentVal = shapeVal.ClientData.Val
|
||||||
|
formControl.MinVal = shapeVal.ClientData.Min
|
||||||
|
formControl.MaxVal = shapeVal.ClientData.Max
|
||||||
|
formControl.IncChange = shapeVal.ClientData.Inc
|
||||||
|
formControl.PageChange = shapeVal.ClientData.Page
|
||||||
|
formControl.Horizontally = shapeVal.ClientData.Horiz != nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return formControl, err
|
||||||
|
}
|
||||||
|
|
|
@ -192,8 +192,17 @@ type decodeShapeVal struct {
|
||||||
// element in the file xl/drawings/vmlDrawing%d.vml.
|
// element in the file xl/drawings/vmlDrawing%d.vml.
|
||||||
type decodeVMLClientData struct {
|
type decodeVMLClientData struct {
|
||||||
ObjectType string `xml:"ObjectType,attr"`
|
ObjectType string `xml:"ObjectType,attr"`
|
||||||
|
FmlaMacro string
|
||||||
Column int
|
Column int
|
||||||
Row int
|
Row int
|
||||||
|
Checked int
|
||||||
|
FmlaLink string
|
||||||
|
Val uint
|
||||||
|
Min uint
|
||||||
|
Max uint
|
||||||
|
Inc uint
|
||||||
|
Page uint
|
||||||
|
Horiz *string
|
||||||
}
|
}
|
||||||
|
|
||||||
// encodeShape defines the structure used to re-serialization shape element.
|
// encodeShape defines the structure used to re-serialization shape element.
|
||||||
|
|
202
vml_test.go
202
vml_test.go
|
@ -13,6 +13,7 @@ package excelize
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -157,62 +158,83 @@ func TestAddDrawingVML(t *testing.T) {
|
||||||
|
|
||||||
func TestFormControl(t *testing.T) {
|
func TestFormControl(t *testing.T) {
|
||||||
f := NewFile()
|
f := NewFile()
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
formControls := []FormControl{
|
||||||
Cell: "D1", Type: FormControlButton, Macro: "Button1_Click",
|
{
|
||||||
}))
|
Cell: "D1", Type: FormControlButton, Macro: "Button1_Click",
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
},
|
||||||
Cell: "A1", Type: FormControlButton, Macro: "Button1_Click",
|
{
|
||||||
Width: 140, Height: 60, Text: "Button 1\r\n",
|
Cell: "A1", Type: FormControlButton, Macro: "Button1_Click",
|
||||||
Paragraph: []RichTextRun{
|
Width: 140, Height: 60, Text: "Button 1\r\n",
|
||||||
{
|
Paragraph: []RichTextRun{
|
||||||
Font: &Font{
|
{
|
||||||
Bold: true,
|
Font: &Font{
|
||||||
Italic: true,
|
Bold: true,
|
||||||
Underline: "single",
|
Italic: true,
|
||||||
Family: "Times New Roman",
|
Underline: "single",
|
||||||
Size: 14,
|
Family: "Times New Roman",
|
||||||
Color: "777777",
|
Size: 14,
|
||||||
|
Color: "777777",
|
||||||
|
},
|
||||||
|
Text: "C1=A1+B1",
|
||||||
},
|
},
|
||||||
Text: "C1=A1+B1",
|
},
|
||||||
|
Format: GraphicOptions{PrintObject: boolPtr(true), Positioning: "absolute"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Cell: "A5", Type: FormControlCheckBox, Text: "Check Box 1",
|
||||||
|
Checked: true, Format: GraphicOptions{
|
||||||
|
PrintObject: boolPtr(false), Positioning: "oneCell",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Format: GraphicOptions{PrintObject: boolPtr(true), Positioning: "absolute"},
|
{
|
||||||
}))
|
Cell: "A6", Type: FormControlCheckBox, Text: "Check Box 2",
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
Format: GraphicOptions{Positioning: "twoCell"},
|
||||||
Cell: "A5", Type: FormControlCheckBox, Text: "Check Box 1",
|
|
||||||
Checked: true, Format: GraphicOptions{
|
|
||||||
PrintObject: boolPtr(false), Positioning: "oneCell",
|
|
||||||
},
|
},
|
||||||
}))
|
{
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
Cell: "A7", Type: FormControlOptionButton, Text: "Option Button 1", Checked: true,
|
||||||
Cell: "A6", Type: FormControlCheckBox, Text: "Check Box 2",
|
},
|
||||||
Format: GraphicOptions{Positioning: "twoCell"},
|
{
|
||||||
}))
|
Cell: "A8", Type: FormControlOptionButton, Text: "Option Button 2",
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
},
|
||||||
Cell: "A7", Type: FormControlOptionButton, Text: "Option Button 1", Checked: true,
|
{
|
||||||
}))
|
Cell: "D3", Type: FormControlGroupBox, Text: "Group Box 1",
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
Width: 140, Height: 60,
|
||||||
Cell: "A8", Type: FormControlOptionButton, Text: "Option Button 2",
|
},
|
||||||
}))
|
{
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
Cell: "A9", Type: FormControlLabel, Text: "Label 1", Width: 140,
|
||||||
Cell: "D3", Type: FormControlGroupBox, Text: "Group Box 1",
|
},
|
||||||
Width: 140, Height: 60,
|
{
|
||||||
}))
|
Cell: "C5", Type: FormControlSpinButton, Width: 40, Height: 60,
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
CurrentVal: 7, MinVal: 5, MaxVal: 10, IncChange: 1, CellLink: "C2",
|
||||||
Cell: "A9", Type: FormControlLabel, Text: "Label 1", Width: 140,
|
},
|
||||||
}))
|
{
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
Cell: "D7", Type: FormControlScrollBar, Width: 140, Height: 20,
|
||||||
Cell: "C5", Type: FormControlSpinButton, Width: 40, Height: 60,
|
CurrentVal: 50, MinVal: 10, MaxVal: 100, IncChange: 1, PageChange: 1, Horizontally: true, CellLink: "C3",
|
||||||
CurrentVal: 7, MinVal: 5, MaxVal: 10, IncChange: 1, CellLink: "C2",
|
},
|
||||||
}))
|
{
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
Cell: "G1", Type: FormControlScrollBar, Width: 20, Height: 140,
|
||||||
Cell: "D7", Type: FormControlScrollBar, Width: 140, Height: 20,
|
CurrentVal: 50, MinVal: 1000, MaxVal: 100, IncChange: 1, PageChange: 1, CellLink: "C4",
|
||||||
CurrentVal: 50, MinVal: 10, MaxVal: 100, IncChange: 1, PageChange: 1, Horizontally: true, CellLink: "C3",
|
},
|
||||||
}))
|
}
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
for _, formCtrl := range formControls {
|
||||||
Cell: "G1", Type: FormControlScrollBar, Width: 20, Height: 140,
|
assert.NoError(t, f.AddFormControl("Sheet1", formCtrl))
|
||||||
CurrentVal: 50, MinVal: 1000, MaxVal: 100, IncChange: 1, PageChange: 1, CellLink: "C4",
|
}
|
||||||
}))
|
// Test get from controls
|
||||||
|
result, err := f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, result, 11)
|
||||||
|
for i, formCtrl := range formControls {
|
||||||
|
assert.Equal(t, formCtrl.Type, result[i].Type)
|
||||||
|
assert.Equal(t, formCtrl.Cell, result[i].Cell)
|
||||||
|
assert.Equal(t, formCtrl.Macro, result[i].Macro)
|
||||||
|
assert.Equal(t, formCtrl.Checked, result[i].Checked)
|
||||||
|
assert.Equal(t, formCtrl.CurrentVal, result[i].CurrentVal)
|
||||||
|
assert.Equal(t, formCtrl.MinVal, result[i].MinVal)
|
||||||
|
assert.Equal(t, formCtrl.MaxVal, result[i].MaxVal)
|
||||||
|
assert.Equal(t, formCtrl.IncChange, result[i].IncChange)
|
||||||
|
assert.Equal(t, formCtrl.Horizontally, result[i].Horizontally)
|
||||||
|
assert.Equal(t, formCtrl.CellLink, result[i].CellLink)
|
||||||
|
}
|
||||||
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{CodeName: stringPtr("Sheet1")}))
|
assert.NoError(t, f.SetSheetProps("Sheet1", &SheetPropsOptions{CodeName: stringPtr("Sheet1")}))
|
||||||
file, err := os.ReadFile(filepath.Join("test", "vbaProject.bin"))
|
file, err := os.ReadFile(filepath.Join("test", "vbaProject.bin"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
@ -221,9 +243,18 @@ func TestFormControl(t *testing.T) {
|
||||||
assert.NoError(t, f.Close())
|
assert.NoError(t, f.Close())
|
||||||
f, err = OpenFile(filepath.Join("test", "TestAddFormControl.xlsm"))
|
f, err = OpenFile(filepath.Join("test", "TestAddFormControl.xlsm"))
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
// Test get from controls before add form controls
|
||||||
|
result, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, result, 11)
|
||||||
|
// Test add from control to a worksheet which already contains form controls
|
||||||
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
assert.NoError(t, f.AddFormControl("Sheet1", FormControl{
|
||||||
Cell: "D4", Type: FormControlButton, Macro: "Button1_Click", Text: "Button 2",
|
Cell: "D4", Type: FormControlButton, Macro: "Button1_Click", Text: "Button 2",
|
||||||
}))
|
}))
|
||||||
|
// Test get from controls after add form controls
|
||||||
|
result, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, result, 12)
|
||||||
// Test add unsupported form control
|
// Test add unsupported form control
|
||||||
assert.Equal(t, f.AddFormControl("Sheet1", FormControl{
|
assert.Equal(t, f.AddFormControl("Sheet1", FormControl{
|
||||||
Cell: "A1", Type: 0x37, Macro: "Button1_Click",
|
Cell: "A1", Type: 0x37, Macro: "Button1_Click",
|
||||||
|
@ -251,9 +282,13 @@ func TestFormControl(t *testing.T) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NoError(t, f.DeleteFormControl("Sheet1", "D1"))
|
assert.NoError(t, f.DeleteFormControl("Sheet1", "D1"))
|
||||||
assert.NoError(t, f.DeleteFormControl("Sheet1", "A1"))
|
assert.NoError(t, f.DeleteFormControl("Sheet1", "A1"))
|
||||||
|
// Test get from controls after delete form controls
|
||||||
|
result, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, result, 9)
|
||||||
// Test delete form control on not exists worksheet
|
// Test delete form control on not exists worksheet
|
||||||
assert.Equal(t, f.DeleteFormControl("SheetN", "A1"), newNoExistSheetError("SheetN"))
|
assert.Equal(t, f.DeleteFormControl("SheetN", "A1"), newNoExistSheetError("SheetN"))
|
||||||
// Test delete form control on not exists worksheet
|
// Test delete form control with illegal cell link reference
|
||||||
assert.Equal(t, f.DeleteFormControl("Sheet1", "A"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")))
|
assert.Equal(t, f.DeleteFormControl("Sheet1", "A"), newCellNameToCoordinatesError("A", newInvalidCellNameError("A")))
|
||||||
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteFormControl.xlsm")))
|
assert.NoError(t, f.SaveAs(filepath.Join("test", "TestDeleteFormControl.xlsm")))
|
||||||
assert.NoError(t, f.Close())
|
assert.NoError(t, f.Close())
|
||||||
|
@ -266,4 +301,65 @@ func TestFormControl(t *testing.T) {
|
||||||
// Test delete form control on a worksheet without form control
|
// Test delete form control on a worksheet without form control
|
||||||
f = NewFile()
|
f = NewFile()
|
||||||
assert.NoError(t, f.DeleteFormControl("Sheet1", "A1"))
|
assert.NoError(t, f.DeleteFormControl("Sheet1", "A1"))
|
||||||
|
// Test get form controls on a worksheet without form control
|
||||||
|
_, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
// Test get form controls on not exists worksheet
|
||||||
|
_, err = f.GetFormControls("SheetN")
|
||||||
|
assert.Equal(t, err, newNoExistSheetError("SheetN"))
|
||||||
|
// Test get form controls with unsupported charset VML drawing
|
||||||
|
f, err = OpenFile(filepath.Join("test", "TestAddFormControl.xlsm"))
|
||||||
|
assert.NoError(t, err)
|
||||||
|
f.Pkg.Store("xl/drawings/vmlDrawing1.vml", MacintoshCyrillicCharset)
|
||||||
|
_, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
|
// Test get form controls with unsupported shape type
|
||||||
|
f.DecodeVMLDrawing["xl/drawings/vmlDrawing1.vml"] = &decodeVmlDrawing{
|
||||||
|
Shape: []decodeShape{{Type: "_x0000_t202"}},
|
||||||
|
}
|
||||||
|
formControls, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, formControls, 0)
|
||||||
|
// Test get form controls with invalid column number
|
||||||
|
f.DecodeVMLDrawing["xl/drawings/vmlDrawing1.vml"] = &decodeVmlDrawing{
|
||||||
|
Shape: []decodeShape{{Type: "#_x0000_t201", Val: fmt.Sprintf("<x:ClientData ObjectType=\"Scroll\"><x:Column>%d</x:Column></x:ClientData>", MaxColumns)}},
|
||||||
|
}
|
||||||
|
formControls, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.Equal(t, err, ErrColumnNumber)
|
||||||
|
assert.Len(t, formControls, 0)
|
||||||
|
// Test get form controls with comment (Note) shape type
|
||||||
|
f.DecodeVMLDrawing["xl/drawings/vmlDrawing1.vml"] = &decodeVmlDrawing{
|
||||||
|
Shape: []decodeShape{{Type: "#_x0000_t201", Val: "<x:ClientData ObjectType=\"Note\"></x:ClientData>"}},
|
||||||
|
}
|
||||||
|
formControls, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, formControls, 0)
|
||||||
|
// Test get form controls with unsupported shape type
|
||||||
|
f.VMLDrawing["xl/drawings/vmlDrawing1.vml"] = &vmlDrawing{
|
||||||
|
Shape: []xlsxShape{{Type: "_x0000_t202"}},
|
||||||
|
}
|
||||||
|
formControls, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, formControls, 0)
|
||||||
|
// Test get form controls with invalid column number
|
||||||
|
f.VMLDrawing["xl/drawings/vmlDrawing1.vml"] = &vmlDrawing{
|
||||||
|
Shape: []xlsxShape{{Type: "#_x0000_t201", Val: fmt.Sprintf("<x:ClientData ObjectType=\"Scroll\"><x:Column>%d</x:Column></x:ClientData>", MaxColumns)}},
|
||||||
|
}
|
||||||
|
formControls, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.Equal(t, err, ErrColumnNumber)
|
||||||
|
assert.Len(t, formControls, 0)
|
||||||
|
// Test get form controls with comment (Note) shape type
|
||||||
|
f.VMLDrawing["xl/drawings/vmlDrawing1.vml"] = &vmlDrawing{
|
||||||
|
Shape: []xlsxShape{{Type: "#_x0000_t201", Val: "<x:ClientData ObjectType=\"Note\"></x:ClientData>"}},
|
||||||
|
}
|
||||||
|
formControls, err = f.GetFormControls("Sheet1")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.Len(t, formControls, 0)
|
||||||
|
assert.NoError(t, f.Close())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestExtractFormControl(t *testing.T) {
|
||||||
|
// Test extract form control with unsupported charset
|
||||||
|
_, err := extractFormControl(string(MacintoshCyrillicCharset))
|
||||||
|
assert.EqualError(t, err, "XML syntax error on line 1: invalid UTF-8")
|
||||||
}
|
}
|
||||||
|
|
|
@ -570,7 +570,7 @@ type Chart struct {
|
||||||
Format GraphicOptions
|
Format GraphicOptions
|
||||||
Dimension ChartDimension
|
Dimension ChartDimension
|
||||||
Legend ChartLegend
|
Legend ChartLegend
|
||||||
Title ChartTitle
|
Title []RichTextRun
|
||||||
VaryColors *bool
|
VaryColors *bool
|
||||||
XAxis ChartAxis
|
XAxis ChartAxis
|
||||||
YAxis ChartAxis
|
YAxis ChartAxis
|
||||||
|
@ -608,8 +608,3 @@ type ChartSeries struct {
|
||||||
Line ChartLine
|
Line ChartLine
|
||||||
Marker ChartMarker
|
Marker ChartMarker
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChartTitle directly maps the format settings of the chart title.
|
|
||||||
type ChartTitle struct {
|
|
||||||
Name string
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in New Issue