Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.61% covered (success)
96.61%
1196 / 1238
56.52% covered (warning)
56.52%
13 / 23
CRAP
0.00% covered (danger)
0.00%
0 / 1
PptCharts
96.61% covered (success)
96.61%
1196 / 1238
56.52% covered (warning)
56.52%
13 / 23
207
0.00% covered (danger)
0.00%
0 / 1
 render
90.91% covered (success)
90.91%
10 / 11
0.00% covered (danger)
0.00%
0 / 1
5.02
 writeChart
84.72% covered (warning)
84.72%
61 / 72
0.00% covered (danger)
0.00%
0 / 1
8.23
 writeSpreadsheet
93.75% covered (success)
93.75%
30 / 32
0.00% covered (danger)
0.00%
0 / 1
6.01
 writeElementWithValAttribute
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 writeSingleValueOrReference
100.00% covered (success)
100.00%
15 / 15
100.00% covered (success)
100.00%
1 / 1
2
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
29 / 29
100.00% covered (success)
100.00%
1 / 1
7
 writeTitle
100.00% covered (success)
100.00%
47 / 47
100.00% covered (success)
100.00%
1 / 1
3
 writePlotArea
100.00% covered (success)
100.00%
27 / 27
100.00% covered (success)
100.00%
1 / 1
12
 writeLegend
100.00% covered (success)
100.00%
46 / 46
100.00% covered (success)
100.00%
1 / 1
4
 writeLayout
76.92% covered (warning)
76.92%
20 / 26
0.00% covered (danger)
0.00%
0 / 1
5.31
 writeTypeArea
93.33% covered (success)
93.33%
42 / 45
0.00% covered (danger)
0.00%
0 / 1
9.02
 writeTypeBar
93.14% covered (success)
93.14%
95 / 102
0.00% covered (danger)
0.00%
0 / 1
16.08
 writeTypeBar3D
96.77% covered (success)
96.77%
90 / 93
0.00% covered (danger)
0.00%
0 / 1
14
 writeTypeDoughnut
95.35% covered (success)
95.35%
82 / 86
0.00% covered (danger)
0.00%
0 / 1
19
 writeTypePie
95.00% covered (success)
95.00%
76 / 80
0.00% covered (danger)
0.00%
0 / 1
14
 writeTypePie3D
100.00% covered (success)
100.00%
77 / 77
100.00% covered (success)
100.00%
1 / 1
12
 writeTypeLine
100.00% covered (success)
100.00%
82 / 82
100.00% covered (success)
100.00%
1 / 1
12
 writeTypeRadar
100.00% covered (success)
100.00%
80 / 80
100.00% covered (success)
100.00%
1 / 1
12
 writeTypeScatter
100.00% covered (success)
100.00%
86 / 86
100.00% covered (success)
100.00%
1 / 1
15
 writeChartRelationships
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
2
 writeSeriesMarker
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
4
 writeAxis
