Completed
Push — master ( c2a964...f9b1b7 )
by
unknown
36s queued 26s
created

Chart   F

Complexity

Total Complexity 367

Size/Duplication

Total Lines 1579
Duplicated Lines 0 %

Test Coverage

Coverage 97.78%

Importance

Changes 0
Metric Value
wmc 367
eloc 1089
dl 0
loc 1579
ccs 1055
cts 1079
cp 0.9778
rs 1.244
c 0
b 0
f 0

20 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getAttributeFloat() 0 8 2
A getAttributeInteger() 0 8 2
A getAttributeString() 0 8 2
A getAttributeBoolean() 0 10 3
C chartTitle() 0 59 16
F chartDataSeries() 0 275 75
A chartLayoutDetails() 0 16 4
F readChart() 0 419 102
F parseRichText() 0 190 37
B chartDataSeriesValueSet() 0 66 10
B chartDataSeriesValuesMultiLevel() 0 37 8
B chartDataSeriesValues() 0 35 7
B readColor() 0 30 7
F readEffects() 0 72 18
C parseFont() 0 43 11
B setChartAttributes() 0 38 10
F setAxisProperties() 0 94 29
F readChartAttributes() 0 55 17
B readLineStyle() 0 53 6

How to fix   Complexity   

Complex Class

