| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439 |
- // Copyright 2016 - 2023 The excelize Authors. All rights reserved. Use of
- // this source code is governed by a BSD-style license that can be found in
- // the LICENSE file.
- //
- // Package excelize providing a set of functions that allow you to write to and
- // read from XLAM / XLSM / XLSX / XLTM / XLTX files. Supports reading and
- // writing spreadsheet documents generated by Microsoft Excel™ 2007 and later.
- // Supports complex components by high compatibility, and provided streaming
- // API for generating or reading data from a worksheet with huge amounts of
- // data. This library needs Go version 1.16 or later.
- package excelize
- import (
- "bytes"
- "encoding/xml"
- "io"
- "reflect"
- "strconv"
- "strings"
- )
- // prepareDrawing provides a function to prepare drawing ID and XML by given
- // drawingID, worksheet name and default drawingXML.
- func (f *File) prepareDrawing(ws *xlsxWorksheet, drawingID int, sheet, drawingXML string) (int, string) {
- sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
- if ws.Drawing != nil {
- // The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
- sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
- drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
- drawingXML = strings.ReplaceAll(sheetRelationshipsDrawingXML, "..", "xl")
- } else {
- // Add first picture for given sheet.
- sheetXMLPath, _ := f.getSheetXMLPath(sheet)
- sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/worksheets/") + ".rels"
- rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
- f.addSheetDrawing(sheet, rID)
- }
- return drawingID, drawingXML
- }
- // prepareChartSheetDrawing provides a function to prepare drawing ID and XML
- // by given drawingID, worksheet name and default drawingXML.
- func (f *File) prepareChartSheetDrawing(cs *xlsxChartsheet, drawingID int, sheet string) {
- sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
- // Only allow one chart in a chartsheet.
- sheetXMLPath, _ := f.getSheetXMLPath(sheet)
- sheetRels := "xl/chartsheets/_rels/" + strings.TrimPrefix(sheetXMLPath, "xl/chartsheets/") + ".rels"
- rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
- f.addSheetNameSpace(sheet, SourceRelationship)
- cs.Drawing = &xlsxDrawing{
- RID: "rId" + strconv.Itoa(rID),
- }
- }
- // addChart provides a function to create chart as xl/charts/chart%d.xml by
- // given format sets.
- func (f *File) addChart(opts *Chart, comboCharts []*Chart) {
- count := f.countCharts()
- xlsxChartSpace := xlsxChartSpace{
- XMLNSa: NameSpaceDrawingML.Value,
- 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: &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{
- RotX: &attrValInt{Val: intPtr(chartView3DRotX[opts.Type])},
- RotY: &attrValInt{Val: intPtr(chartView3DRotY[opts.Type])},
- Perspective: &attrValInt{Val: intPtr(chartView3DPerspective[opts.Type])},
- RAngAx: &attrValInt{Val: intPtr(chartView3DRAngAx[opts.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[opts.Legend.Position])},
- Overlay: &attrValBool{Val: boolPtr(false)},
- },
- PlotVisOnly: &attrValBool{Val: boolPtr(false)},
- DispBlanksAs: &attrValString{Val: stringPtr(opts.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,
- },
- },
- }
- plotAreaFunc := map[ChartType]func(*Chart) *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,
- Line3D: f.drawLine3DChart,
- Pie: f.drawPieChart,
- Pie3D: f.drawPie3DChart,
- PieOfPie: f.drawPieOfPieChart,
- BarOfPie: f.drawBarOfPieChart,
- Radar: f.drawRadarChart,
- Scatter: f.drawScatterChart,
- Surface3D: f.drawSurface3DChart,
- WireframeSurface3D: f.drawSurface3DChart,
- Contour: f.drawSurfaceChart,
- WireframeContour: f.drawSurfaceChart,
- Bubble: f.drawBubbleChart,
- Bubble3D: f.drawBubbleChart,
- }
- if opts.Legend.Position == "none" {
- xlsxChartSpace.Chart.Legend = nil
- }
- 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
- }
- immutable.FieldByName(mutable.Type().Field(i).Name).Set(field)
- }
- }
- addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[opts.Type](opts))
- order := len(opts.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(opts *Chart) *cPlotArea {
- c := cCharts{
- BarDir: &attrValString{
- Val: stringPtr("col"),
- },
- Grouping: &attrValString{
- Val: stringPtr(plotAreaChartGrouping[opts.Type]),
- },
- VaryColors: &attrValBool{
- Val: opts.VaryColors,
- },
- Ser: f.drawChartSeries(opts),
- Shape: f.drawChartShape(opts),
- DLbls: f.drawChartDLbls(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- },
- Overlap: &attrValInt{Val: intPtr(100)},
- }
- var ok bool
- if *c.BarDir.Val, ok = plotAreaChartBarDir[opts.Type]; !ok {
- c.BarDir = nil
- }
- if *c.Overlap.Val, ok = plotAreaChartOverlap[opts.Type]; !ok {
- c.Overlap = nil
- }
- catAx := f.drawPlotAreaCatAx(opts)
- valAx := f.drawPlotAreaValAx(opts)
- charts := map[ChartType]*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[opts.Type]
- }
- // drawDoughnutChart provides a function to draw the c:plotArea element for
- // doughnut chart by given format sets.
- func (f *File) drawDoughnutChart(opts *Chart) *cPlotArea {
- holeSize := 75
- if opts.HoleSize > 0 && opts.HoleSize <= 90 {
- holeSize = opts.HoleSize
- }
- return &cPlotArea{
- DoughnutChart: &cCharts{
- VaryColors: &attrValBool{
- Val: opts.VaryColors,
- },
- Ser: f.drawChartSeries(opts),
- HoleSize: &attrValInt{Val: intPtr(holeSize)},
- },
- }
- }
- // drawLineChart provides a function to draw the c:plotArea element for line
- // chart by given format sets.
- func (f *File) drawLineChart(opts *Chart) *cPlotArea {
- return &cPlotArea{
- LineChart: &cCharts{
- Grouping: &attrValString{
- Val: stringPtr(plotAreaChartGrouping[opts.Type]),
- },
- VaryColors: &attrValBool{
- Val: boolPtr(false),
- },
- Ser: f.drawChartSeries(opts),
- DLbls: f.drawChartDLbls(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- },
- },
- CatAx: f.drawPlotAreaCatAx(opts),
- ValAx: f.drawPlotAreaValAx(opts),
- }
- }
- // drawLine3DChart provides a function to draw the c:plotArea element for line
- // chart by given format sets.
- func (f *File) drawLine3DChart(opts *Chart) *cPlotArea {
- return &cPlotArea{
- Line3DChart: &cCharts{
- Grouping: &attrValString{
- Val: stringPtr(plotAreaChartGrouping[opts.Type]),
- },
- VaryColors: &attrValBool{
- Val: boolPtr(false),
- },
- Ser: f.drawChartSeries(opts),
- DLbls: f.drawChartDLbls(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- },
- },
- CatAx: f.drawPlotAreaCatAx(opts),
- ValAx: f.drawPlotAreaValAx(opts),
- }
- }
- // drawPieChart provides a function to draw the c:plotArea element for pie
- // chart by given format sets.
- func (f *File) drawPieChart(opts *Chart) *cPlotArea {
- return &cPlotArea{
- PieChart: &cCharts{
- VaryColors: &attrValBool{
- Val: opts.VaryColors,
- },
- Ser: f.drawChartSeries(opts),
- },
- }
- }
- // drawPie3DChart provides a function to draw the c:plotArea element for 3D
- // pie chart by given format sets.
- func (f *File) drawPie3DChart(opts *Chart) *cPlotArea {
- return &cPlotArea{
- Pie3DChart: &cCharts{
- VaryColors: &attrValBool{
- Val: opts.VaryColors,
- },
- Ser: f.drawChartSeries(opts),
- },
- }
- }
- // drawPieOfPieChart provides a function to draw the c:plotArea element for
- // pie chart by given format sets.
- func (f *File) drawPieOfPieChart(opts *Chart) *cPlotArea {
- var splitPos *attrValInt
- if opts.PlotArea.SecondPlotValues > 0 {
- splitPos = &attrValInt{Val: intPtr(opts.PlotArea.SecondPlotValues)}
- }
- return &cPlotArea{
- OfPieChart: &cCharts{
- OfPieType: &attrValString{
- Val: stringPtr("pie"),
- },
- VaryColors: &attrValBool{
- Val: opts.VaryColors,
- },
- Ser: f.drawChartSeries(opts),
- SplitPos: splitPos,
- SerLines: &attrValString{},
- },
- }
- }
- // drawBarOfPieChart provides a function to draw the c:plotArea element for
- // pie chart by given format sets.
- func (f *File) drawBarOfPieChart(opts *Chart) *cPlotArea {
- var splitPos *attrValInt
- if opts.PlotArea.SecondPlotValues > 0 {
- splitPos = &attrValInt{Val: intPtr(opts.PlotArea.SecondPlotValues)}
- }
- return &cPlotArea{
- OfPieChart: &cCharts{
- OfPieType: &attrValString{
- Val: stringPtr("bar"),
- },
- VaryColors: &attrValBool{
- Val: opts.VaryColors,
- },
- SplitPos: splitPos,
- Ser: f.drawChartSeries(opts),
- SerLines: &attrValString{},
- },
- }
- }
- // drawRadarChart provides a function to draw the c:plotArea element for radar
- // chart by given format sets.
- func (f *File) drawRadarChart(opts *Chart) *cPlotArea {
- return &cPlotArea{
- RadarChart: &cCharts{
- RadarStyle: &attrValString{
- Val: stringPtr("marker"),
- },
- VaryColors: &attrValBool{
- Val: boolPtr(false),
- },
- Ser: f.drawChartSeries(opts),
- DLbls: f.drawChartDLbls(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- },
- },
- CatAx: f.drawPlotAreaCatAx(opts),
- ValAx: f.drawPlotAreaValAx(opts),
- }
- }
- // drawScatterChart provides a function to draw the c:plotArea element for
- // scatter chart by given format sets.
- func (f *File) drawScatterChart(opts *Chart) *cPlotArea {
- return &cPlotArea{
- ScatterChart: &cCharts{
- ScatterStyle: &attrValString{
- Val: stringPtr("smoothMarker"), // line,lineMarker,marker,none,smooth,smoothMarker
- },
- VaryColors: &attrValBool{
- Val: boolPtr(false),
- },
- Ser: f.drawChartSeries(opts),
- DLbls: f.drawChartDLbls(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- },
- },
- CatAx: f.drawPlotAreaCatAx(opts),
- ValAx: f.drawPlotAreaValAx(opts),
- }
- }
- // drawSurface3DChart provides a function to draw the c:surface3DChart element by
- // given format sets.
- func (f *File) drawSurface3DChart(opts *Chart) *cPlotArea {
- plotArea := &cPlotArea{
- Surface3DChart: &cCharts{
- Ser: f.drawChartSeries(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- {Val: intPtr(832256642)},
- },
- },
- CatAx: f.drawPlotAreaCatAx(opts),
- ValAx: f.drawPlotAreaValAx(opts),
- SerAx: f.drawPlotAreaSerAx(opts),
- }
- if opts.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(opts *Chart) *cPlotArea {
- plotArea := &cPlotArea{
- SurfaceChart: &cCharts{
- Ser: f.drawChartSeries(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- {Val: intPtr(832256642)},
- },
- },
- CatAx: f.drawPlotAreaCatAx(opts),
- ValAx: f.drawPlotAreaValAx(opts),
- SerAx: f.drawPlotAreaSerAx(opts),
- }
- if opts.Type == WireframeContour {
- plotArea.SurfaceChart.Wireframe = &attrValBool{Val: boolPtr(true)}
- }
- return plotArea
- }
- // drawBubbleChart provides a function to draw the c:bubbleChart element by
- // given format sets.
- func (f *File) drawBubbleChart(opts *Chart) *cPlotArea {
- plotArea := &cPlotArea{
- BubbleChart: &cCharts{
- VaryColors: &attrValBool{
- Val: opts.VaryColors,
- },
- Ser: f.drawChartSeries(opts),
- DLbls: f.drawChartDLbls(opts),
- AxID: []*attrValInt{
- {Val: intPtr(754001152)},
- {Val: intPtr(753999904)},
- },
- },
- ValAx: []*cAxs{f.drawPlotAreaCatAx(opts)[0], f.drawPlotAreaValAx(opts)[0]},
- }
- return plotArea
- }
- // drawChartShape provides a function to draw the c:shape element by given
- // format sets.
- func (f *File) drawChartShape(opts *Chart) *attrValString {
- shapes := map[ChartType]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[opts.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(opts *Chart) *[]cSer {
- var ser []cSer
- for k := range opts.Series {
- ser = append(ser, cSer{
- IDx: &attrValInt{Val: intPtr(k + opts.order)},
- Order: &attrValInt{Val: intPtr(k + opts.order)},
- Tx: &cTx{
- StrRef: &cStrRef{
- F: opts.Series[k].Name,
- },
- },
- SpPr: f.drawChartSeriesSpPr(k, opts),
- Marker: f.drawChartSeriesMarker(k, opts),
- DPt: f.drawChartSeriesDPt(k, opts),
- DLbls: f.drawChartSeriesDLbls(opts),
- InvertIfNegative: &attrValBool{Val: boolPtr(false)},
- Cat: f.drawChartSeriesCat(opts.Series[k], opts),
- Smooth: &attrValBool{Val: boolPtr(opts.Series[k].Line.Smooth)},
- Val: f.drawChartSeriesVal(opts.Series[k], opts),
- XVal: f.drawChartSeriesXVal(opts.Series[k], opts),
- YVal: f.drawChartSeriesYVal(opts.Series[k], opts),
- BubbleSize: f.drawCharSeriesBubbleSize(opts.Series[k], opts),
- Bubble3D: f.drawCharSeriesBubble3D(opts),
- })
- }
- return &ser
- }
- // drawChartSeriesSpPr provides a function to draw the c:spPr element by given
- // format sets.
- func (f *File) drawChartSeriesSpPr(i int, opts *Chart) *cSpPr {
- var srgbClr *attrValString
- var schemeClr *aSchemeClr
- if color := opts.Series[i].Fill.Color; len(color) == 1 {
- srgbClr = &attrValString{Val: stringPtr(strings.TrimPrefix(color[0], "#"))}
- } else {
- schemeClr = &aSchemeClr{Val: "accent" + strconv.Itoa((opts.order+i)%6+1)}
- }
- spPr := &cSpPr{SolidFill: &aSolidFill{SchemeClr: schemeClr, SrgbClr: srgbClr}}
- spPrScatter := &cSpPr{
- Ln: &aLn{
- W: 25400,
- NoFill: " ",
- },
- }
- spPrLine := &cSpPr{
- Ln: &aLn{
- W: f.ptToEMUs(opts.Series[i].Line.Width),
- Cap: "rnd", // rnd, sq, flat
- SolidFill: &aSolidFill{
- SchemeClr: schemeClr,
- SrgbClr: srgbClr,
- },
- },
- }
- if chartSeriesSpPr, ok := map[ChartType]*cSpPr{
- Line: spPrLine, Scatter: spPrScatter,
- }[opts.Type]; ok {
- return chartSeriesSpPr
- }
- if srgbClr != nil {
- return spPr
- }
- return nil
- }
- // drawChartSeriesDPt provides a function to draw the c:dPt element by given
- // data index and format sets.
- func (f *File) drawChartSeriesDPt(i int, opts *Chart) []*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[ChartType][]*cDPt{Pie: dpt, Pie3D: dpt}
- return chartSeriesDPt[opts.Type]
- }
- // drawChartSeriesCat provides a function to draw the c:cat element by given
- // chart series and format sets.
- func (f *File) drawChartSeriesCat(v ChartSeries, opts *Chart) *cCat {
- cat := &cCat{
- StrRef: &cStrRef{
- F: v.Categories,
- },
- }
- chartSeriesCat := map[ChartType]*cCat{Scatter: nil, Bubble: nil, Bubble3D: nil}
- if _, ok := chartSeriesCat[opts.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 ChartSeries, opts *Chart) *cVal {
- val := &cVal{
- NumRef: &cNumRef{
- F: v.Values,
- },
- }
- chartSeriesVal := map[ChartType]*cVal{Scatter: nil, Bubble: nil, Bubble3D: nil}
- if _, ok := chartSeriesVal[opts.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, opts *Chart) *cMarker {
- defaultSymbol := map[ChartType]*attrValString{Scatter: {Val: stringPtr("circle")}}
- marker := &cMarker{
- Symbol: defaultSymbol[opts.Type],
- Size: &attrValInt{Val: intPtr(5)},
- }
- if symbol := stringPtr(opts.Series[i].Marker.Symbol); *symbol != "" {
- marker.Symbol = &attrValString{Val: symbol}
- }
- if size := intPtr(opts.Series[i].Marker.Size); *size != 0 {
- marker.Size = &attrValInt{Val: size}
- }
- 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[ChartType]*cMarker{Scatter: marker, Line: marker}
- return chartSeriesMarker[opts.Type]
- }
- // drawChartSeriesXVal provides a function to draw the c:xVal element by given
- // chart series and format sets.
- func (f *File) drawChartSeriesXVal(v ChartSeries, opts *Chart) *cCat {
- cat := &cCat{
- StrRef: &cStrRef{
- F: v.Categories,
- },
- }
- chartSeriesXVal := map[ChartType]*cCat{Scatter: cat, Bubble: cat, Bubble3D: cat}
- return chartSeriesXVal[opts.Type]
- }
- // drawChartSeriesYVal provides a function to draw the c:yVal element by given
- // chart series and format sets.
- func (f *File) drawChartSeriesYVal(v ChartSeries, opts *Chart) *cVal {
- val := &cVal{
- NumRef: &cNumRef{
- F: v.Values,
- },
- }
- chartSeriesYVal := map[ChartType]*cVal{Scatter: val, Bubble: val, Bubble3D: val}
- return chartSeriesYVal[opts.Type]
- }
- // drawCharSeriesBubbleSize provides a function to draw the c:bubbleSize
- // element by given chart series and format sets.
- func (f *File) drawCharSeriesBubbleSize(v ChartSeries, opts *Chart) *cVal {
- if _, ok := map[ChartType]bool{Bubble: true, Bubble3D: true}[opts.Type]; !ok || v.Sizes == "" {
- return nil
- }
- return &cVal{
- NumRef: &cNumRef{
- F: v.Sizes,
- },
- }
- }
- // drawCharSeriesBubble3D provides a function to draw the c:bubble3D element
- // by given format sets.
- func (f *File) drawCharSeriesBubble3D(opts *Chart) *attrValBool {
- if _, ok := map[ChartType]bool{Bubble3D: true}[opts.Type]; !ok {
- return nil
- }
- return &attrValBool{Val: boolPtr(true)}
- }
- // drawChartNumFmt provides a function to draw the c:numFmt element by given
- // data labels format sets.
- func (f *File) drawChartNumFmt(labels ChartNumFmt) *cNumFmt {
- var numFmt *cNumFmt
- if labels.CustomNumFmt != "" || labels.SourceLinked {
- numFmt = &cNumFmt{
- FormatCode: labels.CustomNumFmt,
- SourceLinked: labels.SourceLinked,
- }
- }
- return numFmt
- }
- // drawChartDLbls provides a function to draw the c:dLbls element by given
- // format sets.
- func (f *File) drawChartDLbls(opts *Chart) *cDLbls {
- return &cDLbls{
- NumFmt: f.drawChartNumFmt(opts.PlotArea.NumFmt),
- ShowLegendKey: &attrValBool{Val: boolPtr(opts.Legend.ShowLegendKey)},
- ShowVal: &attrValBool{Val: boolPtr(opts.PlotArea.ShowVal)},
- ShowCatName: &attrValBool{Val: boolPtr(opts.PlotArea.ShowCatName)},
- ShowSerName: &attrValBool{Val: boolPtr(opts.PlotArea.ShowSerName)},
- ShowBubbleSize: &attrValBool{Val: boolPtr(opts.PlotArea.ShowBubbleSize)},
- ShowPercent: &attrValBool{Val: boolPtr(opts.PlotArea.ShowPercent)},
- ShowLeaderLines: &attrValBool{Val: boolPtr(opts.PlotArea.ShowLeaderLines)},
- }
- }
- // drawChartSeriesDLbls provides a function to draw the c:dLbls element by
- // given format sets.
- func (f *File) drawChartSeriesDLbls(opts *Chart) *cDLbls {
- dLbls := f.drawChartDLbls(opts)
- chartSeriesDLbls := map[ChartType]*cDLbls{
- Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil,
- }
- if _, ok := chartSeriesDLbls[opts.Type]; ok {
- return nil
- }
- return dLbls
- }
- // drawPlotAreaCatAx provides a function to draw the c:catAx element.
- func (f *File) drawPlotAreaCatAx(opts *Chart) []*cAxs {
- max := &attrValFloat{Val: opts.XAxis.Maximum}
- min := &attrValFloat{Val: opts.XAxis.Minimum}
- if opts.XAxis.Maximum == nil {
- max = nil
- }
- if opts.XAxis.Minimum == nil {
- min = nil
- }
- axs := []*cAxs{
- {
- AxID: &attrValInt{Val: intPtr(754001152)},
- Scaling: &cScaling{
- Orientation: &attrValString{Val: stringPtr(orientation[opts.XAxis.ReverseOrder])},
- Max: max,
- Min: min,
- },
- Delete: &attrValBool{Val: boolPtr(opts.XAxis.None)},
- AxPos: &attrValString{Val: stringPtr(catAxPos[opts.XAxis.ReverseOrder])},
- NumFmt: &cNumFmt{FormatCode: "General"},
- MajorTickMark: &attrValString{Val: stringPtr("none")},
- MinorTickMark: &attrValString{Val: stringPtr("none")},
- TickLblPos: &attrValString{Val: stringPtr("nextTo")},
- SpPr: f.drawPlotAreaSpPr(),
- TxPr: f.drawPlotAreaTxPr(&opts.YAxis),
- 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 numFmt := f.drawChartNumFmt(opts.XAxis.NumFmt); numFmt != nil {
- axs[0].NumFmt = numFmt
- }
- if opts.XAxis.MajorGridLines {
- axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
- }
- if opts.XAxis.MinorGridLines {
- axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
- }
- if opts.XAxis.TickLabelSkip != 0 {
- axs[0].TickLblSkip = &attrValInt{Val: intPtr(opts.XAxis.TickLabelSkip)}
- }
- return axs
- }
- // drawPlotAreaValAx provides a function to draw the c:valAx element.
- func (f *File) drawPlotAreaValAx(opts *Chart) []*cAxs {
- max := &attrValFloat{Val: opts.YAxis.Maximum}
- min := &attrValFloat{Val: opts.YAxis.Minimum}
- if opts.YAxis.Maximum == nil {
- max = nil
- }
- if opts.YAxis.Minimum == nil {
- min = nil
- }
- var logBase *attrValFloat
- if opts.YAxis.LogBase >= 2 && opts.YAxis.LogBase <= 1000 {
- logBase = &attrValFloat{Val: float64Ptr(opts.YAxis.LogBase)}
- }
- axs := []*cAxs{
- {
- AxID: &attrValInt{Val: intPtr(753999904)},
- Scaling: &cScaling{
- LogBase: logBase,
- Orientation: &attrValString{Val: stringPtr(orientation[opts.YAxis.ReverseOrder])},
- Max: max,
- Min: min,
- },
- Delete: &attrValBool{Val: boolPtr(opts.YAxis.None)},
- AxPos: &attrValString{Val: stringPtr(valAxPos[opts.YAxis.ReverseOrder])},
- NumFmt: &cNumFmt{
- FormatCode: chartValAxNumFmtFormatCode[opts.Type],
- },
- MajorTickMark: &attrValString{Val: stringPtr("none")},
- MinorTickMark: &attrValString{Val: stringPtr("none")},
- TickLblPos: &attrValString{Val: stringPtr("nextTo")},
- SpPr: f.drawPlotAreaSpPr(),
- TxPr: f.drawPlotAreaTxPr(&opts.XAxis),
- CrossAx: &attrValInt{Val: intPtr(754001152)},
- Crosses: &attrValString{Val: stringPtr("autoZero")},
- CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[opts.Type])},
- },
- }
- if numFmt := f.drawChartNumFmt(opts.YAxis.NumFmt); numFmt != nil {
- axs[0].NumFmt = numFmt
- }
- if opts.YAxis.MajorGridLines {
- axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
- }
- if opts.YAxis.MinorGridLines {
- axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
- }
- if pos, ok := valTickLblPos[opts.Type]; ok {
- axs[0].TickLblPos.Val = stringPtr(pos)
- }
- if opts.YAxis.MajorUnit != 0 {
- axs[0].MajorUnit = &attrValFloat{Val: float64Ptr(opts.YAxis.MajorUnit)}
- }
- return axs
- }
- // drawPlotAreaSerAx provides a function to draw the c:serAx element.
- func (f *File) drawPlotAreaSerAx(opts *Chart) []*cAxs {
- max := &attrValFloat{Val: opts.YAxis.Maximum}
- min := &attrValFloat{Val: opts.YAxis.Minimum}
- if opts.YAxis.Maximum == nil {
- max = nil
- }
- if opts.YAxis.Minimum == nil {
- min = nil
- }
- return []*cAxs{
- {
- AxID: &attrValInt{Val: intPtr(832256642)},
- Scaling: &cScaling{
- Orientation: &attrValString{Val: stringPtr(orientation[opts.YAxis.ReverseOrder])},
- Max: max,
- Min: min,
- },
- Delete: &attrValBool{Val: boolPtr(opts.YAxis.None)},
- AxPos: &attrValString{Val: stringPtr(catAxPos[opts.XAxis.ReverseOrder])},
- TickLblPos: &attrValString{Val: stringPtr("nextTo")},
- SpPr: f.drawPlotAreaSpPr(),
- TxPr: f.drawPlotAreaTxPr(nil),
- 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(opts *ChartAxis) *cTxPr {
- cTxPr := &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: &xlsxCTTextFont{Typeface: "+mn-lt"},
- Ea: &aEa{Typeface: "+mn-ea"},
- Cs: &aCs{Typeface: "+mn-cs"},
- },
- },
- EndParaRPr: &aEndParaRPr{Lang: "en-US"},
- },
- }
- if opts != nil {
- cTxPr.P.PPr.DefRPr.B = opts.Font.Bold
- cTxPr.P.PPr.DefRPr.I = opts.Font.Italic
- if idx := inStrSlice(supportedDrawingUnderlineTypes, opts.Font.Underline, true); idx != -1 {
- cTxPr.P.PPr.DefRPr.U = supportedDrawingUnderlineTypes[idx]
- }
- if opts.Font.Color != "" {
- cTxPr.P.PPr.DefRPr.SolidFill.SchemeClr = nil
- cTxPr.P.PPr.DefRPr.SolidFill.SrgbClr = &attrValString{Val: stringPtr(strings.ReplaceAll(strings.ToUpper(opts.Font.Color), "#", ""))}
- }
- }
- return cTxPr
- }
- // 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, error) {
- var (
- err error
- ok bool
- )
- _, ok = f.Drawings.Load(path)
- if !ok {
- content := xlsxWsDr{}
- content.A = NameSpaceDrawingML.Value
- content.Xdr = NameSpaceDrawingMLSpreadSheet.Value
- if _, ok = f.Pkg.Load(path); ok { // Append Model
- decodeWsDr := decodeWsDr{}
- if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).
- Decode(&decodeWsDr); err != nil && err != io.EOF {
- return nil, 0, err
- }
- content.R = decodeWsDr.R
- for _, v := range decodeWsDr.AlternateContent {
- content.AlternateContent = append(content.AlternateContent, &xlsxAlternateContent{
- Content: v.Content,
- XMLNSMC: SourceRelationshipCompatibility.Value,
- })
- }
- 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,
- })
- }
- }
- f.Drawings.Store(path, &content)
- }
- var wsDr *xlsxWsDr
- if drawing, ok := f.Drawings.Load(path); ok && drawing != nil {
- wsDr = drawing.(*xlsxWsDr)
- }
- wsDr.Lock()
- defer wsDr.Unlock()
- return wsDr, len(wsDr.OneCellAnchor) + len(wsDr.TwoCellAnchor) + 2, nil
- }
- // 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, opts *GraphicOptions) error {
- col, row, err := CellNameToCoordinates(cell)
- if err != nil {
- return err
- }
- colIdx := col - 1
- rowIdx := row - 1
- width = int(float64(width) * opts.ScaleX)
- height = int(float64(height) * opts.ScaleY)
- colStart, rowStart, colEnd, rowEnd, x2, y2 := f.positionObjectPixels(sheet, colIdx, rowIdx, opts.OffsetX, opts.OffsetY, width, height)
- content, cNvPrID, err := f.drawingParser(drawingXML)
- if err != nil {
- return err
- }
- twoCellAnchor := xdrCellAnchor{}
- twoCellAnchor.EditAs = opts.Positioning
- from := xlsxFrom{}
- from.Col = colStart
- from.ColOff = opts.OffsetX * EMU
- from.Row = rowStart
- from.RowOff = opts.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.Value,
- Chart: &xlsxChart{
- C: NameSpaceDrawingMLChart.Value,
- R: SourceRelationship.Value,
- RID: "rId" + strconv.Itoa(rID),
- },
- },
- },
- }
- graphic, _ := xml.Marshal(graphicFrame)
- twoCellAnchor.GraphicFrame = string(graphic)
- twoCellAnchor.ClientData = &xdrClientData{
- FLocksWithSheet: *opts.Locked,
- FPrintsWithSheet: *opts.PrintObject,
- }
- content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
- f.Drawings.Store(drawingXML, content)
- return err
- }
- // addSheetDrawingChart provides a function to add chart graphic frame for
- // chartsheet by given sheet, drawingXML, width, height, relationship index
- // and format sets.
- func (f *File) addSheetDrawingChart(drawingXML string, rID int, opts *GraphicOptions) error {
- content, cNvPrID, err := f.drawingParser(drawingXML)
- if err != nil {
- return err
- }
- absoluteAnchor := xdrCellAnchor{
- EditAs: opts.Positioning,
- Pos: &xlsxPoint2D{},
- Ext: &xlsxExt{},
- }
- graphicFrame := xlsxGraphicFrame{
- NvGraphicFramePr: xlsxNvGraphicFramePr{
- CNvPr: &xlsxCNvPr{
- ID: cNvPrID,
- Name: "Chart " + strconv.Itoa(cNvPrID),
- },
- },
- Graphic: &xlsxGraphic{
- GraphicData: &xlsxGraphicData{
- URI: NameSpaceDrawingMLChart.Value,
- Chart: &xlsxChart{
- C: NameSpaceDrawingMLChart.Value,
- R: SourceRelationship.Value,
- RID: "rId" + strconv.Itoa(rID),
- },
- },
- },
- }
- graphic, _ := xml.Marshal(graphicFrame)
- absoluteAnchor.GraphicFrame = string(graphic)
- absoluteAnchor.ClientData = &xdrClientData{
- FLocksWithSheet: *opts.Locked,
- FPrintsWithSheet: *opts.PrintObject,
- }
- content.AbsoluteAnchor = append(content.AbsoluteAnchor, &absoluteAnchor)
- f.Drawings.Store(drawingXML, content)
- return err
- }
- // deleteDrawing provides a function to delete chart graphic frame by given by
- // given coordinates and graphic type.
- func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) error {
- var (
- err error
- wsDr *xlsxWsDr
- deTwoCellAnchor *decodeTwoCellAnchor
- )
- xdrCellAnchorFuncs := map[string]func(anchor *xdrCellAnchor) bool{
- "Chart": func(anchor *xdrCellAnchor) bool { return anchor.Pic == nil },
- "Pic": func(anchor *xdrCellAnchor) bool { return anchor.Pic != nil },
- }
- decodeTwoCellAnchorFuncs := map[string]func(anchor *decodeTwoCellAnchor) bool{
- "Chart": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic == nil },
- "Pic": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic != nil },
- }
- if wsDr, _, err = f.drawingParser(drawingXML); err != nil {
- return err
- }
- for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
- if err = nil; wsDr.TwoCellAnchor[idx].From != nil && xdrCellAnchorFuncs[drawingType](wsDr.TwoCellAnchor[idx]) {
- if wsDr.TwoCellAnchor[idx].From.Col == col && wsDr.TwoCellAnchor[idx].From.Row == row {
- wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
- idx--
- }
- }
- }
- for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
- deTwoCellAnchor = new(decodeTwoCellAnchor)
- if err = f.xmlNewDecoder(strings.NewReader("<decodeTwoCellAnchor>" + wsDr.TwoCellAnchor[idx].GraphicFrame + "</decodeTwoCellAnchor>")).
- Decode(deTwoCellAnchor); err != nil && err != io.EOF {
- return err
- }
- if err = nil; deTwoCellAnchor.From != nil && decodeTwoCellAnchorFuncs[drawingType](deTwoCellAnchor) {
- if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
- wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
- idx--
- }
- }
- }
- f.Drawings.Store(drawingXML, wsDr)
- return err
- }
|