Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx; 4 5 use PhpOffice\PhpSpreadsheet\Chart\Axis; 6 use PhpOffice\PhpSpreadsheet\Chart\DataSeries; 7 use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; 8 use PhpOffice\PhpSpreadsheet\Chart\GridLines; 9 use PhpOffice\PhpSpreadsheet\Chart\Layout; 10 use PhpOffice\PhpSpreadsheet\Chart\Legend; 11 use PhpOffice\PhpSpreadsheet\Chart\PlotArea; 12 use PhpOffice\PhpSpreadsheet\Chart\Title; 13 use PhpOffice\PhpSpreadsheet\Shared\StringHelper; 14 use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; 15 use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; 16 17 class Chart extends WriterPart 18 { 19 protected $calculateCellValues; 20 21 /** 22 * @var int 23 */ 24 private $seriesIndex; 25 26 /** 27 * Write charts to XML format. 28 * 29 * @param mixed $calculateCellValues 30 * 31 * @return string XML Output 32 */ 33 public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calculateCellValues = true) 34 { 35 $this->calculateCellValues = $calculateCellValues; 36 37 // Create XML writer 38 $objWriter = null; 39 if ($this->getParentWriter()->getUseDiskCaching()) { 40 $objWriter = new XMLWriter(XMLWriter::STORAGE_DISK, $this->getParentWriter()->getDiskCachingDirectory()); 41 } else { 42 $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); 43 } 44 // Ensure that data series values are up-to-date before we save 45 if ($this->calculateCellValues) { 46 $chart->refresh(); 47 } 48 49 // XML header 50 $objWriter->startDocument('1.0', 'UTF-8', 'yes'); 51 52 // c:chartSpace 53 $objWriter->startElement('c:chartSpace'); 54 $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart'); 55 $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main'); 56 $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); 57 58 $objWriter->startElement('c:date1904'); 59 $objWriter->writeAttribute('val', 0); 60 $objWriter->endElement(); 61 $objWriter->startElement('c:lang'); 62 $objWriter->writeAttribute('val', 'en-GB'); 63 $objWriter->endElement(); 64 $objWriter->startElement('c:roundedCorners'); 65 $objWriter->writeAttribute('val', 0); 66 $objWriter->endElement(); 67 68 $this->writeAlternateContent($objWriter); 69 70 $objWriter->startElement('c:chart'); 71 72 $this->writeTitle($objWriter, $chart->getTitle()); 73 74 $objWriter->startElement('c:autoTitleDeleted'); 75 $objWriter->writeAttribute('val', 0); 76 $objWriter->endElement(); 77 78 $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart->getXAxisLabel(), $chart->getYAxisLabel(), $chart->getChartAxisX(), $chart->getChartAxisY(), $chart->getMajorGridlines(), $chart->getMinorGridlines()); 79 80 $this->writeLegend($objWriter, $chart->getLegend()); 81 82 $objWriter->startElement('c:plotVisOnly'); 83 $objWriter->writeAttribute('val', (int) $chart->getPlotVisibleOnly()); 84 $objWriter->endElement(); 85 86 $objWriter->startElement('c:dispBlanksAs'); 87 $objWriter->writeAttribute('val', $chart->getDisplayBlanksAs()); 88 $objWriter->endElement(); 89 90 $objWriter->startElement('c:showDLblsOverMax'); 91 $objWriter->writeAttribute('val', 0); 92 $objWriter->endElement(); 93 94 $objWriter->endElement(); 95 96 $this->writePrintSettings($objWriter); 97 98 $objWriter->endElement(); 99 100 // Return 101 return $objWriter->getData(); 102 } 103 104 /** 105 * Write Chart Title. 106 */ 107 private function writeTitle(XMLWriter $objWriter, ?Title $title = null): void 108 { 109 if ($title === null) { 110 return; 111 } 112 113 $objWriter->startElement('c:title'); 114 $objWriter->startElement('c:tx'); 115 $objWriter->startElement('c:rich'); 116 117 $objWriter->startElement('a:bodyPr'); 118 $objWriter->endElement(); 119 120 $objWriter->startElement('a:lstStyle'); 121 $objWriter->endElement(); 122 123 $objWriter->startElement('a:p'); 124 125 $caption = $title->getCaption(); 126 if ((is_array($caption)) && (count($caption) > 0)) { 127 $caption = $caption[0]; 128 } 129 $this->getParentWriter()->getWriterPartstringtable()->writeRichTextForCharts($objWriter, $caption, 'a'); 130 131 $objWriter->endElement(); 132 $objWriter->endElement(); 133 $objWriter->endElement(); 134 135 $this->writeLayout($objWriter, $title->getLayout()); 136 137 $objWriter->startElement('c:overlay'); 138 $objWriter->writeAttribute('val', 0); 139 $objWriter->endElement(); 140 141 $objWriter->endElement(); 142 } 143 144 /** 145 * Write Chart Legend. 146 */ 147 private function writeLegend(XMLWriter $objWriter, ?Legend $legend = null): void 148 { 149 if ($legend === null) { 150 return; 151 } 152 153 $objWriter->startElement('c:legend'); 154 155 $objWriter->startElement('c:legendPos'); 156 $objWriter->writeAttribute('val', $legend->getPosition()); 157 $objWriter->endElement(); 158 159 $this->writeLayout($objWriter, $legend->getLayout()); 160 161 $objWriter->startElement('c:overlay'); 162 $objWriter->writeAttribute('val', ($legend->getOverlay()) ? '1' : '0'); 163 $objWriter->endElement(); 164 165 $objWriter->startElement('c:txPr'); 166 $objWriter->startElement('a:bodyPr'); 167 $objWriter->endElement(); 168 169 $objWriter->startElement('a:lstStyle'); 170 $objWriter->endElement(); 171 172 $objWriter->startElement('a:p'); 173 $objWriter->startElement('a:pPr'); 174 $objWriter->writeAttribute('rtl', 0); 175 176 $objWriter->startElement('a:defRPr'); 177 $objWriter->endElement(); 178 $objWriter->endElement(); 179 180 $objWriter->startElement('a:endParaRPr'); 181 $objWriter->writeAttribute('lang', 'en-US'); 182 $objWriter->endElement(); 183 184 $objWriter->endElement(); 185 $objWriter->endElement(); 186 187 $objWriter->endElement(); 188 } 189 190 /** 191 * Write Chart Plot Area. 192 */ 193 private function writePlotArea(XMLWriter $objWriter, PlotArea $plotArea, ?Title $xAxisLabel = null, ?Title $yAxisLabel = null, ?Axis $xAxis = null, ?Axis $yAxis = null, ?GridLines $majorGridlines = null, ?GridLines $minorGridlines = null): void 194 { 195 if ($plotArea === null) { 196 return; 197 } 198 199 $id1 = $id2 = 0; 200 $this->seriesIndex = 0; 201 $objWriter->startElement('c:plotArea'); 202 203 $layout = $plotArea->getLayout(); 204 205 $this->writeLayout($objWriter, $layout); 206 207 $chartTypes = self::getChartType($plotArea); 208 $catIsMultiLevelSeries = $valIsMultiLevelSeries = false; 209 $plotGroupingType = ''; 210 $chartType = null; 211 foreach ($chartTypes as $chartType) { 212 $objWriter->startElement('c:' . $chartType); 213 214 $groupCount = $plotArea->getPlotGroupCount(); 215 $plotGroup = null; 216 for ($i = 0; $i < $groupCount; ++$i) { 217 $plotGroup = $plotArea->getPlotGroupByIndex($i); 218 $groupType = $plotGroup->getPlotType(); 219 if ($groupType == $chartType) { 220 $plotStyle = $plotGroup->getPlotStyle(); 221 if ($groupType === DataSeries::TYPE_RADARCHART) { 222 $objWriter->startElement('c:radarStyle'); 223 $objWriter->writeAttribute('val', $plotStyle); 224 $objWriter->endElement(); 225 } elseif ($groupType === DataSeries::TYPE_SCATTERCHART) { 226 $objWriter->startElement('c:scatterStyle'); 227 $objWriter->writeAttribute('val', $plotStyle); 228 $objWriter->endElement(); 229 } 230 231 $this->writePlotGroup($plotGroup, $chartType, $objWriter, $catIsMultiLevelSeries, $valIsMultiLevelSeries, $plotGroupingType); 232 } 233 } 234 235 $this->writeDataLabels($objWriter, $layout); 236 237 if ($chartType === DataSeries::TYPE_LINECHART && $plotGroup) { 238 // Line only, Line3D can't be smoothed 239 $objWriter->startElement('c:smooth'); 240 $objWriter->writeAttribute('val', (int) $plotGroup->getSmoothLine()); 241 $objWriter->endElement(); 242 } elseif (($chartType === DataSeries::TYPE_BARCHART) || ($chartType === DataSeries::TYPE_BARCHART_3D)) { 243 $objWriter->startElement('c:gapWidth'); 244 $objWriter->writeAttribute('val', 150); 245 $objWriter->endElement(); 246 247 if ($plotGroupingType == 'percentStacked' || $plotGroupingType == 'stacked') { 248 $objWriter->startElement('c:overlap'); 249 $objWriter->writeAttribute('val', 100); 250 $objWriter->endElement(); 251 } 252 } elseif ($chartType === DataSeries::TYPE_BUBBLECHART) { 253 $objWriter->startElement('c:bubbleScale'); 254 $objWriter->writeAttribute('val', 25); 255 $objWriter->endElement(); 256 257 $objWriter->startElement('c:showNegBubbles'); 258 $objWriter->writeAttribute('val', 0); 259 $objWriter->endElement(); 260 } elseif ($chartType === DataSeries::TYPE_STOCKCHART) { 261 $objWriter->startElement('c:hiLowLines'); 262 $objWriter->endElement(); 263 264 $objWriter->startElement('c:upDownBars'); 265 266 $objWriter->startElement('c:gapWidth'); 267 $objWriter->writeAttribute('val', 300); 268 $objWriter->endElement(); 269 270 $objWriter->startElement('c:upBars'); 271 $objWriter->endElement(); 272 273 $objWriter->startElement('c:downBars'); 274 $objWriter->endElement(); 275 276 $objWriter->endElement(); 277 } 278 279 // Generate 2 unique numbers to use for axId values 280 $id1 = '75091328'; 281 $id2 = '75089408'; 282 283 if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) { 284 $objWriter->startElement('c:axId'); 285 $objWriter->writeAttribute('val', $id1); 286 $objWriter->endElement(); 287 $objWriter->startElement('c:axId'); 288 $objWriter->writeAttribute('val', $id2); 289 $objWriter->endElement(); 290 } else { 291 $objWriter->startElement('c:firstSliceAng'); 292 $objWriter->writeAttribute('val', 0); 293 $objWriter->endElement(); 294 295 if ($chartType === DataSeries::TYPE_DONUTCHART) { 296 $objWriter->startElement('c:holeSize'); 297 $objWriter->writeAttribute('val', 50); 298 $objWriter->endElement(); 299 } 300 } 301 302 $objWriter->endElement(); 303 } 304 305 if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) { 306 if ($chartType === DataSeries::TYPE_BUBBLECHART) { 307 $this->writeValueAxis($objWriter, $xAxisLabel, $chartType, $id1, $id2, $catIsMultiLevelSeries, $xAxis, $majorGridlines, $minorGridlines); 308 } else { 309 $this->writeCategoryAxis($objWriter, $xAxisLabel, $id1, $id2, $catIsMultiLevelSeries, $xAxis); 310 } 311 312 $this->writeValueAxis($objWriter, $yAxisLabel, $chartType, $id1, $id2, $valIsMultiLevelSeries, $yAxis, $majorGridlines, $minorGridlines); 313 } 314 315 $objWriter->endElement(); 316 } 317 318 /** 319 * Write Data Labels. 320 */ 321 private function writeDataLabels(XMLWriter $objWriter, ?Layout $chartLayout = null): void 322 { 323 $objWriter->startElement('c:dLbls'); 324 325 $objWriter->startElement('c:showLegendKey'); 326 $showLegendKey = (empty($chartLayout)) ? 0 : $chartLayout->getShowLegendKey(); 327 $objWriter->writeAttribute('val', ((empty($showLegendKey)) ? 0 : 1)); 328 $objWriter->endElement(); 329 330 $objWriter->startElement('c:showVal'); 331 $showVal = (empty($chartLayout)) ? 0 : $chartLayout->getShowVal(); 332 $objWriter->writeAttribute('val', ((empty($showVal)) ? 0 : 1)); 333 $objWriter->endElement(); 334 335 $objWriter->startElement('c:showCatName'); 336 $showCatName = (empty($chartLayout)) ? 0 : $chartLayout->getShowCatName(); 337 $objWriter->writeAttribute('val', ((empty($showCatName)) ? 0 : 1)); 338 $objWriter->endElement(); 339 340 $objWriter->startElement('c:showSerName'); 341 $showSerName = (empty($chartLayout)) ? 0 : $chartLayout->getShowSerName(); 342 $objWriter->writeAttribute('val', ((empty($showSerName)) ? 0 : 1)); 343 $objWriter->endElement(); 344 345 $objWriter->startElement('c:showPercent'); 346 $showPercent = (empty($chartLayout)) ? 0 : $chartLayout->getShowPercent(); 347 $objWriter->writeAttribute('val', ((empty($showPercent)) ? 0 : 1)); 348 $objWriter->endElement(); 349 350 $objWriter->startElement('c:showBubbleSize'); 351 $showBubbleSize = (empty($chartLayout)) ? 0 : $chartLayout->getShowBubbleSize(); 352 $objWriter->writeAttribute('val', ((empty($showBubbleSize)) ? 0 : 1)); 353 $objWriter->endElement(); 354 355 $objWriter->startElement('c:showLeaderLines'); 356 $showLeaderLines = (empty($chartLayout)) ? 1 : $chartLayout->getShowLeaderLines(); 357 $objWriter->writeAttribute('val', ((empty($showLeaderLines)) ? 0 : 1)); 358 $objWriter->endElement(); 359 360 $objWriter->endElement(); 361 } 362 363 /** 364 * Write Category Axis. 365 * 366 * @param string $id1 367 * @param string $id2 368 * @param bool $isMultiLevelSeries 369 */ 370 private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id1, $id2, $isMultiLevelSeries, Axis $yAxis): void 371 { 372 $objWriter->startElement('c:catAx'); 373 374 if ($id1 > 0) { 375 $objWriter->startElement('c:axId'); 376 $objWriter->writeAttribute('val', $id1); 377 $objWriter->endElement(); 378 } 379 380 $objWriter->startElement('c:scaling'); 381 $objWriter->startElement('c:orientation'); 382 $objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('orientation')); 383 $objWriter->endElement(); 384 $objWriter->endElement(); 385 386 $objWriter->startElement('c:delete'); 387 $objWriter->writeAttribute('val', 0); 388 $objWriter->endElement(); 389 390 $objWriter->startElement('c:axPos'); 391 $objWriter->writeAttribute('val', 'b'); 392 $objWriter->endElement(); 393 394 if ($xAxisLabel !== null) { 395 $objWriter->startElement('c:title'); 396 $objWriter->startElement('c:tx'); 397 $objWriter->startElement('c:rich'); 398 399 $objWriter->startElement('a:bodyPr'); 400 $objWriter->endElement(); 401 402 $objWriter->startElement('a:lstStyle'); 403 $objWriter->endElement(); 404 405 $objWriter->startElement('a:p'); 406 $objWriter->startElement('a:r'); 407 408 $caption = $xAxisLabel->getCaption(); 409 if (is_array($caption)) { 410 $caption = $caption[0]; 411 } 412 $objWriter->startElement('a:t'); 413 $objWriter->writeRawData(StringHelper::controlCharacterPHP2OOXML($caption)); 414 $objWriter->endElement(); 415 416 $objWriter->endElement(); 417 $objWriter->endElement(); 418 $objWriter->endElement(); 419 $objWriter->endElement(); 420 421 $layout = $xAxisLabel->getLayout(); 422 $this->writeLayout($objWriter, $layout); 423 424 $objWriter->startElement('c:overlay'); 425 $objWriter->writeAttribute('val', 0); 426 $objWriter->endElement(); 427 428 $objWriter->endElement(); 429 } 430 431 $objWriter->startElement('c:numFmt'); 432 $objWriter->writeAttribute('formatCode', $yAxis->getAxisNumberFormat()); 433 $objWriter->writeAttribute('sourceLinked', $yAxis->getAxisNumberSourceLinked()); 434 $objWriter->endElement(); 435 436 $objWriter->startElement('c:majorTickMark'); 437 $objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('major_tick_mark')); 438 $objWriter->endElement(); 439 440 $objWriter->startElement('c:minorTickMark'); 441 $objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('minor_tick_mark')); 442 $objWriter->endElement(); 443 444 $objWriter->startElement('c:tickLblPos'); 445 $objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('axis_labels')); 446 $objWriter->endElement(); 447 448 if ($id2 > 0) { 449 $objWriter->startElement('c:crossAx'); 450 $objWriter->writeAttribute('val', $id2); 451 $objWriter->endElement(); 452 453 $objWriter->startElement('c:crosses'); 454 $objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('horizontal_crosses')); 455 $objWriter->endElement(); 456 } 457 458 $objWriter->startElement('c:auto'); 459 $objWriter->writeAttribute('val', 1); 460 $objWriter->endElement(); 461 462 $objWriter->startElement('c:lblAlgn'); 463 $objWriter->writeAttribute('val', 'ctr'); 464 $objWriter->endElement(); 465 466 $objWriter->startElement('c:lblOffset'); 467 $objWriter->writeAttribute('val', 100); 468 $objWriter->endElement(); 469 470 if ($isMultiLevelSeries) { 471 $objWriter->startElement('c:noMultiLvlLbl'); 472 $objWriter->writeAttribute('val', 0); 473 $objWriter->endElement(); 474 } 475 $objWriter->endElement(); 476 } 477 478 /** 479 * Write Value Axis. 480 * 481 * @param null|string $groupType Chart type 482 * @param string $id1 483 * @param string $id2 484 * @param bool $isMultiLevelSeries 485 */ 486 private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $groupType, $id1, $id2, $isMultiLevelSeries, Axis $xAxis, GridLines $majorGridlines, GridLines $minorGridlines): void 487 { 488 $objWriter->startElement('c:valAx'); 489 490 if ($id2 > 0) { 491 $objWriter->startElement('c:axId'); 492 $objWriter->writeAttribute('val', $id2); 493 $objWriter->endElement(); 494 } 495 496 $objWriter->startElement('c:scaling'); 497 498 if ($xAxis->getAxisOptionsProperty('maximum') !== null) { 499 $objWriter->startElement('c:max'); 500 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('maximum')); 501 $objWriter->endElement(); 502 } 503 504 if ($xAxis->getAxisOptionsProperty('minimum') !== null) { 505 $objWriter->startElement('c:min'); 506 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('minimum')); 507 $objWriter->endElement(); 508 } 509 510 $objWriter->startElement('c:orientation'); 511 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('orientation')); 512 513 $objWriter->endElement(); 514 $objWriter->endElement(); 515 516 $objWriter->startElement('c:delete'); 517 $objWriter->writeAttribute('val', 0); 518 $objWriter->endElement(); 519 520 $objWriter->startElement('c:axPos'); 521 $objWriter->writeAttribute('val', 'l'); 522 $objWriter->endElement(); 523 524 $objWriter->startElement('c:majorGridlines'); 525 $objWriter->startElement('c:spPr'); 526 527 if ($majorGridlines->getLineColorProperty('value') !== null) { 528 $objWriter->startElement('a:ln'); 529 $objWriter->writeAttribute('w', $majorGridlines->getLineStyleProperty('width')); 530 $objWriter->startElement('a:solidFill'); 531 $objWriter->startElement("a:{$majorGridlines->getLineColorProperty('type')}"); 532 $objWriter->writeAttribute('val', $majorGridlines->getLineColorProperty('value')); 533 $objWriter->startElement('a:alpha'); 534 $objWriter->writeAttribute('val', $majorGridlines->getLineColorProperty('alpha')); 535 $objWriter->endElement(); //end alpha 536 $objWriter->endElement(); //end srgbClr 537 $objWriter->endElement(); //end solidFill 538 539 $objWriter->startElement('a:prstDash'); 540 $objWriter->writeAttribute('val', $majorGridlines->getLineStyleProperty('dash')); 541 $objWriter->endElement(); 542 543 if ($majorGridlines->getLineStyleProperty('join') == 'miter') { 544 $objWriter->startElement('a:miter'); 545 $objWriter->writeAttribute('lim', '800000'); 546 $objWriter->endElement(); 547 } else { 548 $objWriter->startElement('a:bevel'); 549 $objWriter->endElement(); 550 } 551 552 if ($majorGridlines->getLineStyleProperty(['arrow', 'head', 'type']) !== null) { 553 $objWriter->startElement('a:headEnd'); 554 $objWriter->writeAttribute('type', $majorGridlines->getLineStyleProperty(['arrow', 'head', 'type'])); 555 $objWriter->writeAttribute('w', $majorGridlines->getLineStyleArrowParameters('head', 'w')); 556 $objWriter->writeAttribute('len', $majorGridlines->getLineStyleArrowParameters('head', 'len')); 557 $objWriter->endElement(); 558 } 559 560 if ($majorGridlines->getLineStyleProperty(['arrow', 'end', 'type']) !== null) { 561 $objWriter->startElement('a:tailEnd'); 562 $objWriter->writeAttribute('type', $majorGridlines->getLineStyleProperty(['arrow', 'end', 'type'])); 563 $objWriter->writeAttribute('w', $majorGridlines->getLineStyleArrowParameters('end', 'w')); 564 $objWriter->writeAttribute('len', $majorGridlines->getLineStyleArrowParameters('end', 'len')); 565 $objWriter->endElement(); 566 } 567 $objWriter->endElement(); //end ln 568 } 569 $objWriter->startElement('a:effectLst'); 570 571 if ($majorGridlines->getGlowSize() !== null) { 572 $objWriter->startElement('a:glow'); 573 $objWriter->writeAttribute('rad', $majorGridlines->getGlowSize()); 574 $objWriter->startElement("a:{$majorGridlines->getGlowColor('type')}"); 575 $objWriter->writeAttribute('val', $majorGridlines->getGlowColor('value')); 576 $objWriter->startElement('a:alpha'); 577 $objWriter->writeAttribute('val', $majorGridlines->getGlowColor('alpha')); 578 $objWriter->endElement(); //end alpha 579 $objWriter->endElement(); //end schemeClr 580 $objWriter->endElement(); //end glow 581 } 582 583 if ($majorGridlines->getShadowProperty('presets') !== null) { 584 $objWriter->startElement("a:{$majorGridlines->getShadowProperty('effect')}"); 585 if ($majorGridlines->getShadowProperty('blur') !== null) { 586 $objWriter->writeAttribute('blurRad', $majorGridlines->getShadowProperty('blur')); 587 } 588 if ($majorGridlines->getShadowProperty('distance') !== null) { 589 $objWriter->writeAttribute('dist', $majorGridlines->getShadowProperty('distance')); 590 } 591 if ($majorGridlines->getShadowProperty('direction') !== null) { 592 $objWriter->writeAttribute('dir', $majorGridlines->getShadowProperty('direction')); 593 } 594 if ($majorGridlines->getShadowProperty('algn') !== null) { 595 $objWriter->writeAttribute('algn', $majorGridlines->getShadowProperty('algn')); 596 } 597 if ($majorGridlines->getShadowProperty(['size', 'sx']) !== null) { 598 $objWriter->writeAttribute('sx', $majorGridlines->getShadowProperty(['size', 'sx'])); 599 } 600 if ($majorGridlines->getShadowProperty(['size', 'sy']) !== null) { 601 $objWriter->writeAttribute('sy', $majorGridlines->getShadowProperty(['size', 'sy'])); 602 } 603 if ($majorGridlines->getShadowProperty(['size', 'kx']) !== null) { 604 $objWriter->writeAttribute('kx', $majorGridlines->getShadowProperty(['size', 'kx'])); 605 } 606 if ($majorGridlines->getShadowProperty('rotWithShape') !== null) { 607 $objWriter->writeAttribute('rotWithShape', $majorGridlines->getShadowProperty('rotWithShape')); 608 } 609 $objWriter->startElement("a:{$majorGridlines->getShadowProperty(['color', 'type'])}"); 610 $objWriter->writeAttribute('val', $majorGridlines->getShadowProperty(['color', 'value'])); 611 612 $objWriter->startElement('a:alpha'); 613 $objWriter->writeAttribute('val', $majorGridlines->getShadowProperty(['color', 'alpha'])); 614 $objWriter->endElement(); //end alpha 615 616 $objWriter->endElement(); //end color:type 617 $objWriter->endElement(); //end shadow 618 } 619 620 if ($majorGridlines->getSoftEdgesSize() !== null) { 621 $objWriter->startElement('a:softEdge'); 622 $objWriter->writeAttribute('rad', $majorGridlines->getSoftEdgesSize()); 623 $objWriter->endElement(); //end softEdge 624 } 625 626 $objWriter->endElement(); //end effectLst 627 $objWriter->endElement(); //end spPr 628 $objWriter->endElement(); //end majorGridLines 629 630 if ($minorGridlines->getObjectState()) { 631 $objWriter->startElement('c:minorGridlines'); 632 $objWriter->startElement('c:spPr'); 633 634 if ($minorGridlines->getLineColorProperty('value') !== null) { 635 $objWriter->startElement('a:ln'); 636 $objWriter->writeAttribute('w', $minorGridlines->getLineStyleProperty('width')); 637 $objWriter->startElement('a:solidFill'); 638 $objWriter->startElement("a:{$minorGridlines->getLineColorProperty('type')}"); 639 $objWriter->writeAttribute('val', $minorGridlines->getLineColorProperty('value')); 640 $objWriter->startElement('a:alpha'); 641 $objWriter->writeAttribute('val', $minorGridlines->getLineColorProperty('alpha')); 642 $objWriter->endElement(); //end alpha 643 $objWriter->endElement(); //end srgbClr 644 $objWriter->endElement(); //end solidFill 645 646 $objWriter->startElement('a:prstDash'); 647 $objWriter->writeAttribute('val', $minorGridlines->getLineStyleProperty('dash')); 648 $objWriter->endElement(); 649 650 if ($minorGridlines->getLineStyleProperty('join') == 'miter') { 651 $objWriter->startElement('a:miter'); 652 $objWriter->writeAttribute('lim', '800000'); 653 $objWriter->endElement(); 654 } else { 655 $objWriter->startElement('a:bevel'); 656 $objWriter->endElement(); 657 } 658 659 if ($minorGridlines->getLineStyleProperty(['arrow', 'head', 'type']) !== null) { 660 $objWriter->startElement('a:headEnd'); 661 $objWriter->writeAttribute('type', $minorGridlines->getLineStyleProperty(['arrow', 'head', 'type'])); 662 $objWriter->writeAttribute('w', $minorGridlines->getLineStyleArrowParameters('head', 'w')); 663 $objWriter->writeAttribute('len', $minorGridlines->getLineStyleArrowParameters('head', 'len')); 664 $objWriter->endElement(); 665 } 666 667 if ($minorGridlines->getLineStyleProperty(['arrow', 'end', 'type']) !== null) { 668 $objWriter->startElement('a:tailEnd'); 669 $objWriter->writeAttribute('type', $minorGridlines->getLineStyleProperty(['arrow', 'end', 'type'])); 670 $objWriter->writeAttribute('w', $minorGridlines->getLineStyleArrowParameters('end', 'w')); 671 $objWriter->writeAttribute('len', $minorGridlines->getLineStyleArrowParameters('end', 'len')); 672 $objWriter->endElement(); 673 } 674 $objWriter->endElement(); //end ln 675 } 676 677 $objWriter->startElement('a:effectLst'); 678 679 if ($minorGridlines->getGlowSize() !== null) { 680 $objWriter->startElement('a:glow'); 681 $objWriter->writeAttribute('rad', $minorGridlines->getGlowSize()); 682 $objWriter->startElement("a:{$minorGridlines->getGlowColor('type')}"); 683 $objWriter->writeAttribute('val', $minorGridlines->getGlowColor('value')); 684 $objWriter->startElement('a:alpha'); 685 $objWriter->writeAttribute('val', $minorGridlines->getGlowColor('alpha')); 686 $objWriter->endElement(); //end alpha 687 $objWriter->endElement(); //end schemeClr 688 $objWriter->endElement(); //end glow 689 } 690 691 if ($minorGridlines->getShadowProperty('presets') !== null) { 692 $objWriter->startElement("a:{$minorGridlines->getShadowProperty('effect')}"); 693 if ($minorGridlines->getShadowProperty('blur') !== null) { 694 $objWriter->writeAttribute('blurRad', $minorGridlines->getShadowProperty('blur')); 695 } 696 if ($minorGridlines->getShadowProperty('distance') !== null) { 697 $objWriter->writeAttribute('dist', $minorGridlines->getShadowProperty('distance')); 698 } 699 if ($minorGridlines->getShadowProperty('direction') !== null) { 700 $objWriter->writeAttribute('dir', $minorGridlines->getShadowProperty('direction')); 701 } 702 if ($minorGridlines->getShadowProperty('algn') !== null) { 703 $objWriter->writeAttribute('algn', $minorGridlines->getShadowProperty('algn')); 704 } 705 if ($minorGridlines->getShadowProperty(['size', 'sx']) !== null) { 706 $objWriter->writeAttribute('sx', $minorGridlines->getShadowProperty(['size', 'sx'])); 707 } 708 if ($minorGridlines->getShadowProperty(['size', 'sy']) !== null) { 709 $objWriter->writeAttribute('sy', $minorGridlines->getShadowProperty(['size', 'sy'])); 710 } 711 if ($minorGridlines->getShadowProperty(['size', 'kx']) !== null) { 712 $objWriter->writeAttribute('kx', $minorGridlines->getShadowProperty(['size', 'kx'])); 713 } 714 if ($minorGridlines->getShadowProperty('rotWithShape') !== null) { 715 $objWriter->writeAttribute('rotWithShape', $minorGridlines->getShadowProperty('rotWithShape')); 716 } 717 $objWriter->startElement("a:{$minorGridlines->getShadowProperty(['color', 'type'])}"); 718 $objWriter->writeAttribute('val', $minorGridlines->getShadowProperty(['color', 'value'])); 719 $objWriter->startElement('a:alpha'); 720 $objWriter->writeAttribute('val', $minorGridlines->getShadowProperty(['color', 'alpha'])); 721 $objWriter->endElement(); //end alpha 722 $objWriter->endElement(); //end color:type 723 $objWriter->endElement(); //end shadow 724 } 725 726 if ($minorGridlines->getSoftEdgesSize() !== null) { 727 $objWriter->startElement('a:softEdge'); 728 $objWriter->writeAttribute('rad', $minorGridlines->getSoftEdgesSize()); 729 $objWriter->endElement(); //end softEdge 730 } 731 732 $objWriter->endElement(); //end effectLst 733 $objWriter->endElement(); //end spPr 734 $objWriter->endElement(); //end minorGridLines 735 } 736 737 if ($yAxisLabel !== null) { 738 $objWriter->startElement('c:title'); 739 $objWriter->startElement('c:tx'); 740 $objWriter->startElement('c:rich'); 741 742 $objWriter->startElement('a:bodyPr'); 743 $objWriter->endElement(); 744 745 $objWriter->startElement('a:lstStyle'); 746 $objWriter->endElement(); 747 748 $objWriter->startElement('a:p'); 749 $objWriter->startElement('a:r'); 750 751 $caption = $yAxisLabel->getCaption(); 752 if (is_array($caption)) { 753 $caption = $caption[0]; 754 } 755 756 $objWriter->startElement('a:t'); 757 $objWriter->writeRawData(StringHelper::controlCharacterPHP2OOXML($caption)); 758 $objWriter->endElement(); 759 760 $objWriter->endElement(); 761 $objWriter->endElement(); 762 $objWriter->endElement(); 763 $objWriter->endElement(); 764 765 if ($groupType !== DataSeries::TYPE_BUBBLECHART) { 766 $layout = $yAxisLabel->getLayout(); 767 $this->writeLayout($objWriter, $layout); 768 } 769 770 $objWriter->startElement('c:overlay'); 771 $objWriter->writeAttribute('val', 0); 772 $objWriter->endElement(); 773 774 $objWriter->endElement(); 775 } 776 777 $objWriter->startElement('c:numFmt'); 778 $objWriter->writeAttribute('formatCode', $xAxis->getAxisNumberFormat()); 779 $objWriter->writeAttribute('sourceLinked', $xAxis->getAxisNumberSourceLinked()); 780 $objWriter->endElement(); 781 782 $objWriter->startElement('c:majorTickMark'); 783 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('major_tick_mark')); 784 $objWriter->endElement(); 785 786 $objWriter->startElement('c:minorTickMark'); 787 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('minor_tick_mark')); 788 $objWriter->endElement(); 789 790 $objWriter->startElement('c:tickLblPos'); 791 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('axis_labels')); 792 $objWriter->endElement(); 793 794 $objWriter->startElement('c:spPr'); 795 796 if ($xAxis->getFillProperty('value') !== null) { 797 $objWriter->startElement('a:solidFill'); 798 $objWriter->startElement('a:' . $xAxis->getFillProperty('type')); 799 $objWriter->writeAttribute('val', $xAxis->getFillProperty('value')); 800 $objWriter->startElement('a:alpha'); 801 $objWriter->writeAttribute('val', $xAxis->getFillProperty('alpha')); 802 $objWriter->endElement(); 803 $objWriter->endElement(); 804 $objWriter->endElement(); 805 } 806 807 $objWriter->startElement('a:ln'); 808 809 $objWriter->writeAttribute('w', $xAxis->getLineStyleProperty('width')); 810 $objWriter->writeAttribute('cap', $xAxis->getLineStyleProperty('cap')); 811 $objWriter->writeAttribute('cmpd', $xAxis->getLineStyleProperty('compound')); 812 813 if ($xAxis->getLineProperty('value') !== null) { 814 $objWriter->startElement('a:solidFill'); 815 $objWriter->startElement('a:' . $xAxis->getLineProperty('type')); 816 $objWriter->writeAttribute('val', $xAxis->getLineProperty('value')); 817 $objWriter->startElement('a:alpha'); 818 $objWriter->writeAttribute('val', $xAxis->getLineProperty('alpha')); 819 $objWriter->endElement(); 820 $objWriter->endElement(); 821 $objWriter->endElement(); 822 } 823 824 $objWriter->startElement('a:prstDash'); 825 $objWriter->writeAttribute('val', $xAxis->getLineStyleProperty('dash')); 826 $objWriter->endElement(); 827 828 if ($xAxis->getLineStyleProperty('join') == 'miter') { 829 $objWriter->startElement('a:miter'); 830 $objWriter->writeAttribute('lim', '800000'); 831 $objWriter->endElement(); 832 } else { 833 $objWriter->startElement('a:bevel'); 834 $objWriter->endElement(); 835 } 836 837 if ($xAxis->getLineStyleProperty(['arrow', 'head', 'type']) !== null) { 838 $objWriter->startElement('a:headEnd'); 839 $objWriter->writeAttribute('type', $xAxis->getLineStyleProperty(['arrow', 'head', 'type'])); 840 $objWriter->writeAttribute('w', $xAxis->getLineStyleArrowWidth('head')); 841 $objWriter->writeAttribute('len', $xAxis->getLineStyleArrowLength('head')); 842 $objWriter->endElement(); 843 } 844 845 if ($xAxis->getLineStyleProperty(['arrow', 'end', 'type']) !== null) { 846 $objWriter->startElement('a:tailEnd'); 847 $objWriter->writeAttribute('type', $xAxis->getLineStyleProperty(['arrow', 'end', 'type'])); 848 $objWriter->writeAttribute('w', $xAxis->getLineStyleArrowWidth('end')); 849 $objWriter->writeAttribute('len', $xAxis->getLineStyleArrowLength('end')); 850 $objWriter->endElement(); 851 } 852 853 $objWriter->endElement(); 854 855 $objWriter->startElement('a:effectLst'); 856 857 if ($xAxis->getGlowProperty('size') !== null) { 858 $objWriter->startElement('a:glow'); 859 $objWriter->writeAttribute('rad', $xAxis->getGlowProperty('size')); 860 $objWriter->startElement("a:{$xAxis->getGlowProperty(['color', 'type'])}"); 861 $objWriter->writeAttribute('val', $xAxis->getGlowProperty(['color', 'value'])); 862 $objWriter->startElement('a:alpha'); 863 $objWriter->writeAttribute('val', $xAxis->getGlowProperty(['color', 'alpha'])); 864 $objWriter->endElement(); 865 $objWriter->endElement(); 866 $objWriter->endElement(); 867 } 868 869 if ($xAxis->getShadowProperty('presets') !== null) { 870 $objWriter->startElement("a:{$xAxis->getShadowProperty('effect')}"); 871 872 if ($xAxis->getShadowProperty('blur') !== null) { 873 $objWriter->writeAttribute('blurRad', $xAxis->getShadowProperty('blur')); 874 } 875 if ($xAxis->getShadowProperty('distance') !== null) { 876 $objWriter->writeAttribute('dist', $xAxis->getShadowProperty('distance')); 877 } 878 if ($xAxis->getShadowProperty('direction') !== null) { 879 $objWriter->writeAttribute('dir', $xAxis->getShadowProperty('direction')); 880 } 881 if ($xAxis->getShadowProperty('algn') !== null) { 882 $objWriter->writeAttribute('algn', $xAxis->getShadowProperty('algn')); 883 } 884 if ($xAxis->getShadowProperty(['size', 'sx']) !== null) { 885 $objWriter->writeAttribute('sx', $xAxis->getShadowProperty(['size', 'sx'])); 886 } 887 if ($xAxis->getShadowProperty(['size', 'sy']) !== null) { 888 $objWriter->writeAttribute('sy', $xAxis->getShadowProperty(['size', 'sy'])); 889 } 890 if ($xAxis->getShadowProperty(['size', 'kx']) !== null) { 891 $objWriter->writeAttribute('kx', $xAxis->getShadowProperty(['size', 'kx'])); 892 } 893 if ($xAxis->getShadowProperty('rotWithShape') !== null) { 894 $objWriter->writeAttribute('rotWithShape', $xAxis->getShadowProperty('rotWithShape')); 895 } 896 897 $objWriter->startElement("a:{$xAxis->getShadowProperty(['color', 'type'])}"); 898 $objWriter->writeAttribute('val', $xAxis->getShadowProperty(['color', 'value'])); 899 $objWriter->startElement('a:alpha'); 900 $objWriter->writeAttribute('val', $xAxis->getShadowProperty(['color', 'alpha'])); 901 $objWriter->endElement(); 902 $objWriter->endElement(); 903 904 $objWriter->endElement(); 905 } 906 907 if ($xAxis->getSoftEdgesSize() !== null) { 908 $objWriter->startElement('a:softEdge'); 909 $objWriter->writeAttribute('rad', $xAxis->getSoftEdgesSize()); 910 $objWriter->endElement(); 911 } 912 913 $objWriter->endElement(); //effectList 914 $objWriter->endElement(); //end spPr 915 916 if ($id1 > 0) { 917 $objWriter->startElement('c:crossAx'); 918 $objWriter->writeAttribute('val', $id2); 919 $objWriter->endElement(); 920 921 if ($xAxis->getAxisOptionsProperty('horizontal_crosses_value') !== null) { 922 $objWriter->startElement('c:crossesAt'); 923 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('horizontal_crosses_value')); 924 $objWriter->endElement(); 925 } else { 926 $objWriter->startElement('c:crosses'); 927 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('horizontal_crosses')); 928 $objWriter->endElement(); 929 } 930 931 $objWriter->startElement('c:crossBetween'); 932 $objWriter->writeAttribute('val', 'midCat'); 933 $objWriter->endElement(); 934 935 if ($xAxis->getAxisOptionsProperty('major_unit') !== null) { 936 $objWriter->startElement('c:majorUnit'); 937 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('major_unit')); 938 $objWriter->endElement(); 939 } 940 941 if ($xAxis->getAxisOptionsProperty('minor_unit') !== null) { 942 $objWriter->startElement('c:minorUnit'); 943 $objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('minor_unit')); 944 $objWriter->endElement(); 945 } 946 } 947 948 if ($isMultiLevelSeries) { 949 if ($groupType !== DataSeries::TYPE_BUBBLECHART) { 950 $objWriter->startElement('c:noMultiLvlLbl'); 951 $objWriter->writeAttribute('val', 0); 952 $objWriter->endElement(); 953 } 954 } 955 956 $objWriter->endElement(); 957 } 958 959 /** 960 * Get the data series type(s) for a chart plot series. 961 * 962 * @return string[] 963 */ 964 private static function getChartType(PlotArea $plotArea): array 965 { 966 $groupCount = $plotArea->getPlotGroupCount(); 967 968 if ($groupCount == 1) { 969 $chartType = [$plotArea->getPlotGroupByIndex(0)->getPlotType()]; 970 } else { 971 $chartTypes = []; 972 for ($i = 0; $i < $groupCount; ++$i) { 973 $chartTypes[] = $plotArea->getPlotGroupByIndex($i)->getPlotType(); 974 } 975 $chartType = array_unique($chartTypes); 976 if (count($chartTypes) == 0) { 977 throw new WriterException('Chart is not yet implemented'); 978 } 979 } 980 981 return $chartType; 982 } 983 984 /** 985 * Method writing plot series values. 986 * 987 * @param int $val value for idx (default: 3) 988 * @param string $fillColor hex color (default: FF9900) 989 */ 990 private function writePlotSeriesValuesElement(XMLWriter $objWriter, $val = 3, $fillColor = 'FF9900'): void 991 { 992 $objWriter->startElement('c:dPt'); 993 $objWriter->startElement('c:idx'); 994 $objWriter->writeAttribute('val', $val); 995 $objWriter->endElement(); 996 997 $objWriter->startElement('c:bubble3D'); 998 $objWriter->writeAttribute('val', 0); 999 $objWriter->endElement(); 1000 1001 $objWriter->startElement('c:spPr'); 1002 $objWriter->startElement('a:solidFill'); 1003 $objWriter->startElement('a:srgbClr'); 1004 $objWriter->writeAttribute('val', $fillColor); 1005 $objWriter->endElement(); 1006 $objWriter->endElement(); 1007 $objWriter->endElement(); 1008 $objWriter->endElement(); 1009 } 1010 1011 /** 1012 * Write Plot Group (series of related plots). 1013 * 1014 * @param string $groupType Type of plot for dataseries 1015 * @param bool $catIsMultiLevelSeries Is category a multi-series category 1016 * @param bool $valIsMultiLevelSeries Is value set a multi-series set 1017 * @param string $plotGroupingType Type of grouping for multi-series values 1018 */ 1019 private function writePlotGroup(?DataSeries $plotGroup, $groupType, XMLWriter $objWriter, &$catIsMultiLevelSeries, &$valIsMultiLevelSeries, &$plotGroupingType): void 1020 { 1021 if ($plotGroup === null) { 1022 return; 1023 } 1024 1025 if (($groupType == DataSeries::TYPE_BARCHART) || ($groupType == DataSeries::TYPE_BARCHART_3D)) { 1026 $objWriter->startElement('c:barDir'); 1027 $objWriter->writeAttribute('val', $plotGroup->getPlotDirection()); 1028 $objWriter->endElement(); 1029 } 1030 1031 if ($plotGroup->getPlotGrouping() !== null) { 1032 $plotGroupingType = $plotGroup->getPlotGrouping(); 1033 $objWriter->startElement('c:grouping'); 1034 $objWriter->writeAttribute('val', $plotGroupingType); 1035 $objWriter->endElement(); 1036 } 1037 1038 // Get these details before the loop, because we can use the count to check for varyColors 1039 $plotSeriesOrder = $plotGroup->getPlotOrder(); 1040 $plotSeriesCount = count($plotSeriesOrder); 1041 1042 if (($groupType !== DataSeries::TYPE_RADARCHART) && ($groupType !== DataSeries::TYPE_STOCKCHART)) { 1043 if ($groupType !== DataSeries::TYPE_LINECHART) { 1044 if (($groupType == DataSeries::TYPE_PIECHART) || ($groupType == DataSeries::TYPE_PIECHART_3D) || ($groupType == DataSeries::TYPE_DONUTCHART) || ($plotSeriesCount > 1)) { 1045 $objWriter->startElement('c:varyColors'); 1046 $objWriter->writeAttribute('val', 1); 1047 $objWriter->endElement(); 1048 } else { 1049 $objWriter->startElement('c:varyColors'); 1050 $objWriter->writeAttribute('val', 0); 1051 $objWriter->endElement(); 1052 } 1053 } 1054 } 1055 1056 $plotSeriesIdx = 0; 1057 foreach ($plotSeriesOrder as $plotSeriesIdx => $plotSeriesRef) { 1058 $objWriter->startElement('c:ser'); 1059 1060 $plotLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx); 1061 if ($plotLabel && $groupType !== DataSeries::TYPE_LINECHART) { 1062 $fillColor = $plotLabel->getFillColor(); 1063 if ($fillColor !== null && !is_array($fillColor)) { 1064 $objWriter->startElement('c:spPr'); 1065 $objWriter->startElement('a:solidFill'); 1066 $objWriter->startElement('a:srgbClr'); 1067 $objWriter->writeAttribute('val', $fillColor); 1068 $objWriter->endElement(); 1069 $objWriter->endElement(); 1070 $objWriter->endElement(); 1071 } 1072 } 1073 1074 $objWriter->startElement('c:idx'); 1075 $objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesIdx); 1076 $objWriter->endElement(); 1077 1078 $objWriter->startElement('c:order'); 1079 $objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesRef); 1080 $objWriter->endElement(); 1081 1082 // Values 1083 $plotSeriesValues = $plotGroup->getPlotValuesByIndex($plotSeriesRef); 1084 1085 if (($groupType == DataSeries::TYPE_PIECHART) || ($groupType == DataSeries::TYPE_PIECHART_3D) || ($groupType == DataSeries::TYPE_DONUTCHART)) { 1086 $fillColorValues = $plotSeriesValues->getFillColor(); 1087 if ($fillColorValues !== null && is_array($fillColorValues)) { 1088 foreach ($plotSeriesValues->getDataValues() as $dataKey => $dataValue) { 1089 $this->writePlotSeriesValuesElement($objWriter, $dataKey, ($fillColorValues[$dataKey] ?? 'FF9900')); 1090 } 1091 } else { 1092 $this->writePlotSeriesValuesElement($objWriter); 1093 } 1094 } 1095 1096 // Labels 1097 $plotSeriesLabel = $plotGroup->getPlotLabelByIndex($plotSeriesRef); 1098 if ($plotSeriesLabel && ($plotSeriesLabel->getPointCount() > 0)) { 1099 $objWriter->startElement('c:tx'); 1100 $objWriter->startElement('c:strRef'); 1101 $this->writePlotSeriesLabel($plotSeriesLabel, $objWriter); 1102 $objWriter->endElement(); 1103 $objWriter->endElement(); 1104 } 1105 1106 // Formatting for the points 1107 if (($groupType == DataSeries::TYPE_LINECHART) || ($groupType == DataSeries::TYPE_STOCKCHART)) { 1108 $plotLineWidth = 12700; 1109 if ($plotSeriesValues) { 1110 $plotLineWidth = $plotSeriesValues->getLineWidth(); 1111 } 1112 1113 $objWriter->startElement('c:spPr'); 1114 $objWriter->startElement('a:ln'); 1115 $objWriter->writeAttribute('w', $plotLineWidth); 1116 if ($groupType == DataSeries::TYPE_STOCKCHART) { 1117 $objWriter->startElement('a:noFill'); 1118 $objWriter->endElement(); 1119 } elseif ($plotLabel) { 1120 $fillColor = $plotLabel->getFillColor(); 1121 if (is_string($fillColor)) { 1122 $objWriter->startElement('a:solidFill'); 1123 $objWriter->startElement('a:srgbClr'); 1124 $objWriter->writeAttribute('val', $fillColor); 1125 $objWriter->endElement(); 1126 $objWriter->endElement(); 1127 } 1128 } 1129 $objWriter->endElement(); 1130 $objWriter->endElement(); 1131 } 1132 1133 if ($plotSeriesValues) { 1134 $plotSeriesMarker = $plotSeriesValues->getPointMarker(); 1135 if ($plotSeriesMarker) { 1136 $objWriter->startElement('c:marker'); 1137 $objWriter->startElement('c:symbol'); 1138 $objWriter->writeAttribute('val', $plotSeriesMarker); 1139 $objWriter->endElement(); 1140 1141 if ($plotSeriesMarker !== 'none') { 1142 $objWriter->startElement('c:size'); 1143 $objWriter->writeAttribute('val', 3); 1144 $objWriter->endElement(); 1145 } 1146 1147 $objWriter->endElement(); 1148 } 1149 } 1150 1151 if (($groupType === DataSeries::TYPE_BARCHART) || ($groupType === DataSeries::TYPE_BARCHART_3D) || ($groupType === DataSeries::TYPE_BUBBLECHART)) { 1152 $objWriter->startElement('c:invertIfNegative'); 1153 $objWriter->writeAttribute('val', 0); 1154 $objWriter->endElement(); 1155 } 1156 1157 // Category Labels 1158 $plotSeriesCategory = $plotGroup->getPlotCategoryByIndex($plotSeriesRef); 1159 if ($plotSeriesCategory && ($plotSeriesCategory->getPointCount() > 0)) { 1160 $catIsMultiLevelSeries = $catIsMultiLevelSeries || $plotSeriesCategory->isMultiLevelSeries(); 1161 1162 if (($groupType == DataSeries::TYPE_PIECHART) || ($groupType == DataSeries::TYPE_PIECHART_3D) || ($groupType == DataSeries::TYPE_DONUTCHART)) { 1163 if ($plotGroup->getPlotStyle() !== null) { 1164 $plotStyle = $plotGroup->getPlotStyle(); 1165 if ($plotStyle) { 1166 $objWriter->startElement('c:explosion'); 1167 $objWriter->writeAttribute('val', 25); 1168 $objWriter->endElement(); 1169 } 1170 } 1171 } 1172 1173 if (($groupType === DataSeries::TYPE_BUBBLECHART) || ($groupType === DataSeries::TYPE_SCATTERCHART)) { 1174 $objWriter->startElement('c:xVal'); 1175 } else { 1176 $objWriter->startElement('c:cat'); 1177 } 1178 1179 $this->writePlotSeriesValues($plotSeriesCategory, $objWriter, $groupType, 'str'); 1180 $objWriter->endElement(); 1181 } 1182 1183 // Values 1184 if ($plotSeriesValues) { 1185 $valIsMultiLevelSeries = $valIsMultiLevelSeries || $plotSeriesValues->isMultiLevelSeries(); 1186 1187 if (($groupType === DataSeries::TYPE_BUBBLECHART) || ($groupType === DataSeries::TYPE_SCATTERCHART)) { 1188 $objWriter->startElement('c:yVal'); 1189 } else { 1190 $objWriter->startElement('c:val'); 1191 } 1192 1193 $this->writePlotSeriesValues($plotSeriesValues, $objWriter, $groupType, 'num'); 1194 $objWriter->endElement(); 1195 } 1196 1197 if ($groupType === DataSeries::TYPE_BUBBLECHART) { 1198 $this->writeBubbles($plotSeriesValues, $objWriter); 1199 } 1200 1201 $objWriter->endElement(); 1202 } 1203 1204 $this->seriesIndex += $plotSeriesIdx + 1; 1205 } 1206 1207 /** 1208 * Write Plot Series Label. 1209 */ 1210 private function writePlotSeriesLabel(?DataSeriesValues $plotSeriesLabel, XMLWriter $objWriter): void 1211 { 1212 if ($plotSeriesLabel === null) { 1213 return; 1214 } 1215 1216 $objWriter->startElement('c:f'); 1217 $objWriter->writeRawData($plotSeriesLabel->getDataSource()); 1218 $objWriter->endElement(); 1219 1220 $objWriter->startElement('c:strCache'); 1221 $objWriter->startElement('c:ptCount'); 1222 $objWriter->writeAttribute('val', $plotSeriesLabel->getPointCount()); 1223 $objWriter->endElement(); 1224 1225 foreach ($plotSeriesLabel->getDataValues() as $plotLabelKey => $plotLabelValue) { 1226 $objWriter->startElement('c:pt'); 1227 $objWriter->writeAttribute('idx', $plotLabelKey); 1228 1229 $objWriter->startElement('c:v'); 1230 $objWriter->writeRawData($plotLabelValue); 1231 $objWriter->endElement(); 1232 $objWriter->endElement(); 1233 } 1234 $objWriter->endElement(); 1235 } 1236 1237 /** 1238 * Write Plot Series Values. 1239 * 1240 * @param string $groupType Type of plot for dataseries 1241 * @param string $dataType Datatype of series values 1242 */ 1243 private function writePlotSeriesValues(?DataSeriesValues $plotSeriesValues, XMLWriter $objWriter, $groupType, $dataType = 'str'): void 1244 { 1245 if ($plotSeriesValues === null) { 1246 return; 1247 } 1248 1249 if ($plotSeriesValues->isMultiLevelSeries()) { 1250 $levelCount = $plotSeriesValues->multiLevelCount(); 1251 1252 $objWriter->startElement('c:multiLvlStrRef'); 1253 1254 $objWriter->startElement('c:f'); 1255 $objWriter->writeRawData($plotSeriesValues->getDataSource()); 1256 $objWriter->endElement(); 1257 1258 $objWriter->startElement('c:multiLvlStrCache'); 1259 1260 $objWriter->startElement('c:ptCount'); 1261 $objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); 1262 $objWriter->endElement(); 1263 1264 for ($level = 0; $level < $levelCount; ++$level) { 1265 $objWriter->startElement('c:lvl'); 1266 1267 foreach ($plotSeriesValues->getDataValues() as $plotSeriesKey => $plotSeriesValue) { 1268 if (isset($plotSeriesValue[$level])) { 1269 $objWriter->startElement('c:pt'); 1270 $objWriter->writeAttribute('idx', $plotSeriesKey); 1271 1272 $objWriter->startElement('c:v'); 1273 $objWriter->writeRawData($plotSeriesValue[$level]); 1274 $objWriter->endElement(); 1275 $objWriter->endElement(); 1276 } 1277 } 1278 1279 $objWriter->endElement(); 1280 } 1281 1282 $objWriter->endElement(); 1283 1284 $objWriter->endElement(); 1285 } else { 1286 $objWriter->startElement('c:' . $dataType . 'Ref'); 1287 1288 $objWriter->startElement('c:f'); 1289 $objWriter->writeRawData($plotSeriesValues->getDataSource()); 1290 $objWriter->endElement(); 1291 1292 $objWriter->startElement('c:' . $dataType . 'Cache'); 1293 1294 if (($groupType != DataSeries::TYPE_PIECHART) && ($groupType != DataSeries::TYPE_PIECHART_3D) && ($groupType != DataSeries::TYPE_DONUTCHART)) { 1295 if (($plotSeriesValues->getFormatCode() !== null) && ($plotSeriesValues->getFormatCode() !== '')) { 1296 $objWriter->startElement('c:formatCode'); 1297 $objWriter->writeRawData($plotSeriesValues->getFormatCode()); 1298 $objWriter->endElement(); 1299 } 1300 } 1301 1302 $objWriter->startElement('c:ptCount'); 1303 $objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); 1304 $objWriter->endElement(); 1305 1306 $dataValues = $plotSeriesValues->getDataValues(); 1307 if (!empty($dataValues)) { 1308 if (is_array($dataValues)) { 1309 foreach ($dataValues as $plotSeriesKey => $plotSeriesValue) { 1310 $objWriter->startElement('c:pt'); 1311 $objWriter->writeAttribute('idx', $plotSeriesKey); 1312 1313 $objWriter->startElement('c:v'); 1314 $objWriter->writeRawData($plotSeriesValue); 1315 $objWriter->endElement(); 1316 $objWriter->endElement(); 1317 } 1318 } 1319 } 1320 1321 $objWriter->endElement(); 1322 1323 $objWriter->endElement(); 1324 } 1325 } 1326 1327 /** 1328 * Write Bubble Chart Details. 1329 */ 1330 private function writeBubbles(?DataSeriesValues $plotSeriesValues, XMLWriter $objWriter): void 1331 { 1332 if ($plotSeriesValues === null) { 1333 return; 1334 } 1335 1336 $objWriter->startElement('c:bubbleSize'); 1337 $objWriter->startElement('c:numLit'); 1338 1339 $objWriter->startElement('c:formatCode'); 1340 $objWriter->writeRawData('General'); 1341 $objWriter->endElement(); 1342 1343 $objWriter->startElement('c:ptCount'); 1344 $objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); 1345 $objWriter->endElement(); 1346 1347 $dataValues = $plotSeriesValues->getDataValues(); 1348 if (!empty($dataValues)) { 1349 if (is_array($dataValues)) { 1350 foreach ($dataValues as $plotSeriesKey => $plotSeriesValue) { 1351 $objWriter->startElement('c:pt'); 1352 $objWriter->writeAttribute('idx', $plotSeriesKey); 1353 $objWriter->startElement('c:v'); 1354 $objWriter->writeRawData(1); 1355 $objWriter->endElement(); 1356 $objWriter->endElement(); 1357 } 1358 } 1359 } 1360 1361 $objWriter->endElement(); 1362 $objWriter->endElement(); 1363 1364 $objWriter->startElement('c:bubble3D'); 1365 $objWriter->writeAttribute('val', 0); 1366 $objWriter->endElement(); 1367 } 1368 1369 /** 1370 * Write Layout. 1371 */ 1372 private function writeLayout(XMLWriter $objWriter, ?Layout $layout = null): void 1373 { 1374 $objWriter->startElement('c:layout'); 1375 1376 if ($layout !== null) { 1377 $objWriter->startElement('c:manualLayout'); 1378 1379 $layoutTarget = $layout->getLayoutTarget(); 1380 if ($layoutTarget !== null) { 1381 $objWriter->startElement('c:layoutTarget'); 1382 $objWriter->writeAttribute('val', $layoutTarget); 1383 $objWriter->endElement(); 1384 } 1385 1386 $xMode = $layout->getXMode(); 1387 if ($xMode !== null) { 1388 $objWriter->startElement('c:xMode'); 1389 $objWriter->writeAttribute('val', $xMode); 1390 $objWriter->endElement(); 1391 } 1392 1393 $yMode = $layout->getYMode(); 1394 if ($yMode !== null) { 1395 $objWriter->startElement('c:yMode'); 1396 $objWriter->writeAttribute('val', $yMode); 1397 $objWriter->endElement(); 1398 } 1399 1400 $x = $layout->getXPosition(); 1401 if ($x !== null) { 1402 $objWriter->startElement('c:x'); 1403 $objWriter->writeAttribute('val', $x); 1404 $objWriter->endElement(); 1405 } 1406 1407 $y = $layout->getYPosition(); 1408 if ($y !== null) { 1409 $objWriter->startElement('c:y'); 1410 $objWriter->writeAttribute('val', $y); 1411 $objWriter->endElement(); 1412 } 1413 1414 $w = $layout->getWidth(); 1415 if ($w !== null) { 1416 $objWriter->startElement('c:w'); 1417 $objWriter->writeAttribute('val', $w); 1418 $objWriter->endElement(); 1419 } 1420 1421 $h = $layout->getHeight(); 1422 if ($h !== null) { 1423 $objWriter->startElement('c:h'); 1424 $objWriter->writeAttribute('val', $h); 1425 $objWriter->endElement(); 1426 } 1427 1428 $objWriter->endElement(); 1429 } 1430 1431 $objWriter->endElement(); 1432 } 1433 1434 /** 1435 * Write Alternate Content block. 1436 */ 1437 private function writeAlternateContent(XMLWriter $objWriter): void 1438 { 1439 $objWriter->startElement('mc:AlternateContent'); 1440 $objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006'); 1441 1442 $objWriter->startElement('mc:Choice'); 1443 $objWriter->writeAttribute('xmlns:c14', 'http://schemas.microsoft.com/office/drawing/2007/8/2/chart'); 1444 $objWriter->writeAttribute('Requires', 'c14'); 1445 1446 $objWriter->startElement('c14:style'); 1447 $objWriter->writeAttribute('val', '102'); 1448 $objWriter->endElement(); 1449 $objWriter->endElement(); 1450 1451 $objWriter->startElement('mc:Fallback'); 1452 $objWriter->startElement('c:style'); 1453 $objWriter->writeAttribute('val', '2'); 1454 $objWriter->endElement(); 1455 $objWriter->endElement(); 1456 1457 $objWriter->endElement(); 1458 } 1459 1460 /** 1461 * Write Printer Settings. 1462 */ 1463 private function writePrintSettings(XMLWriter $objWriter): void 1464 { 1465 $objWriter->startElement('c:printSettings'); 1466 1467 $objWriter->startElement('c:headerFooter'); 1468 $objWriter->endElement(); 1469 1470 $objWriter->startElement('c:pageMargins'); 1471 $objWriter->writeAttribute('footer', 0.3); 1472 $objWriter->writeAttribute('header', 0.3); 1473 $objWriter->writeAttribute('r', 0.7); 1474 $objWriter->writeAttribute('l', 0.7); 1475 $objWriter->writeAttribute('t', 0.75); 1476 $objWriter->writeAttribute('b', 0.75); 1477 $objWriter->endElement(); 1478 1479 $objWriter->startElement('c:pageSetup'); 1480 $objWriter->writeAttribute('orientation', 'portrait'); 1481 $objWriter->endElement(); 1482 1483 $objWriter->endElement(); 1484 } 1485 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body