Complex classes like Chart often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Chart, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
4
5
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
6
use PhpOffice\PhpSpreadsheet\Chart\Axis;
7
use PhpOffice\PhpSpreadsheet\Chart\AxisText;
8
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
9
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
10
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
11
use PhpOffice\PhpSpreadsheet\Chart\GridLines;
12
use PhpOffice\PhpSpreadsheet\Chart\Layout;
13
use PhpOffice\PhpSpreadsheet\Chart\Legend;
14
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
15
use PhpOffice\PhpSpreadsheet\Chart\Properties as ChartProperties;
16
use PhpOffice\PhpSpreadsheet\Chart\Title;
17
use PhpOffice\PhpSpreadsheet\Chart\TrendLine;
18
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
19
use PhpOffice\PhpSpreadsheet\RichText\RichText;
20
use PhpOffice\PhpSpreadsheet\Style\Font;
21
use SimpleXMLElement;
22
23
class Chart
24
{
25
    private string $cNamespace;
26
27
    private string $aNamespace;
28
29 69
    public function __construct(string $cNamespace = Namespaces::CHART, string $aNamespace = Namespaces::DRAWINGML)
30
    {
31 69
        $this->cNamespace = $cNamespace;
32 69
        $this->aNamespace = $aNamespace;
33
    }
34
35 69
    private static function getAttributeString(SimpleXMLElement $component, string $name): string|null
36
    {
37 69
        $attributes = $component->attributes();
38 69
        if (@isset($attributes[$name])) {
39 69
            return (string) $attributes[$name];
40
        }
41
42 69
        return null;
43
    }
44
45 69
    private static function getAttributeInteger(SimpleXMLElement $component, string $name): int|null
46
    {
47 69
        $attributes = $component->attributes();
48 69
        if (@isset($attributes[$name])) {
49 69
            return (int) $attributes[$name];
50
        }
51
52 65
        return null;
53
    }
54
55 67
    private static function getAttributeBoolean(SimpleXMLElement $component, string $name): bool|null
56
    {
57 67
        $attributes = $component->attributes();
58 67
        if (@isset($attributes[$name])) {
59 66
            $value = (string) $attributes[$name];
60
61 66
            return $value === 'true' || $value === '1';
62
        }
63
64 64
        return null;
65
    }
66
67 7
    private static function getAttributeFloat(SimpleXMLElement $component, string $name): float|null
68
    {
69 7
        $attributes = $component->attributes();
70 7
        if (@isset($attributes[$name])) {
71 5
            return (float) $attributes[$name];
72
        }
73
74 6
        return null;
75
    }
76
77 69
    public function readChart(SimpleXMLElement $chartElements, string $chartName): \PhpOffice\PhpSpreadsheet\Chart\Chart
78
    {
79 69
        $chartElementsC = $chartElements->children($this->cNamespace);
80
81 69
        $XaxisLabel = $YaxisLabel = $legend = $title = null;
82 69
        $dispBlanksAs = null;
83 69
        $plotVisOnly = false;
84 69
        $plotArea = null;
85 69
        $rotX = $rotY = $rAngAx = $perspective = null;
86 69
        $xAxis = new Axis();
87 69
        $yAxis = new Axis();
88 69
        $autoTitleDeleted = null;
89 69
        $chartNoFill = false;
90 69
        $chartBorderLines = null;
91 69
        $chartFillColor = null;
92 69
        $gradientArray = [];
93 69
        $gradientLin = null;
94 69
        $roundedCorners = false;
95 69
        $gapWidth = null;
96 69
        $useUpBars = null;
97 69
        $useDownBars = null;
98 69
        $noBorder = false;
99 69
        foreach ($chartElementsC as $chartElementKey => $chartElement) {
100
            switch ($chartElementKey) {
101 69
                case 'spPr':
102 51
                    $children = $chartElementsC->spPr->children($this->aNamespace);
103 51
                    if (isset($children->noFill)) {
104 3
                        $chartNoFill = true;
105
                    }
106 51
                    if (isset($children->solidFill)) {
107 11
                        $chartFillColor = $this->readColor($children->solidFill);
108
                    }
109 51
                    if (isset($children->ln)) {
110 51
                        $chartBorderLines = new GridLines();
111 51
                        $this->readLineStyle($chartElementsC, $chartBorderLines);
112 51
                        if (isset($children->ln->noFill)) {
113 2
                            $noBorder = true;
114
                        }
115
                    }
116
117 51
                    break;
118 69
                case 'roundedCorners':
119
                    /** @var bool $roundedCorners */
120 65
                    $roundedCorners = self::getAttributeBoolean($chartElementsC->roundedCorners, 'val');
121
122 65
                    break;
123 69
                case 'chart':
124 69
                    foreach ($chartElement as $chartDetailsKey => $chartDetails) {
125 69
                        $chartDetails = Xlsx::testSimpleXml($chartDetails);
126
                        switch ($chartDetailsKey) {
127 69
                            case 'autoTitleDeleted':
128
                                /** @var bool $autoTitleDeleted */
129 65
                                $autoTitleDeleted = self::getAttributeBoolean($chartElementsC->chart->autoTitleDeleted, 'val');
130
131 65
                                break;
132 69
                            case 'view3D':
133 49
                                $rotX = self::getAttributeInteger($chartDetails->rotX, 'val');
134 49
                                $rotY = self::getAttributeInteger($chartDetails->rotY, 'val');
135 49
                                $rAngAx = self::getAttributeInteger($chartDetails->rAngAx, 'val');
136 49
                                $perspective = self::getAttributeInteger($chartDetails->perspective, 'val');
137
138 49
                                break;
139 69
                            case 'plotArea':
140 69
                                $plotAreaLayout = $XaxisLabel = $YaxisLabel = null;
141 69
                                $plotSeries = $plotAttributes = [];
142 69
                                $catAxRead = false;
143 69
                                $plotNoFill = false;
144 69
                                foreach ($chartDetails as $chartDetailKey => $chartDetail) {
145 69
                                    $chartDetail = Xlsx::testSimpleXml($chartDetail);
146
                                    switch ($chartDetailKey) {
147 69
                                        case 'spPr':
148 19
                                            $possibleNoFill = $chartDetails->spPr->children($this->aNamespace);
149 19
                                            if (isset($possibleNoFill->noFill)) {
150 18
                                                $plotNoFill = true;
151
                                            }
152 19
                                            if (isset($possibleNoFill->gradFill->gsLst)) {
153 3
                                                foreach ($possibleNoFill->gradFill->gsLst->gs as $gradient) {
154 3
                                                    $gradient = Xlsx::testSimpleXml($gradient);
155
                                                    /** @var float $pos */
156 3
                                                    $pos = self::getAttributeFloat($gradient, 'pos');
157 3
                                                    $gradientArray[] = [
158 3
                                                        $pos / ChartProperties::PERCENTAGE_MULTIPLIER,
159 3
                                                        new ChartColor($this->readColor($gradient)),
160 3
                                                    ];
161
                                                }
162
                                            }
163 19
                                            if (isset($possibleNoFill->gradFill->lin)) {
164 3
                                                $gradientLin = ChartProperties::XmlToAngle((string) self::getAttributeString($possibleNoFill->gradFill->lin, 'ang'));
165
                                            }
166
167 19
                                            break;
168 69
                                        case 'layout':
169 66
                                            $plotAreaLayout = $this->chartLayoutDetails($chartDetail);
170
171 66
                                            break;
172 5
                                        case Axis::AXIS_TYPE_CATEGORY:
173 5
                                        case Axis::AXIS_TYPE_DATE:
174 60
                                            $catAxRead = true;
175 60
                                            if (isset($chartDetail->title)) {
176 10
                                                $XaxisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
177
                                            }
178 60
                                            $xAxis->setAxisType($chartDetailKey);
179 60
                                            $this->readEffects($chartDetail, $xAxis);
180 60
                                            $this->readLineStyle($chartDetail, $xAxis);
181 60
                                            if (isset($chartDetail->spPr)) {
182 44
                                                $sppr = $chartDetail->spPr->children($this->aNamespace);
183 44
                                                if (isset($sppr->solidFill)) {
184 4
                                                    $axisColorArray = $this->readColor($sppr->solidFill);
185 4
                                                    $xAxis->setFillParameters($axisColorArray['value'], $axisColorArray['alpha'], $axisColorArray['type']);
186
                                                }
187 44
                                                if (isset($chartDetail->spPr->ln->noFill)) {
188
                                                    $xAxis->setNoFill(true);
189
                                                }
190
                                            }
191 60
                                            if (isset($chartDetail->majorGridlines)) {
192 5
                                                $majorGridlines = new GridLines();
193 5
                                                if (isset($chartDetail->majorGridlines->spPr)) {
194 5
                                                    $this->readEffects($chartDetail->majorGridlines, $majorGridlines);
195 5
                                                    $this->readLineStyle($chartDetail->majorGridlines, $majorGridlines);
196
                                                }
197 5
                                                $xAxis->setMajorGridlines($majorGridlines);
198
                                            }
199 60
                                            if (isset($chartDetail->minorGridlines)) {
200 4
                                                $minorGridlines = new GridLines();
201 4
                                                $minorGridlines->activateObject();
202 4
                                                if (isset($chartDetail->minorGridlines->spPr)) {
203 4
                                                    $this->readEffects($chartDetail->minorGridlines, $minorGridlines);
204 4
                                                    $this->readLineStyle($chartDetail->minorGridlines, $minorGridlines);
205
                                                }
206 4
                                                $xAxis->setMinorGridlines($minorGridlines);
207
                                            }
208 60
                                            $this->setAxisProperties($chartDetail, $xAxis);
209
210 60
                                            break;
211 5
                                        case Axis::AXIS_TYPE_VALUE:
212 66
                                            $whichAxis = null;
213 66
                                            $axPos = null;
214 66
                                            if (isset($chartDetail->axPos)) {
215 66
                                                $axPos = self::getAttributeString($chartDetail->axPos, 'val');
216
                                            }
217 66
                                            if ($catAxRead) {
218 60
                                                $whichAxis = $yAxis;
219 60
                                                $yAxis->setAxisType($chartDetailKey);
220 24
                                            } elseif (!empty($axPos)) {
221
                                                switch ($axPos) {
222 24
                                                    case 't':
223 24
                                                    case 'b':
224 22
                                                        $whichAxis = $xAxis;
225 22
                                                        $xAxis->setAxisType($chartDetailKey);
226
227 22
                                                        break;
228 24
                                                    case 'r':
229 24
                                                    case 'l':
230 24
                                                        $whichAxis = $yAxis;
231 24
                                                        $yAxis->setAxisType($chartDetailKey);
232
233 24
                                                        break;
234
                                                }
235
                                            }
236 66
                                            if (isset($chartDetail->title)) {
237 30
                                                $axisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
238
239
                                                switch ($axPos) {
240 30
                                                    case 't':
241 30
                                                    case 'b':
242 4
                                                        $XaxisLabel = $axisLabel;
243
244 4
                                                        break;
245 30
                                                    case 'r':
246 30
                                                    case 'l':
247 30
                                                        $YaxisLabel = $axisLabel;
248
249 30
                                                        break;
250
                                                }
251
                                            }
252 66
                                            $this->readEffects($chartDetail, $whichAxis);
253 66
                                            $this->readLineStyle($chartDetail, $whichAxis);
254 66
                                            if ($whichAxis !== null && isset($chartDetail->spPr)) {
255 51
                                                $sppr = $chartDetail->spPr->children($this->aNamespace);
256 51
                                                if (isset($sppr->solidFill)) {
257 4
                                                    $axisColorArray = $this->readColor($sppr->solidFill);
258 4
                                                    $whichAxis->setFillParameters($axisColorArray['value'], $axisColorArray['alpha'], $axisColorArray['type']);
259
                                                }
260 51
                                                if (isset($sppr->ln->noFill)) {
261 8
                                                    $whichAxis->setNoFill(true);
262
                                                }
263
                                            }
264 66
                                            if ($whichAxis !== null && isset($chartDetail->majorGridlines)) {
265 49
                                                $majorGridlines = new GridLines();
266 49
                                                if (isset($chartDetail->majorGridlines->spPr)) {
267 33
                                                    $this->readEffects($chartDetail->majorGridlines, $majorGridlines);
268 33
                                                    $this->readLineStyle($chartDetail->majorGridlines, $majorGridlines);
269
                                                }
270 49
                                                $whichAxis->setMajorGridlines($majorGridlines);
271
                                            }
272 66
                                            if ($whichAxis !== null && isset($chartDetail->minorGridlines)) {
273 7
                                                $minorGridlines = new GridLines();
274 7
                                                $minorGridlines->activateObject();
275 7
                                                if (isset($chartDetail->minorGridlines->spPr)) {
276 7
                                                    $this->readEffects($chartDetail->minorGridlines, $minorGridlines);
277 7
                                                    $this->readLineStyle($chartDetail->minorGridlines, $minorGridlines);
278
                                                }
279 7
                                                $whichAxis->setMinorGridlines($minorGridlines);
280
                                            }
281 66
                                            $this->setAxisProperties($chartDetail, $whichAxis);
282
283 66
                                            break;
284 69
                                        case 'barChart':
285 62
                                        case 'bar3DChart':
286 27
                                            $barDirection = self::getAttributeString($chartDetail->barDir, 'val');
287 27
                                            $plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
288 27
                                            $plotSer->setPlotDirection("$barDirection");
289 27
                                            $plotSeries[] = $plotSer;
290 27
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
291
292 27
                                            break;
293 58
                                        case 'lineChart':
294 45
                                        case 'line3DChart':
295 20
                                            $plotSeries[] = $this->chartDataSeries($chartDetail, $chartDetailKey);
296 20
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
297
298 20
                                            break;
299 45
                                        case 'areaChart':
300 32
                                        case 'area3DChart':
301 15
                                            $plotSeries[] = $this->chartDataSeries($chartDetail, $chartDetailKey);
302 15
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
303
304 15
                                            break;
305 32
                                        case 'doughnutChart':
306 32
                                        case 'pieChart':
307 28
                                        case 'pie3DChart':
308 8
                                            $explosion = self::getAttributeString($chartDetail->ser->explosion, 'val');
309 8
                                            $plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
310 8
                                            $plotSer->setPlotStyle("$explosion");
311 8
                                            $plotSeries[] = $plotSer;
312 8
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
313
314 8
                                            break;
315 26
                                        case 'scatterChart':
316
                                            /** @var string $scatterStyle */
317 22
                                            $scatterStyle = self::getAttributeString($chartDetail->scatterStyle, 'val');
318 22
                                            $plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
319 22
                                            $plotSer->setPlotStyle($scatterStyle);
320 22
                                            $plotSeries[] = $plotSer;
321 22
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
322
323 22
                                            break;
324 6
                                        case 'bubbleChart':
325 4
                                            $bubbleScale = self::getAttributeInteger($chartDetail->bubbleScale, 'val');
326 4
                                            $plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
327 4
                                            $plotSer->setPlotStyle("$bubbleScale");
328 4
                                            $plotSeries[] = $plotSer;
329 4
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
330
331 4
                                            break;
332 4
                                        case 'radarChart':
333
                                            /** @var string $radarStyle */
334 2
                                            $radarStyle = self::getAttributeString($chartDetail->radarStyle, 'val');
335 2
                                            $plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
336 2
                                            $plotSer->setPlotStyle($radarStyle);
337 2
                                            $plotSeries[] = $plotSer;
338 2
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
339
340 2
                                            break;
341 4
                                        case 'surfaceChart':
342 4
                                        case 'surface3DChart':
343 2
                                            $wireFrame = self::getAttributeBoolean($chartDetail->wireframe, 'val');
344 2
                                            $plotSer = $this->chartDataSeries($chartDetail, $chartDetailKey);
345 2
                                            $plotSer->setPlotStyle("$wireFrame");
346 2
                                            $plotSeries[] = $plotSer;
347 2
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
348
349 2
                                            break;
350 4
                                        case 'stockChart':
351 4
                                            $plotSeries[] = $this->chartDataSeries($chartDetail, $chartDetailKey);
352 4
                                            if (isset($chartDetail->upDownBars->gapWidth)) {
353 2
                                                $gapWidth = self::getAttributeInteger($chartDetail->upDownBars->gapWidth, 'val');
354
                                            }
355 4
                                            if (isset($chartDetail->upDownBars->upBars)) {
356 2
                                                $useUpBars = true;
357
                                            }
358 4
                                            if (isset($chartDetail->upDownBars->downBars)) {
359 2
                                                $useDownBars = true;
360
                                            }
361 4
                                            $plotAttributes = $this->readChartAttributes($chartDetail);
362
363 4
                                            break;
364
                                    }
365
                                }
366 69
                                if ($plotAreaLayout == null) {
367 57
                                    $plotAreaLayout = new Layout();
368
                                }
369 69
                                $plotArea = new PlotArea($plotAreaLayout, $plotSeries);
370 69
                                $this->setChartAttributes($plotAreaLayout, $plotAttributes);
371 69
                                if ($plotNoFill) {
372 18
                                    $plotArea->setNoFill(true);
373
                                }
374 69
                                if (!empty($gradientArray)) {
375 3
                                    $plotArea->setGradientFillProperties($gradientArray, $gradientLin);
376
                                }
377 69
                                if (is_int($gapWidth)) {
378 2
                                    $plotArea->setGapWidth($gapWidth);
379
                                }
380 69
                                if ($useUpBars === true) {
381 2
                                    $plotArea->setUseUpBars(true);
382
                                }
383 69
                                if ($useDownBars === true) {
384 2
                                    $plotArea->setUseDownBars(true);
385
                                }
386
387 69
                                break;
388 69
                            case 'plotVisOnly':
389 69
                                $plotVisOnly = (bool) self::getAttributeString($chartDetails, 'val');
390
391 69
                                break;
392 69
                            case 'dispBlanksAs':
393 67
                                $dispBlanksAs = self::getAttributeString($chartDetails, 'val');
394
395 67
                                break;
396 68
                            case 'title':
397 63
                                $title = $this->chartTitle($chartDetails);
398
399 63
                                break;
400 68
                            case 'legend':
401 59
                                $legendPos = 'r';
402 59
                                $legendLayout = null;
403 59
                                $legendOverlay = false;
404 59
                                $legendBorderLines = null;
405 59
                                $legendFillColor = null;
406 59
                                $legendText = null;
407 59
                                $addLegendText = false;
408 59
                                foreach ($chartDetails as $chartDetailKey => $chartDetail) {
409 59
                                    $chartDetail = Xlsx::testSimpleXml($chartDetail);
410
                                    switch ($chartDetailKey) {
411 59
                                        case 'legendPos':
412 59
                                            $legendPos = self::getAttributeString($chartDetail, 'val');
413
414 59
                                            break;
415 57
                                        case 'overlay':
416 56
                                            $legendOverlay = self::getAttributeBoolean($chartDetail, 'val');
417
418 56
                                            break;
419 57
                                        case 'layout':
420 53
                                            $legendLayout = $this->chartLayoutDetails($chartDetail);
421
422 53
                                            break;
423 55
                                        case 'spPr':
424 52
                                            $children = $chartDetails->spPr->children($this->aNamespace);
425 52
                                            if (isset($children->solidFill)) {
426 1
                                                $legendFillColor = $this->readColor($children->solidFill);
427
                                            }
428 52
                                            if (isset($children->ln)) {
429 52
                                                $legendBorderLines = new GridLines();
430 52
                                                $this->readLineStyle($chartDetails, $legendBorderLines);
431
                                            }
432
433 52
                                            break;
434 47
                                        case 'txPr':
435 47
                                            $children = $chartDetails->txPr->children($this->aNamespace);
436 47
                                            $addLegendText = false;
437 47
                                            $legendText = new AxisText();
438 47
                                            if (isset($children->p->pPr->defRPr->solidFill)) {
439 6
                                                $colorArray = $this->readColor($children->p->pPr->defRPr->solidFill);
440 6
                                                $legendText->getFillColorObject()->setColorPropertiesArray($colorArray);
441 6
                                                $addLegendText = true;
442
                                            }
443 47
                                            if (isset($children->p->pPr->defRPr->effectLst)) {
444 1
                                                $this->readEffects($children->p->pPr->defRPr, $legendText, false);
445 1
                                                $addLegendText = true;
446
                                            }
447
448 47
                                            break;
449
                                    }
450
                                }
451 59
                                $legend = new Legend("$legendPos", $legendLayout, (bool) $legendOverlay);
452 59
                                if ($legendFillColor !== null) {
453 1
                                    $legend->getFillColor()->setColorPropertiesArray($legendFillColor);
454
                                }
455 59
                                if ($legendBorderLines !== null) {
456 52
                                    $legend->setBorderLines($legendBorderLines);
457
                                }
458 59
                                if ($addLegendText) {
459 6
                                    $legend->setLegendText($legendText);
460
                                }
461
462 59
                                break;
463
                        }
464
                    }
465
            }
466
        }
467 69
        $chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, (string) $dispBlanksAs, $XaxisLabel, $YaxisLabel, $xAxis, $yAxis);
468 69
        if ($chartNoFill) {
469 3
            $chart->setNoFill(true);
470
        }
471 69
        if ($chartFillColor !== null) {
472 11
            $chart->getFillColor()->setColorPropertiesArray($chartFillColor);
473
        }
474 69
        if ($chartBorderLines !== null) {
475 51
            $chart->setBorderLines($chartBorderLines);
476
        }
477 69
        $chart->setNoBorder($noBorder);
478 69
        $chart->setRoundedCorners($roundedCorners);
479 69
        if (is_bool($autoTitleDeleted)) {
480 65
            $chart->setAutoTitleDeleted($autoTitleDeleted);
481
        }
482 69
        if (is_int($rotX)) {
483 8
            $chart->setRotX($rotX);
484
        }
485 69
        if (is_int($rotY)) {
486 8
            $chart->setRotY($rotY);
487
        }
488 69
        if (is_int($rAngAx)) {
489 8
            $chart->setRAngAx($rAngAx);
490
        }
491 69
        if (is_int($perspective)) {
492 2
            $chart->setPerspective($perspective);
493
        }
494
495 69
        return $chart;
496
    }
