Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
99.81% |
537 / 538 |
|
95.45% |
21 / 22 |
CRAP | |
0.00% |
0 / 1 |
ObjectsChart | |
99.81% |
537 / 538 |
|
95.45% |
21 / 22 |
117 | |
0.00% |
0 / 1 |
render | |
100.00% |
5 / 5 |
|
100.00% |
1 / 1 |
3 | |||
writeContentPart | |
100.00% |
92 / 92 |
|
100.00% |
1 / 1 |
8 | |||
writeAxis | |
100.00% |
33 / 33 |
|
100.00% |
1 / 1 |
5 | |||
writeGridline | |
100.00% |
6 / 6 |
|
100.00% |
1 / 1 |
2 | |||
writeAxisStyle | |
100.00% |
9 / 9 |
|
100.00% |
1 / 1 |
1 | |||
writeAxisMainStyle | |
100.00% |
36 / 36 |
|
100.00% |
1 / 1 |
6 | |||
writeAxisTitleStyle | |
100.00% |
14 / 14 |
|
100.00% |
1 / 1 |
2 | |||
writeGridlineStyle | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
2 | |||
writeChartStyle | |
100.00% |
8 / 8 |
|
100.00% |
1 / 1 |
1 | |||
writeFloor | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
writeFloorStyle | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
1 | |||
writeLegend | |
100.00% |
18 / 18 |
|
100.00% |
1 / 1 |
7 | |||
writeLegendStyle | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
2 | |||
writePlotArea | |
100.00% |
33 / 33 |
|
100.00% |
1 / 1 |
7 | |||
writePlotAreaStyle | |
100.00% |
42 / 42 |
|
100.00% |
1 / 1 |
14 | |||
writeSeries | |
100.00% |
39 / 39 |
|
100.00% |
1 / 1 |
10 | |||
writeSeriesStyle | |
98.72% |
77 / 78 |
|
0.00% |
0 / 1 |
24 | |||
writeTable | |
100.00% |
50 / 50 |
|
100.00% |
1 / 1 |
12 | |||
writeTitle | |
100.00% |
10 / 10 |
|
100.00% |
1 / 1 |
2 | |||
writeTitleStyle | |
100.00% |
12 / 12 |
|
100.00% |
1 / 1 |
3 | |||
writeWall | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
1 | |||
writeWallStyle | |
100.00% |
14 / 14 |
|
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 | |
18 | declare(strict_types=1); |
19 | |
20 | namespace PhpOffice\PhpPresentation\Writer\ODPresentation; |
21 | |
22 | use PhpOffice\Common\Adapter\Zip\ZipInterface; |
23 | use PhpOffice\Common\Drawing as CommonDrawing; |
24 | use PhpOffice\Common\Text; |
25 | use PhpOffice\Common\XMLWriter; |
26 | use PhpOffice\PhpPresentation\Shape\Chart; |
27 | use PhpOffice\PhpPresentation\Shape\Chart\Axis; |
28 | use PhpOffice\PhpPresentation\Shape\Chart\Title; |
29 | use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractType; |
30 | use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeBar; |
31 | use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeLine; |
32 | use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypePie; |
33 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Area; |
34 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar; |
35 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D; |
36 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut; |
37 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Line; |
38 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D; |
39 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar; |
40 | use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter; |
41 | use PhpOffice\PhpPresentation\Style\Fill; |
42 | use PhpOffice\PhpPresentation\Style\Outline; |
43 | |
44 | class 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 | } |