99.41% covered (success)
99.41%
169 / 170
0.00% covered (danger)
0.00%
0 / 1
24
 writeAxisGridlines
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4 * presentations documents.
5 *
6 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7 * General Public License version 3 as published by the Free Software Foundation.
8 *
9 * For the full copyright and license information, please read the LICENSE
10 * file that was distributed with this source code. For the full list of
11 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12 *
13 * @see        https://github.com/PHPOffice/PHPPresentation
14 *
15 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
16 */
17
18declare(strict_types=1);
19
20namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
21
22use PhpOffice\Common\Adapter\Zip\ZipInterface;
23use PhpOffice\Common\Drawing as CommonDrawing;
24use PhpOffice\Common\XMLWriter;
25use PhpOffice\PhpPresentation\Exception\FileRemoveException;
26use PhpOffice\PhpPresentation\Exception\UndefinedChartTypeException;
27use PhpOffice\PhpPresentation\PhpPresentation;
28use PhpOffice\PhpPresentation\Shape\Chart;
29use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
30use PhpOffice\PhpPresentation\Shape\Chart\Legend;
31use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
32use PhpOffice\PhpPresentation\Shape\Chart\Title;
33use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
34use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
35use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
36use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
37use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
38use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
39use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
40use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
41use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
42use PhpOffice\PhpPresentation\Style\Border;
43use PhpOffice\PhpPresentation\Style\Fill;
44use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
45use PhpOffice\PhpSpreadsheet\IOFactory;
46use PhpOffice\PhpSpreadsheet\Spreadsheet;
47
48class PptCharts extends AbstractDecoratorWriter
49{
50    public function render(): ZipInterface
51    {
52        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
53            $shape = $this->getDrawingHashTable()->getByIndex($i);
54            if ($shape instanceof Chart) {
55                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
56
57                if ($shape->hasIncludedSpreadsheet()) {
58                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
59                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
60                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
61
62                    // remove temp file
63                    if (false === @unlink($pFilename)) {
64                        throw new FileRemoveException($pFilename);
65                    }
66                }
67            }
68        }
69
70        return $this->getZip();
71    }
72
73    /**
74     * Write chart to XML format.
75     *
76     * @return string XML Output
77     */
78    protected function writeChart(Chart $chart): string
79    {
80        // Create XML writer
81        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
82
83        // XML header
84        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
85
86        // c:chartSpace
87        $objWriter->startElement('c:chartSpace');
88        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
89        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
90        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
91
92        // c:date1904
93        $objWriter->startElement('c:date1904');
94        $objWriter->writeAttribute('val', '1');
95        $objWriter->endElement();
96
97        // c:lang
98        $objWriter->startElement('c:lang');
99        $objWriter->writeAttribute('val', 'en-US');
100        $objWriter->endElement();
101
102        // c:chart
103        $objWriter->startElement('c:chart');
104
105        // Title?
106        if ($chart->getTitle()->isVisible()) {
107            // Write title
108            $this->writeTitle($objWriter, $chart->getTitle());
109        }
110
111        // c:autoTitleDeleted
112        $objWriter->startElement('c:autoTitleDeleted');
113        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
114        $objWriter->endElement();
115
116        // c:view3D
117        $objWriter->startElement('c:view3D');
118
119        // c:rotX
120        $objWriter->startElement('c:rotX');
121        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
122        $objWriter->endElement();
123
124        // c:hPercent
125        $hPercent = $chart->getView3D()->getHeightPercent();
126        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
127
128        // c:rotY
129        $objWriter->startElement('c:rotY');
130        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
131        $objWriter->endElement();
132
133        // c:depthPercent
134        $objWriter->startElement('c:depthPercent');
135        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
136        $objWriter->endElement();
137
138        // c:rAngAx
139        $objWriter->startElement('c:rAngAx');
140        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
141        $objWriter->endElement();
142
143        // c:perspective
144        $objWriter->startElement('c:perspective');
145        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
146        $objWriter->endElement();
147
148        $objWriter->endElement();
149
150        // Write plot area
151        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
152
153        // Legend?
154        if ($chart->getLegend()->isVisible()) {
155            // Write legend
156            $this->writeLegend($objWriter, $chart->getLegend());
157        }
158
159        // c:plotVisOnly
160        $objWriter->startElement('c:plotVisOnly');
161        $objWriter->writeAttribute('val', '1');
162        $objWriter->endElement();
163
164        // c:dispBlanksAs
165        $objWriter->startElement('c:dispBlanksAs');
166        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
167        $objWriter->endElement();
168
169        $objWriter->endElement();
170
171        // c:spPr
172        $objWriter->startElement('c:spPr');
173
174        // Fill
175        $this->writeFill($objWriter, $chart->getFill());
176
177        // Border
178        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
179            $this->writeBorder($objWriter, $chart->getBorder(), '');
180        }
181
182        // Shadow
183        if ($chart->getShadow()->isVisible()) {
184            // a:effectLst
185            $objWriter->startElement('a:effectLst');
186
187            // a:outerShdw
188            $objWriter->startElement('a:outerShdw');
189            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
190            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
191            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $chart->getShadow()->getDirection()));
192            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
193            $objWriter->writeAttribute('rotWithShape', '0');
194
195            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
196
197            $objWriter->endElement();
198
199            $objWriter->endElement();
200        }
201
202        $objWriter->endElement();
203
204        // External data?
205        if ($chart->hasIncludedSpreadsheet()) {
206            // c:externalData
207            $objWriter->startElement('c:externalData');
208            $objWriter->writeAttribute('r:id', 'rId1');
209
210            // c:autoUpdate
211            $objWriter->startElement('c:autoUpdate');
212            $objWriter->writeAttribute('val', '0');
213            $objWriter->endElement();
214
215            $objWriter->endElement();
216        }
217
218        $objWriter->endElement();
219
220        // Return
221        return $objWriter->getData();
222    }
223
224    /**
225     * Write chart to XML format.
226     *
227     * @return string String output
228     */
229    protected function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
230    {
231        // Create new spreadsheet
232        $spreadsheet = new Spreadsheet();
233
234        // Set properties
235        $title = $chart->getTitle()->getText();
236        if (0 == strlen($title)) {
237            $title = 'Chart';
238        }
239        $spreadsheet->getProperties()
240            ->setCreator(
241                $presentation->getDocumentProperties()->getCreator()
242            )
243            ->setLastModifiedBy(
244                $presentation->getDocumentProperties()->getLastModifiedBy()
245            )
246            ->setTitle($title);
247
248        // Add chart data
249        $sheet = $spreadsheet->setActiveSheetIndex(0);
250        $sheet->setTitle('Sheet1');
251
252        // Write series
253        $seriesIndex = 0;
254        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
255            // Title
256            $sheet->setCellValueByColumnAndRow(2 + $seriesIndex, 1, $series->getTitle());
257
258            // X-axis
259            $axisXData = array_keys($series->getValues());
260            $numAxisXData = count($axisXData);
261            for ($i = 0; $i < $numAxisXData; ++$i) {
262                $sheet->setCellValueByColumnAndRow(1, $i + 2, $axisXData[$i]);
263            }
264
265            // Y-axis
266            $axisYData = array_values($series->getValues());
267            $numAxisYData = count($axisYData);
268            for ($i = 0; $i < $numAxisYData; ++$i) {
269                $sheet->setCellValueByColumnAndRow(2 + $seriesIndex, $i + 2, $axisYData[$i]);
270            }
271
272            ++$seriesIndex;
273        }
274
275        // Save to string
276        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
277        $writer->save($tempName);
278
279        // Load file in memory
280        $returnValue = file_get_contents($tempName);
281        if (false === @unlink($tempName)) {
282            throw new FileRemoveException($tempName);
283        }
284
285        return $returnValue;
286    }
287
288    /**
289     * Write element with value attribute.
290     *
291     * @param XMLWriter $objWriter XML Writer
292     */
293    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
294    {
295        $objWriter->startElement($elementName);
296        $objWriter->writeAttribute('val', $value);
297        $objWriter->endElement();
298    }
299
300    /**
301     * Write single value or reference.
302     *
303     * @param XMLWriter $objWriter XML Writer
304     */
305    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
306    {
307        if (!$isReference) {
308            // Value
309            $objWriter->writeElement('c:v', $value);
310
311            return;
312        }
313
314        // Reference and cache
315        // c:strRef
316        $objWriter->startElement('c:strRef');
317        // c:strRef/c:f
318        $objWriter->writeElement('c:f', $reference);
319        // c:strRef/c:strCache
320        $objWriter->startElement('c:strCache');
321        // c:strRef/c:strCache/c:ptCount
322        $objWriter->startElement('c:ptCount');
323        $objWriter->writeAttribute('val', '1');
324        $objWriter->endElement();
325
326        // c:strRef/c:strCache/c:pt
327        $objWriter->startElement('c:pt');
328        $objWriter->writeAttribute('idx', '0');
329        // c:strRef/c:strCache/c:pt/c:v
330        $objWriter->writeElement('c:v', $value);
331        // c:strRef/c:strCache/c:pt
332        $objWriter->endElement();
333        // c:strRef/c:strCache
334        $objWriter->endElement();
335        // c:strRef
336        $objWriter->endElement();
337    }
338
339    /**
340     * Write series value or reference.
341     *
342     * @param XMLWriter $objWriter XML Writer
343     * @param array<int, mixed> $values
344     */
345    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
346    {
347        // c:strLit / c:numLit
348        // c:strRef / c:numRef
349        $referenceType = ($isReference ? 'Ref' : 'Lit');
350
351        // Get data type from first non-null value
352        $dataType = array_reduce($values, function ($carry, $item) {
353            if (!isset($item)) {
354                return $carry;
355            }
356
357            return is_numeric($item) ? 'num' : 'str';
358        }, 'num');
359
360        $objWriter->startElement('c:' . $dataType . $referenceType);
361
362        $numValues = count($values);
363        if (!$isReference) {
364            // Value
365
366            // c:ptCount
367            $objWriter->startElement('c:ptCount');
368            $objWriter->writeAttribute('val', count($values));
369            $objWriter->endElement();
370
371            // Add points
372            for ($i = 0; $i < $numValues; ++$i) {
373                // c:pt
374                $objWriter->startElement('c:pt');
375                $objWriter->writeAttribute('idx', $i);
376                $objWriter->writeElement('c:v', (string) ($values[$i]));
377                $objWriter->endElement();
378            }
379        } else {
380            // Reference
381            $objWriter->writeElement('c:f', $reference);
382            $objWriter->startElement('c:' . $dataType . 'Cache');
383
384            // c:ptCount
385            $objWriter->startElement('c:ptCount');
386            $objWriter->writeAttribute('val', count($values));
387            $objWriter->endElement();
388
389            // Add points
390            for ($i = 0; $i < $numValues; ++$i) {
391                // c:pt
392                $objWriter->startElement('c:pt');
393                $objWriter->writeAttribute('idx', $i);
394                $objWriter->writeElement('c:v', (string) ($values[$i]));
395                $objWriter->endElement();
396            }
397
398            $objWriter->endElement();
399        }
400
401        $objWriter->endElement();
402    }
403
404    /**
405     * Write Title.
406     */
407    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
408    {
409        // c:title
410        $objWriter->startElement('c:title');
411
412        // c:tx
413        $objWriter->startElement('c:tx');
414
415        // c:rich
416        $objWriter->startElement('c:rich');
417
418        // a:bodyPr
419        $objWriter->writeElement('a:bodyPr', null);
420
421        // a:lstStyle
422        $objWriter->writeElement('a:lstStyle', null);
423
424        // a:p
425        $objWriter->startElement('a:p');
426
427        // a:pPr
428        $objWriter->startElement('a:pPr');
429        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
430        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
431        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
432        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
433        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
434        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
435
436        // a:defRPr
437        $objWriter->writeElement('a:defRPr', null);
438
439        $objWriter->endElement();
440
441        // a:r
442        $objWriter->startElement('a:r');
443
444        // a:rPr
445        $objWriter->startElement('a:rPr');
446        $objWriter->writeAttribute('lang', 'en-US');
447        $objWriter->writeAttribute('dirty', '0');
448        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
449        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
450        $objWriter->writeAttribute('strike', $subject->getFont()->getStrikethrough());
451        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
452        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
453        $objWriter->writeAttributeIf($subject->getFont()->getBaseline() !== 0, 'baseline', $subject->getFont()->getBaseline());
454        $objWriter->writeAttribute('cap', $subject->getFont()->getCapitalization());
455
456        // Font - a:solidFill
457        $objWriter->startElement('a:solidFill');
458
459        $this->writeColor($objWriter, $subject->getFont()->getColor());
460
461        $objWriter->endElement();
462
463        // Font - a:latin
464        $objWriter->startElement('a:latin');
465        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
466        $objWriter->endElement();
467
468        $objWriter->endElement();
469
470        // a:t
471        $objWriter->writeElement('a:t', $subject->getText());
472
473        $objWriter->endElement();
474
475        // a:endParaRPr
476        $objWriter->startElement('a:endParaRPr');
477        $objWriter->writeAttribute('lang', 'en-US');
478        $objWriter->writeAttribute('dirty', '0');
479        $objWriter->endElement();
480
481        $objWriter->endElement();
482
483        $objWriter->endElement();
484
485        $objWriter->endElement();
486
487        // Write layout
488        $this->writeLayout($objWriter, $subject);
489
490        // c:overlay
491        $objWriter->startElement('c:overlay');
492        $objWriter->writeAttribute('val', '0');
493        $objWriter->endElement();
494
495        $objWriter->endElement();
496    }
497
498    /**
499     * Write Plot Area.
500     *
501     * @param XMLWriter $objWriter XML Writer
502     */
503    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
504    {
505        // c:plotArea
506        $objWriter->startElement('c:plotArea');
507
508        // Write layout
509        $this->writeLayout($objWriter, $subject);
510
511        // Write chart
512        $chartType = $subject->getType();
513        if ($chartType instanceof Area) {
514            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
515        } elseif ($chartType instanceof Bar) {
516            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
517        } elseif ($chartType instanceof Bar3D) {
518            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
519        } elseif ($chartType instanceof Doughnut) {
520            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
521        } elseif ($chartType instanceof Pie) {
522            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
523        } elseif ($chartType instanceof Pie3D) {
524            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
525        } elseif ($chartType instanceof Line) {
526            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
527        } elseif ($chartType instanceof Radar) {
528            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
529        } elseif ($chartType instanceof Scatter) {
530            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
531        } else {
532            throw new UndefinedChartTypeException();
533        }
534
535        // Write X axis?
536        if ($chartType->hasAxisX()) {
537            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
538        }
539
540        // Write Y axis?
541        if ($chartType->hasAxisY()) {
542            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
543        }
544
545        $objWriter->endElement();
546    }
547
548    /**
549     * Write Legend.
550     *
551     * @param XMLWriter $objWriter XML Writer
552     */
553    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
554    {
555        // c:legend
556        $objWriter->startElement('c:legend');
557
558        // c:legendPos
559        $objWriter->startElement('c:legendPos');
560        $objWriter->writeAttribute('val', $subject->getPosition());
561        $objWriter->endElement();
562
563        // Write layout
564        $this->writeLayout($objWriter, $subject);
565
566        // c:overlay
567        $objWriter->startElement('c:overlay');
568        $objWriter->writeAttribute('val', '0');
569        $objWriter->endElement();
570
571        // c:spPr
572        $objWriter->startElement('c:spPr');
573
574        // Fill
575        $this->writeFill($objWriter, $subject->getFill());
576
577        // Border
578        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
579            $this->writeBorder($objWriter, $subject->getBorder(), '');
580        }
581
582        $objWriter->endElement();
583
584        // c:txPr
585        $objWriter->startElement('c:txPr');
586
587        // a:bodyPr
588        $objWriter->writeElement('a:bodyPr', null);
589
590        // a:lstStyle
591        $objWriter->writeElement('a:lstStyle', null);
592
593        // a:p
594        $objWriter->startElement('a:p');
595
596        // a:pPr
597        $objWriter->startElement('a:pPr');
598        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
599        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
600        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
601        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
602        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
603        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
604
605        // a:defRPr
606        $objWriter->startElement('a:defRPr');
607
608        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
609        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
610        $objWriter->writeAttribute('strike', $subject->getFont()->getStrikethrough());
611        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
612        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
613        $objWriter->writeAttributeIf($subject->getFont()->getBaseline() !== 0, 'baseline', $subject->getFont()->getBaseline());
614
615        // Font - a:solidFill
616        $objWriter->startElement('a:solidFill');
617
618        $this->writeColor($objWriter, $subject->getFont()->getColor());
619
620        $objWriter->endElement();
621
622        // Font - a:latin
623        $objWriter->startElement('a:latin');
624        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
625        $objWriter->endElement();
626
627        $objWriter->endElement();
628
629        $objWriter->endElement();
630
631        // a:endParaRPr
632        $objWriter->startElement('a:endParaRPr');
633        $objWriter->writeAttribute('lang', 'en-US');
634        $objWriter->writeAttribute('dirty', '0');
635        $objWriter->endElement();
636
637        $objWriter->endElement();
638
639        $objWriter->endElement();
640
641        $objWriter->endElement();
642    }
643
644    /**
645     * Write Layout.
646     *
647     * @param XMLWriter $objWriter XML Writer
648     * @param Legend|PlotArea|Title $subject
649     */
650    protected function writeLayout(XMLWriter $objWriter, $subject): void
651    {
652        // c:layout
653        $objWriter->startElement('c:layout');
654
655        // c:manualLayout
656        $objWriter->startElement('c:manualLayout');
657        // c:xMode
658        $objWriter->startElement('c:xMode');
659        $objWriter->writeAttribute('val', 'edge');
660        $objWriter->endElement();
661
662        // c:yMode
663        $objWriter->startElement('c:yMode');
664        $objWriter->writeAttribute('val', 'edge');
665        $objWriter->endElement();
666
667        if (0 != $subject->getOffsetX()) {
668            // c:x
669            $objWriter->startElement('c:x');
670            $objWriter->writeAttribute('val', $subject->getOffsetX());
671            $objWriter->endElement();
672        }
673
674        if (0 != $subject->getOffsetY()) {
675            // c:y
676            $objWriter->startElement('c:y');
677            $objWriter->writeAttribute('val', $subject->getOffsetY());
678            $objWriter->endElement();
679        }
680
681        if (0 != $subject->getWidth()) {
682            // c:w
683            $objWriter->startElement('c:w');
684            $objWriter->writeAttribute('val', $subject->getWidth());
685            $objWriter->endElement();
686        }
687
688        if (0 != $subject->getHeight()) {
689            // c:h
690            $objWriter->startElement('c:h');
691            $objWriter->writeAttribute('val', $subject->getHeight());
692            $objWriter->endElement();
693        }
694
695        $objWriter->endElement();
696        $objWriter->endElement();
697    }
698
699    /**
700     * Write Type Area.
701     *
702     * @param XMLWriter $objWriter XML Writer
703     */
704    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
705    {
706        // c:lineChart
707        $objWriter->startElement('c:areaChart');
708
709        // c:grouping
710        $objWriter->startElement('c:grouping');
711        $objWriter->writeAttribute('val', 'standard');
712        $objWriter->endElement();
713
714        // Write series
715        $seriesIndex = 0;
716        foreach ($subject->getSeries() as $series) {
717            // c:ser
718            $objWriter->startElement('c:ser');
719
720            // c:ser > c:idx
721            $objWriter->startElement('c:idx');
722            $objWriter->writeAttribute('val', $seriesIndex);
723            $objWriter->endElement();
724
725            // c:ser > c:order
726            $objWriter->startElement('c:order');
727            $objWriter->writeAttribute('val', $seriesIndex);
728            $objWriter->endElement();
729
730            // c:ser > c:tx
731            $objWriter->startElement('c:tx');
732            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
733            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
734            $objWriter->endElement();
735
736            // c:ser > c:dLbls
737            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
738            $objWriter->startElement('c:dLbls');
739
740            // c:ser > c:dLbls > c:showVal
741            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
742
743            // c:ser > c:dLbls > c:showCatName
744            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
745
746            // c:ser > c:dLbls > c:showSerName
747            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
748
749            // c:ser > c:dLbls > c:showPercent
750            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
751
752            // c:ser > ##c:dLbls
753            $objWriter->endElement();
754
755            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
756                // c:spPr
757                $objWriter->startElement('c:spPr');
758                // Write fill
759                $this->writeFill($objWriter, $series->getFill());
760                // ## c:spPr
761                $objWriter->endElement();
762            }
763
764            // Write X axis data
765            $axisXData = array_keys($series->getValues());
766
767            // c:cat
768            $objWriter->startElement('c:cat');
769            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
770            $objWriter->endElement();
771
772            // Write Y axis data
773            $axisYData = array_values($series->getValues());
774
775            // c:val
776            $objWriter->startElement('c:val');
777            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
778            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
779            $objWriter->endElement();
780
781            $objWriter->endElement();
782
783            ++$seriesIndex;
784        }
785
786        // c:axId
787        $objWriter->startElement('c:axId');
788        $objWriter->writeAttribute('val', '52743552');
789        $objWriter->endElement();
790
791        // c:axId
792        $objWriter->startElement('c:axId');
793        $objWriter->writeAttribute('val', '52749440');
794        $objWriter->endElement();
795
796        $objWriter->endElement();
797    }
798
799    /**
800     * Write Type Bar.
801     *
802     * @param XMLWriter $objWriter XML Writer
803     */
804    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
805    {
806        // c:barChart
807        $objWriter->startElement('c:barChart');
808
809        // c:barDir
810        $objWriter->startElement('c:barDir');
811        $objWriter->writeAttribute('val', $subject->getBarDirection());
812        $objWriter->endElement();
813
814        // c:grouping
815        $objWriter->startElement('c:grouping');
816        $objWriter->writeAttribute('val', $subject->getBarGrouping());
817        $objWriter->endElement();
818
819        // Write series
820        $seriesIndex = 0;
821        foreach ($subject->getSeries() as $series) {
822            // c:ser
823            $objWriter->startElement('c:ser');
824
825            // c:idx
826            $objWriter->startElement('c:idx');
827            $objWriter->writeAttribute('val', $seriesIndex);
828            $objWriter->endElement();
829
830            // c:order
831            $objWriter->startElement('c:order');
832            $objWriter->writeAttribute('val', $seriesIndex);
833            $objWriter->endElement();
834
835            // c:tx
836            $objWriter->startElement('c:tx');
837            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
838            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
839            $objWriter->endElement();
840
841            // Fills for points?
842            $dataPointFills = $series->getDataPointFills();
843            foreach ($dataPointFills as $key => $value) {
844                // c:dPt
845                $objWriter->startElement('c:dPt');
846
847                // c:idx
848                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
849
850                if (Fill::FILL_NONE != $value->getFillType()) {
851                    // c:spPr
852                    $objWriter->startElement('c:spPr');
853                    // Write fill
854                    $this->writeFill($objWriter, $value);
855                    // ## c:spPr
856                    $objWriter->endElement();
857                }
858
859                // ## c:dPt
860                $objWriter->endElement();
861            }
862
863            // c:dLbls
864            $objWriter->startElement('c:dLbls');
865
866            if ($series->hasDlblNumFormat()) {
867                //c:numFmt
868                $objWriter->startElement('c:numFmt');
869                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
870                $objWriter->writeAttribute('sourceLinked', '0');
871                $objWriter->endElement();
872            }
873
874            // c:txPr
875            $objWriter->startElement('c:txPr');
876
877            // a:bodyPr
878            $objWriter->writeElement('a:bodyPr');
879
880            // a:lstStyle
881            $objWriter->writeElement('a:lstStyle');
882
883            // a:p
884            $objWriter->startElement('a:p');
885
886            // a:pPr
887            $objWriter->startElement('a:pPr');
888
889            // a:defRPr
890            $objWriter->startElement('a:defRPr');
891            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
892            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
893            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
894            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
895            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
896            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
897
898            // a:solidFill
899            $objWriter->startElement('a:solidFill');
900            $this->writeColor($objWriter, $series->getFont()->getColor());
901            $objWriter->endElement();
902
903            // a:latin
904            $objWriter->startElement('a:latin');
905            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
906            $objWriter->endElement();
907
908            // a:ea
909            $objWriter->startElement('a:ea');
910            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
911            $objWriter->endElement();
912
913            // >a:defRPr
914            $objWriter->endElement();
915            // >a:pPr
916            $objWriter->endElement();
917
918            // a:endParaRPr
919            $objWriter->startElement('a:endParaRPr');
920            $objWriter->writeAttribute('lang', 'en-US');
921            $objWriter->writeAttribute('dirty', '0');
922            $objWriter->endElement();
923
924            // >a:p
925            $objWriter->endElement();
926            // >a:lstStyle
927            $objWriter->endElement();
928
929            // c:dLblPos
930            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
931
932            // c:showVal
933            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
934
935            // c:showCatName
936            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
937
938            // c:showSerName
939            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
940
941            // c:showPercent
942            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
943
944            // c:separator
945            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
946
947            // c:showLeaderLines
948            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
949
950            $objWriter->endElement();
951
952            // c:spPr
953            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
954                // c:spPr
955                $objWriter->startElement('c:spPr');
956                // Write fill
957                $this->writeFill($objWriter, $series->getFill());
958                // ## c:spPr
959                $objWriter->endElement();
960            }
961
962            // Write X axis data
963            $axisXData = array_keys($series->getValues());
964
965            // c:cat
966            $objWriter->startElement('c:cat');
967            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
968            $objWriter->endElement();
969
970            // Write Y axis data
971            $axisYData = array_values($series->getValues());
972
973            // c:val
974            $objWriter->startElement('c:val');
975            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
976            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
977            $objWriter->endElement();
978
979            $objWriter->endElement();
980
981            ++$seriesIndex;
982        }
983
984        // c:gapWidth
985        $objWriter->startElement('c:gapWidth');
986        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
987        $objWriter->endElement();
988
989        // c:overlap
990        $objWriter->startElement('c:overlap');
991        $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent());
992        $objWriter->endElement();
993
994        // c:axId
995        $objWriter->startElement('c:axId');
996        $objWriter->writeAttribute('val', '52743552');
997        $objWriter->endElement();
998
999        // c:axId
1000        $objWriter->startElement('c:axId');
1001        $objWriter->writeAttribute('val', '52749440');
1002        $objWriter->endElement();
1003
1004        // c:extLst
1005        $objWriter->startElement('c:extLst');
1006        $objWriter->endElement();
1007
1008        $objWriter->endElement();
1009    }
1010
1011    /**
1012     * Write Type Bar3D.
1013     *
1014     * @param XMLWriter $objWriter XML Writer
1015     */
1016    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1017    {
1018        // c:bar3DChart
1019        $objWriter->startElement('c:bar3DChart');
1020
1021        // c:barDir
1022        $objWriter->startElement('c:barDir');
1023        $objWriter->writeAttribute('val', $subject->getBarDirection());
1024        $objWriter->endElement();
1025
1026        // c:grouping
1027        $objWriter->startElement('c:grouping');
1028        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1029        $objWriter->endElement();
1030
1031        // Write series
1032        $seriesIndex = 0;
1033        foreach ($subject->getSeries() as $series) {
1034            // c:ser
1035            $objWriter->startElement('c:ser');
1036
1037            // c:idx
1038            $objWriter->startElement('c:idx');
1039            $objWriter->writeAttribute('val', $seriesIndex);
1040            $objWriter->endElement();
1041
1042            // c:order
1043            $objWriter->startElement('c:order');
1044            $objWriter->writeAttribute('val', $seriesIndex);
1045            $objWriter->endElement();
1046
1047            // c:tx
1048            $objWriter->startElement('c:tx');
1049            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1050            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1051            $objWriter->endElement();
1052
1053            // Fills for points?
1054            $dataPointFills = $series->getDataPointFills();
1055            foreach ($dataPointFills as $key => $value) {
1056                // c:dPt
1057                $objWriter->startElement('c:dPt');
1058
1059                // c:idx
1060                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1061
1062                if (Fill::FILL_NONE != $value->getFillType()) {
1063                    // c:spPr
1064                    $objWriter->startElement('c:spPr');
1065                    // Write fill
1066                    $this->writeFill($objWriter, $value);
1067                    // ## c:spPr
1068                    $objWriter->endElement();
1069                }
1070
1071                // ## c:dPt
1072                $objWriter->endElement();
1073            }
1074
1075            // c:dLbls
1076            $objWriter->startElement('c:dLbls');
1077
1078            // c:txPr
1079            $objWriter->startElement('c:txPr');
1080
1081            // a:bodyPr
1082            $objWriter->writeElement('a:bodyPr', null);
1083
1084            // a:lstStyle
1085            $objWriter->writeElement('a:lstStyle', null);
1086
1087            // a:p
1088            $objWriter->startElement('a:p');
1089
1090            // a:pPr
1091            $objWriter->startElement('a:pPr');
1092
1093            // a:defRPr
1094            $objWriter->startElement('a:defRPr');
1095
1096            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1097            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1098            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1099            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1100            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1101            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1102
1103            // Font - a:solidFill
1104            $objWriter->startElement('a:solidFill');
1105
1106            $this->writeColor($objWriter, $series->getFont()->getColor());
1107
1108            $objWriter->endElement();
1109
1110            // Font - a:latin
1111            $objWriter->startElement('a:latin');
1112            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1113            $objWriter->endElement();
1114            // a:ea
1115            $objWriter->startElement('a:ea');
1116            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1117            $objWriter->endElement();
1118
1119            $objWriter->endElement();
1120
1121            $objWriter->endElement();
1122
1123            // a:endParaRPr
1124            $objWriter->startElement('a:endParaRPr');
1125            $objWriter->writeAttribute('lang', 'en-US');
1126            $objWriter->writeAttribute('dirty', '0');
1127            $objWriter->endElement();
1128
1129            $objWriter->endElement();
1130
1131            $objWriter->endElement();
1132
1133            // c:showVal
1134            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1135
1136            // c:showCatName
1137            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1138
1139            // c:showSerName
1140            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1141
1142            // c:showPercent
1143            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1144
1145            // c:showLeaderLines
1146            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1147
1148            $objWriter->endElement();
1149
1150            // c:spPr
1151            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1152                // c:spPr
1153                $objWriter->startElement('c:spPr');
1154                // Write fill
1155                $this->writeFill($objWriter, $series->getFill());
1156                // ## c:spPr
1157                $objWriter->endElement();
1158            }
1159
1160            // Write X axis data
1161            $axisXData = array_keys($series->getValues());
1162
1163            // c:cat
1164            $objWriter->startElement('c:cat');
1165            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1166            $objWriter->endElement();
1167
1168            // Write Y axis data
1169            $axisYData = array_values($series->getValues());
1170
1171            // c:val
1172            $objWriter->startElement('c:val');
1173            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1174            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1175            $objWriter->endElement();
1176
1177            $objWriter->endElement();
1178
1179            ++$seriesIndex;
1180        }
1181
1182        // c:gapWidth
1183        $objWriter->startElement('c:gapWidth');
1184        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1185        $objWriter->endElement();
1186
1187        // c:axId
1188        $objWriter->startElement('c:axId');
1189        $objWriter->writeAttribute('val', '52743552');
1190        $objWriter->endElement();
1191
1192        // c:axId
1193        $objWriter->startElement('c:axId');
1194        $objWriter->writeAttribute('val', '52749440');
1195        $objWriter->endElement();
1196
1197        // c:axId
1198        $objWriter->startElement('c:axId');
1199        $objWriter->writeAttribute('val', '0');
1200        $objWriter->endElement();
1201
1202        $objWriter->endElement();
1203    }
1204
1205    /**
1206     * Write Type Pie.
1207     *
1208     * @param XMLWriter $objWriter XML Writer
1209     */
1210    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1211    {
1212        // c:pieChart
1213        $objWriter->startElement('c:doughnutChart');
1214
1215        // c:varyColors
1216        $objWriter->startElement('c:varyColors');
1217        $objWriter->writeAttribute('val', '1');
1218        $objWriter->endElement();
1219
1220        // Write series
1221        $seriesIndex = 0;
1222        foreach ($subject->getSeries() as $series) {
1223            // c:ser
1224            $objWriter->startElement('c:ser');
1225
1226            // c:idx
1227            $objWriter->startElement('c:idx');
1228            $objWriter->writeAttribute('val', $seriesIndex);
1229            $objWriter->endElement();
1230
1231            // c:order
1232            $objWriter->startElement('c:order');
1233            $objWriter->writeAttribute('val', $seriesIndex);
1234            $objWriter->endElement();
1235
1236            // c:tx
1237            $objWriter->startElement('c:tx');
1238            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1239            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1240            $objWriter->endElement();
1241
1242            // Fills for points?
1243            $dataPointFills = $series->getDataPointFills();
1244            foreach ($dataPointFills as $key => $value) {
1245                // c:dPt
1246                $objWriter->startElement('c:dPt');
1247                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1248                // c:dPt/c:spPr
1249                $objWriter->startElement('c:spPr');
1250                $this->writeFill($objWriter, $value);
1251                // c:dPt/##c:spPr
1252                $objWriter->endElement();
1253                // ##c:dPt
1254                $objWriter->endElement();
1255            }
1256
1257            // Write X axis data
1258            $axisXData = array_keys($series->getValues());
1259
1260            // c:cat
1261            $objWriter->startElement('c:cat');
1262            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1263            $objWriter->endElement();
1264
1265            // Write Y axis data
1266            $axisYData = array_values($series->getValues());
1267
1268            // c:val
1269            $objWriter->startElement('c:val');
1270            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1271            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1272            $objWriter->endElement();
1273
1274            $objWriter->endElement();
1275
1276            ++$seriesIndex;
1277        }
1278
1279        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1280            // c:dLbls
1281            $objWriter->startElement('c:dLbls');
1282
1283            if ($series->hasDlblNumFormat()) {
1284                //c:numFmt
1285                $objWriter->startElement('c:numFmt');
1286                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1287                $objWriter->writeAttribute('sourceLinked', '0');
1288                $objWriter->endElement();
1289            }
1290
1291            // c:dLbls\c:txPr
1292            $objWriter->startElement('c:txPr');
1293            $objWriter->writeElement('a:bodyPr', null);
1294            $objWriter->writeElement('a:lstStyle', null);
1295
1296            // c:dLbls\c:txPr\a:p
1297            $objWriter->startElement('a:p');
1298
1299            // c:dLbls\c:txPr\a:p\a:pPr
1300            $objWriter->startElement('a:pPr');
1301
1302            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1303            $objWriter->startElement('a:defRPr');
1304            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1305            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1306            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1307            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1308            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1309            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1310
1311            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1312            $objWriter->startElement('a:solidFill');
1313            $this->writeColor($objWriter, $series->getFont()->getColor());
1314            $objWriter->endElement();
1315
1316            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1317            $objWriter->startElement('a:latin');
1318            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1319            $objWriter->endElement();
1320            // a:ea
1321            $objWriter->startElement('a:ea');
1322            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1323            $objWriter->endElement();
1324
1325            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1326            $objWriter->endElement();
1327            // c:dLbls\c:txPr\a:p\a:pPr\
1328            $objWriter->endElement();
1329
1330            // c:dLbls\c:txPr\a:p\a:endParaRPr
1331            $objWriter->startElement('a:endParaRPr');
1332            $objWriter->writeAttribute('lang', 'en-US');
1333            $objWriter->writeAttribute('dirty', '0');
1334            $objWriter->endElement();
1335
1336            // c:dLbls\c:txPr\a:p\
1337            $objWriter->endElement();
1338            // c:dLbls\c:txPr\
1339            $objWriter->endElement();
1340
1341            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1342            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1343            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1344            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1345            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1346            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1347            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1348
1349            $separator = $series->getSeparator();
1350            if (!empty($separator) && PHP_EOL != $separator) {
1351                // c:dLbls\c:separator
1352                $objWriter->writeElement('c:separator', $separator);
1353            }
1354
1355            // c:dLbls\
1356            $objWriter->endElement();
1357        }
1358
1359        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1360        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1361
1362        $objWriter->endElement();
1363    }
1364
1365    /**
1366     * Write Type Pie.
1367     *
1368     * @param XMLWriter $objWriter XML Writer
1369     */
1370    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1371    {
1372        // c:pieChart
1373        $objWriter->startElement('c:pieChart');
1374
1375        // c:varyColors
1376        $objWriter->startElement('c:varyColors');
1377        $objWriter->writeAttribute('val', '1');
1378        $objWriter->endElement();
1379
1380        // Write series
1381        $seriesIndex = 0;
1382        foreach ($subject->getSeries() as $series) {
1383            // c:ser
1384            $objWriter->startElement('c:ser');
1385
1386            // c:idx
1387            $objWriter->startElement('c:idx');
1388            $objWriter->writeAttribute('val', $seriesIndex);
1389            $objWriter->endElement();
1390
1391            // c:order
1392            $objWriter->startElement('c:order');
1393            $objWriter->writeAttribute('val', $seriesIndex);
1394            $objWriter->endElement();
1395
1396            // c:tx
1397            $objWriter->startElement('c:tx');
1398            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1399            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1400            $objWriter->endElement();
1401
1402            // Fills for points?
1403            $dataPointFills = $series->getDataPointFills();
1404            foreach ($dataPointFills as $key => $value) {
1405                // c:dPt
1406                $objWriter->startElement('c:dPt');
1407                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1408                // c:dPt/c:spPr
1409                $objWriter->startElement('c:spPr');
1410                $this->writeFill($objWriter, $value);
1411                // c:dPt/##c:spPr
1412                $objWriter->endElement();
1413                // ##c:dPt
1414                $objWriter->endElement();
1415            }
1416
1417            // c:dLbls
1418            $objWriter->startElement('c:dLbls');
1419
1420            if ($series->hasDlblNumFormat()) {
1421                //c:numFmt
1422                $objWriter->startElement('c:numFmt');
1423                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1424                $objWriter->writeAttribute('sourceLinked', '0');
1425                $objWriter->endElement();
1426            }
1427
1428            // c:txPr
1429            $objWriter->startElement('c:txPr');
1430
1431            // a:bodyPr
1432            $objWriter->writeElement('a:bodyPr', null);
1433
1434            // a:lstStyle
1435            $objWriter->writeElement('a:lstStyle', null);
1436
1437            // a:p
1438            $objWriter->startElement('a:p');
1439
1440            // a:pPr
1441            $objWriter->startElement('a:pPr');
1442
1443            // a:defRPr
1444            $objWriter->startElement('a:defRPr');
1445
1446            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1447            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1448            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1449            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1450            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1451            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1452
1453            // Font - a:solidFill
1454            $objWriter->startElement('a:solidFill');
1455
1456            $this->writeColor($objWriter, $series->getFont()->getColor());
1457
1458            $objWriter->endElement();
1459
1460            // Font - a:latin
1461            $objWriter->startElement('a:latin');
1462            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1463            $objWriter->endElement();
1464            // a:ea
1465            $objWriter->startElement('a:ea');
1466            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1467            $objWriter->endElement();
1468
1469            $objWriter->endElement();
1470
1471            $objWriter->endElement();
1472
1473            // a:endParaRPr
1474            $objWriter->startElement('a:endParaRPr');
1475            $objWriter->writeAttribute('lang', 'en-US');
1476            $objWriter->writeAttribute('dirty', '0');
1477            $objWriter->endElement();
1478
1479            $objWriter->endElement();
1480
1481            $objWriter->endElement();
1482
1483            // c:dLblPos
1484            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1485
1486            // c:showLegendKey
1487            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1488
1489            // c:showVal
1490            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1491
1492            // c:showCatName
1493            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1494
1495            // c:showSerName
1496            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1497
1498            // c:showPercent
1499            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1500
1501            // c:showLeaderLines
1502            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1503
1504            $objWriter->endElement();
1505
1506            // Write X axis data
1507            $axisXData = array_keys($series->getValues());
1508
1509            // c:cat
1510            $objWriter->startElement('c:cat');
1511            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1512            $objWriter->endElement();
1513
1514            // Write Y axis data
1515            $axisYData = array_values($series->getValues());
1516
1517            // c:val
1518            $objWriter->startElement('c:val');
1519            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1520            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1521            $objWriter->endElement();
1522
1523            $objWriter->endElement();
1524
1525            ++$seriesIndex;
1526        }
1527
1528        $objWriter->endElement();
1529    }
1530
1531    /**
1532     * Write Type Pie3D.
1533     *
1534     * @param XMLWriter $objWriter XML Writer
1535     */
1536    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1537    {
1538        // c:pie3DChart
1539        $objWriter->startElement('c:pie3DChart');
1540
1541        // c:varyColors
1542        $objWriter->startElement('c:varyColors');
1543        $objWriter->writeAttribute('val', '1');
1544        $objWriter->endElement();
1545
1546        // Write series
1547        $seriesIndex = 0;
1548        foreach ($subject->getSeries() as $series) {
1549            // c:ser
1550            $objWriter->startElement('c:ser');
1551
1552            // c:idx
1553            $objWriter->startElement('c:idx');
1554            $objWriter->writeAttribute('val', $seriesIndex);
1555            $objWriter->endElement();
1556
1557            // c:order
1558            $objWriter->startElement('c:order');
1559            $objWriter->writeAttribute('val', $seriesIndex);
1560            $objWriter->endElement();
1561
1562            // c:tx
1563            $objWriter->startElement('c:tx');
1564            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1565            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1566            $objWriter->endElement();
1567
1568            // c:explosion
1569            $objWriter->startElement('c:explosion');
1570            $objWriter->writeAttribute('val', $subject->getExplosion());
1571            $objWriter->endElement();
1572
1573            // Fills for points?
1574            $dataPointFills = $series->getDataPointFills();
1575            foreach ($dataPointFills as $key => $value) {
1576                // c:dPt
1577                $objWriter->startElement('c:dPt');
1578                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1579                // c:dPt/c:spPr
1580                $objWriter->startElement('c:spPr');
1581                $this->writeFill($objWriter, $value);
1582                // c:dPt/##c:spPr
1583                $objWriter->endElement();
1584                // ##c:dPt
1585                $objWriter->endElement();
1586            }
1587
1588            // c:dLbls
1589            $objWriter->startElement('c:dLbls');
1590
1591            // c:txPr
1592            $objWriter->startElement('c:txPr');
1593
1594            // a:bodyPr
1595            $objWriter->writeElement('a:bodyPr', null);
1596
1597            // a:lstStyle
1598            $objWriter->writeElement('a:lstStyle', null);
1599
1600            // a:p
1601            $objWriter->startElement('a:p');
1602
1603            // a:pPr
1604            $objWriter->startElement('a:pPr');
1605
1606            // a:defRPr
1607            $objWriter->startElement('a:defRPr');
1608
1609            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1610            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1611            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1612            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1613            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1614            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1615
1616            // Font - a:solidFill
1617            $objWriter->startElement('a:solidFill');
1618
1619            $this->writeColor($objWriter, $series->getFont()->getColor());
1620
1621            $objWriter->endElement();
1622
1623            // Font - a:latin
1624            $objWriter->startElement('a:latin');
1625            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1626            $objWriter->endElement();
1627            // a:ea
1628            $objWriter->startElement('a:ea');
1629            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1630            $objWriter->endElement();
1631
1632            $objWriter->endElement();
1633
1634            $objWriter->endElement();
1635
1636            // a:endParaRPr
1637            $objWriter->startElement('a:endParaRPr');
1638            $objWriter->writeAttribute('lang', 'en-US');
1639            $objWriter->writeAttribute('dirty', '0');
1640            $objWriter->endElement();
1641
1642            $objWriter->endElement();
1643
1644            $objWriter->endElement();
1645
1646            // c:dLblPos
1647            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1648
1649            // c:showVal
1650            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1651
1652            // c:showCatName
1653            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1654
1655            // c:showSerName
1656            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1657
1658            // c:showPercent
1659            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1660
1661            // c:showLeaderLines
1662            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1663
1664            $objWriter->endElement();
1665
1666            // Write X axis data
1667            $axisXData = array_keys($series->getValues());
1668
1669            // c:cat
1670            $objWriter->startElement('c:cat');
1671            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1672            $objWriter->endElement();
1673
1674            // Write Y axis data
1675            $axisYData = array_values($series->getValues());
1676
1677            // c:val
1678            $objWriter->startElement('c:val');
1679            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1680            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1681            $objWriter->endElement();
1682
1683            $objWriter->endElement();
1684
1685            ++$seriesIndex;
1686        }
1687
1688        $objWriter->endElement();
1689    }
1690
1691    /**
1692     * Write Type Line.
1693     *
1694     * @param XMLWriter $objWriter XML Writer
1695     */
1696    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1697    {
1698        // c:lineChart
1699        $objWriter->startElement('c:lineChart');
1700
1701        // c:grouping
1702        $objWriter->startElement('c:grouping');
1703        $objWriter->writeAttribute('val', 'standard');
1704        $objWriter->endElement();
1705
1706        // Write series
1707        $seriesIndex = 0;
1708        foreach ($subject->getSeries() as $series) {
1709            // c:ser
1710            $objWriter->startElement('c:ser');
1711
1712            // c:idx
1713            $objWriter->startElement('c:idx');
1714            $objWriter->writeAttribute('val', $seriesIndex);
1715            $objWriter->endElement();
1716
1717            // c:order
1718            $objWriter->startElement('c:order');
1719            $objWriter->writeAttribute('val', $seriesIndex);
1720            $objWriter->endElement();
1721
1722            // c:tx
1723            $objWriter->startElement('c:tx');
1724            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1725            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1726            $objWriter->endElement();
1727
1728            // c:spPr
1729            $objWriter->startElement('c:spPr');
1730            // Write fill
1731            $this->writeFill($objWriter, $series->getFill());
1732            // Write outline
1733            $this->writeOutline($objWriter, $series->getOutline());
1734            // ## c:spPr
1735            $objWriter->endElement();
1736
1737            // Marker
1738            $this->writeSeriesMarker($objWriter, $series->getMarker());
1739
1740            // c:dLbls
1741            $objWriter->startElement('c:dLbls');
1742
1743            // c:txPr
1744            $objWriter->startElement('c:txPr');
1745
1746            // a:bodyPr
1747            $objWriter->writeElement('a:bodyPr', null);
1748
1749            // a:lstStyle
1750            $objWriter->writeElement('a:lstStyle', null);
1751
1752            // a:p
1753            $objWriter->startElement('a:p');
1754
1755            // a:pPr
1756            $objWriter->startElement('a:pPr');
1757
1758            // a:defRPr
1759            $objWriter->startElement('a:defRPr');
1760
1761            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1762            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1763            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1764            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1765            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1766            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1767
1768            // Font - a:solidFill
1769            $objWriter->startElement('a:solidFill');
1770
1771            $this->writeColor($objWriter, $series->getFont()->getColor());
1772
1773            $objWriter->endElement();
1774
1775            // Font - a:latin
1776            $objWriter->startElement('a:latin');
1777            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1778            $objWriter->endElement();
1779            // a:ea
1780            $objWriter->startElement('a:ea');
1781            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1782            $objWriter->endElement();
1783
1784            $objWriter->endElement();
1785
1786            $objWriter->endElement();
1787
1788            // a:endParaRPr
1789            $objWriter->startElement('a:endParaRPr');
1790            $objWriter->writeAttribute('lang', 'en-US');
1791            $objWriter->writeAttribute('dirty', '0');
1792            $objWriter->endElement();
1793
1794            $objWriter->endElement();
1795
1796            $objWriter->endElement();
1797
1798            // c:showVal
1799            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1800
1801            // c:showCatName
1802            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1803
1804            // c:showSerName
1805            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1806
1807            // c:showPercent
1808            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1809
1810            // c:showLeaderLines
1811            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1812
1813            // > c:dLbls
1814            $objWriter->endElement();
1815
1816            // Write X axis data
1817            $axisXData = array_keys($series->getValues());
1818
1819            // c:cat
1820            $objWriter->startElement('c:cat');
1821            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1822            $objWriter->endElement();
1823
1824            // Write Y axis data
1825            $axisYData = array_values($series->getValues());
1826
1827            // c:val
1828            $objWriter->startElement('c:val');
1829            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
1830            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1831            $objWriter->endElement();
1832
1833            // c:smooth
1834            $objWriter->startElement('c:smooth');
1835            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1836            $objWriter->endElement();
1837
1838            $objWriter->endElement();
1839
1840            ++$seriesIndex;
1841        }
1842
1843        // c:marker
1844        $objWriter->startElement('c:marker');
1845        $objWriter->writeAttribute('val', '1');
1846        $objWriter->endElement();
1847
1848        // c:axId
1849        $objWriter->startElement('c:axId');
1850        $objWriter->writeAttribute('val', '52743552');
1851        $objWriter->endElement();
1852
1853        // c:axId
1854        $objWriter->startElement('c:axId');
1855        $objWriter->writeAttribute('val', '52749440');
1856        $objWriter->endElement();
1857
1858        $objWriter->endElement();
1859    }
1860
1861    /**
1862     * Write Type Radar.
1863     *
1864     * @param XMLWriter $objWriter XML Writer
1865     */
1866    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1867    {
1868        // c:scatterChart
1869        $objWriter->startElement('c:radarChart');
1870
1871        // c:radarStyle
1872        $objWriter->startElement('c:radarStyle');
1873        $objWriter->writeAttribute('val', 'marker');
1874        $objWriter->endElement();
1875
1876        // c:varyColors
1877        $objWriter->startElement('c:varyColors');
1878        $objWriter->writeAttribute('val', '0');
1879        $objWriter->endElement();
1880
1881        // Write series
1882        $seriesIndex = 0;
1883        foreach ($subject->getSeries() as $series) {
1884            // c:ser
1885            $objWriter->startElement('c:ser');
1886
1887            // c:idx
1888            $objWriter->startElement('c:idx');
1889            $objWriter->writeAttribute('val', $seriesIndex);
1890            $objWriter->endElement();
1891
1892            // c:order
1893            $objWriter->startElement('c:order');
1894            $objWriter->writeAttribute('val', $seriesIndex);
1895            $objWriter->endElement();
1896
1897            // c:tx
1898            $objWriter->startElement('c:tx');
1899            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
1900            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1901            $objWriter->endElement();
1902
1903            // c:spPr
1904            $objWriter->startElement('c:spPr');
1905            // Write fill
1906            $this->writeFill($objWriter, $series->getFill());
1907            // Write outline
1908            $this->writeOutline($objWriter, $series->getOutline());
1909            // ## c:spPr
1910            $objWriter->endElement();
1911
1912            // Marker
1913            $this->writeSeriesMarker($objWriter, $series->getMarker());
1914
1915            // c:dLbls
1916            $objWriter->startElement('c:dLbls');
1917
1918            // c:txPr
1919            $objWriter->startElement('c:txPr');
1920
1921            // a:bodyPr
1922            $objWriter->writeElement('a:bodyPr', null);
1923
1924            // a:lstStyle
1925            $objWriter->writeElement('a:lstStyle', null);
1926
1927            // a:p
1928            $objWriter->startElement('a:p');
1929
1930            // a:pPr
1931            $objWriter->startElement('a:pPr');
1932
1933            // a:defRPr
1934            $objWriter->startElement('a:defRPr');
1935
1936            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1937            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1938            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
1939            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1940            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1941            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
1942
1943            // Font - a:solidFill
1944            $objWriter->startElement('a:solidFill');
1945
1946            $this->writeColor($objWriter, $series->getFont()->getColor());
1947
1948            $objWriter->endElement();
1949
1950            // Font - a:latin
1951            $objWriter->startElement('a:latin');
1952            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1953            $objWriter->endElement();
1954            // a:ea
1955            $objWriter->startElement('a:ea');
1956            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1957            $objWriter->endElement();
1958
1959            $objWriter->endElement();
1960
1961            $objWriter->endElement();
1962
1963            // a:endParaRPr
1964            $objWriter->startElement('a:endParaRPr');
1965            $objWriter->writeAttribute('lang', 'en-US');
1966            $objWriter->writeAttribute('dirty', '0');
1967            $objWriter->endElement();
1968
1969            $objWriter->endElement();
1970
1971            $objWriter->endElement();
1972
1973            // c:showLegendKey
1974            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1975
1976            // c:showVal
1977            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1978
1979            // c:showCatName
1980            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1981
1982            // c:showSerName
1983            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1984
1985            // c:showPercent
1986            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1987
1988            // c:showLeaderLines
1989            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1990
1991            $objWriter->endElement();
1992
1993            // Write X axis data
1994            $axisXData = array_keys($series->getValues());
1995
1996            // c:cat
1997            $objWriter->startElement('c:cat');
1998            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1999            $objWriter->endElement();
2000
2001            // Write Y axis data
2002            $axisYData = array_values($series->getValues());
2003
2004            // c:val
2005            $objWriter->startElement('c:val');
2006            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2007            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2008            $objWriter->endElement();
2009
2010            $objWriter->endElement();
2011
2012            ++$seriesIndex;
2013        }
2014
2015        // c:axId
2016        $objWriter->startElement('c:axId');
2017        $objWriter->writeAttribute('val', '52743552');
2018        $objWriter->endElement();
2019
2020        // c:axId
2021        $objWriter->startElement('c:axId');
2022        $objWriter->writeAttribute('val', '52749440');
2023        $objWriter->endElement();
2024
2025        $objWriter->endElement();
2026    }
2027
2028    /**
2029     * Write Type Scatter.
2030     */
2031    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2032    {
2033        // c:scatterChart
2034        $objWriter->startElement('c:scatterChart');
2035
2036        // c:scatterStyle
2037        $objWriter->startElement('c:scatterStyle');
2038        $objWriter->writeAttribute('val', 'lineMarker');
2039        $objWriter->endElement();
2040
2041        // c:varyColors
2042        $objWriter->startElement('c:varyColors');
2043        $objWriter->writeAttribute('val', '0');
2044        $objWriter->endElement();
2045
2046        // Write series
2047        $seriesIndex = 0;
2048        foreach ($subject->getSeries() as $series) {
2049            // c:ser
2050            $objWriter->startElement('c:ser');
2051
2052            // c:idx
2053            $objWriter->startElement('c:idx');
2054            $objWriter->writeAttribute('val', $seriesIndex);
2055            $objWriter->endElement();
2056
2057            // c:order
2058            $objWriter->startElement('c:order');
2059            $objWriter->writeAttribute('val', $seriesIndex);
2060            $objWriter->endElement();
2061
2062            // c:tx
2063            $objWriter->startElement('c:tx');
2064            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(2 + $seriesIndex) . '$1' : '');
2065            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2066            $objWriter->endElement();
2067
2068            // c:spPr
2069            $objWriter->startElement('c:spPr');
2070            // Write fill
2071            $this->writeFill($objWriter, $series->getFill());
2072            // Write outline
2073            $this->writeOutline($objWriter, $series->getOutline());
2074            // ## c:spPr
2075            $objWriter->endElement();
2076
2077            // Marker
2078            $this->writeSeriesMarker($objWriter, $series->getMarker());
2079
2080            // c:dLbls
2081            $objWriter->startElement('c:dLbls');
2082
2083            // c:txPr
2084            $objWriter->startElement('c:txPr');
2085
2086            // a:bodyPr
2087            $objWriter->writeElement('a:bodyPr', null);
2088
2089            // a:lstStyle
2090            $objWriter->writeElement('a:lstStyle', null);
2091
2092            // a:p
2093            $objWriter->startElement('a:p');
2094
2095            // a:pPr
2096            $objWriter->startElement('a:pPr');
2097
2098            // a:defRPr
2099            $objWriter->startElement('a:defRPr');
2100
2101            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2102            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2103            $objWriter->writeAttribute('strike', $series->getFont()->getStrikethrough());
2104            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2105            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2106            $objWriter->writeAttributeIf($series->getFont()->getBaseline() !== 0, 'baseline', $series->getFont()->getBaseline());
2107
2108            // Font - a:solidFill
2109            $objWriter->startElement('a:solidFill');
2110
2111            $this->writeColor($objWriter, $series->getFont()->getColor());
2112
2113            $objWriter->endElement();
2114
2115            // Font - a:latin
2116            $objWriter->startElement('a:latin');
2117            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2118            $objWriter->endElement();
2119            // a:ea
2120            $objWriter->startElement('a:ea');
2121            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2122            $objWriter->endElement();
2123
2124            $objWriter->endElement();
2125
2126            $objWriter->endElement();
2127
2128            // a:endParaRPr
2129            $objWriter->startElement('a:endParaRPr');
2130            $objWriter->writeAttribute('lang', 'en-US');
2131            $objWriter->writeAttribute('dirty', '0');
2132            $objWriter->endElement();
2133
2134            $objWriter->endElement();
2135
2136            $objWriter->endElement();
2137
2138            // c:showLegendKey
2139            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2140
2141            // c:showVal
2142            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2143
2144            // c:showCatName
2145            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2146
2147            // c:showSerName
2148            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2149
2150            // c:showPercent
2151            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2152
2153            // c:separator
2154            $separator = $series->getSeparator();
2155            if (!empty($separator) && PHP_EOL != $separator) {
2156                // c:dLbls\c:separator
2157                $objWriter->writeElement('c:separator', $separator);
2158            }
2159
2160            // c:showLeaderLines
2161            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2162
2163            $objWriter->endElement();
2164
2165            // Write X axis data
2166            $axisXData = array_keys($series->getValues());
2167
2168            // c:xVal
2169            $objWriter->startElement('c:xVal');
2170            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2171            $objWriter->endElement();
2172
2173            // Write Y axis data
2174            $axisYData = array_values($series->getValues());
2175
2176            // c:yVal
2177            $objWriter->startElement('c:yVal');
2178            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 2) . '$' . (1 + count($axisYData)) : '');
2179            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2180            $objWriter->endElement();
2181
2182            // c:smooth
2183            $objWriter->startElement('c:smooth');
2184            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2185            $objWriter->endElement();
2186
2187            $objWriter->endElement();
2188
2189            ++$seriesIndex;
2190        }
2191
2192        // c:axId
2193        $objWriter->startElement('c:axId');
2194        $objWriter->writeAttribute('val', '52743552');
2195        $objWriter->endElement();
2196
2197        // c:axId
2198        $objWriter->startElement('c:axId');
2199        $objWriter->writeAttribute('val', '52749440');
2200        $objWriter->endElement();
2201
2202        $objWriter->endElement();
2203    }
2204
2205    /**
2206     * Write chart relationships to XML format.
2207     *
2208     * @return string XML Output
2209     */
2210    protected function writeChartRelationships(Chart $pChart): string
2211    {
2212        // Create XML writer
2213        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2214
2215        // XML header
2216        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2217
2218        // Relationships
2219        $objWriter->startElement('Relationships');
2220        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2221
2222        // Write spreadsheet relationship?
2223        if ($pChart->hasIncludedSpreadsheet()) {
2224            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2225        }
2226
2227        $objWriter->endElement();
2228
2229        // Return
2230        return $objWriter->getData();
2231    }
2232
2233    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2234    {
2235        // c:marker
2236        $objWriter->startElement('c:marker');
2237        // c:marker > c:symbol
2238        $objWriter->startElement('c:symbol');
2239        $objWriter->writeAttribute('val', $marker->getSymbol());
2240        $objWriter->endElement();
2241
2242        // Size if different of none
2243        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2244            $markerSize = (int) $marker->getSize();
2245            if ($markerSize < 2) {
2246                $markerSize = 2;
2247            }
2248            if ($markerSize > 72) {
2249                $markerSize = 72;
2250            }
2251
2252            /*
2253             * c:marker > c:size
2254             * Size in points
2255             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2256             */
2257            $objWriter->startElement('c:size');
2258            $objWriter->writeAttribute('val', $markerSize);
2259            $objWriter->endElement();
2260        }
2261
2262        // // c:marker > c:spPr
2263        $objWriter->startElement('c:spPr');
2264        $this->writeFill($objWriter, $marker->getFill());
2265        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2266        $objWriter->endElement();
2267
2268        // > c:marker
2269        $objWriter->endElement();
2270    }
2271
2272    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2273    {
2274        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2275            return;
2276        }
2277
2278        $crossesAt = $oAxis->getCrossesAt();
2279        $orientation = $oAxis->isReversedOrder() ? 'maxMin' : 'minMax';
2280
2281        if (Chart\Axis::AXIS_X == $typeAxis) {
2282            $mainElement = 'c:catAx';
2283            $axIdVal = '52743552';
2284            $axPosVal = $crossesAt === 'max' ? 't' : 'b';
2285            $crossAxVal = '52749440';
2286        } else {
2287            $mainElement = 'c:valAx';
2288            $axIdVal = '52749440';
2289            $axPosVal = $crossesAt === 'max' ? 'r' : 'l';
2290            $crossAxVal = '52743552';
2291        }
2292
2293        // $mainElement
2294        $objWriter->startElement($mainElement);
2295
2296        // $mainElement > c:axId
2297        $objWriter->startElement('c:axId');
2298        $objWriter->writeAttribute('val', $axIdVal);
2299        $objWriter->endElement();
2300
2301        // $mainElement > c:scaling
2302        $objWriter->startElement('c:scaling');
2303
2304        // $mainElement > c:scaling > c:orientation
2305        $objWriter->startElement('c:orientation');
2306        $objWriter->writeAttribute('val', $orientation);
2307        $objWriter->endElement();
2308
2309        if (null !== $oAxis->getMaxBounds()) {
2310            $objWriter->startElement('c:max');
2311            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2312            $objWriter->endElement();
2313        }
2314
2315        if (null !== $oAxis->getMinBounds()) {
2316            $objWriter->startElement('c:min');
2317            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2318            $objWriter->endElement();
2319        }
2320
2321        // $mainElement > ##c:scaling
2322        $objWriter->endElement();
2323
2324        // $mainElement > c:delete
2325        $objWriter->startElement('c:delete');
2326        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2327        $objWriter->endElement();
2328
2329        // $mainElement > c:axPos
2330        $objWriter->startElement('c:axPos');
2331        $objWriter->writeAttribute('val', $axPosVal);
2332        $objWriter->endElement();
2333
2334        $oMajorGridlines = $oAxis->getMajorGridlines();
2335        if ($oMajorGridlines instanceof Gridlines) {
2336            $objWriter->startElement('c:majorGridlines');
2337
2338            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2339
2340            $objWriter->endElement();
2341        }
2342
2343        $oMinorGridlines = $oAxis->getMinorGridlines();
2344        if ($oMinorGridlines instanceof Gridlines) {
2345            $objWriter->startElement('c:minorGridlines');
2346
2347            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2348
2349            $objWriter->endElement();
2350        }
2351
2352        if ('' != $oAxis->getTitle()) {
2353            // c:title
2354            $objWriter->startElement('c:title');
2355
2356            // c:tx
2357            $objWriter->startElement('c:tx');
2358
2359            // c:rich
2360            $objWriter->startElement('c:rich');
2361
2362            // a:bodyPr
2363            $objWriter->startElement('a:bodyPr');
2364            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $oAxis->getTitleRotation()));
2365            $objWriter->endElement();
2366
2367            // a:lstStyle
2368            $objWriter->writeElement('a:lstStyle', null);
2369
2370            // a:p
2371            $objWriter->startElement('a:p');
2372
2373            // a:pPr
2374            $objWriter->startElement('a:pPr');
2375
2376            // a:defRPr
2377            $objWriter->startElement('a:defRPr');
2378
2379            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2380            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2381            $objWriter->writeAttribute('strike', $oAxis->getFont()->getStrikethrough());
2382            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2383            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2384            $objWriter->writeAttributeIf($oAxis->getFont()->getBaseline() !== 0, 'baseline', $oAxis->getFont()->getBaseline());
2385
2386            // Font - a:solidFill
2387            $objWriter->startElement('a:solidFill');
2388            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2389            $objWriter->endElement();
2390
2391            // Font - a:latin
2392            $objWriter->startElement('a:latin');
2393            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2394            $objWriter->endElement();
2395            // a:ea
2396            $objWriter->startElement('a:ea');
2397            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2398            $objWriter->endElement();
2399
2400            $objWriter->endElement();
2401
2402            // ## a:pPr
2403            $objWriter->endElement();
2404
2405            // a:r
2406            $objWriter->startElement('a:r');
2407
2408            // a:rPr
2409            $objWriter->startElement('a:rPr');
2410            $objWriter->writeAttribute('lang', 'en-US');
2411            $objWriter->writeAttribute('dirty', '0');
2412            $objWriter->endElement();
2413
2414            // a:t
2415            $objWriter->writeElement('a:t', $oAxis->getTitle());
2416
2417            // ## a:r
2418            $objWriter->endElement();
2419
2420            // a:endParaRPr
2421            $objWriter->startElement('a:endParaRPr');
2422            $objWriter->writeAttribute('lang', 'en-US');
2423            $objWriter->writeAttribute('dirty', '0');
2424            $objWriter->endElement();
2425
2426            // ## a:p
2427            $objWriter->endElement();
2428
2429            // ## c:rich
2430            $objWriter->endElement();
2431
2432            // ## c:tx
2433            $objWriter->endElement();
2434
2435            // ## c:title
2436            $objWriter->endElement();
2437        }
2438
2439        // c:numFmt
2440        $objWriter->startElement('c:numFmt');
2441        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2442        $objWriter->writeAttribute('sourceLinked', '1');
2443        $objWriter->endElement();
2444
2445        // c:majorTickMark
2446        $objWriter->startElement('c:majorTickMark');
2447        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2448        $objWriter->endElement();
2449
2450        // c:minorTickMark
2451        $objWriter->startElement('c:minorTickMark');
2452        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2453        $objWriter->endElement();
2454
2455        // c:tickLblPos
2456        $objWriter->startElement('c:tickLblPos');
2457        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2458        $objWriter->endElement();
2459
2460        // c:spPr
2461        $objWriter->startElement('c:spPr');
2462        $this->writeOutline($objWriter, $oAxis->getOutline());
2463        $objWriter->endElement();
2464
2465        // c:txPr
2466        $objWriter->startElement('c:txPr');
2467
2468        // a:bodyPr
2469        $objWriter->writeElement('a:bodyPr', null);
2470
2471        // a:lstStyle
2472        $objWriter->writeElement('a:lstStyle', null);
2473
2474        // a:p
2475        $objWriter->startElement('a:p');
2476
2477        // a:pPr
2478        $objWriter->startElement('a:pPr');
2479
2480        // a:defRPr
2481        $objWriter->startElement('a:defRPr');
2482        $objWriter->writeAttribute('b', ($oAxis->getTickLabelFont()->isBold() ? 'true' : 'false'));
2483        $objWriter->writeAttribute('i', ($oAxis->getTickLabelFont()->isItalic() ? 'true' : 'false'));
2484        $objWriter->writeAttribute('strike', $oAxis->getFont()->getStrikethrough());
2485        $objWriter->writeAttribute('sz', ($oAxis->getTickLabelFont()->getSize() * 100));
2486        $objWriter->writeAttribute('u', $oAxis->getTickLabelFont()->getUnderline());
2487        $objWriter->writeAttributeIf($oAxis->getTickLabelFont()->getBaseline() !== 0, 'baseline', $oAxis->getTickLabelFont()->getBaseline());
2488
2489        // Font - a:solidFill
2490        $objWriter->startElement('a:solidFill');
2491        $this->writeColor($objWriter, $oAxis->getTickLabelFont()->getColor());
2492        $objWriter->endElement();
2493
2494        // Font - a:latin
2495        $objWriter->startElement('a:latin');
2496        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2497        $objWriter->endElement();
2498
2499        // Font - a:ea
2500        $objWriter->startElement('a:ea');
2501        $objWriter->writeAttribute('typeface', $oAxis->getTickLabelFont()->getName());
2502        $objWriter->endElement();
2503
2504        //## a:defRPr
2505        $objWriter->endElement();
2506
2507        //## a:pPr
2508        $objWriter->endElement();
2509
2510        // a:endParaRPr
2511        $objWriter->startElement('a:endParaRPr');
2512        $objWriter->writeAttribute('lang', 'en-US');
2513        $objWriter->writeAttribute('dirty', '0');
2514        $objWriter->endElement();
2515
2516        // ## a:p
2517        $objWriter->endElement();
2518
2519        // ## c:txPr
2520        $objWriter->endElement();
2521
2522        // c:crossAx
2523        $objWriter->startElement('c:crossAx');
2524        $objWriter->writeAttribute('val', $crossAxVal);
2525        $objWriter->endElement();
2526
2527        // c:crosses "autoZero" | "min" | "max" | custom string value
2528        if (in_array($crossesAt, ['autoZero', 'min', 'max'])) {
2529            $objWriter->startElement('c:crosses');
2530            $objWriter->writeAttribute('val', $crossesAt);
2531            $objWriter->endElement();
2532        } else {
2533            $objWriter->startElement('c:crossesAt');
2534            $objWriter->writeAttribute('val', $crossesAt);
2535            $objWriter->endElement();
2536        }
2537
2538        if (Chart\Axis::AXIS_X == $typeAxis) {
2539            // c:lblAlgn
2540            $objWriter->startElement('c:lblAlgn');
2541            $objWriter->writeAttribute('val', 'ctr');
2542            $objWriter->endElement();
2543
2544            // c:lblOffset
2545            $objWriter->startElement('c:lblOffset');
2546            $objWriter->writeAttribute('val', '100');
2547            $objWriter->endElement();
2548
2549            // c:majorUnit
2550            if ($oAxis->getMajorUnit() !== null) {
2551                $objWriter->startElement('c:tickLblSkip');
2552                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2553                $objWriter->endElement();
2554            }
2555        }
2556
2557        if (Chart\Axis::AXIS_Y == $typeAxis) {
2558            // c:crossBetween
2559            $objWriter->startElement('c:crossBetween');
2560            // midCat : Position Axis On Tick Marks
2561            // between : Between Tick Marks
2562            if ($typeChart instanceof Area) {
2563                $objWriter->writeAttribute('val', 'midCat');
2564            } else {
2565                $objWriter->writeAttribute('val', 'between');
2566            }
2567            $objWriter->endElement();
2568
2569            // c:majorUnit
2570            if ($oAxis->getMajorUnit() !== null) {
2571                $objWriter->startElement('c:majorUnit');
2572                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2573                $objWriter->endElement();
2574            }
2575
2576            // c:minorUnit
2577            if ($oAxis->getMinorUnit() !== null) {
2578                $objWriter->startElement('c:minorUnit');
2579                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2580                $objWriter->endElement();
2581            }
2582        }
2583
2584        $objWriter->endElement();
2585    }
2586
2587    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2588    {
2589        // c:spPr
2590        $objWriter->startElement('c:spPr');
2591
2592        // Outline
2593        $this->writeOutline($objWriter, $oGridlines->getOutline());
2594
2595        // ##c:spPr
2596        $objWriter->endElement();
2597    }
2598}