497
498 63
    private function chartTitle(SimpleXMLElement $titleDetails): Title
499
    {
500 63
        $caption = '';
501 63
        $titleLayout = null;
502 63
        $titleOverlay = false;
503 63
        $titleFormula = null;
504 63
        $titleFont = null;
505 63
        foreach ($titleDetails as $titleDetailKey => $chartDetail) {
506 63
            $chartDetail = Xlsx::testSimpleXml($chartDetail);
507
            switch ($titleDetailKey) {
508 63
                case 'tx':
509 63
                    $caption = [];
510 63
                    if (isset($chartDetail->rich)) {
511 60
                        $titleDetails = $chartDetail->rich->children($this->aNamespace);
512 60
                        foreach ($titleDetails as $titleKey => $titleDetail) {
513 60
                            $titleDetail = Xlsx::testSimpleXml($titleDetail);
514
                            switch ($titleKey) {
515 60
                                case 'p':
516 60
                                    $titleDetailPart = $titleDetail->children($this->aNamespace);
517 60
                                    $caption[] = $this->parseRichText($titleDetailPart);
518
                            }
519
                        }
520 3
                    } elseif (isset($chartDetail->strRef->strCache)) {
521 3
                        foreach ($chartDetail->strRef->strCache->pt as $pt) {
522 3
                            if (isset($pt->v)) {
523 3
                                $caption[] = (string) $pt->v;
524
                            }
525
                        }
526 3
                        if (isset($chartDetail->strRef->f)) {
527 3
                            $titleFormula = (string) $chartDetail->strRef->f;
528
                        }
529
                    }
530
531 63
                    break;
532 63
                case 'overlay':
533 62
                    $titleOverlay = self::getAttributeBoolean($chartDetail, 'val');
534
535 62
                    break;
536 61
                case 'layout':
537 59
                    $titleLayout = $this->chartLayoutDetails($chartDetail);
538
539 59
                    break;
540 33
                case 'txPr':
541 8
                    if (isset($chartDetail->children($this->aNamespace)->p)) {
542 8
                        $titleFont = $this->parseFont($chartDetail->children($this->aNamespace)->p);
543
                    }
544
545 8
                    break;
546
            }
547
        }
548 63
        $title = new Title($caption, $titleLayout, (bool) $titleOverlay);
549 63
        if (!empty($titleFormula)) {
550 3
            $title->setCellReference($titleFormula);
551
        }
552 63
        if ($titleFont !== null) {
553 8
            $title->setFont($titleFont);
554
        }
555
556 63
        return $title;
557
    }
558
559 66
    private function chartLayoutDetails(SimpleXMLElement $chartDetail): ?Layout
560
    {
561 66
        if (!isset($chartDetail->manualLayout)) {
562 55
            return null;
563
        }
564 41
        $details = $chartDetail->manualLayout->children($this->cNamespace);
565 41
        if ($details === null) {
566
            return null;
567
        }
568 41
        $layout = [];
569 41
        foreach ($details as $detailKey => $detail) {
570 23
            $detail = Xlsx::testSimpleXml($detail);
571 23
            $layout[$detailKey] = self::getAttributeString($detail, 'val');
572
        }
573
574 41
        return new Layout($layout);
575
    }
576
577 69
    private function chartDataSeries(SimpleXMLElement $chartDetail, string $plotType): DataSeries
