Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
99.81% covered (success)
99.81%
537 / 538
95.45% covered (success)
95.45%
21 / 22
CRAP
0.00% covered (danger)
0.00%
0 / 1
ObjectsChart
99.81% covered (success)
99.81%
537 / 538
95.45% covered (success)
95.45%
21 / 22
117
0.00% covered (danger)
0.00%
0 / 1
 render
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 writeContentPart
100.00% covered (success)
100.00%
92 / 92
100.00% covered (success)
100.00%
1 / 1
8
 writeAxis
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
5
 writeGridline
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
2
 writeAxisStyle
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
1
 writeAxisMainStyle
100.00% covered (success)
100.00%
36 / 36
100.00% covered (success)
100.00%
1 / 1
6
 writeAxisTitleStyle
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
2
 writeGridlineStyle
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 writeChartStyle
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
1
 writeFloor
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 writeFloorStyle
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
1
 writeLegend
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
7
 writeLegendStyle
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
 writePlotArea
100.00% covered (success)
100.00%
33 / 33
100.00% covered (success)
100.00%
1 / 1
7
 writePlotAreaStyle
100.00% covered (success)
100.00%
42 / 42
100.00% covered (success)
100.00%
1 / 1
14
 writeSeries
100.00% covered (success)
100.00%
39 / 39
100.00% covered (success)
100.00%
1 / 1
10
 writeSeriesStyle
98.72% covered (success)
98.72%
77 / 78
0.00% covered (danger)
0.00%
0 / 1
24
 writeTable
100.00% covered (success)
100.00%
50 / 50
100.00% covered (success)
100.00%
1 / 1
12
 writeTitle
100.00% covered (success)
100.00%
10 / 10
100.00% covered (success)
100.00%
1 / 1
2
 writeTitleStyle
