drawing.go 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323
  1. // Copyright 2016 - 2021 The excelize Authors. All rights reserved. Use of
  2. // this source code is governed by a BSD-style license that can be found in
  3. // the LICENSE file.
  4. //
  5. // Package excelize providing a set of functions that allow you to write to
  6. // and read from XLSX / XLSM / XLTM files. Supports reading and writing
  7. // spreadsheet documents generated by Microsoft Excel™ 2007 and later. Supports
  8. // complex components by high compatibility, and provided streaming API for
  9. // generating or reading data from a worksheet with huge amounts of data. This
  10. // library needs Go version 1.15 or later.
  11. package excelize
  12. import (
  13. "bytes"
  14. "encoding/xml"
  15. "fmt"
  16. "io"
  17. "log"
  18. "reflect"
  19. "strconv"
  20. "strings"
  21. )
  22. // prepareDrawing provides a function to prepare drawing ID and XML by given
  23. // drawingID, worksheet name and default drawingXML.
  24. func (f *File) prepareDrawing(ws *xlsxWorksheet, drawingID int, sheet, drawingXML string) (int, string) {
  25. sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
  26. if ws.Drawing != nil {
  27. // The worksheet already has a picture or chart relationships, use the relationships drawing ../drawings/drawing%d.xml.
  28. sheetRelationshipsDrawingXML = f.getSheetRelationshipsTargetByID(sheet, ws.Drawing.RID)
  29. drawingID, _ = strconv.Atoi(strings.TrimSuffix(strings.TrimPrefix(sheetRelationshipsDrawingXML, "../drawings/drawing"), ".xml"))
  30. drawingXML = strings.Replace(sheetRelationshipsDrawingXML, "..", "xl", -1)
  31. } else {
  32. // Add first picture for given sheet.
  33. sheetRels := "xl/worksheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/worksheets/") + ".rels"
  34. rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
  35. f.addSheetDrawing(sheet, rID)
  36. }
  37. return drawingID, drawingXML
  38. }
  39. // prepareChartSheetDrawing provides a function to prepare drawing ID and XML
  40. // by given drawingID, worksheet name and default drawingXML.
  41. func (f *File) prepareChartSheetDrawing(cs *xlsxChartsheet, drawingID int, sheet string) {
  42. sheetRelationshipsDrawingXML := "../drawings/drawing" + strconv.Itoa(drawingID) + ".xml"
  43. // Only allow one chart in a chartsheet.
  44. sheetRels := "xl/chartsheets/_rels/" + strings.TrimPrefix(f.sheetMap[trimSheetName(sheet)], "xl/chartsheets/") + ".rels"
  45. rID := f.addRels(sheetRels, SourceRelationshipDrawingML, sheetRelationshipsDrawingXML, "")
  46. f.addSheetNameSpace(sheet, SourceRelationship)
  47. cs.Drawing = &xlsxDrawing{
  48. RID: "rId" + strconv.Itoa(rID),
  49. }
  50. }
  51. // addChart provides a function to create chart as xl/charts/chart%d.xml by
  52. // given format sets.
  53. func (f *File) addChart(formatSet *formatChart, comboCharts []*formatChart) {
  54. count := f.countCharts()
  55. xlsxChartSpace := xlsxChartSpace{
  56. XMLNSa: NameSpaceDrawingML.Value,
  57. Date1904: &attrValBool{Val: boolPtr(false)},
  58. Lang: &attrValString{Val: stringPtr("en-US")},
  59. RoundedCorners: &attrValBool{Val: boolPtr(false)},
  60. Chart: cChart{
  61. Title: &cTitle{
  62. Tx: cTx{
  63. Rich: &cRich{
  64. P: aP{
  65. PPr: &aPPr{
  66. DefRPr: aRPr{
  67. Kern: 1200,
  68. Strike: "noStrike",
  69. U: "none",
  70. Sz: 1400,
  71. SolidFill: &aSolidFill{
  72. SchemeClr: &aSchemeClr{
  73. Val: "tx1",
  74. LumMod: &attrValInt{
  75. Val: intPtr(65000),
  76. },
  77. LumOff: &attrValInt{
  78. Val: intPtr(35000),
  79. },
  80. },
  81. },
  82. Ea: &aEa{
  83. Typeface: "+mn-ea",
  84. },
  85. Cs: &aCs{
  86. Typeface: "+mn-cs",
  87. },
  88. Latin: &aLatin{
  89. Typeface: "+mn-lt",
  90. },
  91. },
  92. },
  93. R: &aR{
  94. RPr: aRPr{
  95. Lang: "en-US",
  96. AltLang: "en-US",
  97. },
  98. T: formatSet.Title.Name,
  99. },
  100. },
  101. },
  102. },
  103. TxPr: cTxPr{
  104. P: aP{
  105. PPr: &aPPr{
  106. DefRPr: aRPr{
  107. Kern: 1200,
  108. U: "none",
  109. Sz: 14000,
  110. Strike: "noStrike",
  111. },
  112. },
  113. EndParaRPr: &aEndParaRPr{
  114. Lang: "en-US",
  115. },
  116. },
  117. },
  118. Overlay: &attrValBool{Val: boolPtr(false)},
  119. },
  120. View3D: &cView3D{
  121. RotX: &attrValInt{Val: intPtr(chartView3DRotX[formatSet.Type])},
  122. RotY: &attrValInt{Val: intPtr(chartView3DRotY[formatSet.Type])},
  123. Perspective: &attrValInt{Val: intPtr(chartView3DPerspective[formatSet.Type])},
  124. RAngAx: &attrValInt{Val: intPtr(chartView3DRAngAx[formatSet.Type])},
  125. },
  126. Floor: &cThicknessSpPr{
  127. Thickness: &attrValInt{Val: intPtr(0)},
  128. },
  129. SideWall: &cThicknessSpPr{
  130. Thickness: &attrValInt{Val: intPtr(0)},
  131. },
  132. BackWall: &cThicknessSpPr{
  133. Thickness: &attrValInt{Val: intPtr(0)},
  134. },
  135. PlotArea: &cPlotArea{},
  136. Legend: &cLegend{
  137. LegendPos: &attrValString{Val: stringPtr(chartLegendPosition[formatSet.Legend.Position])},
  138. Overlay: &attrValBool{Val: boolPtr(false)},
  139. },
  140. PlotVisOnly: &attrValBool{Val: boolPtr(false)},
  141. DispBlanksAs: &attrValString{Val: stringPtr(formatSet.ShowBlanksAs)},
  142. ShowDLblsOverMax: &attrValBool{Val: boolPtr(false)},
  143. },
  144. SpPr: &cSpPr{
  145. SolidFill: &aSolidFill{
  146. SchemeClr: &aSchemeClr{Val: "bg1"},
  147. },
  148. Ln: &aLn{
  149. W: 9525,
  150. Cap: "flat",
  151. Cmpd: "sng",
  152. Algn: "ctr",
  153. SolidFill: &aSolidFill{
  154. SchemeClr: &aSchemeClr{Val: "tx1",
  155. LumMod: &attrValInt{
  156. Val: intPtr(15000),
  157. },
  158. LumOff: &attrValInt{
  159. Val: intPtr(85000),
  160. },
  161. },
  162. },
  163. },
  164. },
  165. PrintSettings: &cPrintSettings{
  166. PageMargins: &cPageMargins{
  167. B: 0.75,
  168. L: 0.7,
  169. R: 0.7,
  170. T: 0.7,
  171. Header: 0.3,
  172. Footer: 0.3,
  173. },
  174. },
  175. }
  176. plotAreaFunc := map[string]func(*formatChart) *cPlotArea{
  177. Area: f.drawBaseChart,
  178. AreaStacked: f.drawBaseChart,
  179. AreaPercentStacked: f.drawBaseChart,
  180. Area3D: f.drawBaseChart,
  181. Area3DStacked: f.drawBaseChart,
  182. Area3DPercentStacked: f.drawBaseChart,
  183. Bar: f.drawBaseChart,
  184. BarStacked: f.drawBaseChart,
  185. BarPercentStacked: f.drawBaseChart,
  186. Bar3DClustered: f.drawBaseChart,
  187. Bar3DStacked: f.drawBaseChart,
  188. Bar3DPercentStacked: f.drawBaseChart,
  189. Bar3DConeClustered: f.drawBaseChart,
  190. Bar3DConeStacked: f.drawBaseChart,
  191. Bar3DConePercentStacked: f.drawBaseChart,
  192. Bar3DPyramidClustered: f.drawBaseChart,
  193. Bar3DPyramidStacked: f.drawBaseChart,
  194. Bar3DPyramidPercentStacked: f.drawBaseChart,
  195. Bar3DCylinderClustered: f.drawBaseChart,
  196. Bar3DCylinderStacked: f.drawBaseChart,
  197. Bar3DCylinderPercentStacked: f.drawBaseChart,
  198. Col: f.drawBaseChart,
  199. ColStacked: f.drawBaseChart,
  200. ColPercentStacked: f.drawBaseChart,
  201. Col3D: f.drawBaseChart,
  202. Col3DClustered: f.drawBaseChart,
  203. Col3DStacked: f.drawBaseChart,
  204. Col3DPercentStacked: f.drawBaseChart,
  205. Col3DCone: f.drawBaseChart,
  206. Col3DConeClustered: f.drawBaseChart,
  207. Col3DConeStacked: f.drawBaseChart,
  208. Col3DConePercentStacked: f.drawBaseChart,
  209. Col3DPyramid: f.drawBaseChart,
  210. Col3DPyramidClustered: f.drawBaseChart,
  211. Col3DPyramidStacked: f.drawBaseChart,
  212. Col3DPyramidPercentStacked: f.drawBaseChart,
  213. Col3DCylinder: f.drawBaseChart,
  214. Col3DCylinderClustered: f.drawBaseChart,
  215. Col3DCylinderStacked: f.drawBaseChart,
  216. Col3DCylinderPercentStacked: f.drawBaseChart,
  217. Doughnut: f.drawDoughnutChart,
  218. Line: f.drawLineChart,
  219. Pie3D: f.drawPie3DChart,
  220. Pie: f.drawPieChart,
  221. PieOfPieChart: f.drawPieOfPieChart,
  222. BarOfPieChart: f.drawBarOfPieChart,
  223. Radar: f.drawRadarChart,
  224. Scatter: f.drawScatterChart,
  225. Surface3D: f.drawSurface3DChart,
  226. WireframeSurface3D: f.drawSurface3DChart,
  227. Contour: f.drawSurfaceChart,
  228. WireframeContour: f.drawSurfaceChart,
  229. Bubble: f.drawBaseChart,
  230. Bubble3D: f.drawBaseChart,
  231. }
  232. if formatSet.Legend.None {
  233. xlsxChartSpace.Chart.Legend = nil
  234. }
  235. addChart := func(c, p *cPlotArea) {
  236. immutable, mutable := reflect.ValueOf(c).Elem(), reflect.ValueOf(p).Elem()
  237. for i := 0; i < mutable.NumField(); i++ {
  238. field := mutable.Field(i)
  239. if field.IsNil() {
  240. continue
  241. }
  242. immutable.FieldByName(mutable.Type().Field(i).Name).Set(field)
  243. }
  244. }
  245. addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[formatSet.Type](formatSet))
  246. order := len(formatSet.Series)
  247. for idx := range comboCharts {
  248. comboCharts[idx].order = order
  249. addChart(xlsxChartSpace.Chart.PlotArea, plotAreaFunc[comboCharts[idx].Type](comboCharts[idx]))
  250. order += len(comboCharts[idx].Series)
  251. }
  252. chart, _ := xml.Marshal(xlsxChartSpace)
  253. media := "xl/charts/chart" + strconv.Itoa(count+1) + ".xml"
  254. f.saveFileList(media, chart)
  255. }
  256. // drawBaseChart provides a function to draw the c:plotArea element for bar,
  257. // and column series charts by given format sets.
  258. func (f *File) drawBaseChart(formatSet *formatChart) *cPlotArea {
  259. c := cCharts{
  260. BarDir: &attrValString{
  261. Val: stringPtr("col"),
  262. },
  263. Grouping: &attrValString{
  264. Val: stringPtr("clustered"),
  265. },
  266. VaryColors: &attrValBool{
  267. Val: boolPtr(formatSet.VaryColors),
  268. },
  269. Ser: f.drawChartSeries(formatSet),
  270. Shape: f.drawChartShape(formatSet),
  271. DLbls: f.drawChartDLbls(formatSet),
  272. AxID: []*attrValInt{
  273. {Val: intPtr(754001152)},
  274. {Val: intPtr(753999904)},
  275. },
  276. Overlap: &attrValInt{Val: intPtr(100)},
  277. }
  278. var ok bool
  279. if *c.BarDir.Val, ok = plotAreaChartBarDir[formatSet.Type]; !ok {
  280. c.BarDir = nil
  281. }
  282. if *c.Grouping.Val, ok = plotAreaChartGrouping[formatSet.Type]; !ok {
  283. c.Grouping = nil
  284. }
  285. if *c.Overlap.Val, ok = plotAreaChartOverlap[formatSet.Type]; !ok {
  286. c.Overlap = nil
  287. }
  288. catAx := f.drawPlotAreaCatAx(formatSet)
  289. valAx := f.drawPlotAreaValAx(formatSet)
  290. charts := map[string]*cPlotArea{
  291. "area": {
  292. AreaChart: &c,
  293. CatAx: catAx,
  294. ValAx: valAx,
  295. },
  296. "areaStacked": {
  297. AreaChart: &c,
  298. CatAx: catAx,
  299. ValAx: valAx,
  300. },
  301. "areaPercentStacked": {
  302. AreaChart: &c,
  303. CatAx: catAx,
  304. ValAx: valAx,
  305. },
  306. "area3D": {
  307. Area3DChart: &c,
  308. CatAx: catAx,
  309. ValAx: valAx,
  310. },
  311. "area3DStacked": {
  312. Area3DChart: &c,
  313. CatAx: catAx,
  314. ValAx: valAx,
  315. },
  316. "area3DPercentStacked": {
  317. Area3DChart: &c,
  318. CatAx: catAx,
  319. ValAx: valAx,
  320. },
  321. "bar": {
  322. BarChart: &c,
  323. CatAx: catAx,
  324. ValAx: valAx,
  325. },
  326. "barStacked": {
  327. BarChart: &c,
  328. CatAx: catAx,
  329. ValAx: valAx,
  330. },
  331. "barPercentStacked": {
  332. BarChart: &c,
  333. CatAx: catAx,
  334. ValAx: valAx,
  335. },
  336. "bar3DClustered": {
  337. Bar3DChart: &c,
  338. CatAx: catAx,
  339. ValAx: valAx,
  340. },
  341. "bar3DStacked": {
  342. Bar3DChart: &c,
  343. CatAx: catAx,
  344. ValAx: valAx,
  345. },
  346. "bar3DPercentStacked": {
  347. Bar3DChart: &c,
  348. CatAx: catAx,
  349. ValAx: valAx,
  350. },
  351. "bar3DConeClustered": {
  352. Bar3DChart: &c,
  353. CatAx: catAx,
  354. ValAx: valAx,
  355. },
  356. "bar3DConeStacked": {
  357. Bar3DChart: &c,
  358. CatAx: catAx,
  359. ValAx: valAx,
  360. },
  361. "bar3DConePercentStacked": {
  362. Bar3DChart: &c,
  363. CatAx: catAx,
  364. ValAx: valAx,
  365. },
  366. "bar3DPyramidClustered": {
  367. Bar3DChart: &c,
  368. CatAx: catAx,
  369. ValAx: valAx,
  370. },
  371. "bar3DPyramidStacked": {
  372. Bar3DChart: &c,
  373. CatAx: catAx,
  374. ValAx: valAx,
  375. },
  376. "bar3DPyramidPercentStacked": {
  377. Bar3DChart: &c,
  378. CatAx: catAx,
  379. ValAx: valAx,
  380. },
  381. "bar3DCylinderClustered": {
  382. Bar3DChart: &c,
  383. CatAx: catAx,
  384. ValAx: valAx,
  385. },
  386. "bar3DCylinderStacked": {
  387. Bar3DChart: &c,
  388. CatAx: catAx,
  389. ValAx: valAx,
  390. },
  391. "bar3DCylinderPercentStacked": {
  392. Bar3DChart: &c,
  393. CatAx: catAx,
  394. ValAx: valAx,
  395. },
  396. "col": {
  397. BarChart: &c,
  398. CatAx: catAx,
  399. ValAx: valAx,
  400. },
  401. "colStacked": {
  402. BarChart: &c,
  403. CatAx: catAx,
  404. ValAx: valAx,
  405. },
  406. "colPercentStacked": {
  407. BarChart: &c,
  408. CatAx: catAx,
  409. ValAx: valAx,
  410. },
  411. "col3D": {
  412. Bar3DChart: &c,
  413. CatAx: catAx,
  414. ValAx: valAx,
  415. },
  416. "col3DClustered": {
  417. Bar3DChart: &c,
  418. CatAx: catAx,
  419. ValAx: valAx,
  420. },
  421. "col3DStacked": {
  422. Bar3DChart: &c,
  423. CatAx: catAx,
  424. ValAx: valAx,
  425. },
  426. "col3DPercentStacked": {
  427. Bar3DChart: &c,
  428. CatAx: catAx,
  429. ValAx: valAx,
  430. },
  431. "col3DCone": {
  432. Bar3DChart: &c,
  433. CatAx: catAx,
  434. ValAx: valAx,
  435. },
  436. "col3DConeClustered": {
  437. Bar3DChart: &c,
  438. CatAx: catAx,
  439. ValAx: valAx,
  440. },
  441. "col3DConeStacked": {
  442. Bar3DChart: &c,
  443. CatAx: catAx,
  444. ValAx: valAx,
  445. },
  446. "col3DConePercentStacked": {
  447. Bar3DChart: &c,
  448. CatAx: catAx,
  449. ValAx: valAx,
  450. },
  451. "col3DPyramid": {
  452. Bar3DChart: &c,
  453. CatAx: catAx,
  454. ValAx: valAx,
  455. },
  456. "col3DPyramidClustered": {
  457. Bar3DChart: &c,
  458. CatAx: catAx,
  459. ValAx: valAx,
  460. },
  461. "col3DPyramidStacked": {
  462. Bar3DChart: &c,
  463. CatAx: catAx,
  464. ValAx: valAx,
  465. },
  466. "col3DPyramidPercentStacked": {
  467. Bar3DChart: &c,
  468. CatAx: catAx,
  469. ValAx: valAx,
  470. },
  471. "col3DCylinder": {
  472. Bar3DChart: &c,
  473. CatAx: catAx,
  474. ValAx: valAx,
  475. },
  476. "col3DCylinderClustered": {
  477. Bar3DChart: &c,
  478. CatAx: catAx,
  479. ValAx: valAx,
  480. },
  481. "col3DCylinderStacked": {
  482. Bar3DChart: &c,
  483. CatAx: catAx,
  484. ValAx: valAx,
  485. },
  486. "col3DCylinderPercentStacked": {
  487. Bar3DChart: &c,
  488. CatAx: catAx,
  489. ValAx: valAx,
  490. },
  491. "bubble": {
  492. BubbleChart: &c,
  493. CatAx: catAx,
  494. ValAx: valAx,
  495. },
  496. "bubble3D": {
  497. BubbleChart: &c,
  498. CatAx: catAx,
  499. ValAx: valAx,
  500. },
  501. }
  502. return charts[formatSet.Type]
  503. }
  504. // drawDoughnutChart provides a function to draw the c:plotArea element for
  505. // doughnut chart by given format sets.
  506. func (f *File) drawDoughnutChart(formatSet *formatChart) *cPlotArea {
  507. return &cPlotArea{
  508. DoughnutChart: &cCharts{
  509. VaryColors: &attrValBool{
  510. Val: boolPtr(formatSet.VaryColors),
  511. },
  512. Ser: f.drawChartSeries(formatSet),
  513. HoleSize: &attrValInt{Val: intPtr(75)},
  514. },
  515. }
  516. }
  517. // drawLineChart provides a function to draw the c:plotArea element for line
  518. // chart by given format sets.
  519. func (f *File) drawLineChart(formatSet *formatChart) *cPlotArea {
  520. return &cPlotArea{
  521. LineChart: &cCharts{
  522. Grouping: &attrValString{
  523. Val: stringPtr(plotAreaChartGrouping[formatSet.Type]),
  524. },
  525. VaryColors: &attrValBool{
  526. Val: boolPtr(false),
  527. },
  528. Ser: f.drawChartSeries(formatSet),
  529. DLbls: f.drawChartDLbls(formatSet),
  530. Smooth: &attrValBool{
  531. Val: boolPtr(false),
  532. },
  533. AxID: []*attrValInt{
  534. {Val: intPtr(754001152)},
  535. {Val: intPtr(753999904)},
  536. },
  537. },
  538. CatAx: f.drawPlotAreaCatAx(formatSet),
  539. ValAx: f.drawPlotAreaValAx(formatSet),
  540. }
  541. }
  542. // drawPieChart provides a function to draw the c:plotArea element for pie
  543. // chart by given format sets.
  544. func (f *File) drawPieChart(formatSet *formatChart) *cPlotArea {
  545. return &cPlotArea{
  546. PieChart: &cCharts{
  547. VaryColors: &attrValBool{
  548. Val: boolPtr(formatSet.VaryColors),
  549. },
  550. Ser: f.drawChartSeries(formatSet),
  551. },
  552. }
  553. }
  554. // drawPie3DChart provides a function to draw the c:plotArea element for 3D
  555. // pie chart by given format sets.
  556. func (f *File) drawPie3DChart(formatSet *formatChart) *cPlotArea {
  557. return &cPlotArea{
  558. Pie3DChart: &cCharts{
  559. VaryColors: &attrValBool{
  560. Val: boolPtr(formatSet.VaryColors),
  561. },
  562. Ser: f.drawChartSeries(formatSet),
  563. },
  564. }
  565. }
  566. // drawPieOfPieChart provides a function to draw the c:plotArea element for
  567. // pie chart by given format sets.
  568. func (f *File) drawPieOfPieChart(formatSet *formatChart) *cPlotArea {
  569. return &cPlotArea{
  570. OfPieChart: &cCharts{
  571. OfPieType: &attrValString{
  572. Val: stringPtr("pie"),
  573. },
  574. VaryColors: &attrValBool{
  575. Val: boolPtr(formatSet.VaryColors),
  576. },
  577. Ser: f.drawChartSeries(formatSet),
  578. SerLines: &attrValString{},
  579. },
  580. }
  581. }
  582. // drawBarOfPieChart provides a function to draw the c:plotArea element for
  583. // pie chart by given format sets.
  584. func (f *File) drawBarOfPieChart(formatSet *formatChart) *cPlotArea {
  585. return &cPlotArea{
  586. OfPieChart: &cCharts{
  587. OfPieType: &attrValString{
  588. Val: stringPtr("bar"),
  589. },
  590. VaryColors: &attrValBool{
  591. Val: boolPtr(formatSet.VaryColors),
  592. },
  593. Ser: f.drawChartSeries(formatSet),
  594. SerLines: &attrValString{},
  595. },
  596. }
  597. }
  598. // drawRadarChart provides a function to draw the c:plotArea element for radar
  599. // chart by given format sets.
  600. func (f *File) drawRadarChart(formatSet *formatChart) *cPlotArea {
  601. return &cPlotArea{
  602. RadarChart: &cCharts{
  603. RadarStyle: &attrValString{
  604. Val: stringPtr("marker"),
  605. },
  606. VaryColors: &attrValBool{
  607. Val: boolPtr(false),
  608. },
  609. Ser: f.drawChartSeries(formatSet),
  610. DLbls: f.drawChartDLbls(formatSet),
  611. AxID: []*attrValInt{
  612. {Val: intPtr(754001152)},
  613. {Val: intPtr(753999904)},
  614. },
  615. },
  616. CatAx: f.drawPlotAreaCatAx(formatSet),
  617. ValAx: f.drawPlotAreaValAx(formatSet),
  618. }
  619. }
  620. // drawScatterChart provides a function to draw the c:plotArea element for
  621. // scatter chart by given format sets.
  622. func (f *File) drawScatterChart(formatSet *formatChart) *cPlotArea {
  623. return &cPlotArea{
  624. ScatterChart: &cCharts{
  625. ScatterStyle: &attrValString{
  626. Val: stringPtr("smoothMarker"), // line,lineMarker,marker,none,smooth,smoothMarker
  627. },
  628. VaryColors: &attrValBool{
  629. Val: boolPtr(false),
  630. },
  631. Ser: f.drawChartSeries(formatSet),
  632. DLbls: f.drawChartDLbls(formatSet),
  633. AxID: []*attrValInt{
  634. {Val: intPtr(754001152)},
  635. {Val: intPtr(753999904)},
  636. },
  637. },
  638. CatAx: f.drawPlotAreaCatAx(formatSet),
  639. ValAx: f.drawPlotAreaValAx(formatSet),
  640. }
  641. }
  642. // drawSurface3DChart provides a function to draw the c:surface3DChart element by
  643. // given format sets.
  644. func (f *File) drawSurface3DChart(formatSet *formatChart) *cPlotArea {
  645. plotArea := &cPlotArea{
  646. Surface3DChart: &cCharts{
  647. Ser: f.drawChartSeries(formatSet),
  648. AxID: []*attrValInt{
  649. {Val: intPtr(754001152)},
  650. {Val: intPtr(753999904)},
  651. {Val: intPtr(832256642)},
  652. },
  653. },
  654. CatAx: f.drawPlotAreaCatAx(formatSet),
  655. ValAx: f.drawPlotAreaValAx(formatSet),
  656. SerAx: f.drawPlotAreaSerAx(formatSet),
  657. }
  658. if formatSet.Type == WireframeSurface3D {
  659. plotArea.Surface3DChart.Wireframe = &attrValBool{Val: boolPtr(true)}
  660. }
  661. return plotArea
  662. }
  663. // drawSurfaceChart provides a function to draw the c:surfaceChart element by
  664. // given format sets.
  665. func (f *File) drawSurfaceChart(formatSet *formatChart) *cPlotArea {
  666. plotArea := &cPlotArea{
  667. SurfaceChart: &cCharts{
  668. Ser: f.drawChartSeries(formatSet),
  669. AxID: []*attrValInt{
  670. {Val: intPtr(754001152)},
  671. {Val: intPtr(753999904)},
  672. {Val: intPtr(832256642)},
  673. },
  674. },
  675. CatAx: f.drawPlotAreaCatAx(formatSet),
  676. ValAx: f.drawPlotAreaValAx(formatSet),
  677. SerAx: f.drawPlotAreaSerAx(formatSet),
  678. }
  679. if formatSet.Type == WireframeContour {
  680. plotArea.SurfaceChart.Wireframe = &attrValBool{Val: boolPtr(true)}
  681. }
  682. return plotArea
  683. }
  684. // drawChartShape provides a function to draw the c:shape element by given
  685. // format sets.
  686. func (f *File) drawChartShape(formatSet *formatChart) *attrValString {
  687. shapes := map[string]string{
  688. Bar3DConeClustered: "cone",
  689. Bar3DConeStacked: "cone",
  690. Bar3DConePercentStacked: "cone",
  691. Bar3DPyramidClustered: "pyramid",
  692. Bar3DPyramidStacked: "pyramid",
  693. Bar3DPyramidPercentStacked: "pyramid",
  694. Bar3DCylinderClustered: "cylinder",
  695. Bar3DCylinderStacked: "cylinder",
  696. Bar3DCylinderPercentStacked: "cylinder",
  697. Col3DCone: "cone",
  698. Col3DConeClustered: "cone",
  699. Col3DConeStacked: "cone",
  700. Col3DConePercentStacked: "cone",
  701. Col3DPyramid: "pyramid",
  702. Col3DPyramidClustered: "pyramid",
  703. Col3DPyramidStacked: "pyramid",
  704. Col3DPyramidPercentStacked: "pyramid",
  705. Col3DCylinder: "cylinder",
  706. Col3DCylinderClustered: "cylinder",
  707. Col3DCylinderStacked: "cylinder",
  708. Col3DCylinderPercentStacked: "cylinder",
  709. }
  710. if shape, ok := shapes[formatSet.Type]; ok {
  711. return &attrValString{Val: stringPtr(shape)}
  712. }
  713. return nil
  714. }
  715. // drawChartSeries provides a function to draw the c:ser element by given
  716. // format sets.
  717. func (f *File) drawChartSeries(formatSet *formatChart) *[]cSer {
  718. ser := []cSer{}
  719. for k := range formatSet.Series {
  720. ser = append(ser, cSer{
  721. IDx: &attrValInt{Val: intPtr(k + formatSet.order)},
  722. Order: &attrValInt{Val: intPtr(k + formatSet.order)},
  723. Tx: &cTx{
  724. StrRef: &cStrRef{
  725. F: formatSet.Series[k].Name,
  726. },
  727. },
  728. SpPr: f.drawChartSeriesSpPr(k, formatSet),
  729. Marker: f.drawChartSeriesMarker(k, formatSet),
  730. DPt: f.drawChartSeriesDPt(k, formatSet),
  731. DLbls: f.drawChartSeriesDLbls(formatSet),
  732. InvertIfNegative: &attrValBool{Val: boolPtr(false)},
  733. Cat: f.drawChartSeriesCat(formatSet.Series[k], formatSet),
  734. Val: f.drawChartSeriesVal(formatSet.Series[k], formatSet),
  735. XVal: f.drawChartSeriesXVal(formatSet.Series[k], formatSet),
  736. YVal: f.drawChartSeriesYVal(formatSet.Series[k], formatSet),
  737. BubbleSize: f.drawCharSeriesBubbleSize(formatSet.Series[k], formatSet),
  738. Bubble3D: f.drawCharSeriesBubble3D(formatSet),
  739. })
  740. }
  741. return &ser
  742. }
  743. // drawChartSeriesSpPr provides a function to draw the c:spPr element by given
  744. // format sets.
  745. func (f *File) drawChartSeriesSpPr(i int, formatSet *formatChart) *cSpPr {
  746. spPrScatter := &cSpPr{
  747. Ln: &aLn{
  748. W: 25400,
  749. NoFill: " ",
  750. },
  751. }
  752. spPrLine := &cSpPr{
  753. Ln: &aLn{
  754. W: f.ptToEMUs(formatSet.Series[i].Line.Width),
  755. Cap: "rnd", // rnd, sq, flat
  756. SolidFill: &aSolidFill{
  757. SchemeClr: &aSchemeClr{Val: "accent" + strconv.Itoa((formatSet.order+i)%6+1)},
  758. },
  759. },
  760. }
  761. chartSeriesSpPr := map[string]*cSpPr{Line: spPrLine, Scatter: spPrScatter}
  762. return chartSeriesSpPr[formatSet.Type]
  763. }
  764. // drawChartSeriesDPt provides a function to draw the c:dPt element by given
  765. // data index and format sets.
  766. func (f *File) drawChartSeriesDPt(i int, formatSet *formatChart) []*cDPt {
  767. dpt := []*cDPt{{
  768. IDx: &attrValInt{Val: intPtr(i)},
  769. Bubble3D: &attrValBool{Val: boolPtr(false)},
  770. SpPr: &cSpPr{
  771. SolidFill: &aSolidFill{
  772. SchemeClr: &aSchemeClr{Val: "accent" + strconv.Itoa(i+1)},
  773. },
  774. Ln: &aLn{
  775. W: 25400,
  776. Cap: "rnd",
  777. SolidFill: &aSolidFill{
  778. SchemeClr: &aSchemeClr{Val: "lt" + strconv.Itoa(i+1)},
  779. },
  780. },
  781. Sp3D: &aSp3D{
  782. ContourW: 25400,
  783. ContourClr: &aContourClr{
  784. SchemeClr: &aSchemeClr{Val: "lt" + strconv.Itoa(i+1)},
  785. },
  786. },
  787. },
  788. }}
  789. chartSeriesDPt := map[string][]*cDPt{Pie: dpt, Pie3D: dpt}
  790. return chartSeriesDPt[formatSet.Type]
  791. }
  792. // drawChartSeriesCat provides a function to draw the c:cat element by given
  793. // chart series and format sets.
  794. func (f *File) drawChartSeriesCat(v formatChartSeries, formatSet *formatChart) *cCat {
  795. cat := &cCat{
  796. StrRef: &cStrRef{
  797. F: v.Categories,
  798. },
  799. }
  800. chartSeriesCat := map[string]*cCat{Scatter: nil, Bubble: nil, Bubble3D: nil}
  801. if _, ok := chartSeriesCat[formatSet.Type]; ok || v.Categories == "" {
  802. return nil
  803. }
  804. return cat
  805. }
  806. // drawChartSeriesVal provides a function to draw the c:val element by given
  807. // chart series and format sets.
  808. func (f *File) drawChartSeriesVal(v formatChartSeries, formatSet *formatChart) *cVal {
  809. val := &cVal{
  810. NumRef: &cNumRef{
  811. F: v.Values,
  812. },
  813. }
  814. chartSeriesVal := map[string]*cVal{Scatter: nil, Bubble: nil, Bubble3D: nil}
  815. if _, ok := chartSeriesVal[formatSet.Type]; ok {
  816. return nil
  817. }
  818. return val
  819. }
  820. // drawChartSeriesMarker provides a function to draw the c:marker element by
  821. // given data index and format sets.
  822. func (f *File) drawChartSeriesMarker(i int, formatSet *formatChart) *cMarker {
  823. defaultSymbol := map[string]*attrValString{Scatter: {Val: stringPtr("circle")}}
  824. marker := &cMarker{
  825. Symbol: defaultSymbol[formatSet.Type],
  826. Size: &attrValInt{Val: intPtr(5)},
  827. }
  828. if symbol := stringPtr(formatSet.Series[i].Marker.Symbol); *symbol != "" {
  829. marker.Symbol = &attrValString{Val: symbol}
  830. }
  831. if size := intPtr(formatSet.Series[i].Marker.Size); *size != 0 {
  832. marker.Size = &attrValInt{Val: size}
  833. }
  834. if i < 6 {
  835. marker.SpPr = &cSpPr{
  836. SolidFill: &aSolidFill{
  837. SchemeClr: &aSchemeClr{
  838. Val: "accent" + strconv.Itoa(i+1),
  839. },
  840. },
  841. Ln: &aLn{
  842. W: 9252,
  843. SolidFill: &aSolidFill{
  844. SchemeClr: &aSchemeClr{
  845. Val: "accent" + strconv.Itoa(i+1),
  846. },
  847. },
  848. },
  849. }
  850. }
  851. chartSeriesMarker := map[string]*cMarker{Scatter: marker, Line: marker}
  852. return chartSeriesMarker[formatSet.Type]
  853. }
  854. // drawChartSeriesXVal provides a function to draw the c:xVal element by given
  855. // chart series and format sets.
  856. func (f *File) drawChartSeriesXVal(v formatChartSeries, formatSet *formatChart) *cCat {
  857. cat := &cCat{
  858. StrRef: &cStrRef{
  859. F: v.Categories,
  860. },
  861. }
  862. chartSeriesXVal := map[string]*cCat{Scatter: cat}
  863. return chartSeriesXVal[formatSet.Type]
  864. }
  865. // drawChartSeriesYVal provides a function to draw the c:yVal element by given
  866. // chart series and format sets.
  867. func (f *File) drawChartSeriesYVal(v formatChartSeries, formatSet *formatChart) *cVal {
  868. val := &cVal{
  869. NumRef: &cNumRef{
  870. F: v.Values,
  871. },
  872. }
  873. chartSeriesYVal := map[string]*cVal{Scatter: val, Bubble: val, Bubble3D: val}
  874. return chartSeriesYVal[formatSet.Type]
  875. }
  876. // drawCharSeriesBubbleSize provides a function to draw the c:bubbleSize
  877. // element by given chart series and format sets.
  878. func (f *File) drawCharSeriesBubbleSize(v formatChartSeries, formatSet *formatChart) *cVal {
  879. if _, ok := map[string]bool{Bubble: true, Bubble3D: true}[formatSet.Type]; !ok {
  880. return nil
  881. }
  882. return &cVal{
  883. NumRef: &cNumRef{
  884. F: v.Values,
  885. },
  886. }
  887. }
  888. // drawCharSeriesBubble3D provides a function to draw the c:bubble3D element
  889. // by given format sets.
  890. func (f *File) drawCharSeriesBubble3D(formatSet *formatChart) *attrValBool {
  891. if _, ok := map[string]bool{Bubble3D: true}[formatSet.Type]; !ok {
  892. return nil
  893. }
  894. return &attrValBool{Val: boolPtr(true)}
  895. }
  896. // drawChartDLbls provides a function to draw the c:dLbls element by given
  897. // format sets.
  898. func (f *File) drawChartDLbls(formatSet *formatChart) *cDLbls {
  899. return &cDLbls{
  900. ShowLegendKey: &attrValBool{Val: boolPtr(formatSet.Legend.ShowLegendKey)},
  901. ShowVal: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowVal)},
  902. ShowCatName: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowCatName)},
  903. ShowSerName: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowSerName)},
  904. ShowBubbleSize: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowBubbleSize)},
  905. ShowPercent: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowPercent)},
  906. ShowLeaderLines: &attrValBool{Val: boolPtr(formatSet.Plotarea.ShowLeaderLines)},
  907. }
  908. }
  909. // drawChartSeriesDLbls provides a function to draw the c:dLbls element by
  910. // given format sets.
  911. func (f *File) drawChartSeriesDLbls(formatSet *formatChart) *cDLbls {
  912. dLbls := f.drawChartDLbls(formatSet)
  913. chartSeriesDLbls := map[string]*cDLbls{
  914. Scatter: nil, Surface3D: nil, WireframeSurface3D: nil, Contour: nil, WireframeContour: nil, Bubble: nil, Bubble3D: nil}
  915. if _, ok := chartSeriesDLbls[formatSet.Type]; ok {
  916. return nil
  917. }
  918. return dLbls
  919. }
  920. // drawPlotAreaCatAx provides a function to draw the c:catAx element.
  921. func (f *File) drawPlotAreaCatAx(formatSet *formatChart) []*cAxs {
  922. min := &attrValFloat{Val: float64Ptr(formatSet.XAxis.Minimum)}
  923. max := &attrValFloat{Val: float64Ptr(formatSet.XAxis.Maximum)}
  924. if formatSet.XAxis.Minimum == 0 {
  925. min = nil
  926. }
  927. if formatSet.XAxis.Maximum == 0 {
  928. max = nil
  929. }
  930. axs := []*cAxs{
  931. {
  932. AxID: &attrValInt{Val: intPtr(754001152)},
  933. Scaling: &cScaling{
  934. Orientation: &attrValString{Val: stringPtr(orientation[formatSet.XAxis.ReverseOrder])},
  935. Max: max,
  936. Min: min,
  937. },
  938. Delete: &attrValBool{Val: boolPtr(formatSet.XAxis.None)},
  939. AxPos: &attrValString{Val: stringPtr(catAxPos[formatSet.XAxis.ReverseOrder])},
  940. NumFmt: &cNumFmt{
  941. FormatCode: "General",
  942. SourceLinked: true,
  943. },
  944. MajorTickMark: &attrValString{Val: stringPtr("none")},
  945. MinorTickMark: &attrValString{Val: stringPtr("none")},
  946. TickLblPos: &attrValString{Val: stringPtr("nextTo")},
  947. SpPr: f.drawPlotAreaSpPr(),
  948. TxPr: f.drawPlotAreaTxPr(),
  949. CrossAx: &attrValInt{Val: intPtr(753999904)},
  950. Crosses: &attrValString{Val: stringPtr("autoZero")},
  951. Auto: &attrValBool{Val: boolPtr(true)},
  952. LblAlgn: &attrValString{Val: stringPtr("ctr")},
  953. LblOffset: &attrValInt{Val: intPtr(100)},
  954. NoMultiLvlLbl: &attrValBool{Val: boolPtr(false)},
  955. },
  956. }
  957. if formatSet.XAxis.MajorGridlines {
  958. axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
  959. }
  960. if formatSet.XAxis.MinorGridlines {
  961. axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
  962. }
  963. if formatSet.XAxis.TickLabelSkip != 0 {
  964. axs[0].TickLblSkip = &attrValInt{Val: intPtr(formatSet.XAxis.TickLabelSkip)}
  965. }
  966. return axs
  967. }
  968. // drawPlotAreaValAx provides a function to draw the c:valAx element.
  969. func (f *File) drawPlotAreaValAx(formatSet *formatChart) []*cAxs {
  970. min := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Minimum)}
  971. max := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Maximum)}
  972. if formatSet.YAxis.Minimum == 0 {
  973. min = nil
  974. }
  975. if formatSet.YAxis.Maximum == 0 {
  976. max = nil
  977. }
  978. var logBase *attrValFloat
  979. if formatSet.YAxis.LogBase >= 2 && formatSet.YAxis.LogBase <= 1000 {
  980. logBase = &attrValFloat{Val: float64Ptr(formatSet.YAxis.LogBase)}
  981. }
  982. axs := []*cAxs{
  983. {
  984. AxID: &attrValInt{Val: intPtr(753999904)},
  985. Scaling: &cScaling{
  986. LogBase: logBase,
  987. Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
  988. Max: max,
  989. Min: min,
  990. },
  991. Delete: &attrValBool{Val: boolPtr(formatSet.YAxis.None)},
  992. AxPos: &attrValString{Val: stringPtr(valAxPos[formatSet.YAxis.ReverseOrder])},
  993. NumFmt: &cNumFmt{
  994. FormatCode: chartValAxNumFmtFormatCode[formatSet.Type],
  995. SourceLinked: true,
  996. },
  997. MajorTickMark: &attrValString{Val: stringPtr("none")},
  998. MinorTickMark: &attrValString{Val: stringPtr("none")},
  999. TickLblPos: &attrValString{Val: stringPtr("nextTo")},
  1000. SpPr: f.drawPlotAreaSpPr(),
  1001. TxPr: f.drawPlotAreaTxPr(),
  1002. CrossAx: &attrValInt{Val: intPtr(754001152)},
  1003. Crosses: &attrValString{Val: stringPtr("autoZero")},
  1004. CrossBetween: &attrValString{Val: stringPtr(chartValAxCrossBetween[formatSet.Type])},
  1005. },
  1006. }
  1007. if formatSet.YAxis.MajorGridlines {
  1008. axs[0].MajorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
  1009. }
  1010. if formatSet.YAxis.MinorGridlines {
  1011. axs[0].MinorGridlines = &cChartLines{SpPr: f.drawPlotAreaSpPr()}
  1012. }
  1013. if pos, ok := valTickLblPos[formatSet.Type]; ok {
  1014. axs[0].TickLblPos.Val = stringPtr(pos)
  1015. }
  1016. if formatSet.YAxis.MajorUnit != 0 {
  1017. axs[0].MajorUnit = &attrValFloat{Val: float64Ptr(formatSet.YAxis.MajorUnit)}
  1018. }
  1019. return axs
  1020. }
  1021. // drawPlotAreaSerAx provides a function to draw the c:serAx element.
  1022. func (f *File) drawPlotAreaSerAx(formatSet *formatChart) []*cAxs {
  1023. min := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Minimum)}
  1024. max := &attrValFloat{Val: float64Ptr(formatSet.YAxis.Maximum)}
  1025. if formatSet.YAxis.Minimum == 0 {
  1026. min = nil
  1027. }
  1028. if formatSet.YAxis.Maximum == 0 {
  1029. max = nil
  1030. }
  1031. return []*cAxs{
  1032. {
  1033. AxID: &attrValInt{Val: intPtr(832256642)},
  1034. Scaling: &cScaling{
  1035. Orientation: &attrValString{Val: stringPtr(orientation[formatSet.YAxis.ReverseOrder])},
  1036. Max: max,
  1037. Min: min,
  1038. },
  1039. Delete: &attrValBool{Val: boolPtr(formatSet.YAxis.None)},
  1040. AxPos: &attrValString{Val: stringPtr(catAxPos[formatSet.XAxis.ReverseOrder])},
  1041. TickLblPos: &attrValString{Val: stringPtr("nextTo")},
  1042. SpPr: f.drawPlotAreaSpPr(),
  1043. TxPr: f.drawPlotAreaTxPr(),
  1044. CrossAx: &attrValInt{Val: intPtr(753999904)},
  1045. },
  1046. }
  1047. }
  1048. // drawPlotAreaSpPr provides a function to draw the c:spPr element.
  1049. func (f *File) drawPlotAreaSpPr() *cSpPr {
  1050. return &cSpPr{
  1051. Ln: &aLn{
  1052. W: 9525,
  1053. Cap: "flat",
  1054. Cmpd: "sng",
  1055. Algn: "ctr",
  1056. SolidFill: &aSolidFill{
  1057. SchemeClr: &aSchemeClr{
  1058. Val: "tx1",
  1059. LumMod: &attrValInt{Val: intPtr(15000)},
  1060. LumOff: &attrValInt{Val: intPtr(85000)},
  1061. },
  1062. },
  1063. },
  1064. }
  1065. }
  1066. // drawPlotAreaTxPr provides a function to draw the c:txPr element.
  1067. func (f *File) drawPlotAreaTxPr() *cTxPr {
  1068. return &cTxPr{
  1069. BodyPr: aBodyPr{
  1070. Rot: -60000000,
  1071. SpcFirstLastPara: true,
  1072. VertOverflow: "ellipsis",
  1073. Vert: "horz",
  1074. Wrap: "square",
  1075. Anchor: "ctr",
  1076. AnchorCtr: true,
  1077. },
  1078. P: aP{
  1079. PPr: &aPPr{
  1080. DefRPr: aRPr{
  1081. Sz: 900,
  1082. B: false,
  1083. I: false,
  1084. U: "none",
  1085. Strike: "noStrike",
  1086. Kern: 1200,
  1087. Baseline: 0,
  1088. SolidFill: &aSolidFill{
  1089. SchemeClr: &aSchemeClr{
  1090. Val: "tx1",
  1091. LumMod: &attrValInt{Val: intPtr(15000)},
  1092. LumOff: &attrValInt{Val: intPtr(85000)},
  1093. },
  1094. },
  1095. Latin: &aLatin{Typeface: "+mn-lt"},
  1096. Ea: &aEa{Typeface: "+mn-ea"},
  1097. Cs: &aCs{Typeface: "+mn-cs"},
  1098. },
  1099. },
  1100. EndParaRPr: &aEndParaRPr{Lang: "en-US"},
  1101. },
  1102. }
  1103. }
  1104. // drawingParser provides a function to parse drawingXML. In order to solve
  1105. // the problem that the label structure is changed after serialization and
  1106. // deserialization, two different structures: decodeWsDr and encodeWsDr are
  1107. // defined.
  1108. func (f *File) drawingParser(path string) (*xlsxWsDr, int) {
  1109. var (
  1110. err error
  1111. ok bool
  1112. )
  1113. _, ok = f.Drawings.Load(path)
  1114. if !ok {
  1115. content := xlsxWsDr{}
  1116. content.A = NameSpaceDrawingML.Value
  1117. content.Xdr = NameSpaceDrawingMLSpreadSheet.Value
  1118. if _, ok = f.Pkg.Load(path); ok { // Append Model
  1119. decodeWsDr := decodeWsDr{}
  1120. if err = f.xmlNewDecoder(bytes.NewReader(namespaceStrictToTransitional(f.readXML(path)))).
  1121. Decode(&decodeWsDr); err != nil && err != io.EOF {
  1122. log.Printf("xml decode error: %s", err)
  1123. }
  1124. content.R = decodeWsDr.R
  1125. for _, v := range decodeWsDr.OneCellAnchor {
  1126. content.OneCellAnchor = append(content.OneCellAnchor, &xdrCellAnchor{
  1127. EditAs: v.EditAs,
  1128. GraphicFrame: v.Content,
  1129. })
  1130. }
  1131. for _, v := range decodeWsDr.TwoCellAnchor {
  1132. content.TwoCellAnchor = append(content.TwoCellAnchor, &xdrCellAnchor{
  1133. EditAs: v.EditAs,
  1134. GraphicFrame: v.Content,
  1135. })
  1136. }
  1137. }
  1138. f.Drawings.Store(path, &content)
  1139. }
  1140. var wsDr *xlsxWsDr
  1141. if drawing, ok := f.Drawings.Load(path); ok && drawing != nil {
  1142. wsDr = drawing.(*xlsxWsDr)
  1143. }
  1144. wsDr.Lock()
  1145. defer wsDr.Unlock()
  1146. return wsDr, len(wsDr.OneCellAnchor) + len(wsDr.TwoCellAnchor) + 2
  1147. }
  1148. // addDrawingChart provides a function to add chart graphic frame by given
  1149. // sheet, drawingXML, cell, width, height, relationship index and format sets.
  1150. func (f *File) addDrawingChart(sheet, drawingXML, cell string, width, height, rID int, formatSet *formatPicture) error {
  1151. col, row, err := CellNameToCoordinates(cell)
  1152. if err != nil {
  1153. return err
  1154. }
  1155. colIdx := col - 1
  1156. rowIdx := row - 1
  1157. width = int(float64(width) * formatSet.XScale)
  1158. height = int(float64(height) * formatSet.YScale)
  1159. colStart, rowStart, colEnd, rowEnd, x2, y2 :=
  1160. f.positionObjectPixels(sheet, colIdx, rowIdx, formatSet.OffsetX, formatSet.OffsetY, width, height)
  1161. content, cNvPrID := f.drawingParser(drawingXML)
  1162. twoCellAnchor := xdrCellAnchor{}
  1163. twoCellAnchor.EditAs = formatSet.Positioning
  1164. from := xlsxFrom{}
  1165. from.Col = colStart
  1166. from.ColOff = formatSet.OffsetX * EMU
  1167. from.Row = rowStart
  1168. from.RowOff = formatSet.OffsetY * EMU
  1169. to := xlsxTo{}
  1170. to.Col = colEnd
  1171. to.ColOff = x2 * EMU
  1172. to.Row = rowEnd
  1173. to.RowOff = y2 * EMU
  1174. twoCellAnchor.From = &from
  1175. twoCellAnchor.To = &to
  1176. graphicFrame := xlsxGraphicFrame{
  1177. NvGraphicFramePr: xlsxNvGraphicFramePr{
  1178. CNvPr: &xlsxCNvPr{
  1179. ID: cNvPrID,
  1180. Name: "Chart " + strconv.Itoa(cNvPrID),
  1181. },
  1182. },
  1183. Graphic: &xlsxGraphic{
  1184. GraphicData: &xlsxGraphicData{
  1185. URI: NameSpaceDrawingMLChart.Value,
  1186. Chart: &xlsxChart{
  1187. C: NameSpaceDrawingMLChart.Value,
  1188. R: SourceRelationship.Value,
  1189. RID: "rId" + strconv.Itoa(rID),
  1190. },
  1191. },
  1192. },
  1193. }
  1194. graphic, _ := xml.Marshal(graphicFrame)
  1195. twoCellAnchor.GraphicFrame = string(graphic)
  1196. twoCellAnchor.ClientData = &xdrClientData{
  1197. FLocksWithSheet: formatSet.FLocksWithSheet,
  1198. FPrintsWithSheet: formatSet.FPrintsWithSheet,
  1199. }
  1200. content.TwoCellAnchor = append(content.TwoCellAnchor, &twoCellAnchor)
  1201. f.Drawings.Store(drawingXML, content)
  1202. return err
  1203. }
  1204. // addSheetDrawingChart provides a function to add chart graphic frame for
  1205. // chartsheet by given sheet, drawingXML, width, height, relationship index
  1206. // and format sets.
  1207. func (f *File) addSheetDrawingChart(drawingXML string, rID int, formatSet *formatPicture) {
  1208. content, cNvPrID := f.drawingParser(drawingXML)
  1209. absoluteAnchor := xdrCellAnchor{
  1210. EditAs: formatSet.Positioning,
  1211. Pos: &xlsxPoint2D{},
  1212. Ext: &xlsxExt{},
  1213. }
  1214. graphicFrame := xlsxGraphicFrame{
  1215. NvGraphicFramePr: xlsxNvGraphicFramePr{
  1216. CNvPr: &xlsxCNvPr{
  1217. ID: cNvPrID,
  1218. Name: "Chart " + strconv.Itoa(cNvPrID),
  1219. },
  1220. },
  1221. Graphic: &xlsxGraphic{
  1222. GraphicData: &xlsxGraphicData{
  1223. URI: NameSpaceDrawingMLChart.Value,
  1224. Chart: &xlsxChart{
  1225. C: NameSpaceDrawingMLChart.Value,
  1226. R: SourceRelationship.Value,
  1227. RID: "rId" + strconv.Itoa(rID),
  1228. },
  1229. },
  1230. },
  1231. }
  1232. graphic, _ := xml.Marshal(graphicFrame)
  1233. absoluteAnchor.GraphicFrame = string(graphic)
  1234. absoluteAnchor.ClientData = &xdrClientData{
  1235. FLocksWithSheet: formatSet.FLocksWithSheet,
  1236. FPrintsWithSheet: formatSet.FPrintsWithSheet,
  1237. }
  1238. content.AbsoluteAnchor = append(content.AbsoluteAnchor, &absoluteAnchor)
  1239. f.Drawings.Store(drawingXML, content)
  1240. }
  1241. // deleteDrawing provides a function to delete chart graphic frame by given by
  1242. // given coordinates and graphic type.
  1243. func (f *File) deleteDrawing(col, row int, drawingXML, drawingType string) (err error) {
  1244. var (
  1245. wsDr *xlsxWsDr
  1246. deTwoCellAnchor *decodeTwoCellAnchor
  1247. )
  1248. xdrCellAnchorFuncs := map[string]func(anchor *xdrCellAnchor) bool{
  1249. "Chart": func(anchor *xdrCellAnchor) bool { return anchor.Pic == nil },
  1250. "Pic": func(anchor *xdrCellAnchor) bool { return anchor.Pic != nil },
  1251. }
  1252. decodeTwoCellAnchorFuncs := map[string]func(anchor *decodeTwoCellAnchor) bool{
  1253. "Chart": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic == nil },
  1254. "Pic": func(anchor *decodeTwoCellAnchor) bool { return anchor.Pic != nil },
  1255. }
  1256. wsDr, _ = f.drawingParser(drawingXML)
  1257. for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
  1258. if err = nil; wsDr.TwoCellAnchor[idx].From != nil && xdrCellAnchorFuncs[drawingType](wsDr.TwoCellAnchor[idx]) {
  1259. if wsDr.TwoCellAnchor[idx].From.Col == col && wsDr.TwoCellAnchor[idx].From.Row == row {
  1260. wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
  1261. idx--
  1262. }
  1263. }
  1264. }
  1265. for idx := 0; idx < len(wsDr.TwoCellAnchor); idx++ {
  1266. deTwoCellAnchor = new(decodeTwoCellAnchor)
  1267. if err = f.xmlNewDecoder(strings.NewReader("<decodeTwoCellAnchor>" + wsDr.TwoCellAnchor[idx].GraphicFrame + "</decodeTwoCellAnchor>")).
  1268. Decode(deTwoCellAnchor); err != nil && err != io.EOF {
  1269. err = fmt.Errorf("xml decode error: %s", err)
  1270. return
  1271. }
  1272. if err = nil; deTwoCellAnchor.From != nil && decodeTwoCellAnchorFuncs[drawingType](deTwoCellAnchor) {
  1273. if deTwoCellAnchor.From.Col == col && deTwoCellAnchor.From.Row == row {
  1274. wsDr.TwoCellAnchor = append(wsDr.TwoCellAnchor[:idx], wsDr.TwoCellAnchor[idx+1:]...)
  1275. idx--
  1276. }
  1277. }
  1278. }
  1279. f.Drawings.Store(drawingXML, wsDr)
  1280. return err
  1281. }