578
    {
579 69
        $multiSeriesType = null;
580 69
        $smoothLine = false;
581 69
        $seriesLabel = $seriesCategory = $seriesValues = $plotOrder = $seriesBubbles = [];
582 69
        $plotDirection = null;
583
584 69
        $seriesDetailSet = $chartDetail->children($this->cNamespace);
585 69
        foreach ($seriesDetailSet as $seriesDetailKey => $seriesDetails) {
586
            switch ($seriesDetailKey) {
587 69
                case 'grouping':
588 57
                    $multiSeriesType = self::getAttributeString($chartDetail->grouping, 'val');
589
590 57
                    break;
591 69
                case 'ser':
592 69
                    $marker = null;
593 69
                    $seriesIndex = '';
594 69
                    $fillColor = null;
595 69
                    $pointSize = null;
596 69
                    $noFill = false;
597 69
                    $bubble3D = false;
598 69
                    $dptColors = [];
599 69
                    $markerFillColor = null;
600 69
                    $markerBorderColor = null;
601 69
                    $lineStyle = null;
602 69
                    $labelLayout = null;
603 69
                    $trendLines = [];
604 69
                    foreach ($seriesDetails as $seriesKey => $seriesDetail) {
605 69
                        $seriesDetail = Xlsx::testSimpleXml($seriesDetail);
606
                        switch ($seriesKey) {
607 69
                            case 'idx':
608 69
                                $seriesIndex = self::getAttributeInteger($seriesDetail, 'val');
609
610 69
                                break;
611 69
                            case 'order':
612 69
                                $seriesOrder = self::getAttributeInteger($seriesDetail, 'val');
613 69
                                if ($seriesOrder !== null) {
614 69
                                    $plotOrder[$seriesIndex] = $seriesOrder;
615
                                }
616
617 69
                                break;
618 69
                            case 'tx':
619 67
                                $temp = $this->chartDataSeriesValueSet($seriesDetail);
620 67
                                if ($temp !== null) {
621 67
                                    $seriesLabel[$seriesIndex] = $temp;
622
                                }
623
624 67
                                break;
625 69
                            case 'spPr':
626 66
                                $children = $seriesDetail->children($this->aNamespace);
627 66
                                if (isset($children->ln)) {
628 66
                                    $ln = $children->ln;
629 66
                                    if (is_countable($ln->noFill) && count($ln->noFill) === 1) {
630 23
                                        $noFill = true;
631
                                    }
632 66
                                    $lineStyle = new GridLines();
633 66
                                    $this->readLineStyle($seriesDetails, $lineStyle);
634
                                }
635 66
                                if (isset($children->effectLst)) {
636 6
                                    if ($lineStyle === null) {
637 3
                                        $lineStyle = new GridLines();
638
                                    }
639 6
                                    $this->readEffects($seriesDetails, $lineStyle);
640
                                }
641 66
                                if (isset($children->solidFill)) {
642 21
                                    $fillColor = new ChartColor($this->readColor($children->solidFill));
643
                                }
644
645 66
                                break;
646 69
                            case 'dPt':
647 8
                                $dptIdx = (int) self::getAttributeString($seriesDetail->idx, 'val');
648 8
                                if (isset($seriesDetail->spPr)) {
649 8
                                    $children = $seriesDetail->spPr->children($this->aNamespace);
650 8
                                    if (isset($children->solidFill)) {
651 8
                                        $arrayColors = $this->readColor($children->solidFill);
652 8
                                        $dptColors[$dptIdx] = new ChartColor($arrayColors);
653
                                    }
654
                                }
655
656 8
                                break;
657 69
                            case 'trendline':
658 6
                                $trendLine = new TrendLine();
659 6
                                $this->readLineStyle($seriesDetail, $trendLine);
660 6
                                $trendLineType = self::getAttributeString($seriesDetail->trendlineType, 'val');
661 6
                                $dispRSqr = self::getAttributeBoolean($seriesDetail->dispRSqr, 'val');
662 6
                                $dispEq = self::getAttributeBoolean($seriesDetail->dispEq, 'val');
663 6
                                $order = self::getAttributeInteger($seriesDetail->order, 'val');
664 6
                                $period = self::getAttributeInteger($seriesDetail->period, 'val');
665 6
                                $forward = self::getAttributeFloat($seriesDetail->forward, 'val');
666 6
                                $backward = self::getAttributeFloat($seriesDetail->backward, 'val');
667 6
                                $intercept = self::getAttributeFloat($seriesDetail->intercept, 'val');
668 6
                                $name = (string) $seriesDetail->name;
669 6
                                $trendLine->setTrendLineProperties(
670 6
                                    $trendLineType,
671 6
                                    $order,
672 6
                                    $period,
673 6
                                    $dispRSqr,
674 6
                                    $dispEq,
675 6
                                    $backward,
676 6
                                    $forward,
677 6
                                    $intercept,
678 6
                                    $name
679 6
                                );
680 6
                                $trendLines[] = $trendLine;
681
682 6
                                break;
683 69
                            case 'marker':
684 29
                                $marker = self::getAttributeString($seriesDetail->symbol, 'val');
685 29
                                $pointSize = self::getAttributeString($seriesDetail->size, 'val');
686 29
                                $pointSize = is_numeric($pointSize) ? ((int) $pointSize) : null;
687 29
                                if (isset($seriesDetail->spPr)) {
688 26
                                    $children = $seriesDetail->spPr->children($this->aNamespace);
689 26
                                    if (isset($children->solidFill)) {
690 24
                                        $markerFillColor = $this->readColor($children->solidFill);
691
                                    }
692 26
                                    if (isset($children->ln->solidFill)) {
693 16
                                        $markerBorderColor = $this->readColor($children->ln->solidFill);
694
                                    }
695
                                }
696
697 29
                                break;
698 69
                            case 'smooth':
699 34
                                $smoothLine = self::getAttributeBoolean($seriesDetail, 'val') ?? false;
700
701 34
                                break;
702 69
                            case 'cat':
703 51
                                $temp = $this->chartDataSeriesValueSet($seriesDetail);
704 51
                                if ($temp !== null) {
705 51
                                    $seriesCategory[$seriesIndex] = $temp;
706
                                }
707
708 51
                                break;
709 69
                            case 'val':
710 61
                                $temp = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
711 61
                                if ($temp !== null) {
712 61
                                    $seriesValues[$seriesIndex] = $temp;
713
                                }
714
715 61
                                break;
716 49
                            case 'xVal':
717 24
                                $temp = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
718 24
                                if ($temp !== null) {
719 24
                                    $seriesCategory[$seriesIndex] = $temp;
720
                                }
721
722 24
                                break;
723 49
                            case 'yVal':
724 24
                                $temp = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
725 24
                                if ($temp !== null) {
726 24
                                    $seriesValues[$seriesIndex] = $temp;
727
                                }
728
729 24
                                break;
730 46
                            case 'bubbleSize':
731 4
                                $seriesBubble = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
732 4
                                if ($seriesBubble !== null) {
733 3
                                    $seriesBubbles[$seriesIndex] = $seriesBubble;
734
                                }
735
736 4
                                break;
737 44
                            case 'bubble3D':
738 2
                                $bubble3D = self::getAttributeBoolean($seriesDetail, 'val');
739
740 2
                                break;
741 44
                            case 'dLbls':
742 8
                                $labelLayout = new Layout($this->readChartAttributes($seriesDetails));
743
744 8
                                break;
745
                        }
746
                    }
747 69
                    if ($labelLayout) {
748 8
                        if (isset($seriesLabel[$seriesIndex])) {
749 8
                            $seriesLabel[$seriesIndex]->setLabelLayout($labelLayout);
750
                        }
751 8
                        if (isset($seriesCategory[$seriesIndex])) {
752 5
                            $seriesCategory[$seriesIndex]->setLabelLayout($labelLayout);
753
                        }
754 8
                        if (isset($seriesValues[$seriesIndex])) {
755 8
                            $seriesValues[$seriesIndex]->setLabelLayout($labelLayout);
756
                        }
757
                    }
758 69
                    if ($noFill) {
759 23
                        if (isset($seriesLabel[$seriesIndex])) {
760 23
                            $seriesLabel[$seriesIndex]->setScatterLines(false);
761
                        }
762 23
                        if (isset($seriesCategory[$seriesIndex])) {
763 23
                            $seriesCategory[$seriesIndex]->setScatterLines(false);
764
                        }
765 23
                        if (isset($seriesValues[$seriesIndex])) {
766 23
                            $seriesValues[$seriesIndex]->setScatterLines(false);
767
                        }
768
                    }
769 69
                    if ($lineStyle !== null) {
770 66
                        if (isset($seriesLabel[$seriesIndex])) {
771 65
                            $seriesLabel[$seriesIndex]->copyLineStyles($lineStyle);
772
                        }
773 66
                        if (isset($seriesCategory[$seriesIndex])) {
774 56
                            $seriesCategory[$seriesIndex]->copyLineStyles($lineStyle);
775
                        }
776 66
                        if (isset($seriesValues[$seriesIndex])) {
777 66
                            $seriesValues[$seriesIndex]->copyLineStyles($lineStyle);
778
                        }
779
                    }
780 69
                    if ($bubble3D) {
781 2
                        if (isset($seriesLabel[$seriesIndex])) {
782 2
                            $seriesLabel[$seriesIndex]->setBubble3D($bubble3D);
783
                        }
784 2
                        if (isset($seriesCategory[$seriesIndex])) {
785 2
                            $seriesCategory[$seriesIndex]->setBubble3D($bubble3D);
786
                        }
787 2
                        if (isset($seriesValues[$seriesIndex])) {
788 2
                            $seriesValues[$seriesIndex]->setBubble3D($bubble3D);
789
                        }
790
                    }
791 69
                    if (!empty($dptColors)) {
792 8
                        if (isset($seriesLabel[$seriesIndex])) {
793 6
                            $seriesLabel[$seriesIndex]->setFillColor($dptColors);
794
                        }
795 8
                        if (isset($seriesCategory[$seriesIndex])) {
796 8
                            $seriesCategory[$seriesIndex]->setFillColor($dptColors);
797
                        }
798 8
                        if (isset($seriesValues[$seriesIndex])) {
799 8
                            $seriesValues[$seriesIndex]->setFillColor($dptColors);
800
                        }
801
                    }
802 69
                    if ($markerFillColor !== null) {
803 24
                        if (isset($seriesLabel[$seriesIndex])) {
804 24
                            $seriesLabel[$seriesIndex]->getMarkerFillColor()->setColorPropertiesArray($markerFillColor);
805
                        }
806 24
                        if (isset($seriesCategory[$seriesIndex])) {
807 24
                            $seriesCategory[$seriesIndex]->getMarkerFillColor()->setColorPropertiesArray($markerFillColor);
808
                        }
809 24
                        if (isset($seriesValues[$seriesIndex])) {
810 24
                            $seriesValues[$seriesIndex]->getMarkerFillColor()->setColorPropertiesArray($markerFillColor);
811
                        }
812
                    }
813 69
                    if ($markerBorderColor !== null) {
814 16
                        if (isset($seriesLabel[$seriesIndex])) {
815 16
                            $seriesLabel[$seriesIndex]->getMarkerBorderColor()->setColorPropertiesArray($markerBorderColor);
816
                        }
817 16
                        if (isset($seriesCategory[$seriesIndex])) {
818 16
                            $seriesCategory[$seriesIndex]->getMarkerBorderColor()->setColorPropertiesArray($markerBorderColor);
819
                        }
820 16
                        if (isset($seriesValues[$seriesIndex])) {
821 16
                            $seriesValues[$seriesIndex]->getMarkerBorderColor()->setColorPropertiesArray($markerBorderColor);
822
                        }
823
                    }
824 69
                    if ($smoothLine) {
825 11
                        if (isset($seriesLabel[$seriesIndex])) {
826 11
                            $seriesLabel[$seriesIndex]->setSmoothLine(true);
827
                        }
828 11
                        if (isset($seriesCategory[$seriesIndex])) {
829 11
                            $seriesCategory[$seriesIndex]->setSmoothLine(true);
830
                        }
831 11
                        if (isset($seriesValues[$seriesIndex])) {
832 11
                            $seriesValues[$seriesIndex]->setSmoothLine(true);
833
                        }
834
                    }
835 69
                    if (!empty($trendLines)) {
836 6
                        if (isset($seriesLabel[$seriesIndex])) {
837 6
                            $seriesLabel[$seriesIndex]->setTrendLines($trendLines);
838
                        }
839 6
                        if (isset($seriesCategory[$seriesIndex])) {
840 6
                            $seriesCategory[$seriesIndex]->setTrendLines($trendLines);
841
                        }
842 6
                        if (isset($seriesValues[$seriesIndex])) {
843 6
                            $seriesValues[$seriesIndex]->setTrendLines($trendLines);
844
                        }
845
                    }
846
            }
847
        }
848 69
        $series = new DataSeries($plotType, $multiSeriesType, $plotOrder, $seriesLabel, $seriesCategory, $seriesValues, $plotDirection, $smoothLine);
849 69
        $series->setPlotBubbleSizes($seriesBubbles);
850
851 69
        return $series;
852
    }