100.00% covered (success)
100.00%
12 / 12
100.00% covered (success)
100.00%
1 / 1
3
 writeWall
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 writeWallStyle
100.00% covered (success)
100.00%
14 / 14
100.00% covered (success)
100.00%
1 / 1
3
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\ODPresentation;
21
22use PhpOffice\Common\Adapter\Zip\ZipInterface;
23use PhpOffice\Common\Drawing as CommonDrawing;
24use PhpOffice\Common\Text;
25use PhpOffice\Common\XMLWriter;
26use PhpOffice\PhpPresentation\Shape\Chart;
27use PhpOffice\PhpPresentation\Shape\Chart\Axis;
28use PhpOffice\PhpPresentation\Shape\Chart\Title;
29use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType;
30use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeBar;
31use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeLine;
32use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypePie;
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\Pie3D;
39use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
40use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
41use PhpOffice\PhpPresentation\Style\Fill;
42use PhpOffice\PhpPresentation\Style\Outline;
43
44class ObjectsChart extends AbstractDecoratorWriter
45{
46    /**
47     * @var XMLWriter
48     */
49    protected $xmlContent;
50
51    /**
52     * @var mixed
53     */
54    protected $arrayData;
55
56    /**
57     * @var mixed
58     */
59    protected $arrayTitle;
60
61    /**
62     * @var int
63     */
64    protected $numData;
65
66    /**
67     * @var int
68     */
69    protected $numSeries;
70
71    /**
72     * @var string
73     */
74    protected $rangeCol;
75
76    public function render(): ZipInterface
77    {
78        foreach ($this->getArrayChart() as $keyChart => $shapeChart) {
79            $content = $this->writeContentPart($shapeChart);
80
81            if (!empty($content)) {
82                $this->getZip()->addFromString('Object ' . $keyChart . '/content.xml', $content);
83            }
84        }
85
86        return $this->getZip();
87    }
88
89    protected function writeContentPart(Chart $chart): string
90    {
91        $this->xmlContent = new XMLWriter(XMLWriter::STORAGE_MEMORY);
92
93        $chartType = $chart->getPlotArea()->getType();
94
95        // Data
96        $this->arrayData = [];
97        $this->arrayTitle = [];
98        $this->numData = 0;
99        foreach ($chartType->getSeries() as $series) {
100            $inc = 0;
101            $this->arrayTitle[] = $series->getTitle();
102            foreach ($series->getValues() as $key => $value) {
103                if (!isset($this->arrayData[$inc])) {
104                    $this->arrayData[$inc] = [];
105                }
106                if (empty($this->arrayData[$inc])) {
107                    $this->arrayData[$inc][] = $key;
108                }
109                $this->arrayData[$inc][] = $value;
110                ++$inc;
111            }
112            if ($inc > $this->numData) {
113                $this->numData = $inc;
114            }
115        }
116
117        // office:document-content
118        $this->xmlContent->startElement('office:document-content');
119        $this->xmlContent->writeAttribute('xmlns:office', 'urn:oasis:names:tc:opendocument:xmlns:office:1.0');
120        $this->xmlContent->writeAttribute('xmlns:style', 'urn:oasis:names:tc:opendocument:xmlns:style:1.0');
121        $this->xmlContent->writeAttribute('xmlns:text', 'urn:oasis:names:tc:opendocument:xmlns:text:1.0');
122        $this->xmlContent->writeAttribute('xmlns:table', 'urn:oasis:names:tc:opendocument:xmlns:table:1.0');
123        $this->xmlContent->writeAttribute('xmlns:draw', 'urn:oasis:names:tc:opendocument:xmlns:drawing:1.0');
124        $this->xmlContent->writeAttribute('xmlns:fo', 'urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0');
125        $this->xmlContent->writeAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
126        $this->xmlContent->writeAttribute('xmlns:dc', 'http://purl.org/dc/elements/1.1/');
127        $this->xmlContent->writeAttribute('xmlns:meta', 'urn:oasis:names:tc:opendocument:xmlns:meta:1.0');
128        $this->xmlContent->writeAttribute('xmlns:number', 'urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0');
129        $this->xmlContent->writeAttribute('xmlns:svg', 'urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0');
130        $this->xmlContent->writeAttribute('xmlns:chart', 'urn:oasis:names:tc:opendocument:xmlns:chart:1.0');
131        $this->xmlContent->writeAttribute('xmlns:dr3d', 'urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0');
132        $this->xmlContent->writeAttribute('xmlns:math', 'http://www.w3.org/1998/Math/MathML');
133        $this->xmlContent->writeAttribute('xmlns:form', 'urn:oasis:names:tc:opendocument:xmlns:form:1.0');
134        $this->xmlContent->writeAttribute('xmlns:script', 'urn:oasis:names:tc:opendocument:xmlns:script:1.0');
135        $this->xmlContent->writeAttribute('xmlns:ooo', 'http://openoffice.org/2004/office');
136        $this->xmlContent->writeAttribute('xmlns:ooow', 'http://openoffice.org/2004/writer');
137        $this->xmlContent->writeAttribute('xmlns:oooc', 'http://openoffice.org/2004/calc');
138        $this->xmlContent->writeAttribute('xmlns:dom', 'http://www.w3.org/2001/xml-events');
139        $this->xmlContent->writeAttribute('xmlns:xforms', 'http://www.w3.org/2002/xforms');
140        $this->xmlContent->writeAttribute('xmlns:xsd', 'http://www.w3.org/2001/XMLSchema');
141        $this->xmlContent->writeAttribute('xmlns:xsi', 'http://www.w3.org/2001/XMLSchema-instance');
142        $this->xmlContent->writeAttribute('xmlns:rpt', 'http://openoffice.org/2005/report');
143        $this->xmlContent->writeAttribute('xmlns:of', 'urn:oasis:names:tc:opendocument:xmlns:of:1.2');
144        $this->xmlContent->writeAttribute('xmlns:xhtml', 'http://www.w3.org/1999/xhtml');
145        $this->xmlContent->writeAttribute('xmlns:grddl', 'http://www.w3.org/2003/g/data-view#');
146        $this->xmlContent->writeAttribute('xmlns:tableooo', 'http://openoffice.org/2009/table');
147        $this->xmlContent->writeAttribute('xmlns:chartooo', 'http://openoffice.org/2010/chart');
148        $this->xmlContent->writeAttribute('xmlns:drawooo', 'http://openoffice.org/2010/draw');
149        $this->xmlContent->writeAttribute('xmlns:calcext', 'urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0');
150        $this->xmlContent->writeAttribute('xmlns:loext', 'urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0');
151        $this->xmlContent->writeAttribute('xmlns:field', 'urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0');
152        $this->xmlContent->writeAttribute('xmlns:formx', 'urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0');
153        $this->xmlContent->writeAttribute('xmlns:css3t', 'http://www.w3.org/TR/css3-text/');
154        $this->xmlContent->writeAttribute('office:version', '1.2');
155
156        // office:automatic-styles
157        $this->xmlContent->startElement('office:automatic-styles');
158
159        // Styles
160        $this->writeChartStyle($chart);
161        $this->writeAxisStyle($chart);
162        $this->numSeries = 0;
163        foreach ($chartType->getSeries() as $series) {
164            $this->writeSeriesStyle($chart, $series);
165            ++$this->numSeries;
166        }
167        $this->writeFloorStyle();
168        $this->writeLegendStyle($chart);
169        $this->writePlotAreaStyle($chart);
170        $this->writeTitleStyle($chart->getTitle());
171        $this->writeWallStyle($chart);
172
173        // > office:automatic-styles
174        $this->xmlContent->endElement();
175
176        // office:body
177        $this->xmlContent->startElement('office:body');
178        // office:chart
179        $this->xmlContent->startElement('office:chart');
180        // office:chart
181        $this->xmlContent->startElement('chart:chart');
182        $this->xmlContent->writeAttribute('svg:width', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getWidth()), 3) . 'cm');
183        $this->xmlContent->writeAttribute('svg:height', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getHeight()), 3) . 'cm');
184        $this->xmlContent->writeAttribute('xlink:href', '.');
185        $this->xmlContent->writeAttribute('xlink:type', 'simple');
186        $this->xmlContent->writeAttribute('chart:style-name', 'styleChart');
187        $this->xmlContent->writeAttributeIf($chartType instanceof Area, 'chart:class', 'chart:area');
188        $this->xmlContent->writeAttributeIf($chartType instanceof AbstractTypeBar, 'chart:class', 'chart:bar');
189        if (!($chartType instanceof Doughnut)) {
190            $this->xmlContent->writeAttributeIf($chartType instanceof AbstractTypePie, 'chart:class', 'chart:circle');
191        }
192        $this->xmlContent->writeAttributeIf($chartType instanceof Doughnut, 'chart:class', 'chart:ring');
193        $this->xmlContent->writeAttributeIf($chartType instanceof Line, 'chart:class', 'chart:line');
194        $this->xmlContent->writeAttributeIf($chartType instanceof Radar, 'chart:class', 'chart:radar');
195        $this->xmlContent->writeAttributeIf($chartType instanceof Scatter, 'chart:class', 'chart:scatter');
196
197        $this->writeTitle($chart->getTitle());
198        $this->writeLegend($chart);
199        $this->writePlotArea($chart);
200        $this->writeTable();
201
202        // > chart:chart
203        $this->xmlContent->endElement();
204        // > office:chart
205        $this->xmlContent->endElement();
206        // > office:body
207        $this->xmlContent->endElement();
208        // > office:document-content
209        $this->xmlContent->endElement();
210
211        return $this->xmlContent->getData();
212    }
213
214    protected function writeAxis(Chart $chart): void
215    {
216        $chartType = $chart->getPlotArea()->getType();
217
218        // chart:axis
219        $this->xmlContent->startElement('chart:axis');
220        $this->xmlContent->writeAttribute('chart:dimension', 'x');
221        $this->xmlContent->writeAttribute('chart:name', 'primary-x');
222        $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisX');
223        // chart:axis > chart:title
224        if ($chart->getPlotArea()->getAxisX()->isVisible()) {
225            $this->xmlContent->startElement('chart:title');
226            $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisXTitle');
227            $this->xmlContent->writeElement('text:p', $chart->getPlotArea()->getAxisX()->getTitle());
228            $this->xmlContent->endElement();
229        }
230        // chart:axis > chart:categories
231        $this->xmlContent->startElement('chart:categories');
232        $this->xmlContent->writeAttribute('table:cell-range-address', 'table-local.$A$2:.$A$' . ($this->numData + 1));
233        $this->xmlContent->endElement();
234        // chart:axis > chart:grid
235        $this->writeGridline($chart->getPlotArea()->getAxisX()->getMajorGridlines(), 'styleAxisXGridlinesMajor', 'major');
236        // chart:axis > chart:grid
237        $this->writeGridline($chart->getPlotArea()->getAxisX()->getMinorGridlines(), 'styleAxisXGridlinesMinor', 'minor');
238        // ##chart:axis
239        $this->xmlContent->endElement();
240
241        // chart:axis
242        $this->xmlContent->startElement('chart:axis');
243        $this->xmlContent->writeAttribute('chart:dimension', 'y');
244        $this->xmlContent->writeAttribute('chart:name', 'primary-y');
245        $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisY');
246        // chart:axis > chart:title
247        if ($chart->getPlotArea()->getAxisY()->isVisible()) {
248            $this->xmlContent->startElement('chart:title');
249            $this->xmlContent->writeAttribute('chart:style-name', 'styleAxisYTitle');
250            $this->xmlContent->writeElement('text:p', $chart->getPlotArea()->getAxisY()->getTitle());
251            $this->xmlContent->endElement();
252        }
253        // chart:axis > chart:grid
254        $this->writeGridline($chart->getPlotArea()->getAxisY()->getMajorGridlines(), 'styleAxisYGridlinesMajor', 'major');
255        // chart:axis > chart:grid
256        $this->writeGridline($chart->getPlotArea()->getAxisY()->getMinorGridlines(), 'styleAxisYGridlinesMinor', 'minor');
257        // ##chart:axis
258        $this->xmlContent->endElement();
259
260        if ($chartType instanceof Bar3D || $chartType instanceof Pie3D) {
261            // chart:axis
262            $this->xmlContent->startElement('chart:axis');
263            $this->xmlContent->writeAttribute('chart:dimension', 'z');
264            $this->xmlContent->writeAttribute('chart:name', 'primary-z');
265            // > chart:axis
266            $this->xmlContent->endElement();
267        }
268    }
269
270    protected function writeGridline(?Chart\Gridlines $oGridlines, string $styleName, string $chartClass): void
271    {
272        if (!$oGridlines) {
273            return;
274        }
275
276        $this->xmlContent->startElement('chart:grid');
277        $this->xmlContent->writeAttribute('chart:style-name', $styleName);
278        $this->xmlContent->writeAttribute('chart:class', $chartClass);
279        $this->xmlContent->endElement();
280    }
281
282    /**
283     * @todo Set function in \PhpPresentation\Shape\Chart\Axis for defining width and color of the axis
284     */
285    protected function writeAxisStyle(Chart $chart): void
286    {
287        $chartType = $chart->getPlotArea()->getType();
288
289        // AxisX
290        $this->writeAxisMainStyle($chart->getPlotArea()->getAxisX(), 'styleAxisX', $chartType);
291
292        // AxisX Title
293        $this->writeAxisTitleStyle($chart->getPlotArea()->getAxisX(), 'styleAxisXTitle');
294
295        // AxisX GridLines Major
296        $this->writeGridlineStyle($chart->getPlotArea()->getAxisX()->getMajorGridlines(), 'styleAxisXGridlinesMajor');
297
298        // AxisX GridLines Minor
299        $this->writeGridlineStyle($chart->getPlotArea()->getAxisX()->getMinorGridlines(), 'styleAxisXGridlinesMinor');
300
301        // AxisY
302        $this->writeAxisMainStyle($chart->getPlotArea()->getAxisY(), 'styleAxisY', $chartType);
303
304        // AxisY Title
305        $this->writeAxisTitleStyle($chart->getPlotArea()->getAxisY(), 'styleAxisYTitle');
306
307        // AxisY GridLines Major
308        $this->writeGridlineStyle($chart->getPlotArea()->getAxisY()->getMajorGridlines(), 'styleAxisYGridlinesMajor');
309
310        // AxisY GridLines Minor
311        $this->writeGridlineStyle($chart->getPlotArea()->getAxisY()->getMinorGridlines(), 'styleAxisYGridlinesMinor');
312    }
313
314    protected function writeAxisMainStyle(Axis $axis, string $styleName, AbstractType $chartType): void
315    {
316        // style:style
317        $this->xmlContent->startElement('style:style');
318        $this->xmlContent->writeAttribute('style:name', $styleName);
319        $this->xmlContent->writeAttribute('style:family', 'chart');
320        // style:style > style:chart-properties
321        $this->xmlContent->startElement('style:chart-properties');
322        $this->xmlContent->writeAttribute('chart:display-label', 'true');
323        $this->xmlContent->writeAttribute('chart:tick-marks-major-inner', 'false');
324        $this->xmlContent->writeAttribute('chart:tick-marks-major-outer', 'false');
325        $this->xmlContent->writeAttributeIf($chartType instanceof AbstractTypePie, 'chart:reverse-direction', 'true');
326        $this->xmlContent->writeAttributeIf(null !== $axis->getMinBounds(), 'chart:minimum', $axis->getMinBounds());
327        $this->xmlContent->writeAttributeIf(null !== $axis->getMaxBounds(), 'chart:maximum', $axis->getMaxBounds());
328        $this->xmlContent->writeAttributeIf(null !== $axis->getMajorUnit(), 'chart:interval-major', $axis->getMajorUnit());
329        $this->xmlContent->writeAttributeIf(null !== $axis->getMinorUnit(), 'chart:interval-minor-divisor', $axis->getMinorUnit());
330        switch ($axis->getTickLabelPosition()) {
331            case Axis::TICK_LABEL_POSITION_NEXT_TO:
332                $this->xmlContent->writeAttribute('chart:axis-label-position', 'near-axis');
333
334                break;
335            case Axis::TICK_LABEL_POSITION_HIGH:
336                $this->xmlContent->writeAttribute('chart:axis-position', '0');
337                $this->xmlContent->writeAttribute('chart:axis-label-position', 'outside-end');
338
339                break;
340            case Axis::TICK_LABEL_POSITION_LOW:
341                $this->xmlContent->writeAttribute('chart:axis-position', '0');
342                $this->xmlContent->writeAttribute('chart:axis-label-position', 'outside-start');
343                $this->xmlContent->writeAttribute('chart:tick-mark-position', 'at-axis');
344
345                break;
346        }
347        $this->xmlContent->writeAttributeIf($chartType instanceof Radar && $styleName == 'styleAxisX', 'chart:reverse-direction', 'true');
348        $this->xmlContent->endElement();
349        // style:graphic-properties
350        $this->xmlContent->startElement('style:graphic-properties');
351        $this->xmlContent->writeAttribute('draw:stroke', $axis->getOutline()->getFill()->getFillType());
352        $this->xmlContent->writeAttribute('svg:stroke-width', number_format(CommonDrawing::pointsToCentimeters($axis->getOutline()->getWidth()), 3, '.', '') . 'cm');
353        $this->xmlContent->writeAttribute('svg:stroke-color', '#' . $axis->getOutline()->getFill()->getStartColor()->getRGB());
354        $this->xmlContent->endElement();
355        // style:style > style:text-properties
356        $this->xmlContent->startElement('style:text-properties');
357        $this->xmlContent->writeAttribute('fo:color', '#' . $axis->getFont()->getColor()->getRGB());
358        $this->xmlContent->writeAttribute('fo:font-family', $axis->getFont()->getName());
359        $this->xmlContent->writeAttribute('fo:font-size', $axis->getFont()->getSize() . 'pt');
360        $this->xmlContent->writeAttribute('fo:font-style', $axis->getFont()->isItalic() ? 'italic' : 'normal');
361        $this->xmlContent->endElement();
362        // ## style:style
363        $this->xmlContent->endElement();
364    }
365
366    protected function writeAxisTitleStyle(Axis $axis, string $styleName): void
367    {
368        // style:style
369        $this->xmlContent->startElement('style:style');
370        $this->xmlContent->writeAttribute('style:name', $styleName);
371        $this->xmlContent->writeAttribute('style:family', 'chart');
372        // style:chart-properties
373        $this->xmlContent->startElement('style:chart-properties');
374        $this->xmlContent->writeAttribute('chart:auto-position', 'true');
375        $this->xmlContent->writeAttributeIf($axis->getTitleRotation() != 0, 'style:rotation-angle', '-' . $axis->getTitleRotation());
376        // > style:chart-properties
377        $this->xmlContent->endElement();
378        // style:text-properties
379        $this->xmlContent->startElement('style:text-properties');
380        $this->xmlContent->writeAttribute('fo:color', '#' . $axis->getFont()->getColor()->getRGB());
381        $this->xmlContent->writeAttribute('fo:font-family', $axis->getFont()->getName());
382        $this->xmlContent->writeAttribute('fo:font-size', $axis->getFont()->getSize() . 'pt');
383        $this->xmlContent->writeAttribute('fo:font-style', $axis->getFont()->isItalic() ? 'italic' : 'normal');
384        // > style:text-properties
385        $this->xmlContent->endElement();
386        // > style:style
387        $this->xmlContent->endElement();
388    }
389
390    protected function writeGridlineStyle(?Chart\Gridlines $oGridlines, string $styleName): void
391    {
392        if (!$oGridlines) {
393            return;
394        }
395        // style:style
396        $this->xmlContent->startElement('style:style');
397        $this->xmlContent->writeAttribute('style:name', $styleName);
398        $this->xmlContent->writeAttribute('style:family', 'chart');
399        // style:style > style:graphic-properties
400        $this->xmlContent->startElement('style:graphic-properties');
401        $this->xmlContent->writeAttribute('svg:stroke-width', number_format(CommonDrawing::pointsToCentimeters($oGridlines->getOutline()->getWidth()), 2, '.', '') . 'cm');
402        $this->xmlContent->writeAttribute('svg:stroke-color', '#' . $oGridlines->getOutline()->getFill()->getStartColor()->getRGB());
403        $this->xmlContent->endElement();
404        // ##style:style
405        $this->xmlContent->endElement();
406    }
407
408    protected function writeChartStyle(Chart $chart): void
409    {
410        // style:style
411        $this->xmlContent->startElement('style:style');
412        $this->xmlContent->writeAttribute('style:name', 'styleChart');
413        $this->xmlContent->writeAttribute('style:family', 'chart');
414        // style:graphic-properties
415        $this->xmlContent->startElement('style:graphic-properties');
416        $this->xmlContent->writeAttribute('draw:stroke', $chart->getFill()->getFillType());
417        $this->xmlContent->writeAttribute('draw:fill-color', '#' . $chart->getFill()->getStartColor()->getRGB());
418        // > style:graphic-properties
419        $this->xmlContent->endElement();
420        // > style:style
421        $this->xmlContent->endElement();
422    }
423
424    protected function writeFloor(): void
425    {
426        // chart:floor
427        $this->xmlContent->startElement('chart:floor');
428        $this->xmlContent->writeAttribute('chart:style-name', 'styleFloor');
429        // > chart:floor
430        $this->xmlContent->endElement();
431    }
432
433    protected function writeFloorStyle(): void
434    {
435        // style:style
436        $this->xmlContent->startElement('style:style');
437        $this->xmlContent->writeAttribute('style:name', 'styleFloor');
438        $this->xmlContent->writeAttribute('style:family', 'chart');
439        // style:chart-properties
440        $this->xmlContent->startElement('style:graphic-properties');
441        $this->xmlContent->writeAttribute('draw:fill', 'none');
442        //@todo : Permit edit color and size border of floor
443        $this->xmlContent->writeAttribute('draw:stroke', 'solid');
444        $this->xmlContent->writeAttribute('svg:stroke-width', '0.026cm');
445        $this->xmlContent->writeAttribute('svg:stroke-color', '#878787');
446        // > style:chart-properties
447        $this->xmlContent->endElement();
448        // > style:style
449        $this->xmlContent->endElement();
450    }
451
452    protected function writeLegend(Chart $chart): void
453    {
454        // chart:legend
455        $this->xmlContent->startElement('chart:legend');
456        switch ($chart->getLegend()->getPosition()) {
457            case Chart\Legend::POSITION_BOTTOM:
458                $position = 'bottom';
459
460                break;
461            case Chart\Legend::POSITION_LEFT:
462                $position = 'start';
463
464                break;
465            case Chart\Legend::POSITION_TOP:
466                $position = 'top';
467
468                break;
469            case Chart\Legend::POSITION_TOPRIGHT:
470                $position = 'top-end';
471
472                break;
473            case Chart\Legend::POSITION_RIGHT:
474            default:
475                $position = 'end';
476
477                break;
478        }
479        $this->xmlContent->writeAttribute('chart:legend-position', $position);
480        $this->xmlContent->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getLegend()->getOffsetX()), 3) . 'cm');
481        $this->xmlContent->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $chart->getLegend()->getOffsetY()), 3) . 'cm');
482        $this->xmlContent->writeAttribute('style:legend-expansion', 'high');
483        $this->xmlContent->writeAttribute('chart:style-name', 'styleLegend');
484        // > chart:legend
485        $this->xmlContent->endElement();
486    }
487
488    protected function writeLegendStyle(Chart $chart): void
489    {
490        // style:style
491        $this->xmlContent->startElement('style:style');
492        $this->xmlContent->writeAttribute('style:name', 'styleLegend');
493        $this->xmlContent->writeAttribute('style:family', 'chart');
494        // style:chart-properties
495        $this->xmlContent->startElement('style:chart-properties');
496        $this->xmlContent->writeAttribute('chart:auto-position', 'true');
497        // > style:chart-properties
498        $this->xmlContent->endElement();
499        // style:text-properties
500        $this->xmlContent->startElement('style:text-properties');
501        $this->xmlContent->writeAttribute('fo:color', '#' . $chart->getLegend()->getFont()->getColor()->getRGB());
502        $this->xmlContent->writeAttribute('fo:font-family', $chart->getLegend()->getFont()->getName());
503        $this->xmlContent->writeAttribute('fo:font-size', $chart->getLegend()->getFont()->getSize() . 'pt');
504        $this->xmlContent->writeAttribute('fo:font-style', $chart->getLegend()->getFont()->isItalic() ? 'italic' : 'normal');
505        // > style:text-properties
506        $this->xmlContent->endElement();
507        // > style:style
508        $this->xmlContent->endElement();
509    }
510
511    protected function writePlotArea(Chart $chart): void
512    {
513        $chartType = $chart->getPlotArea()->getType();
514
515        // chart:plot-area
516        $this->xmlContent->startElement('chart:plot-area');
517        $this->xmlContent->writeAttribute('chart:style-name', 'stylePlotArea');
518        if ($chartType instanceof Bar3D || $chartType instanceof Pie3D) {
519            $this->xmlContent->writeAttribute('dr3d:ambient-color', '#cccccc');
520            $this->xmlContent->writeAttribute('dr3d:lighting-mode', 'true');
521        }
522        if ($chartType instanceof Bar3D || $chartType instanceof Pie3D) {
523            // dr3d:light
524            $arrayLight = [
525                ['#808080', '(0 0 1)', 'false', 'true'],
526                ['#666666', '(0.2 0.4 1)', 'true', 'false'],
527                ['#808080', '(0 0 1)', 'false', 'false'],
528                ['#808080', '(0 0 1)', 'false', 'false'],
529                ['#808080', '(0 0 1)', 'false', 'false'],
530                ['#808080', '(0 0 1)', 'false', 'false'],
531                ['#808080', '(0 0 1)', 'false', 'false'],
532            ];
533            foreach ($arrayLight as $light) {
534                $this->xmlContent->startElement('dr3d:light');
535                $this->xmlContent->writeAttribute('dr3d:diffuse-color', $light[0]);
536                $this->xmlContent->writeAttribute('dr3d:direction', $light[1]);
537                $this->xmlContent->writeAttribute('dr3d:enabled', $light[2]);
538                $this->xmlContent->writeAttribute('dr3d:specular', $light[3]);
539                $this->xmlContent->endElement();
540            }
541        }
542
543        //**** Axis ****
544        $this->writeAxis($chart);
545
546        //**** Series ****
547        $this->rangeCol = 'B';
548        $this->numSeries = 0;
549        foreach ($chartType->getSeries() as $series) {
550            $this->writeSeries($chart, $series);
551            ++$this->rangeCol;
552            ++$this->numSeries;
553        }
554
555        //**** Wall ****
556        $this->writeWall();
557        //**** Floor ****
558        $this->writeFloor();
559        // > chart:plot-area
560        $this->xmlContent->endElement();
561    }
562
563    /**
564     * @see : http://books.evc-cit.info/odbook/ch08.html#chart-plot-area-section
565     */
566    protected function writePlotAreaStyle(Chart $chart): void
567    {
568        $chartType = $chart->getPlotArea()->getType();
569
570        // style:style
571        $this->xmlContent->startElement('style:style');
572        $this->xmlContent->writeAttribute('style:name', 'stylePlotArea');
573        $this->xmlContent->writeAttribute('style:family', 'chart');
574        // style:text-properties
575        $this->xmlContent->startElement('style:chart-properties');
576        if ($chartType instanceof Bar3D) {
577            $this->xmlContent->writeAttribute('chart:three-dimensional', 'true');
578            $this->xmlContent->writeAttribute('chart:right-angled-axes', 'true');
579        } elseif ($chartType instanceof Pie3D) {
580            $this->xmlContent->writeAttribute('chart:three-dimensional', 'true');
581            $this->xmlContent->writeAttribute('chart:right-angled-axes', 'true');
582        } elseif ($chartType instanceof AbstractTypeLine) {
583            $this->xmlContent->writeAttributeIf($chartType->isSmooth(), 'chart:interpolation', 'cubic-spline');
584        }
585        switch ($chart->getDisplayBlankAs()) {
586            case Chart::BLANKAS_ZERO:
587                $this->xmlContent->writeAttribute('chart:treat-empty-cells', 'use-zero');
588
589                break;
590            case Chart::BLANKAS_GAP:
591                $this->xmlContent->writeAttribute('chart:treat-empty-cells', 'leave-gap');
592
593                break;
594            case Chart::BLANKAS_SPAN:
595                $this->xmlContent->writeAttribute('chart:treat-empty-cells', 'ignore');
596
597                break;
598        }
599        if ($chartType instanceof AbstractTypeBar) {
600            $chartVertical = 'false';
601            if (AbstractTypeBar::DIRECTION_HORIZONTAL == $chartType->getBarDirection()) {
602                $chartVertical = 'true';
603            }
604            $this->xmlContent->writeAttribute('chart:vertical', $chartVertical);
605            if (Bar::GROUPING_CLUSTERED == $chartType->getBarGrouping()) {
606                $this->xmlContent->writeAttribute('chart:stacked', 'false');
607                $this->xmlContent->writeAttribute('chart:overlap', '0');
608            } elseif (Bar::GROUPING_STACKED == $chartType->getBarGrouping()) {
609                $this->xmlContent->writeAttribute('chart:stacked', 'true');
610                $this->xmlContent->writeAttribute('chart:overlap', '100');
611            } elseif (Bar::GROUPING_PERCENTSTACKED == $chartType->getBarGrouping()) {
612                $this->xmlContent->writeAttribute('chart:stacked', 'true');
613                $this->xmlContent->writeAttribute('chart:overlap', '100');
614                $this->xmlContent->writeAttribute('chart:percentage', 'true');
615            }
616        }
617        $labelFormat = 'value';
618        if ($chartType instanceof AbstractTypeBar) {
619            if (Bar::GROUPING_PERCENTSTACKED == $chartType->getBarGrouping()) {
620                $labelFormat = 'percentage';
621            }
622        }
623        $this->xmlContent->writeAttribute('chart:data-label-number', $labelFormat);
624
625        // > style:text-properties
626        $this->xmlContent->endElement();
627        // > style:style
628        $this->xmlContent->endElement();
629    }
630
631    protected function writeSeries(Chart $chart, Chart\Series $series): void
632    {
633        $chartType = $chart->getPlotArea()->getType();
634
635        $numRange = count($series->getValues());
636        // chart:series
637        $this->xmlContent->startElement('chart:series');
638        $this->xmlContent->writeAttribute('chart:values-cell-range-address', 'table-local.$' . $this->rangeCol . '$2:.$' . $this->rangeCol . '$' . ($numRange + 1));
639        $this->xmlContent->writeAttribute('chart:label-cell-address', 'table-local.$' . $this->rangeCol . '$1');
640        $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries' . $this->numSeries);
641        if ($chartType instanceof Area
642            || $chartType instanceof AbstractTypeBar
643            || $chartType instanceof Line
644            || $chartType instanceof Radar
645            || $chartType instanceof Scatter
646        ) {
647            $dataPointFills = $series->getDataPointFills();
648
649            $incRepeat = $numRange;
650            if (!empty($dataPointFills)) {
651                $inc = 0;
652                $incRepeat = 1;
653                $newFill = new Fill();
654                do {
655                    if ($series->getDataPointFill($inc)->getHashCode() !== $newFill->getHashCode()) {
656                        // chart:data-point
657                        $this->xmlContent->startElement('chart:data-point');
658                        $this->xmlContent->writeAttribute('chart:repeated', $incRepeat);
659                        // > chart:data-point
660                        $this->xmlContent->endElement();
661                        $incRepeat = 1;
662
663                        // chart:data-point
664                        $this->xmlContent->startElement('chart:data-point');
665                        $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries' . $this->numSeries . '_' . $inc);
666                        // > chart:data-point
667                        $this->xmlContent->endElement();
668                    }
669                    ++$inc;
670                    ++$incRepeat;
671                } while ($inc < $numRange);
672                --$incRepeat;
673            }
674            // chart:data-point
675            $this->xmlContent->startElement('chart:data-point');
676            $this->xmlContent->writeAttribute('chart:repeated', $incRepeat);
677            // > chart:data-point
678            $this->xmlContent->endElement();
679        } elseif ($chartType instanceof AbstractTypePie) {
680            $count = count($series->getDataPointFills());
681            for ($inc = 0; $inc < $count; ++$inc) {
682                // chart:data-point
683                $this->xmlContent->startElement('chart:data-point');
684                $this->xmlContent->writeAttribute('chart:style-name', 'styleSeries' . $this->numSeries . '_' . $inc);
685                // > chart:data-point
686                $this->xmlContent->endElement();
687            }
688        }
689
690        // > chart:series
691        $this->xmlContent->endElement();
692    }
693
694    protected function writeSeriesStyle(Chart $chart, Chart\Series $series): void
695    {
696        $chartType = $chart->getPlotArea()->getType();
697
698        // style:style
699        $this->xmlContent->startElement('style:style');
700        $this->xmlContent->writeAttribute('style:name', 'styleSeries' . $this->numSeries);
701        $this->xmlContent->writeAttribute('style:family', 'chart');
702        // style:chart-properties
703        $this->xmlContent->startElement('style:chart-properties');
704        if ($series->hasShowValue()) {
705            if ($series->hasShowPercentage()) {
706                $this->xmlContent->writeAttribute('chart:data-label-number', 'value-and-percentage');
707            } else {
708                $this->xmlContent->writeAttribute('chart:data-label-number', 'value');
709            }
710        } else {
711            if ($series->hasShowPercentage()) {
712                $this->xmlContent->writeAttribute('chart:data-label-number', 'percentage');
713            }
714        }
715        if ($series->hasShowCategoryName()) {
716            $this->xmlContent->writeAttribute('chart:data-label-text', 'true');
717        }
718        $this->xmlContent->writeAttribute('chart:label-position', 'center');
719        if ($chartType instanceof AbstractTypePie) {
720            $this->xmlContent->writeAttribute('chart:pie-offset', $chartType->getExplosion());
721        }
722        if ($chartType instanceof Line || $chartType instanceof Scatter) {
723            $oMarker = $series->getMarker();
724            // @link : http://www.datypic.com/sc/odf/a-chart_symbol-type.html
725            $this->xmlContent->writeAttributeIf(Chart\Marker::SYMBOL_NONE == $oMarker->getSymbol(), 'chart:symbol-type', 'none');
726            // @link : http://www.datypic.com/sc/odf/a-chart_symbol-name.html
727            $this->xmlContent->writeAttributeIf(Chart\Marker::SYMBOL_NONE != $oMarker->getSymbol(), 'chart:symbol-type', 'named-symbol');
728            if (Chart\Marker::SYMBOL_NONE != $oMarker->getSymbol()) {
729                switch ($oMarker->getSymbol()) {
730                    case Chart\Marker::SYMBOL_DASH:
731                        $symbolName = 'horizontal-bar';
732
733                        break;
734                    case Chart\Marker::SYMBOL_DOT:
735                        $symbolName = 'circle';
736
737                        break;
738                    case Chart\Marker::SYMBOL_TRIANGLE:
739                        $symbolName = 'arrow-up';
740
741                        break;
742                    default:
743                        $symbolName = $oMarker->getSymbol();
744
745                        break;
746                }
747                $this->xmlContent->writeAttribute('chart:symbol-name', $symbolName);
748                $symbolSize = number_format(CommonDrawing::pointsToCentimeters($oMarker->getSize()), 2, '.', '');
749                $this->xmlContent->writeAttribute('chart:symbol-width', $symbolSize . 'cm');
750                $this->xmlContent->writeAttribute('chart:symbol-height', $symbolSize . 'cm');
751            }
752        }
753
754        $separator = $series->getSeparator();
755        if (!empty($separator)) {
756            // style:chart-properties/chart:label-separator
757            $this->xmlContent->startElement('chart:label-separator');
758            if (PHP_EOL == $separator) {
759                $this->xmlContent->writeRaw('<text:p><text:line-break /></text:p>');
760            } else {
761                $this->xmlContent->writeElement('text:p', $separator);
762            }
763            $this->xmlContent->endElement();
764        }
765
766        // > style:chart-properties
767        $this->xmlContent->endElement();
768        // style:graphic-properties
769        $this->xmlContent->startElement('style:graphic-properties');
770        if ($chartType instanceof Line || $chartType instanceof Radar || $chartType instanceof Scatter) {
771            $outlineWidth = '';
772            $outlineColor = '';
773
774            $oOutline = $series->getOutline();
775            if ($oOutline instanceof Outline) {
776                $outlineWidth = $oOutline->getWidth();
777                if (!empty($outlineWidth)) {
778                    $outlineWidth = number_format(CommonDrawing::pixelsToCentimeters($outlineWidth), 3, '.', '');
779                }
780                $outlineColor = $oOutline->getFill()->getStartColor()->getRGB();
781            }
782            if (empty($outlineWidth)) {
783                $outlineWidth = '0.079';
784            }
785            if (empty($outlineColor)) {
786                $outlineColor = '4a7ebb';
787            }
788            $this->xmlContent->writeAttribute('svg:stroke-width', $outlineWidth . 'cm');
789            $this->xmlContent->writeAttribute('svg:stroke-color', '#' . $outlineColor);
790        } else {
791            $this->xmlContent->writeAttribute('draw:stroke', 'none');
792            if (!($chartType instanceof Area)) {
793                $this->xmlContent->writeAttribute('draw:fill', $series->getFill()->getFillType());
794            }
795        }
796        $this->xmlContent->writeAttribute('draw:fill-color', '#' . $series->getFill()->getStartColor()->getRGB());
797        // > style:graphic-properties
798        $this->xmlContent->endElement();
799        // style:text-properties
800        $this->xmlContent->startElement('style:text-properties');
801        $this->xmlContent->writeAttribute('fo:color', '#' . $series->getFont()->getColor()->getRGB());
802        $this->xmlContent->writeAttribute('fo:font-family', $series->getFont()->getName());
803        $this->xmlContent->writeAttribute('fo:font-size', $series->getFont()->getSize() . 'pt');
804        // > style:text-properties
805        $this->xmlContent->endElement();
806
807        // > style:style
808        $this->xmlContent->endElement();
809
810        foreach ($series->getDataPointFills() as $idx => $oFill) {
811            // style:style
812            $this->xmlContent->startElement('style:style');
813            $this->xmlContent->writeAttribute('style:name', 'styleSeries' . $this->numSeries . '_' . $idx);
814            $this->xmlContent->writeAttribute('style:family', 'chart');
815            // style:graphic-properties
816            $this->xmlContent->startElement('style:graphic-properties');
817            $this->xmlContent->writeAttribute('draw:fill', $oFill->getFillType());
818            $this->xmlContent->writeAttribute('draw:fill-color', '#' . $oFill->getStartColor()->getRGB());
819            // > style:graphic-properties
820            $this->xmlContent->endElement();
821            // > style:style
822            $this->xmlContent->endElement();
823        }
824    }
825
826    protected function writeTable(): void
827    {
828        // table:table
829        $this->xmlContent->startElement('table:table');
830        $this->xmlContent->writeAttribute('table:name', 'table-local');
831
832        // table:table-columns
833        $this->xmlContent->startElement('table:table-columns');
834        // table:table-column
835        $this->xmlContent->startElement('table:table-column');
836        if (!empty($this->arrayData)) {
837            $rowFirst = reset($this->arrayData);
838            $this->xmlContent->writeAttribute('table:number-columns-repeated', count($rowFirst) - 1);
839        }
840        // > table:table-column
841        $this->xmlContent->endElement();
842        // > table:table-columns
843        $this->xmlContent->endElement();
844
845        // table:table-header-columns
846        $this->xmlContent->startElement('table:table-header-columns');
847        // table:table-column
848        $this->xmlContent->writeElement('table:table-column');
849        // > table:table-header-columns
850        $this->xmlContent->endElement();
851
852        // table:table-header-rows
853        $this->xmlContent->startElement('table:table-header-rows');
854        // table:table-row
855        $this->xmlContent->startElement('table:table-row');
856        if (empty($this->arrayData)) {
857            $this->xmlContent->startElement('table:table-cell');
858            $this->xmlContent->endElement();
859        } else {
860            $rowFirst = reset($this->arrayData);
861            foreach ($rowFirst as $key => $cell) {
862                // table:table-cell
863                $this->xmlContent->startElement('table:table-cell');
864                if (isset($this->arrayTitle[$key - 1])) {
865                    $this->xmlContent->writeAttribute('office:value-type', 'string');
866                }
867                // text:p
868                $this->xmlContent->startElement('text:p');
869                if (isset($this->arrayTitle[$key - 1])) {
870                    $this->xmlContent->text($this->arrayTitle[$key - 1]);
871                }
872                // > text:p
873                $this->xmlContent->endElement();
874                // > table:table-cell
875                $this->xmlContent->endElement();
876            }
877        }
878        // > table:table-row
879        $this->xmlContent->endElement();
880        // > table:table-header-rows
881        $this->xmlContent->endElement();
882
883        // table:table-rows
884        $this->xmlContent->startElement('table:table-rows');
885        if (empty($this->arrayData)) {
886            $this->xmlContent->startElement('table:table-row');
887            $this->xmlContent->startElement('table:table-cell');
888            $this->xmlContent->endElement();
889            $this->xmlContent->endElement();
890        } else {
891            foreach ($this->arrayData as $row) {
892                // table:table-row
893                $this->xmlContent->startElement('table:table-row');
894                foreach ($row as $cell) {
895                    // table:table-cell
896                    $this->xmlContent->startElement('table:table-cell');
897
898                    $cellValueTypeFloat = null === $cell ? true : is_numeric($cell);
899                    $this->xmlContent->writeAttributeIf(!$cellValueTypeFloat, 'office:value-type', 'string');
900                    $this->xmlContent->writeAttributeIf($cellValueTypeFloat, 'office:value-type', 'float');
901                    $this->xmlContent->writeAttributeIf($cellValueTypeFloat, 'office:value', null === $cell ? 'NaN' : $cell);
902                    // text:p
903                    $this->xmlContent->startElement('text:p');
904                    $this->xmlContent->text(null === $cell ? 'NaN' : (string) $cell);
905                    $this->xmlContent->endElement();
906                    // > table:table-cell
907                    $this->xmlContent->endElement();
908                }
909                // > table:table-row
910                $this->xmlContent->endElement();
911            }
912        }
913        // > table:table-rows
914        $this->xmlContent->endElement();
915
916        // > table:table
917        $this->xmlContent->endElement();
918    }
919
920    protected function writeTitle(Title $oTitle): void
921    {
922        if (!$oTitle->isVisible()) {
923            return;
924        }
925        // chart:title
926        $this->xmlContent->startElement('chart:title');
927        $this->xmlContent->writeAttribute('svg:x', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $oTitle->getOffsetX()), 3) . 'cm');
928        $this->xmlContent->writeAttribute('svg:y', Text::numberFormat(CommonDrawing::pixelsToCentimeters((int) $oTitle->getOffsetY()), 3) . 'cm');
929        $this->xmlContent->writeAttribute('chart:style-name', 'styleTitle');
930        // > text:p
931        $this->xmlContent->startElement('text:p');
932        $this->xmlContent->text($oTitle->getText());
933        $this->xmlContent->endElement();
934        // > chart:title
935        $this->xmlContent->endElement();
936    }
937
938    protected function writeTitleStyle(Title $oTitle): void
939    {
940        if (!$oTitle->isVisible()) {
941            return;
942        }
943        // style:style
944        $this->xmlContent->startElement('style:style');
945        $this->xmlContent->writeAttribute('style:name', 'styleTitle');
946        $this->xmlContent->writeAttribute('style:family', 'chart');
947        // style:text-properties
948        $this->xmlContent->startElement('style:text-properties');
949        $this->xmlContent->writeAttribute('fo:color', '#' . $oTitle->getFont()->getColor()->getRGB());
950        $this->xmlContent->writeAttribute('fo:font-family', $oTitle->getFont()->getName());
951        $this->xmlContent->writeAttribute('fo:font-size', $oTitle->getFont()->getSize() . 'pt');
952        $this->xmlContent->writeAttribute('fo:font-style', $oTitle->getFont()->isItalic() ? 'italic' : 'normal');
953        // > style:text-properties
954        $this->xmlContent->endElement();
955        // > style:style
956        $this->xmlContent->endElement();
957    }
958
959    protected function writeWall(): void
960    {
961        // chart:wall
962        $this->xmlContent->startElement('chart:wall');
963        $this->xmlContent->writeAttribute('chart:style-name', 'styleWall');
964        $this->xmlContent->endElement();
965    }
966
967    protected function writeWallStyle(Chart $chart): void
968    {
969        $chartType = $chart->getPlotArea()->getType();
970
971        // style:style
972        $this->xmlContent->startElement('style:style');
973        $this->xmlContent->writeAttribute('style:name', 'styleWall');
974        $this->xmlContent->writeAttribute('style:family', 'chart');
975        // style:chart-properties
976        $this->xmlContent->startElement('style:graphic-properties');
977        //@todo : Permit edit color and size border of wall
978        if ($chartType instanceof Line || $chartType instanceof Scatter) {
979            $this->xmlContent->writeAttribute('draw:fill', 'solid');
980            $this->xmlContent->writeAttribute('draw:fill-color', '#FFFFFF');
981        } else {
982            $this->xmlContent->writeAttribute('draw:fill', 'none');
983            $this->xmlContent->writeAttribute('draw:stroke', 'solid');
984            $this->xmlContent->writeAttribute('svg:stroke-width', '0.026cm');
985            $this->xmlContent->writeAttribute('svg:stroke-color', '#878787');
986        }
987        // > style:chart-properties
988        $this->xmlContent->endElement();
989        // > style:style
990        $this->xmlContent->endElement();
991    }
992}