|
|
@@ -12,11 +12,9 @@ package excelize
|
|
|
import (
|
|
|
"bytes"
|
|
|
"encoding/json"
|
|
|
- "encoding/xml"
|
|
|
"errors"
|
|
|
+ "fmt"
|
|
|
"io"
|
|
|
- "log"
|
|
|
- "reflect"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
)
|
|
|
@@ -765,1205 +763,75 @@ func (f *File) AddChart(sheet, cell, format string, combo ...string) error {
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
-// countCharts provides a function to get chart files count storage in the
|
|
|
-// folder xl/charts.
|
|
|
-func (f *File) countCharts() int {
|
|
|
- count := 0
|
|
|
- for k := range f.XLSX {
|
|
|
- if strings.Contains(k, "xl/charts/chart") {
|
|
|
- count++
|
|
|
- }
|
|
|
- }
|
|
|
- return count
|
|
|
-}
|
|
|
-
|
|
|
-// prepareDrawing provides a function to prepare drawing ID and XML by given
|
|
|
-// drawingID, worksheet name and default drawingXML.
|
|
|
-func (f *File) prepareDrawing(xlsx *xlsxWorksheet, drawingID int, sheet, drawingXML string) (int, string) {
|
|
|
- sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
|
|
|
- if xlsx.Drawing != nil {
|
|
|
- // The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
|
|
|
- sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, xlsx.Drawing.RID)
|
|
|
- drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
|
|
|
- drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
|
|
|
- } else {
|
|
|
- // Add first picture for given sheet.
|
|
|
- sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/worksheets/") + ".rels"
|
|
|
- rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
|
|
|
- f.addSheetDrawing(sheet, rID)
|
|
|
+// DeleteChart provides a function to delete chart in XLSX by given worksheet
|
|
|
+// and cell name.
|
|
|
+func (f *File) DeleteChart(sheet, cell string) (err error) {
|
|
|
+ var wsDr *xlsxWsDr
|
|
|
+ col, row, err := CellNameToCoordinates(cell)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
}
|
|
|
- return drawingID, drawingXML
|
|
|
-}
|
|
|
-
|
|
|
-// addChart provides a function to create chart as xl/charts/chart%d.xml by
|
|
|
-// given format sets.
|
|
|
-func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
|
|
|
- count := f.countCharts()
|
|
|
- xlsxChartSpace := xlsxChartSpace{
|
|
|
- XMLNSc: NameSpaceDrawingMLChart,
|
|
|
- XMLNSa: NameSpaceDrawingML,
|
|
|
- XMLNSr: SourceRelationship,
|
|
|
- XMLNSc16r2: SourceRelationshipChart201506,
|
|
|
- Date1904: &attrValBool{Val: boolPtr(false)},
|
|
|
- Lang: &attrValString{Val: stringPtr("en-US")},
|
|
|
- RoundedCorners: &attrValBool{Val: boolPtr(false)},
|
|
|
- Chart: cChart{
|
|
|
- Title: &cTitle{
|
|
|
- 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: &aLatin{
|
|
|
- Typeface: "+mn-lt",
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- R: &aR{
|
|
|
- RPr: aRPr{
|
|
|
- Lang: "en-US",
|
|
|
- AltLang: "en-US",
|
|
|
- },
|
|
|
- T: formatSet.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{
|
|
|
- RotX: &attrValInt{Val: intPtr(chartView3DRotX[formatSet.Type])},
|
|
|
- RotY: &attrValInt{Val: intPtr(chartView3DRotY[formatSet.Type])},
|
|
|
- Perspective: &attrValInt{Val: intPtr(chartView3DPerspective[formatSet.Type])},
|
|
|
- RAngAx: &attrValInt{Val: intPtr(chartView3DRAngAx[formatSet.Type])},
|
|
|
- },
|
|
|
- Floor: &cThicknessSpPr{
|
|
|
- Thickness: &attrValInt{Val: intPtr(0)},
|
|
|
- },
|
|
|
- SideWall: &cThicknessSpPr{
|
|
|
- Thickness: &attrValInt{Val: intPtr(0)},
|
|
|
- },
|
|
|
- BackWall: &cThicknessSpPr{
|
|
|
- Thickness: &attrValInt{Val: intPtr(0)},
|
|
|
- },
|
|
|
- PlotArea: &cPlotArea{},
|
|
|
- Legend: &cLegend{
|
|
|
- LegendPos: &attrValString{Val: stringPtr(chartLegendPosition[formatSet.Legend.Position])},
|
|
|
- Overlay: &attrValBool{Val: boolPtr(false)},
|
|
|
- },
|
|
|
-
|
|
|
- PlotVisOnly: &attrValBool{Val: boolPtr(false)},
|
|
|
- DispBlanksAs: &attrValString{Val: stringPtr(formatSet.ShowBlanksAs)},
|
|
|
- ShowDLblsOverMax: &attrValBool{Val: boolPtr(false)},
|
|
|
- },
|
|
|
- SpPr: &cSpPr{
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{Val: "bg1"},
|
|
|
- },
|
|
|
- Ln: &aLn{
|
|
|
- W: 9525,
|
|
|
- Cap: "flat",
|
|
|
- Cmpd: "sng",
|
|
|
- Algn: "ctr",
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{Val: "tx1",
|
|
|
- LumMod: &attrValInt{
|
|
|
- Val: intPtr(15000),
|
|
|
- },
|
|
|
- LumOff: &attrValInt{
|
|
|
- Val: intPtr(85000),
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- PrintSettings: &cPrintSettings{
|
|
|
- PageMargins: &cPageMargins{
|
|
|
- B: 0.75,
|
|
|
- L: 0.7,
|
|
|
- R: 0.7,
|
|
|
- T: 0.7,
|
|
|
- Header: 0.3,
|
|
|
- Footer: 0.3,
|
|
|
- },
|
|
|
- },
|
|
|
+ col--
|
|
|
+ row--
|
|
|
+ ws, err := f.workSheetReader(sheet)
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
}
|
|
|
- plotAreaFunc := map[string]func(*formatChart) *cPlotArea{
|
|
|
- Area: f.drawBaseChart,
|
|
|
- AreaStacked: f.drawBaseChart,
|
|
|
- AreaPercentStacked: f.drawBaseChart,
|
|
|
- Area3D: f.drawBaseChart,
|
|
|
- Area3DStacked: f.drawBaseChart,
|
|
|
- Area3DPercentStacked: f.drawBaseChart,
|
|
|
- Bar: f.drawBaseChart,
|
|
|
- BarStacked: f.drawBaseChart,
|
|
|
- BarPercentStacked: f.drawBaseChart,
|
|
|
- Bar3DClustered: f.drawBaseChart,
|
|
|
- Bar3DStacked: f.drawBaseChart,
|
|
|
- Bar3DPercentStacked: f.drawBaseChart,
|
|
|
- Bar3DConeClustered: f.drawBaseChart,
|
|
|
- Bar3DConeStacked: f.drawBaseChart,
|
|
|
- Bar3DConePercentStacked: f.drawBaseChart,
|
|
|
- Bar3DPyramidClustered: f.drawBaseChart,
|
|
|
- Bar3DPyramidStacked: f.drawBaseChart,
|
|
|
- Bar3DPyramidPercentStacked: f.drawBaseChart,
|
|
|
- Bar3DCylinderClustered: f.drawBaseChart,
|
|
|
- Bar3DCylinderStacked: f.drawBaseChart,
|
|
|
- Bar3DCylinderPercentStacked: f.drawBaseChart,
|
|
|
- Col: f.drawBaseChart,
|
|
|
- ColStacked: f.drawBaseChart,
|
|
|
- ColPercentStacked: f.drawBaseChart,
|
|
|
- Col3D: f.drawBaseChart,
|
|
|
- Col3DClustered: f.drawBaseChart,
|
|
|
- Col3DStacked: f.drawBaseChart,
|
|
|
- Col3DPercentStacked: f.drawBaseChart,
|
|
|
- Col3DCone: f.drawBaseChart,
|
|
|
- Col3DConeClustered: f.drawBaseChart,
|
|
|
- Col3DConeStacked: f.drawBaseChart,
|
|
|
- Col3DConePercentStacked: f.drawBaseChart,
|
|
|
- Col3DPyramid: f.drawBaseChart,
|
|
|
- Col3DPyramidClustered: f.drawBaseChart,
|
|
|
- Col3DPyramidStacked: f.drawBaseChart,
|
|
|
- Col3DPyramidPercentStacked: f.drawBaseChart,
|
|
|
- Col3DCylinder: f.drawBaseChart,
|
|
|
- Col3DCylinderClustered: f.drawBaseChart,
|
|
|
- Col3DCylinderStacked: f.drawBaseChart,
|
|
|
- Col3DCylinderPercentStacked: f.drawBaseChart,
|
|
|
- Doughnut: f.drawDoughnutChart,
|
|
|
- Line: f.drawLineChart,
|
|
|
- Pie3D: f.drawPie3DChart,
|
|
|
- Pie: f.drawPieChart,
|
|
|
- PieOfPieChart: f.drawPieOfPieChart,
|
|
|
- BarOfPieChart: f.drawBarOfPieChart,
|
|
|
- Radar: f.drawRadarChart,
|
|
|
- Scatter: f.drawScatterChart,
|
|
|
- Surface3D: f.drawSurface3DChart,
|
|
|
- WireframeSurface3D: f.drawSurface3DChart,
|
|
|
- Contour: f.drawSurfaceChart,
|
|
|
- WireframeContour: f.drawSurfaceChart,
|
|
|
- Bubble: f.drawBaseChart,
|
|
|
- Bubble3D: f.drawBaseChart,
|
|
|
+ if ws.Drawing == nil {
|
|
|
+ return
|
|
|
}
|
|
|
- addChart := func(c, p *cPlotArea) {
|
|
|
- immutable, mutable := reflect.ValueOf(c).Elem(), reflect.ValueOf(p).Elem()
|
|
|
- for i := 0; i < mutable.NumField(); i++ {
|
|
|
- field := mutable.Field(i)
|
|
|
- if field.IsNil() {
|
|
|
- continue
|
|
|
+ drawingXML := strings.Replace(f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID), "..", "xl", -1)
|
|
|
+ wsDr, _ = f.drawingParser(drawingXML)
|
|
|
+ for idx, anchor := range wsDr.TwoCellAnchor {
|
|
|
+ if err = nil; anchor.From != nil && anchor.Pic == nil {
|
|
|
+ if anchor.From.Col == col && anchor.From.Row == row {
|
|
|
+ wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
|
|
|
}
|
|
|
- immutable.FieldByName(mutable.Type().Field(i).Name).Set(field)
|
|
|
- }
|
|
|
- }
|
|
|
- addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[formatSet.Type](formatSet))
|
|
|
- order := len(formatSet.Series)
|
|
|
- for idx := range comboCharts {
|
|
|
- comboCharts[idx].order = order
|
|
|
- addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[comboCharts[idx].Type](comboCharts[idx]))
|
|
|
- order += len(comboCharts[idx].Series)
|
|
|
- }
|
|
|
- chart, _ := xml.Marshal(xlsxChartSpace)
|
|
|
- media := "xl/charts/chart" + strconv.Itoa(count+1) + ".xml"
|
|
|
- f.saveFileList(media, 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(formatSet *formatChart) *cPlotArea {
|
|
|
- c := cCharts{
|
|
|
- BarDir: &attrValString{
|
|
|
- Val: stringPtr("col"),
|
|
|
- },
|
|
|
- Grouping: &attrValString{
|
|
|
- Val: stringPtr("clustered"),
|
|
|
- },
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(true),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- Shape: f.drawChartShape(formatSet),
|
|
|
- DLbls: f.drawChartDLbls(formatSet),
|
|
|
- AxID: []*attrValInt{
|
|
|
- {Val: intPtr(754001152)},
|
|
|
- {Val: intPtr(753999904)},
|
|
|
- },
|
|
|
- Overlap: &attrValInt{Val: intPtr(100)},
|
|
|
- }
|
|
|
- var ok bool
|
|
|
- if *c.BarDir.Val, ok = plotAreaChartBarDir[formatSet.Type]; !ok {
|
|
|
- c.BarDir = nil
|
|
|
- }
|
|
|
- if *c.Grouping.Val, ok = plotAreaChartGrouping[formatSet.Type]; !ok {
|
|
|
- c.Grouping = nil
|
|
|
- }
|
|
|
- if *c.Overlap.Val, ok = plotAreaChartOverlap[formatSet.Type]; !ok {
|
|
|
- c.Overlap = nil
|
|
|
- }
|
|
|
- catAx := f.drawPlotAreaCatAx(formatSet)
|
|
|
- valAx := f.drawPlotAreaValAx(formatSet)
|
|
|
- charts := map[string]*cPlotArea{
|
|
|
- "area": {
|
|
|
- AreaChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "areaStacked": {
|
|
|
- AreaChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "areaPercentStacked": {
|
|
|
- AreaChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "area3D": {
|
|
|
- Area3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "area3DStacked": {
|
|
|
- Area3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "area3DPercentStacked": {
|
|
|
- Area3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar": {
|
|
|
- BarChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "barStacked": {
|
|
|
- BarChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "barPercentStacked": {
|
|
|
- BarChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DPercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DConeClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DConeStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DConePercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DPyramidClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DPyramidStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DPyramidPercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DCylinderClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DCylinderStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bar3DCylinderPercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col": {
|
|
|
- BarChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "colStacked": {
|
|
|
- BarChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "colPercentStacked": {
|
|
|
- BarChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3D": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DPercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DCone": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DConeClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DConeStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DConePercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DPyramid": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DPyramidClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DPyramidStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DPyramidPercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DCylinder": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DCylinderClustered": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DCylinderStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "col3DCylinderPercentStacked": {
|
|
|
- Bar3DChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bubble": {
|
|
|
- BubbleChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- "bubble3D": {
|
|
|
- BubbleChart: &c,
|
|
|
- CatAx: catAx,
|
|
|
- ValAx: valAx,
|
|
|
- },
|
|
|
- }
|
|
|
- return charts[formatSet.Type]
|
|
|
-}
|
|
|
-
|
|
|
-// drawDoughnutChart provides a function to draw the c:plotArea element for
|
|
|
-// doughnut chart by given format sets.
|
|
|
-func (f *File) drawDoughnutChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- DoughnutChart: &cCharts{
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(true),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- HoleSize: &attrValInt{Val: intPtr(75)},
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawLineChart provides a function to draw the c:plotArea element for line
|
|
|
-// chart by given format sets.
|
|
|
-func (f *File) drawLineChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- LineChart: &cCharts{
|
|
|
- Grouping: &attrValString{
|
|
|
- Val: stringPtr(plotAreaChartGrouping[formatSet.Type]),
|
|
|
- },
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(false),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- DLbls: f.drawChartDLbls(formatSet),
|
|
|
- Smooth: &attrValBool{
|
|
|
- Val: boolPtr(false),
|
|
|
- },
|
|
|
- AxID: []*attrValInt{
|
|
|
- {Val: intPtr(754001152)},
|
|
|
- {Val: intPtr(753999904)},
|
|
|
- },
|
|
|
- },
|
|
|
- CatAx: f.drawPlotAreaCatAx(formatSet),
|
|
|
- ValAx: f.drawPlotAreaValAx(formatSet),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawPieChart provides a function to draw the c:plotArea element for pie
|
|
|
-// chart by given format sets.
|
|
|
-func (f *File) drawPieChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- PieChart: &cCharts{
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(true),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawPie3DChart provides a function to draw the c:plotArea element for 3D
|
|
|
-// pie chart by given format sets.
|
|
|
-func (f *File) drawPie3DChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- Pie3DChart: &cCharts{
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(true),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawPieOfPieChart provides a function to draw the c:plotArea element for
|
|
|
-// pie chart by given format sets.
|
|
|
-func (f *File) drawPieOfPieChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- PieChart: &cCharts{
|
|
|
- OfPieType: &attrValString{
|
|
|
- Val: stringPtr("pie"),
|
|
|
- },
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(true),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- SerLines: &attrValString{},
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawBarOfPieChart provides a function to draw the c:plotArea element for
|
|
|
-// pie chart by given format sets.
|
|
|
-func (f *File) drawBarOfPieChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- PieChart: &cCharts{
|
|
|
- OfPieType: &attrValString{
|
|
|
- Val: stringPtr("bar"),
|
|
|
- },
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(true),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- SerLines: &attrValString{},
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawRadarChart provides a function to draw the c:plotArea element for radar
|
|
|
-// chart by given format sets.
|
|
|
-func (f *File) drawRadarChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- RadarChart: &cCharts{
|
|
|
- RadarStyle: &attrValString{
|
|
|
- Val: stringPtr("marker"),
|
|
|
- },
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(false),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- DLbls: f.drawChartDLbls(formatSet),
|
|
|
- AxID: []*attrValInt{
|
|
|
- {Val: intPtr(754001152)},
|
|
|
- {Val: intPtr(753999904)},
|
|
|
- },
|
|
|
- },
|
|
|
- CatAx: f.drawPlotAreaCatAx(formatSet),
|
|
|
- ValAx: f.drawPlotAreaValAx(formatSet),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawScatterChart provides a function to draw the c:plotArea element for
|
|
|
-// scatter chart by given format sets.
|
|
|
-func (f *File) drawScatterChart(formatSet *formatChart) *cPlotArea {
|
|
|
- return &cPlotArea{
|
|
|
- ScatterChart: &cCharts{
|
|
|
- ScatterStyle: &attrValString{
|
|
|
- Val: stringPtr("smoothMarker"), // line,lineMarker,marker,none,smooth,smoothMarker
|
|
|
- },
|
|
|
- VaryColors: &attrValBool{
|
|
|
- Val: boolPtr(false),
|
|
|
- },
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- DLbls: f.drawChartDLbls(formatSet),
|
|
|
- AxID: []*attrValInt{
|
|
|
- {Val: intPtr(754001152)},
|
|
|
- {Val: intPtr(753999904)},
|
|
|
- },
|
|
|
- },
|
|
|
- CatAx: f.drawPlotAreaCatAx(formatSet),
|
|
|
- ValAx: f.drawPlotAreaValAx(formatSet),
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawSurface3DChart provides a function to draw the c:surface3DChart element by
|
|
|
-// given format sets.
|
|
|
-func (f *File) drawSurface3DChart(formatSet *formatChart) *cPlotArea {
|
|
|
- plotArea := &cPlotArea{
|
|
|
- Surface3DChart: &cCharts{
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- AxID: []*attrValInt{
|
|
|
- {Val: intPtr(754001152)},
|
|
|
- {Val: intPtr(753999904)},
|
|
|
- {Val: intPtr(832256642)},
|
|
|
- },
|
|
|
- },
|
|
|
- CatAx: f.drawPlotAreaCatAx(formatSet),
|
|
|
- ValAx: f.drawPlotAreaValAx(formatSet),
|
|
|
- SerAx: f.drawPlotAreaSerAx(formatSet),
|
|
|
- }
|
|
|
- if formatSet.Type == WireframeSurface3D {
|
|
|
- plotArea.Surface3DChart.Wireframe = &attrValBool{Val: boolPtr(true)}
|
|
|
- }
|
|
|
- return plotArea
|
|
|
-}
|
|
|
-
|
|
|
-// drawSurfaceChart provides a function to draw the c:surfaceChart element by
|
|
|
-// given format sets.
|
|
|
-func (f *File) drawSurfaceChart(formatSet *formatChart) *cPlotArea {
|
|
|
- plotArea := &cPlotArea{
|
|
|
- SurfaceChart: &cCharts{
|
|
|
- Ser: f.drawChartSeries(formatSet),
|
|
|
- AxID: []*attrValInt{
|
|
|
- {Val: intPtr(754001152)},
|
|
|
- {Val: intPtr(753999904)},
|
|
|
- {Val: intPtr(832256642)},
|
|
|
- },
|
|
|
- },
|
|
|
- CatAx: f.drawPlotAreaCatAx(formatSet),
|
|
|
- ValAx: f.drawPlotAreaValAx(formatSet),
|
|
|
- SerAx: f.drawPlotAreaSerAx(formatSet),
|
|
|
- }
|
|
|
- if formatSet.Type == WireframeContour {
|
|
|
- plotArea.SurfaceChart.Wireframe = &attrValBool{Val: boolPtr(true)}
|
|
|
- }
|
|
|
- return plotArea
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartShape provides a function to draw the c:shape element by given
|
|
|
-// format sets.
|
|
|
-func (f *File) drawChartShape(formatSet *formatChart) *attrValString {
|
|
|
- shapes := map[string]string{
|
|
|
- Bar3DConeClustered: "cone",
|
|
|
- Bar3DConeStacked: "cone",
|
|
|
- Bar3DConePercentStacked: "cone",
|
|
|
- Bar3DPyramidClustered: "pyramid",
|
|
|
- Bar3DPyramidStacked: "pyramid",
|
|
|
- Bar3DPyramidPercentStacked: "pyramid",
|
|
|
- Bar3DCylinderClustered: "cylinder",
|
|
|
- Bar3DCylinderStacked: "cylinder",
|
|
|
- Bar3DCylinderPercentStacked: "cylinder",
|
|
|
- Col3DCone: "cone",
|
|
|
- Col3DConeClustered: "cone",
|
|
|
- Col3DConeStacked: "cone",
|
|
|
- Col3DConePercentStacked: "cone",
|
|
|
- Col3DPyramid: "pyramid",
|
|
|
- Col3DPyramidClustered: "pyramid",
|
|
|
- Col3DPyramidStacked: "pyramid",
|
|
|
- Col3DPyramidPercentStacked: "pyramid",
|
|
|
- Col3DCylinder: "cylinder",
|
|
|
- Col3DCylinderClustered: "cylinder",
|
|
|
- Col3DCylinderStacked: "cylinder",
|
|
|
- Col3DCylinderPercentStacked: "cylinder",
|
|
|
- }
|
|
|
- if shape, ok := shapes[formatSet.Type]; ok {
|
|
|
- return &attrValString{Val: stringPtr(shape)}
|
|
|
- }
|
|
|
- return nil
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeries provides a function to draw the c:ser element by given
|
|
|
-// format sets.
|
|
|
-func (f *File) drawChartSeries(formatSet *formatChart) *[]cSer {
|
|
|
- ser := []cSer{}
|
|
|
- for k := range formatSet.Series {
|
|
|
- ser = append(ser, cSer{
|
|
|
- IDx: &attrValInt{Val: intPtr(k + formatSet.order)},
|
|
|
- Order: &attrValInt{Val: intPtr(k + formatSet.order)},
|
|
|
- Tx: &cTx{
|
|
|
- StrRef: &cStrRef{
|
|
|
- F: formatSet.Series[k].Name,
|
|
|
- },
|
|
|
- },
|
|
|
- SpPr: f.drawChartSeriesSpPr(k, formatSet),
|
|
|
- Marker: f.drawChartSeriesMarker(k, formatSet),
|
|
|
- DPt: f.drawChartSeriesDPt(k, formatSet),
|
|
|
- DLbls: f.drawChartSeriesDLbls(formatSet),
|
|
|
- Cat: f.drawChartSeriesCat(formatSet.Series[k], formatSet),
|
|
|
- Val: f.drawChartSeriesVal(formatSet.Series[k], formatSet),
|
|
|
- XVal: f.drawChartSeriesXVal(formatSet.Series[k], formatSet),
|
|
|
- YVal: f.drawChartSeriesYVal(formatSet.Series[k], formatSet),
|
|
|
- BubbleSize: f.drawCharSeriesBubbleSize(formatSet.Series[k], formatSet),
|
|
|
- Bubble3D: f.drawCharSeriesBubble3D(formatSet),
|
|
|
- })
|
|
|
- }
|
|
|
- return &ser
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeriesSpPr provides a function to draw the c:spPr element by given
|
|
|
-// format sets.
|
|
|
-func (f *File) drawChartSeriesSpPr(i int, formatSet *formatChart) *cSpPr {
|
|
|
- spPrScatter := &cSpPr{
|
|
|
- Ln: &aLn{
|
|
|
- W: 25400,
|
|
|
- NoFill: " ",
|
|
|
- },
|
|
|
- }
|
|
|
- spPrLine := &cSpPr{
|
|
|
- Ln: &aLn{
|
|
|
- W: f.ptToEMUs(formatSet.Series[i].Line.Width),
|
|
|
- Cap: "rnd", // rnd, sq, flat
|
|
|
- },
|
|
|
- }
|
|
|
- if i+formatSet.order < 6 {
|
|
|
- spPrLine.Ln.SolidFill = &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{Val: "accent" + strconv.Itoa(i+formatSet.order+1)},
|
|
|
- }
|
|
|
- }
|
|
|
- chartSeriesSpPr := map[string]*cSpPr{Line: spPrLine, Scatter: spPrScatter}
|
|
|
- return chartSeriesSpPr[formatSet.Type]
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeriesDPt provides a function to draw the c:dPt element by given
|
|
|
-// data index and format sets.
|
|
|
-func (f *File) drawChartSeriesDPt(i int, formatSet *formatChart) []*cDPt {
|
|
|
- dpt := []*cDPt{{
|
|
|
- IDx: &attrValInt{Val: intPtr(i)},
|
|
|
- Bubble3D: &attrValBool{Val: boolPtr(false)},
|
|
|
- SpPr: &cSpPr{
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{Val: "accent" + strconv.Itoa(i+1)},
|
|
|
- },
|
|
|
- Ln: &aLn{
|
|
|
- W: 25400,
|
|
|
- Cap: "rnd",
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{Val: "lt" + strconv.Itoa(i+1)},
|
|
|
- },
|
|
|
- },
|
|
|
- Sp3D: &aSp3D{
|
|
|
- ContourW: 25400,
|
|
|
- ContourClr: &aContourClr{
|
|
|
- SchemeClr: &aSchemeClr{Val: "lt" + strconv.Itoa(i+1)},
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- }}
|
|
|
- chartSeriesDPt := map[string][]*cDPt{Pie: dpt, Pie3D: dpt}
|
|
|
- return chartSeriesDPt[formatSet.Type]
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeriesCat provides a function to draw the c:cat element by given
|
|
|
-// chart series and format sets.
|
|
|
-func (f *File) drawChartSeriesCat(v formatChartSeries, formatSet *formatChart) *cCat {
|
|
|
- cat := &cCat{
|
|
|
- StrRef: &cStrRef{
|
|
|
- F: v.Categories,
|
|
|
- },
|
|
|
- }
|
|
|
- chartSeriesCat := map[string]*cCat{Scatter: nil, Bubble: nil, Bubble3D: nil}
|
|
|
- if _, ok := chartSeriesCat[formatSet.Type]; ok || v.Categories == "" {
|
|
|
- return nil
|
|
|
- }
|
|
|
- return cat
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeriesVal provides a function to draw the c:val element by given
|
|
|
-// chart series and format sets.
|
|
|
-func (f *File) drawChartSeriesVal(v formatChartSeries, formatSet *formatChart) *cVal {
|
|
|
- val := &cVal{
|
|
|
- NumRef: &cNumRef{
|
|
|
- F: v.Values,
|
|
|
- },
|
|
|
- }
|
|
|
- chartSeriesVal := map[string]*cVal{Scatter: nil, Bubble: nil, Bubble3D: nil}
|
|
|
- if _, ok := chartSeriesVal[formatSet.Type]; ok {
|
|
|
- return nil
|
|
|
- }
|
|
|
- return val
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeriesMarker provides a function to draw the c:marker element by
|
|
|
-// given data index and format sets.
|
|
|
-func (f *File) drawChartSeriesMarker(i int, formatSet *formatChart) *cMarker {
|
|
|
- marker := &cMarker{
|
|
|
- Symbol: &attrValString{Val: stringPtr("circle")},
|
|
|
- Size: &attrValInt{Val: intPtr(5)},
|
|
|
- }
|
|
|
- if i < 6 {
|
|
|
- marker.SpPr = &cSpPr{
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{
|
|
|
- Val: "accent" + strconv.Itoa(i+1),
|
|
|
- },
|
|
|
- },
|
|
|
- Ln: &aLn{
|
|
|
- W: 9252,
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{
|
|
|
- Val: "accent" + strconv.Itoa(i+1),
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
}
|
|
|
}
|
|
|
- chartSeriesMarker := map[string]*cMarker{Scatter: marker}
|
|
|
- return chartSeriesMarker[formatSet.Type]
|
|
|
+ return f.deleteChart(col, row, drawingXML, wsDr)
|
|
|
}
|
|
|
|
|
|
-// drawChartSeriesXVal provides a function to draw the c:xVal element by given
|
|
|
-// chart series and format sets.
|
|
|
-func (f *File) drawChartSeriesXVal(v formatChartSeries, formatSet *formatChart) *cCat {
|
|
|
- cat := &cCat{
|
|
|
- StrRef: &cStrRef{
|
|
|
- F: v.Categories,
|
|
|
- },
|
|
|
- }
|
|
|
- chartSeriesXVal := map[string]*cCat{Scatter: cat}
|
|
|
- return chartSeriesXVal[formatSet.Type]
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeriesYVal provides a function to draw the c:yVal element by given
|
|
|
-// chart series and format sets.
|
|
|
-func (f *File) drawChartSeriesYVal(v formatChartSeries, formatSet *formatChart) *cVal {
|
|
|
- val := &cVal{
|
|
|
- NumRef: &cNumRef{
|
|
|
- F: v.Values,
|
|
|
- },
|
|
|
- }
|
|
|
- chartSeriesYVal := map[string]*cVal{Scatter: val, Bubble: val, Bubble3D: val}
|
|
|
- return chartSeriesYVal[formatSet.Type]
|
|
|
-}
|
|
|
-
|
|
|
-// drawCharSeriesBubbleSize provides a function to draw the c:bubbleSize
|
|
|
-// element by given chart series and format sets.
|
|
|
-func (f *File) drawCharSeriesBubbleSize(v formatChartSeries, formatSet *formatChart) *cVal {
|
|
|
- if _, ok := map[string]bool{Bubble: true, Bubble3D: true}[formatSet.Type]; !ok {
|
|
|
- return nil
|
|
|
- }
|
|
|
- return &cVal{
|
|
|
- NumRef: &cNumRef{
|
|
|
- F: v.Values,
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawCharSeriesBubble3D provides a function to draw the c:bubble3D element
|
|
|
-// by given format sets.
|
|
|
-func (f *File) drawCharSeriesBubble3D(formatSet *formatChart) *attrValBool {
|
|
|
- if _, ok := map[string]bool{Bubble3D: true}[formatSet.Type]; !ok {
|
|
|
- return nil
|
|
|
- }
|
|
|
- return &attrValBool{Val: boolPtr(true)}
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartDLbls provides a function to draw the c:dLbls element by given
|
|
|
-// format sets.
|
|
|
-func (f *File) drawChartDLbls(formatSet *formatChart) *cDLbls {
|
|
|
- return &cDLbls{
|
|
|
- ShowLegendKey: &attrValBool{Val: boolPtr(formatSet.Legend.ShowLegendKey)},
|
|
|
- ShowVal: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowVal)},
|
|
|
- ShowCatName: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowCatName)},
|
|
|
- ShowSerName: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowSerName)},
|
|
|
- ShowBubbleSize: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowBubbleSize)},
|
|
|
- ShowPercent: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowPercent)},
|
|
|
- ShowLeaderLines: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowLeaderLines)},
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawChartSeriesDLbls provides a function to draw the c:dLbls element by
|
|
|
-// given format sets.
|
|
|
-func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls {
|
|
|
- dLbls := f.drawChartDLbls(formatSet)
|
|
|
- chartSeriesDLbls := map[string]*cDLbls{Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil}
|
|
|
- if _, ok := chartSeriesDLbls[formatSet.Type]; ok {
|
|
|
- return nil
|
|
|
- }
|
|
|
- return dLbls
|
|
|
-}
|
|
|
-
|
|
|
-// drawPlotAreaCatAx provides a function to draw the c:catAx element.
|
|
|
-func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs {
|
|
|
- min := &attrValFloat{Val: float64Ptr(formatSet.XAxis.Minimum)}
|
|
|
- max := &attrValFloat{Val: float64Ptr(formatSet.XAxis.Maximum)}
|
|
|
- if formatSet.XAxis.Minimum == 0 {
|
|
|
- min = nil
|
|
|
- }
|
|
|
- if formatSet.XAxis.Maximum == 0 {
|
|
|
- max = nil
|
|
|
- }
|
|
|
- axs := []*cAxs{
|
|
|
- {
|
|
|
- AxID: &attrValInt{Val: intPtr(754001152)},
|
|
|
- Scaling: &cScaling{
|
|
|
- Orientation: &attrValString{Val: stringPtr(orientation[formatSet.XAxis.ReverseOrder])},
|
|
|
- Max: max,
|
|
|
- Min: min,
|
|
|
- },
|
|
|
- Delete: &attrValBool{Val: boolPtr(false)},
|
|
|
- AxPos: &attrValString{Val: stringPtr(catAxPos[formatSet.XAxis.ReverseOrder])},
|
|
|
- NumFmt: &cNumFmt{
|
|
|
- FormatCode: "General",
|
|
|
- SourceLinked: true,
|
|
|
- },
|
|
|
- MajorTickMark: &attrValString{Val: stringPtr("none")},
|
|
|
- MinorTickMark: &attrValString{Val: stringPtr("none")},
|
|
|
- TickLblPos: &attrValString{Val: stringPtr("nextTo")},
|
|
|
- SpPr: f.drawPlotAreaSpPr(),
|
|
|
- TxPr: f.drawPlotAreaTxPr(),
|
|
|
- CrossAx: &attrValInt{Val: intPtr(753999904)},
|
|
|
- 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 formatSet.XAxis.MajorGridlines {
|
|
|
- axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
|
|
|
- }
|
|
|
- if formatSet.XAxis.MinorGridlines {
|
|
|
- axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
|
|
|
- }
|
|
|
- if formatSet.XAxis.TickLabelSkip != 0 {
|
|
|
- axs[0].TickLblSkip = &attrValInt{Val: intPtr(formatSet.XAxis.TickLabelSkip)}
|
|
|
- }
|
|
|
- return axs
|
|
|
-}
|
|
|
-
|
|
|
-// drawPlotAreaValAx provides a function to draw the c:valAx element.
|
|
|
-func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs {
|
|
|
- min := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Minimum)}
|
|
|
- max := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Maximum)}
|
|
|
- if formatSet.YAxis.Minimum == 0 {
|
|
|
- min = nil
|
|
|
- }
|
|
|
- if formatSet.YAxis.Maximum == 0 {
|
|
|
- max = nil
|
|
|
- }
|
|
|
- axs := []*cAxs{
|
|
|
- {
|
|
|
- AxID: &attrValInt{Val: intPtr(753999904)},
|
|
|
- Scaling: &cScaling{
|
|
|
- Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
|
|
|
- Max: max,
|
|
|
- Min: min,
|
|
|
- },
|
|
|
- Delete: &attrValBool{Val: boolPtr(false)},
|
|
|
- AxPos: &attrValString{Val: stringPtr(valAxPos[formatSet.YAxis.ReverseOrder])},
|
|
|
- NumFmt: &cNumFmt{
|
|
|
- FormatCode: chartValAxNumFmtFormatCode[formatSet.Type],
|
|
|
- SourceLinked: true,
|
|
|
- },
|
|
|
- MajorTickMark: &attrValString{Val: stringPtr("none")},
|
|
|
- MinorTickMark: &attrValString{Val: stringPtr("none")},
|
|
|
- TickLblPos: &attrValString{Val: stringPtr("nextTo")},
|
|
|
- SpPr: f.drawPlotAreaSpPr(),
|
|
|
- TxPr: f.drawPlotAreaTxPr(),
|
|
|
- CrossAx: &attrValInt{Val: intPtr(754001152)},
|
|
|
- Crosses: &attrValString{Val: stringPtr("autoZero")},
|
|
|
- CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[formatSet.Type])},
|
|
|
- },
|
|
|
- }
|
|
|
- if formatSet.YAxis.MajorGridlines {
|
|
|
- axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
|
|
|
- }
|
|
|
- if formatSet.YAxis.MinorGridlines {
|
|
|
- axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
|
|
|
- }
|
|
|
- if pos, ok := valTickLblPos[formatSet.Type]; ok {
|
|
|
- axs[0].TickLblPos.Val = stringPtr(pos)
|
|
|
- }
|
|
|
- if formatSet.YAxis.MajorUnit != 0 {
|
|
|
- axs[0].MajorUnit = &attrValFloat{Val: float64Ptr(formatSet.YAxis.MajorUnit)}
|
|
|
- }
|
|
|
- return axs
|
|
|
-}
|
|
|
-
|
|
|
-// drawPlotAreaSerAx provides a function to draw the c:serAx element.
|
|
|
-func (f *File) drawPlotAreaSerAx(formatSet *formatChart) []*cAxs {
|
|
|
- min := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Minimum)}
|
|
|
- max := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Maximum)}
|
|
|
- if formatSet.YAxis.Minimum == 0 {
|
|
|
- min = nil
|
|
|
- }
|
|
|
- if formatSet.YAxis.Maximum == 0 {
|
|
|
- max = nil
|
|
|
- }
|
|
|
- return []*cAxs{
|
|
|
- {
|
|
|
- AxID: &attrValInt{Val: intPtr(832256642)},
|
|
|
- Scaling: &cScaling{
|
|
|
- Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
|
|
|
- Max: max,
|
|
|
- Min: min,
|
|
|
- },
|
|
|
- Delete: &attrValBool{Val: boolPtr(false)},
|
|
|
- AxPos: &attrValString{Val: stringPtr(catAxPos[formatSet.XAxis.ReverseOrder])},
|
|
|
- TickLblPos: &attrValString{Val: stringPtr("nextTo")},
|
|
|
- SpPr: f.drawPlotAreaSpPr(),
|
|
|
- TxPr: f.drawPlotAreaTxPr(),
|
|
|
- CrossAx: &attrValInt{Val: intPtr(753999904)},
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawPlotAreaSpPr provides a function to draw the c:spPr element.
|
|
|
-func (f *File) drawPlotAreaSpPr() *cSpPr {
|
|
|
- return &cSpPr{
|
|
|
- Ln: &aLn{
|
|
|
- W: 9525,
|
|
|
- Cap: "flat",
|
|
|
- Cmpd: "sng",
|
|
|
- Algn: "ctr",
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{
|
|
|
- Val: "tx1",
|
|
|
- LumMod: &attrValInt{Val: intPtr(15000)},
|
|
|
- LumOff: &attrValInt{Val: intPtr(85000)},
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawPlotAreaTxPr provides a function to draw the c:txPr element.
|
|
|
-func (f *File) drawPlotAreaTxPr() *cTxPr {
|
|
|
- return &cTxPr{
|
|
|
- BodyPr: aBodyPr{
|
|
|
- Rot: -60000000,
|
|
|
- SpcFirstLastPara: true,
|
|
|
- VertOverflow: "ellipsis",
|
|
|
- Vert: "horz",
|
|
|
- Wrap: "square",
|
|
|
- Anchor: "ctr",
|
|
|
- AnchorCtr: true,
|
|
|
- },
|
|
|
- P: aP{
|
|
|
- PPr: &aPPr{
|
|
|
- DefRPr: aRPr{
|
|
|
- Sz: 900,
|
|
|
- B: false,
|
|
|
- I: false,
|
|
|
- U: "none",
|
|
|
- Strike: "noStrike",
|
|
|
- Kern: 1200,
|
|
|
- Baseline: 0,
|
|
|
- SolidFill: &aSolidFill{
|
|
|
- SchemeClr: &aSchemeClr{
|
|
|
- Val: "tx1",
|
|
|
- LumMod: &attrValInt{Val: intPtr(15000)},
|
|
|
- LumOff: &attrValInt{Val: intPtr(85000)},
|
|
|
- },
|
|
|
- },
|
|
|
- Latin: &aLatin{Typeface: "+mn-lt"},
|
|
|
- Ea: &aEa{Typeface: "+mn-ea"},
|
|
|
- Cs: &aCs{Typeface: "+mn-cs"},
|
|
|
- },
|
|
|
- },
|
|
|
- EndParaRPr: &aEndParaRPr{Lang: "en-US"},
|
|
|
- },
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-// drawingParser provides a function to parse drawingXML. In order to solve
|
|
|
-// the problem that the label structure is changed after serialization and
|
|
|
-// deserialization, two different structures: decodeWsDr and encodeWsDr are
|
|
|
-// defined.
|
|
|
-func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
|
|
|
+// deleteChart provides a function to delete chart graphic frame by given by
|
|
|
+// given coordinates.
|
|
|
+func (f *File) deleteChart(col, row int, drawingXML string, wsDr *xlsxWsDr) (err error) {
|
|
|
var (
|
|
|
- err error
|
|
|
- ok bool
|
|
|
+ deWsDr *decodeWsDr
|
|
|
+ deTwoCellAnchor *decodeTwoCellAnchor
|
|
|
)
|
|
|
-
|
|
|
- if f.Drawings[path] == nil {
|
|
|
- content := xlsxWsDr{}
|
|
|
- content.A = NameSpaceDrawingML
|
|
|
- content.Xdr = NameSpaceDrawingMLSpreadSheet
|
|
|
- if _, ok = f.XLSX[path]; ok { // Append Model
|
|
|
- decodeWsDr := decodeWsDr{}
|
|
|
- if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).
|
|
|
- Decode(&decodeWsDr); err != nil && err != io.EOF {
|
|
|
- log.Printf("xml decode error: %s", err)
|
|
|
- }
|
|
|
- content.R = decodeWsDr.R
|
|
|
- for _, v := range decodeWsDr.OneCellAnchor {
|
|
|
- content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
|
|
|
- EditAs: v.EditAs,
|
|
|
- GraphicFrame: v.Content,
|
|
|
- })
|
|
|
- }
|
|
|
- for _, v := range decodeWsDr.TwoCellAnchor {
|
|
|
- content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
|
|
|
- EditAs: v.EditAs,
|
|
|
- GraphicFrame: v.Content,
|
|
|
- })
|
|
|
+ deWsDr = new(decodeWsDr)
|
|
|
+ if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(drawingXML)))).
|
|
|
+ Decode(deWsDr); err != nil && err != io.EOF {
|
|
|
+ err = fmt.Errorf("xml decode error: %s", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for idx, anchor := range deWsDr.TwoCellAnchor {
|
|
|
+ deTwoCellAnchor = new(decodeTwoCellAnchor)
|
|
|
+ if err = f.xmlNewDecoder(bytes.NewReader([]byte("<decodeTwoCellAnchor>" + anchor.Content + "</decodeTwoCellAnchor>"))).
|
|
|
+ Decode(deTwoCellAnchor); err != nil && err != io.EOF {
|
|
|
+ err = fmt.Errorf("xml decode error: %s", err)
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if err = nil; deTwoCellAnchor.From != nil && deTwoCellAnchor.Pic == nil {
|
|
|
+ if anchor.From.Col == col && anchor.From.Row == row {
|
|
|
+ wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
|
|
|
}
|
|
|
}
|
|
|
- f.Drawings[path] = &content
|
|
|
}
|
|
|
- wsDr := f.Drawings[path]
|
|
|
- return wsDr, len(wsDr.OneCellAnchor) + len(wsDr.TwoCellAnchor) + 2
|
|
|
+ f.Drawings[drawingXML] = wsDr
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
-// addDrawingChart provides a function to add chart graphic frame by given
|
|
|
-// sheet, drawingXML, cell, width, height, relationship index and format sets.
|
|
|
-func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rID int, formatSet *formatPicture) error {
|
|
|
- col, row, err := CellNameToCoordinates(cell)
|
|
|
- if err != nil {
|
|
|
- return err
|
|
|
- }
|
|
|
- colIdx := col - 1
|
|
|
- rowIdx := row - 1
|
|
|
-
|
|
|
- width = int(float64(width) * formatSet.XScale)
|
|
|
- height = int(float64(height) * formatSet.YScale)
|
|
|
- colStart, rowStart, _, _, colEnd, rowEnd, x2, y2 :=
|
|
|
- f.positionObjectPixels(sheet, colIdx, rowIdx, formatSet.OffsetX, formatSet.OffsetY, width, height)
|
|
|
- content, cNvPrID := f.drawingParser(drawingXML)
|
|
|
- twoCellAnchor := xdrCellAnchor{}
|
|
|
- twoCellAnchor.EditAs = formatSet.Positioning
|
|
|
- from := xlsxFrom{}
|
|
|
- from.Col = colStart
|
|
|
- from.ColOff = formatSet.OffsetX * EMU
|
|
|
- from.Row = rowStart
|
|
|
- from.RowOff = formatSet.OffsetY * EMU
|
|
|
- to := xlsxTo{}
|
|
|
- to.Col = colEnd
|
|
|
- to.ColOff = x2 * EMU
|
|
|
- to.Row = rowEnd
|
|
|
- to.RowOff = y2 * EMU
|
|
|
- twoCellAnchor.From = &from
|
|
|
- twoCellAnchor.To = &to
|
|
|
-
|
|
|
- graphicFrame := xlsxGraphicFrame{
|
|
|
- NvGraphicFramePr: xlsxNvGraphicFramePr{
|
|
|
- CNvPr: &xlsxCNvPr{
|
|
|
- ID: cNvPrID,
|
|
|
- Name: "Chart " + strconv.Itoa(cNvPrID),
|
|
|
- },
|
|
|
- },
|
|
|
- Graphic: &xlsxGraphic{
|
|
|
- GraphicData: &xlsxGraphicData{
|
|
|
- URI: NameSpaceDrawingMLChart,
|
|
|
- Chart: &xlsxChart{
|
|
|
- C: NameSpaceDrawingMLChart,
|
|
|
- R: SourceRelationship,
|
|
|
- RID: "rId" + strconv.Itoa(rID),
|
|
|
- },
|
|
|
- },
|
|
|
- },
|
|
|
- }
|
|
|
- graphic, _ := xml.Marshal(graphicFrame)
|
|
|
- twoCellAnchor.GraphicFrame = string(graphic)
|
|
|
- twoCellAnchor.ClientData = &xdrClientData{
|
|
|
- FLocksWithSheet: formatSet.FLocksWithSheet,
|
|
|
- FPrintsWithSheet: formatSet.FPrintsWithSheet,
|
|
|
+// countCharts provides a function to get chart files count storage in the
|
|
|
+// folder xl/charts.
|
|
|
+func (f *File) countCharts() int {
|
|
|
+ count := 0
|
|
|
+ for k := range f.XLSX {
|
|
|
+ if strings.Contains(k, "xl/charts/chart") {
|
|
|
+ count++
|
|
|
+ }
|
|
|
}
|
|
|
- content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
|
|
|
- f.Drawings[drawingXML] = content
|
|
|
- return err
|
|
|
+ return count
|
|
|
}
|
|
|
|
|
|
// ptToEMUs provides a function to convert pt to EMUs, 1 pt = 12700 EMUs. The
|