853
854 69
    private function chartDataSeriesValueSet(SimpleXMLElement $seriesDetail, ?string $marker = null, ?ChartColor $fillColor = null, ?string $pointSize = null): ?DataSeriesValues
855
    {
856 69
        if (isset($seriesDetail->strRef)) {
857 67
            $seriesSource = (string) $seriesDetail->strRef->f;
858 67
            $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
859
860 67
            if (isset($seriesDetail->strRef->strCache)) {
861 66
                /** @var array{formatCode: string, dataValues: mixed[]} */
862 66
                $seriesData = $this->chartDataSeriesValues($seriesDetail->strRef->strCache->children($this->cNamespace), 's');
863 66
                $seriesValues
864 66
                    ->setFormatCode($seriesData['formatCode'])
865
                    ->setDataValues($seriesData['dataValues']);
866
            }
867 67
868 69
            return $seriesValues;
869 69
        } elseif (isset($seriesDetail->numRef)) {
870 69
            $seriesSource = (string) $seriesDetail->numRef->f;
871 69
            $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
872 67
            if (isset($seriesDetail->numRef->numCache)) {
873 67
                /** @var array{formatCode: string, dataValues: mixed[]} */
874 67
                $seriesData = $this->chartDataSeriesValues($seriesDetail->numRef->numCache->children($this->cNamespace));
875 67
                $seriesValues
876
                    ->setFormatCode($seriesData['formatCode'])
877
                    ->setDataValues($seriesData['dataValues']);
878 69
            }
879 27
880 21
            return $seriesValues;
881 21
        } elseif (isset($seriesDetail->multiLvlStrRef)) {
882
            $seriesSource = (string) $seriesDetail->multiLvlStrRef->f;
883 21
            $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
884 21
885 21
            if (isset($seriesDetail->multiLvlStrRef->multiLvlStrCache)) {
886 21
                /** @var array{formatCode: string, dataValues: mixed[]} */
887 21
                $seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($this->cNamespace), 's');
888
                $seriesValues
889
                    ->setFormatCode($seriesData['formatCode'])
890 21
                    ->setDataValues($seriesData['dataValues']);
891 8
            }
892
893
            return $seriesValues;
894
        } elseif (isset($seriesDetail->multiLvlNumRef)) {
895
            $seriesSource = (string) $seriesDetail->multiLvlNumRef->f;
896
            $seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
897
898
            if (isset($seriesDetail->multiLvlNumRef->multiLvlNumCache)) {
899
                /** @var array{formatCode: string, dataValues: mixed[]} */
900
                $seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($this->cNamespace), 's');
901
                $seriesValues
902
                    ->setFormatCode($seriesData['formatCode'])
903
                    ->setDataValues($seriesData['dataValues']);
904
            }
905 8
906 7
            return $seriesValues;
907 7
        }
908 7
909 7
        if (isset($seriesDetail->v)) {
910 7
            return new DataSeriesValues(
911 7
                DataSeriesValues::DATASERIES_TYPE_STRING,
912 7
                null,
913
                null,
914
                1,
915 2
                [(string) $seriesDetail->v]
916
            );
917
        }
918 67
919
        return null;
920 67
    }
921 67
922 67
    /** @return mixed[] */
923
    private function chartDataSeriesValues(SimpleXMLElement $seriesValueSet, string $dataType = 'n'): array
924 67
    {
925 66
        $seriesVal = [];
926
        $formatCode = '';
927 66
        $pointCount = 0;
928 66
929
        foreach ($seriesValueSet as $seriesValueIdx => $seriesValue) {
930 66
            $seriesValue = Xlsx::testSimpleXml($seriesValue);
931 66
            switch ($seriesValueIdx) {
932 48
                case 'ptCount':
933
                    $pointCount = self::getAttributeInteger($seriesValue, 'val');
934 48
935 66
                    break;
936 66
                case 'formatCode':
937 66
                    $formatCode = (string) $seriesValue;
938 66
939 66
                    break;
940
                case 'pt':
941
                    $pointVal = self::getAttributeInteger($seriesValue, 'idx');
942 66
                    if ($dataType == 's') {
943
                        $seriesVal[$pointVal] = (string) $seriesValue->v;
944
                    } elseif ((string) $seriesValue->v === ExcelError::NA()) {
945 66
                        $seriesVal[$pointVal] = null;
946
                    } else {
947
                        $seriesVal[$pointVal] = (float) $seriesValue->v;
948
                    }
949 67
950 67
                    break;
951 67
            }
952 67
        }
953 67
954
        return [
955
            'formatCode' => $formatCode,
956 21
            'pointCount' => $pointCount,
957
            'dataValues' => $seriesVal,
958 21
        ];
959 21
    }
960 21
961
    /** @return mixed[] */
962 21
    private function chartDataSeriesValuesMultiLevel(SimpleXMLElement $seriesValueSet, string $dataType = 'n'): array
963 21
    {
964 21
        $seriesVal = [];
965
        $formatCode = '';
966 21
        $pointCount = 0;
967
968
        foreach ($seriesValueSet->lvl as $seriesLevelIdx => $seriesLevel) {
969
            foreach ($seriesLevel as $seriesValueIdx => $seriesValue) {
970 21
                $seriesValue = Xlsx::testSimpleXml($seriesValue);
971
                switch ($seriesValueIdx) {
972
                    case 'ptCount':
973
                        $pointCount = self::getAttributeInteger($seriesValue, 'val');
974 21
975 21
                        break;
976 21
                    case 'formatCode':
977 21
                        $formatCode = (string) $seriesValue;
978
979
                        break;
980
                    case 'pt':
981
                        $pointVal = self::getAttributeInteger($seriesValue, 'idx');
982
                        if ($dataType == 's') {
983
                            $seriesVal[$pointVal][] = (string) $seriesValue->v;
984 21
                        } elseif ((string) $seriesValue->v === ExcelError::NA()) {
985
                            $seriesVal[$pointVal] = null;
986
                        } else {
987
                            $seriesVal[$pointVal][] = (float) $seriesValue->v;
988
                        }
989 21
990 21
                        break;
991 21
                }
992 21
            }
993 21
        }
994
995
        return [
996 60
            'formatCode' => $formatCode,
997
            'pointCount' => $pointCount,
998 60
            'dataValues' => $seriesVal,
999 60
        ];
1000 60
    }
1001 60
1002 60
    private function parseRichText(SimpleXMLElement $titleDetailPart): RichText
1003 60
    {
1004 60
        $value = new RichText();
1005 60
        $defaultFontSize = null;
1006 60
        $defaultBold = null;
1007 60
        $defaultItalic = null;
1008 60
        $defaultUnderscore = null;
1009 60
        $defaultStrikethrough = null;
1010 60
        $defaultBaseline = null;
1011 60
        $defaultFontName = null;
1012 60
        $defaultLatin = null;
1013 60
        $defaultEastAsian = null;
1014 60
        $defaultComplexScript = null;
1015 60
        $defaultFontColor = null;
1016 60
        if (isset($titleDetailPart->pPr->defRPr)) {
1017 60
            $defaultFontSize = self::getAttributeInteger($titleDetailPart->pPr->defRPr, 'sz');
1018
            $defaultBold = self::getAttributeBoolean($titleDetailPart->pPr->defRPr, 'b');
1019
            $defaultItalic = self::getAttributeBoolean($titleDetailPart->pPr->defRPr, 'i');
1020 60
            $defaultUnderscore = self::getAttributeString($titleDetailPart->pPr->defRPr, 'u');
1021 30
            $defaultStrikethrough = self::getAttributeString($titleDetailPart->pPr->defRPr, 'strike');
1022
            $defaultBaseline = self::getAttributeInteger($titleDetailPart->pPr->defRPr, 'baseline');
1023 60
            if (isset($titleDetailPart->defRPr->rFont['val'])) {
1024 28
                $defaultFontName = (string) $titleDetailPart->defRPr->rFont['val'];
1025
            }
1026 60
            if (isset($titleDetailPart->pPr->defRPr->latin)) {
1027 28
                $defaultLatin = self::getAttributeString($titleDetailPart->pPr->defRPr->latin, 'typeface');
1028
            }
1029 60
            if (isset($titleDetailPart->pPr->defRPr->ea)) {
1030 30
                $defaultEastAsian = self::getAttributeString($titleDetailPart->pPr->defRPr->ea, 'typeface');
1031
            }
1032
            if (isset($titleDetailPart->pPr->defRPr->cs)) {
1033 60
                $defaultComplexScript = self::getAttributeString($titleDetailPart->pPr->defRPr->cs, 'typeface');
1034
            }
1035 60
            if (isset($titleDetailPart->pPr->defRPr->solidFill)) {
1036 60
                $defaultFontColor = $this->readColor($titleDetailPart->pPr->defRPr->solidFill);
1037
            }
1038 60
        }
1039
        foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
1040 60
            if (
1041 60
                (string) $titleDetailElementKey !== 'r'
1042
                || !isset($titleDetailElement->t)
1043
            ) {
1044
                continue;
1045
            }
1046 60
            $objText = $value->createTextRun((string) $titleDetailElement->t);
1047 60
            if ($objText->getFont() === null) {
1048 60
                // @codeCoverageIgnoreStart
1049 60
                continue;
1050 60
                // @codeCoverageIgnoreEnd
1051 60
            }
1052 60
            $fontSize = null;
1053 60
            $bold = null;
1054 60
            $italic = null;
1055 60
            $underscore = null;
1056 60
            $strikethrough = null;
1057 60
            $baseline = null;
1058 60
            $fontName = null;
1059
            $latinName = null;
1060 41
            $eastAsian = null;
1061
            $complexScript = null;
1062
            $fontColor = null;
1063
            $underlineColor = null;
1064
            if (isset($titleDetailElement->rPr)) {
1065 41
                // not used now, not sure it ever was, grandfathering
1066 22
                if (isset($titleDetailElement->rPr->rFont['val'])) {
1067
                    // @codeCoverageIgnoreStart
1068 41
                    $fontName = (string) $titleDetailElement->rPr->rFont['val'];
1069 11
                    // @codeCoverageIgnoreEnd
1070
                }
1071 41
                if (isset($titleDetailElement->rPr->latin)) {
1072 13
                    $latinName = self::getAttributeString($titleDetailElement->rPr->latin, 'typeface');
1073
                }
1074 41
                if (isset($titleDetailElement->rPr->ea)) {
1075
                    $eastAsian = self::getAttributeString($titleDetailElement->rPr->ea, 'typeface');
1076
                }
1077 41
                if (isset($titleDetailElement->rPr->cs)) {
1078 21
                    $complexScript = self::getAttributeString($titleDetailElement->rPr->cs, 'typeface');
1079
                }
1080
                $fontSize = self::getAttributeInteger($titleDetailElement->rPr, 'sz');
1081 41
1082 41
                // not used now, not sure it ever was, grandfathering
1083 41
                if (isset($titleDetailElement->rPr->solidFill)) {
1084 41
                    $fontColor = $this->readColor($titleDetailElement->rPr->solidFill);
1085 41
                }
1086 7
1087
                $bold = self::getAttributeBoolean($titleDetailElement->rPr, 'b');
1088
                $italic = self::getAttributeBoolean($titleDetailElement->rPr, 'i');
1089 41
                $baseline = self::getAttributeInteger($titleDetailElement->rPr, 'baseline');
1090
                $underscore = self::getAttributeString($titleDetailElement->rPr, 'u');
1091
                if (isset($titleDetailElement->rPr->uFill->solidFill)) {
1092 60
                    $underlineColor = $this->readColor($titleDetailElement->rPr->uFill->solidFill);
1093 60
                }
1094 60
1095 31
                $strikethrough = self::getAttributeString($titleDetailElement->rPr, 'strike');
1096 31
            }
1097
1098 60
            $fontFound = false;
1099 60
            $latinName = $latinName ?? $defaultLatin;
1100 28
            if ($latinName !== null) {
1101 28
                $objText->getFont()->setLatin($latinName);
1102
                $fontFound = true;
1103 60
            }
1104 60
            $eastAsian = $eastAsian ?? $defaultEastAsian;
1105 28
            if ($eastAsian !== null) {
1106 28
                $objText->getFont()->setEastAsian($eastAsian);
1107
                $fontFound = true;
1108 60
            }
1109 60
            $complexScript = $complexScript ?? $defaultComplexScript;
1110
            if ($complexScript !== null) {
1111
                $objText->getFont()->setComplexScript($complexScript);
1112
                $fontFound = true;
1113
            }
1114
            $fontName = $fontName ?? $defaultFontName;
1115
            if ($fontName !== null) {
1116 60
                // @codeCoverageIgnoreStart
1117 60
                $objText->getFont()->setName($fontName);
1118 29
                $fontFound = true;
1119 29
                // @codeCoverageIgnoreEnd
1120
            }
1121 33
1122
            $fontSize = $fontSize ?? $defaultFontSize;
1123
            if (is_int($fontSize)) {
1124 60
                $objText->getFont()->setSize(floor($fontSize / 100));
1125 60
                $fontFound = true;
1126 30
            } else {
1127 30
                $objText->getFont()->setSize(null, true);
1128
            }
1129
1130 60
            $fontColor = $fontColor ?? $defaultFontColor;
1131 60
            if (!empty($fontColor)) {
1132 36
                $objText->getFont()->setChartColor($fontColor);
1133 36
                $fontFound = true;
1134
            }
1135
1136 60
            $bold = $bold ?? $defaultBold;
1137 60
            if ($bold !== null) {
1138 35
                $objText->getFont()->setBold($bold);
1139 35
                $fontFound = true;
1140
            }
1141
1142 60
            $italic = $italic ?? $defaultItalic;
1143 60
            if ($italic !== null) {
1144 32
                $objText->getFont()->setItalic($italic);
1145 32
                $fontFound = true;
1146 7
            }
1147 32
1148 7
            $baseline = $baseline ?? $defaultBaseline;
1149
            if ($baseline !== null) {
1150 32
                $objText->getFont()->setBaseLine($baseline);
1151
                if ($baseline > 0) {
1152
                    $objText->getFont()->setSuperscript(true);
1153 60
                } elseif ($baseline < 0) {
1154 60
                    $objText->getFont()->setSubscript(true);
1155 35
                }
1156 8
                $fontFound = true;
1157 35
            }
1158 7
1159 35
            $underscore = $underscore ?? $defaultUnderscore;
1160 35
            if ($underscore !== null) {
1161
                if ($underscore == 'sng') {
1162
                    $objText->getFont()->setUnderline(Font::UNDERLINE_SINGLE);
1163
                } elseif ($underscore == 'dbl') {
1164 35
                    $objText->getFont()->setUnderline(Font::UNDERLINE_DOUBLE);
1165 35
                } elseif ($underscore !== '') {
1166 7
                    $objText->getFont()->setUnderline($underscore);
1167
                } else {
1168
                    $objText->getFont()->setUnderline(Font::UNDERLINE_NONE);
1169
                }
1170 60
                $fontFound = true;
1171 60
                if ($underlineColor) {
1172 35
                    $objText->getFont()->setUnderlineColor($underlineColor);
1173 35
                }
1174 35
            }
1175
1176 7
            $strikethrough = $strikethrough ?? $defaultStrikethrough;
1177
            if ($strikethrough !== null) {
1178 35
                $objText->getFont()->setStrikeType($strikethrough);
1179
                if ($strikethrough == 'noStrike') {
1180 60
                    $objText->getFont()->setStrikethrough(false);
1181 32
                } else {
1182
                    $objText->getFont()->setStrikethrough(true);
1183
                }
1184
                $fontFound = true;
1185 60
            }
1186
            if ($fontFound === false) {
1187
                $objText->setFont(null);
1188 21
            }
1189
        }
1190 21
1191
        return $value;
1192
    }
1193 21
1194 21
    private function parseFont(SimpleXMLElement $titleDetailPart): ?Font
1195 21
    {
1196 13
        if (!isset($titleDetailPart->pPr->defRPr)) {
1197
            return null;
1198 21
        }
1199 21
        $fontArray = [];
1200 21
        $fontArray['size'] = self::getAttributeInteger($titleDetailPart->pPr->defRPr, 'sz');
1201 21
        if ($fontArray['size'] !== null && $fontArray['size'] >= 100) {
1202 21
            $fontArray['size'] /= 100.0;
1203
        }
1204 21
        if ($fontArray['size'] !== null) {
1205 13
            $fontArray['size'] = (int) ($fontArray['size']);
1206
        }
1207 21
        $fontArray['bold'] = (bool) self::getAttributeBoolean($titleDetailPart->pPr->defRPr, 'b');
1208 5
        $fontArray['italic'] = (bool) self::getAttributeBoolean($titleDetailPart->pPr->defRPr, 'i');
1209
        $fontArray['underscore'] = self::getAttributeString($titleDetailPart->pPr->defRPr, 'u');
1210 21
        $strikethrough = self::getAttributeString($titleDetailPart->pPr->defRPr, 'strike');
1211 5
        if ($strikethrough !== null) {
1212
            if ($strikethrough == 'noStrike') {
1213 21
                $fontArray['strikethrough'] = false;
1214 13
            } else {
1215
                $fontArray['strikethrough'] = true;
1216 21
            }
1217 21
        }
1218 21
        $fontArray['cap'] = (string) self::getAttributeString($titleDetailPart->pPr->defRPr, 'cap');
1219
1220 21
        if (isset($titleDetailPart->pPr->defRPr->latin)) {
1221
            $fontArray['latin'] = (string) self::getAttributeString($titleDetailPart->pPr->defRPr->latin, 'typeface');
1222
        }
1223 69
        if (isset($titleDetailPart->pPr->defRPr->ea)) {
1224
            $fontArray['eastAsian'] = (string) self::getAttributeString($titleDetailPart->pPr->defRPr->ea, 'typeface');
1225 69
        }
1226 69
        if (isset($titleDetailPart->pPr->defRPr->cs)) {
1227 49
            $fontArray['complexScript'] = (string) self::getAttributeString($titleDetailPart->pPr->defRPr->cs, 'typeface');
1228 6
        }
1229
        if (isset($titleDetailPart->pPr->defRPr->solidFill)) {
1230 49
            $fontArray['chartColor'] = new ChartColor($this->readColor($titleDetailPart->pPr->defRPr->solidFill));
1231 4
        }
1232 4
        $font = new Font();
1233
        //$font->setSize(null, true);
1234 49
        $font->applyFromArray($fontArray);
1235 46
1236
        return $font;
1237 49
    }
1238 49
1239
    /** @return mixed[] */
1240 49
    private function readChartAttributes(?SimpleXMLElement $chartDetail): array
1241 47
    {
1242
        $plotAttributes = [];
1243 49
        if (isset($chartDetail->dLbls)) {
1244 46
            if (isset($chartDetail->dLbls->dLblPos)) {
1245
                $plotAttributes['dLblPos'] = self::getAttributeString($chartDetail->dLbls->dLblPos, 'val');
1246 49
            }
1247 48
            if (isset($chartDetail->dLbls->numFmt)) {
1248
                $plotAttributes['numFmtCode'] = self::getAttributeString($chartDetail->dLbls->numFmt, 'formatCode');
1249 49
                $plotAttributes['numFmtLinked'] = self::getAttributeBoolean($chartDetail->dLbls->numFmt, 'sourceLinked');
1250 43
            }
1251
            if (isset($chartDetail->dLbls->showLegendKey)) {
1252 49
                $plotAttributes['showLegendKey'] = self::getAttributeString($chartDetail->dLbls->showLegendKey, 'val');
1253 10
            }
1254
            if (isset($chartDetail->dLbls->showVal)) {
1255 49
                $plotAttributes['showVal'] = self::getAttributeString($chartDetail->dLbls->showVal, 'val');
1256 5
            }
1257 5
            if (isset($chartDetail->dLbls->showCatName)) {
1258 3
                $plotAttributes['showCatName'] = self::getAttributeString($chartDetail->dLbls->showCatName, 'val');
1259
            }
1260 5
            if (isset($chartDetail->dLbls->showSerName)) {
1261 3
                $plotAttributes['showSerName'] = self::getAttributeString($chartDetail->dLbls->showSerName, 'val');
1262
            }
1263
            if (isset($chartDetail->dLbls->showPercent)) {
1264 49
                $plotAttributes['showPercent'] = self::getAttributeString($chartDetail->dLbls->showPercent, 'val');
1265 9
            }
1266 9
            if (isset($chartDetail->dLbls->showBubbleSize)) {
1267 9
                $plotAttributes['showBubbleSize'] = self::getAttributeString($chartDetail->dLbls->showBubbleSize, 'val');
1268 9
            }
1269 3
            if (isset($chartDetail->dLbls->showLeaderLines)) {
1270 3
                $plotAttributes['showLeaderLines'] = self::getAttributeString($chartDetail->dLbls->showLeaderLines, 'val');
1271 3
            }
1272
            if (isset($chartDetail->dLbls->spPr)) {
1273
                $sppr = $chartDetail->dLbls->spPr->children($this->aNamespace);
1274
                if (isset($sppr->solidFill)) {
1275
                    $plotAttributes['labelFillColor'] = new ChartColor($this->readColor($sppr->solidFill));
1276
                }
1277 69
                if (isset($sppr->ln->solidFill)) {
1278
                    $plotAttributes['labelBorderColor'] = new ChartColor($this->readColor($sppr->ln->solidFill));
1279
                }
1280 69
            }
1281
            if (isset($chartDetail->dLbls->txPr)) {
1282 69
                $txpr = $chartDetail->dLbls->txPr->children($this->aNamespace);
1283
                if (isset($txpr->p)) {
1284 46
                    $plotAttributes['labelFont'] = $this->parseFont($txpr->p);
1285 43
                    if (isset($txpr->p->pPr->defRPr->effectLst)) {
1286
                        $labelEffects = new GridLines();
1287 43
                        $this->readEffects($txpr->p->pPr->defRPr, $labelEffects, false);
1288 46
                        $plotAttributes['labelEffects'] = $labelEffects;
1289 46
                    }
1290
                }
1291 46
            }
1292 46
        }
1293 44
1294
        return $plotAttributes;
1295 44
    }
1296 46
1297 43
    /** @param array<mixed> $plotAttributes */
1298
    private function setChartAttributes(Layout $plotArea, array $plotAttributes): void
1299 43
    {
1300 46
        foreach ($plotAttributes as $plotAttributeKey => $plotAttributeValue) {
1301 45
            /** @var ?bool $plotAttributeValue */
1302
            switch ($plotAttributeKey) {
1303 45
                case 'showLegendKey':
1304 44
                    $plotArea->setShowLegendKey($plotAttributeValue);
1305 43
1306
                    break;
1307 43
                case 'showVal':
1308 5
                    $plotArea->setShowVal($plotAttributeValue);
1309 4
1310
                    break;
1311 4
                case 'showCatName':
1312 1
                    $plotArea->setShowCatName($plotAttributeValue);
1313 1
1314
                    break;
1315 1
                case 'showSerName':
1316
                    $plotArea->setShowSerName($plotAttributeValue);
1317
1318
                    break;
1319
                case 'showPercent':
1320 66
                    $plotArea->setShowPercent($plotAttributeValue);
1321
1322 66
                    break;
1323
                case 'showBubbleSize':
1324
                    $plotArea->setShowBubbleSize($plotAttributeValue);
1325 66
1326 66
                    break;
1327 35
                case 'showLeaderLines':
1328
                    $plotArea->setShowLeaderLines($plotAttributeValue);
1329 51
1330
                    break;
1331 5
                case 'labelFont':
1332
                    /** @var ?Font $plotAttributeValue */
1333 51
                    $plotArea->setLabelFont($plotAttributeValue);
1334 8
1335 8
                    break;
1336 8
            }
1337 8
        }
1338
    }
1339
1340
    private function readEffects(SimpleXMLElement $chartDetail, ?ChartProperties $chartObject, bool $getSppr = true): void
1341 51
    {
1342 2
        if (!isset($chartObject)) {
1343 2
            return;
1344 2
        }
1345
        if ($getSppr) {
1346
            if (!isset($chartDetail->spPr)) {
1347
                return;
1348 51
            }
1349 51
            $sppr = $chartDetail->spPr->children($this->aNamespace);
1350 51
        } else {
1351 6
            $sppr = $chartDetail;
1352
        }
1353 6
        if (isset($sppr->effectLst->glow)) {
1354
            $axisGlowSize = (float) self::getAttributeInteger($sppr->effectLst->glow, 'rad') / ChartProperties::POINTS_WIDTH_MULTIPLIER;
1355
            if ($axisGlowSize != 0.0) {
1356 51
                $colorArray = $this->readColor($sppr->effectLst->glow);
1357 6
                $chartObject->setGlowProperties($axisGlowSize, $colorArray['value'], $colorArray['alpha'], $colorArray['type']);
1358 6
            }
1359 6
        }
1360 6
1361 6
        if (isset($sppr->effectLst->softEdge)) {
1362 6
            $softEdgeSize = self::getAttributeString($sppr->effectLst->softEdge, 'rad');
1363 6
            if (is_numeric($softEdgeSize)) {
1364 6
                $chartObject->setSoftEdges((float) ChartProperties::xmlToPoints($softEdgeSize));
1365 6
            }
1366 6
        }
1367 6
1368 6
        $type = '';
1369 1
        foreach (self::SHADOW_TYPES as $shadowType) {
1370
            if (isset($sppr->effectLst->$shadowType)) {
1371 6
                $type = $shadowType;
1372
1373
                break;
1374 6
            }
1375 6
        }
1376 6
        if ($type !== '') {
1377 1
            $blur = self::getAttributeString($sppr->effectLst->$type, 'blurRad');
1378
            $blur = is_numeric($blur) ? ChartProperties::xmlToPoints($blur) : null;
1379 6
            $dist = self::getAttributeString($sppr->effectLst->$type, 'dist');
1380
            $dist = is_numeric($dist) ? ChartProperties::xmlToPoints($dist) : null;
1381
            $direction = self::getAttributeString($sppr->effectLst->$type, 'dir');
1382 6
            $direction = is_numeric($direction) ? ChartProperties::xmlToAngle($direction) : null;
1383 6
            $algn = self::getAttributeString($sppr->effectLst->$type, 'algn');
1384 6
            $rot = self::getAttributeString($sppr->effectLst->$type, 'rotWithShape');
1385 6
            $size = [];
1386 6
            foreach (['sx', 'sy'] as $sizeType) {
1387 6
                $sizeValue = self::getAttributeString($sppr->effectLst->$type, $sizeType);
1388 6
                if (is_numeric($sizeValue)) {
1389 6
                    $size[$sizeType] = ChartProperties::xmlToTenthOfPercent((string) $sizeValue);
1390 6
                } else {
1391 6
                    $size[$sizeType] = null;
1392
                }
1393
            }
1394
            foreach (['kx', 'ky'] as $sizeType) {
1395
                $sizeValue = self::getAttributeString($sppr->effectLst->$type, $sizeType);
1396
                if (is_numeric($sizeValue)) {
1397
                    $size[$sizeType] = ChartProperties::xmlToAngle((string) $sizeValue);
1398
                } else {
1399
                    $size[$sizeType] = null;
1400 69
                }
1401
            }
1402 69
            $colorArray = $this->readColor($sppr->effectLst->$type);
1403 69
            $chartObject
1404 69
                ->setShadowProperty('effect', $type)
1405 69
                ->setShadowProperty('blur', $blur)
1406 69
                ->setShadowProperty('direction', $direction)
1407 69
                ->setShadowProperty('distance', $dist)
1408 69
                ->setShadowProperty('algn', $algn)
1409 69
                ->setShadowProperty('rotWithShape', $rot)
1410 59
                ->setShadowProperty('size', $size)
1411 59
                ->setShadowProperty('color', $colorArray);
1412 59
        }
1413 20
    }
1414 20
1415 20
    private const SHADOW_TYPES = [
1416
        'outerShdw',
1417
        'innerShdw',
1418 59
    ];
1419 14
1420 14
    /** @return array{type: ?string, value: ?string, alpha: ?int, brightness: ?int} */
1421 14
    private function readColor(SimpleXMLElement $colorXml): array
1422
    {
1423
        $result = [
1424
            'type' => null,
1425 59
            'value' => null,
1426
            'alpha' => null,
1427
            'brightness' => null,
1428
        ];
1429 69
        foreach (ChartColor::EXCEL_COLOR_TYPES as $type) {
1430
            if (isset($colorXml->$type)) {
1431
                $result['type'] = $type;
1432 69
                $result['value'] = self::getAttributeString($colorXml->$type, 'val');
1433
                if (isset($colorXml->$type->alpha)) {
1434 69
                    $alpha = self::getAttributeString($colorXml->$type->alpha, 'val');
1435 35
                    if (is_numeric($alpha)) {
1436
                        $result['alpha'] = ChartColor::alphaFromXml($alpha);
1437 69
                    }
1438
                }
1439 69
                if (isset($colorXml->$type->lumMod)) {
1440 7
                    $brightness = self::getAttributeString($colorXml->$type->lumMod, 'val');
1441
                    if (is_numeric($brightness)) {
1442 69
                        $result['brightness'] = ChartColor::alphaFromXml($brightness);
1443 69
                    }
1444 69
                }
1445 46
1446
                break;
1447
            }
1448 69
        }
1449
1450 69
        return $result;
1451
    }
1452 69
1453 69
    private function readLineStyle(SimpleXMLElement $chartDetail, ?ChartProperties $chartObject): void
1454 12
    {
1455 69
        if (!isset($chartObject, $chartDetail->spPr)) {
1456 5
            return;
1457
        }
1458 69
        $sppr = $chartDetail->spPr->children($this->aNamespace);
1459
1460 69
        if (!isset($sppr->ln)) {
1461 69
            return;
1462 69
        }
1463 69
        $lineWidth = null;
1464 69
        $lineWidthTemp = self::getAttributeString($sppr->ln, 'w');
1465 69
        if (is_numeric($lineWidthTemp)) {
1466 69
            $lineWidth = ChartProperties::xmlToPoints($lineWidthTemp);
1467 69
        }
1468 69
        /** @var string $compoundType */
1469 69
        $compoundType = self::getAttributeString($sppr->ln, 'cmpd');
1470 69
        /** @var string $dashType */
1471 69
        $dashType = self::getAttributeString($sppr->ln->prstDash, 'val');
1472 69
        /** @var string $capType */
1473 69
        $capType = self::getAttributeString($sppr->ln, 'cap');
1474 69
        if (isset($sppr->ln->miter)) {
1475 69
            $joinType = ChartProperties::LINE_STYLE_JOIN_MITER;
1476 69
        } elseif (isset($sppr->ln->bevel)) {
1477 69
            $joinType = ChartProperties::LINE_STYLE_JOIN_BEVEL;
1478 69
        } else {
1479 69
            $joinType = '';
1480 69
        }
1481 69
        $headArrowSize = 0;
1482 69
        $endArrowSize = 0;
1483 69
        $headArrowType = self::getAttributeString($sppr->ln->headEnd, 'type');
1484 69
        $headArrowWidth = self::getAttributeString($sppr->ln->headEnd, 'w');
1485
        $headArrowLength = self::getAttributeString($sppr->ln->headEnd, 'len');
1486
        $endArrowType = self::getAttributeString($sppr->ln->tailEnd, 'type');
1487 66
        $endArrowWidth = self::getAttributeString($sppr->ln->tailEnd, 'w');
1488
        $endArrowLength = self::getAttributeString($sppr->ln->tailEnd, 'len');
1489 66
        $chartObject->setLineStyleProperties(
1490
            $lineWidth,
1491
            $compoundType,
1492 66
            $dashType,
1493 63
            $capType,
1494
            $joinType,
1495 66
            $headArrowType,
1496 64
            $headArrowSize,
1497 64
            $endArrowType,
1498 64
            $endArrowSize,
1499 64
            $headArrowWidth,
1500 64
            $headArrowLength,
1501
            $endArrowWidth,
1502 66
            $endArrowLength
1503 46
        );
1504
        $colorArray = $this->readColor($sppr->ln->solidFill);
1505 66
        $chartObject->getLineColor()->setColorPropertiesArray($colorArray);
1506 3
    }
1507 3
1508 3
    private function setAxisProperties(SimpleXMLElement $chartDetail, ?Axis $whichAxis): void
1509
    {
1510
        if (!isset($whichAxis)) {
1511
            return;
1512 66
        }
1513 66
        if (isset($chartDetail->delete)) {
1514
            $whichAxis->setAxisOption('hidden', (string) self::getAttributeString($chartDetail->delete, 'val'));
1515 66
        }
1516 65
        if (isset($chartDetail->numFmt)) {
1517
            $whichAxis->setAxisNumberProperties(
1518 66
                (string) self::getAttributeString($chartDetail->numFmt, 'formatCode'),
1519 64
                null,
1520
                (int) self::getAttributeInteger($chartDetail->numFmt, 'sourceLinked')
1521 66
            );
1522 63
        }
1523
        if (isset($chartDetail->crossBetween)) {
1524 66
            $whichAxis->setCrossBetween((string) self::getAttributeString($chartDetail->crossBetween, 'val'));
1525
        }
1526
        if (isset($chartDetail->dispUnits, $chartDetail->dispUnits->builtInUnit)) {
1527 66
            $whichAxis->setAxisOption('dispUnitsBuiltIn', (string) self::getAttributeString($chartDetail->dispUnits->builtInUnit, 'val'));
1528 1
            if (isset($chartDetail->dispUnits->dispUnitsLbl)) {
1529
                $whichAxis->setDispUnitsTitle(new Title());
1530 66
                // TODO parse title elements
1531 66
            }
1532
        }
1533 66
        if (isset($chartDetail->majorTickMark)) {
1534 8
            $whichAxis->setAxisOption('major_tick_mark', (string) self::getAttributeString($chartDetail->majorTickMark, 'val'));
1535
        }
1536 66
        if (isset($chartDetail->minorTickMark)) {
1537 8
            $whichAxis->setAxisOption('minor_tick_mark', (string) self::getAttributeString($chartDetail->minorTickMark, 'val'));
1538
        }
1539 66
        if (isset($chartDetail->tickLblPos)) {
1540 8
            $whichAxis->setAxisOption('axis_labels', (string) self::getAttributeString($chartDetail->tickLblPos, 'val'));
1541
        }
1542 66
        if (isset($chartDetail->crosses)) {
1543 4
            $whichAxis->setAxisOption('horizontal_crosses', (string) self::getAttributeString($chartDetail->crosses, 'val'));
1544
        }
1545 66
        if (isset($chartDetail->crossesAt)) {
1546 1
            $whichAxis->setAxisOption('horizontal_crosses_value', (string) self::getAttributeString($chartDetail->crossesAt, 'val'));
1547
        }
1548 66
        if (isset($chartDetail->scaling->logBase)) {
1549 3
            $whichAxis->setAxisOption('logBase', (string) self::getAttributeString($chartDetail->scaling->logBase, 'val'));
1550
        }
1551 66
        if (isset($chartDetail->scaling->orientation)) {
1552 3
            $whichAxis->setAxisOption('orientation', (string) self::getAttributeString($chartDetail->scaling->orientation, 'val'));
1553
        }
1554 66
        if (isset($chartDetail->scaling->max)) {
1555 3
            $whichAxis->setAxisOption('maximum', (string) self::getAttributeString($chartDetail->scaling->max, 'val'));
1556
        }
1557 66
        if (isset($chartDetail->scaling->min)) {
1558 14
            $whichAxis->setAxisOption('minimum', (string) self::getAttributeString($chartDetail->scaling->min, 'val'));
1559 14
        }
1560 14
        if (isset($chartDetail->scaling->min)) {
1561 14
            $whichAxis->setAxisOption('minimum', (string) self::getAttributeString($chartDetail->scaling->min, 'val'));
1562 14
        }
1563 14
        if (isset($chartDetail->majorUnit)) {
1564 9
            $whichAxis->setAxisOption('major_unit', (string) self::getAttributeString($chartDetail->majorUnit, 'val'));
1565 9
        }
1566
        if (isset($chartDetail->minorUnit)) {
1567
            $whichAxis->setAxisOption('minor_unit', (string) self::getAttributeString($chartDetail->minorUnit, 'val'));
1568 14
        }
1569 14
        if (isset($chartDetail->baseTimeUnit)) {
1570 14
            $whichAxis->setAxisOption('baseTimeUnit', (string) self::getAttributeString($chartDetail->baseTimeUnit, 'val'));
1571 14
        }
1572 14
        if (isset($chartDetail->majorTimeUnit)) {
1573
            $whichAxis->setAxisOption('majorTimeUnit', (string) self::getAttributeString($chartDetail->majorTimeUnit, 'val'));
1574
        }
1575 14
        if (isset($chartDetail->minorTimeUnit)) {
1576 4
            $whichAxis->setAxisOption('minorTimeUnit', (string) self::getAttributeString($chartDetail->minorTimeUnit, 'val'));
1577 4
        }
1578
        if (isset($chartDetail->txPr)) {
1579 14
            $children = $chartDetail->txPr->children($this->aNamespace);
1580 14
            $addAxisText = false;
1581
            $axisText = new AxisText();
1582
            if (isset($children->bodyPr)) {
1583
                $textRotation = self::getAttributeString($children->bodyPr, 'rot');
1584
                if (is_numeric($textRotation)) {
1585
                    $axisText->setRotation((int) ChartProperties::xmlToAngle($textRotation));
1586
                    $addAxisText = true;
1587
                }
1588
            }
1589
            if (isset($children->p->pPr->defRPr)) {
1590
                $font = $this->parseFont($children->p);
1591
                if ($font !== null) {
1592
                    $axisText->setFont($font);
1593
                    $addAxisText = true;
1594
                }
1595
            }
1596
            if (isset($children->p->pPr->defRPr->effectLst)) {
1597
                $this->readEffects($children->p->pPr->defRPr, $axisText, false);
1598
                $addAxisText = true;
1599
            }
1600
            if ($addAxisText) {
1601
                $whichAxis->setAxisText($axisText);
1602
            }
1603
        }
1604
    }
1605
}
1606