diff --git a/CHANGELOG.md b/CHANGELOG.md index b7d55bbebf..6e3a4db15e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Time interval formatting [Issue #2768](https://github.com/PHPOffice/PhpSpreadsheet/issues/2768) [PR #2772](https://github.com/PHPOffice/PhpSpreadsheet/pull/2772) - Copy from Xls(x) to Html/Pdf loses drawings [PR #2788](https://github.com/PHPOffice/PhpSpreadsheet/pull/2788) - Html Reader converting cell containing 0 to null string [Issue #2810](https://github.com/PHPOffice/PhpSpreadsheet/issues/2810) [PR #2813](https://github.com/PHPOffice/PhpSpreadsheet/pull/2813) -- Many fixes for Charts, especially, but not limited to, Scatter, Bubble, and Surface charts. [Issue #2762](https://github.com/PHPOffice/PhpSpreadsheet/issues/2762) [Issue #2299](https://github.com/PHPOffice/PhpSpreadsheet/issues/2299) [Issue #2700](https://github.com/PHPOffice/PhpSpreadsheet/issues/2700) [Issue #2817](https://github.com/PHPOffice/PhpSpreadsheet/issues/2817) [Issue #2763](https://github.com/PHPOffice/PhpSpreadsheet/issues/2763) [Issue #2219](https://github.com/PHPOffice/PhpSpreadsheet/issues/2219) [Issue #2863](https://github.com/PHPOffice/PhpSpreadsheet/issues/2863) [PR #2828](https://github.com/PHPOffice/PhpSpreadsheet/pull/2828) [PR #2841](https://github.com/PHPOffice/PhpSpreadsheet/pull/2841) [PR #2846](https://github.com/PHPOffice/PhpSpreadsheet/pull/2846) [PR #2852](https://github.com/PHPOffice/PhpSpreadsheet/pull/2852) [PR #2856](https://github.com/PHPOffice/PhpSpreadsheet/pull/2856) [PR #2865](https://github.com/PHPOffice/PhpSpreadsheet/pull/2865) [PR #2872](https://github.com/PHPOffice/PhpSpreadsheet/pull/2872) [PR #2879](https://github.com/PHPOffice/PhpSpreadsheet/pull/2879) [PR #2898](https://github.com/PHPOffice/PhpSpreadsheet/pull/2898) [PR #2906](https://github.com/PHPOffice/PhpSpreadsheet/pull/2906) +- Many fixes for Charts, especially, but not limited to, Scatter, Bubble, and Surface charts. [Issue #2762](https://github.com/PHPOffice/PhpSpreadsheet/issues/2762) [Issue #2299](https://github.com/PHPOffice/PhpSpreadsheet/issues/2299) [Issue #2700](https://github.com/PHPOffice/PhpSpreadsheet/issues/2700) [Issue #2817](https://github.com/PHPOffice/PhpSpreadsheet/issues/2817) [Issue #2763](https://github.com/PHPOffice/PhpSpreadsheet/issues/2763) [Issue #2219](https://github.com/PHPOffice/PhpSpreadsheet/issues/2219) [Issue #2863](https://github.com/PHPOffice/PhpSpreadsheet/issues/2863) [PR #2828](https://github.com/PHPOffice/PhpSpreadsheet/pull/2828) [PR #2841](https://github.com/PHPOffice/PhpSpreadsheet/pull/2841) [PR #2846](https://github.com/PHPOffice/PhpSpreadsheet/pull/2846) [PR #2852](https://github.com/PHPOffice/PhpSpreadsheet/pull/2852) [PR #2856](https://github.com/PHPOffice/PhpSpreadsheet/pull/2856) [PR #2865](https://github.com/PHPOffice/PhpSpreadsheet/pull/2865) [PR #2872](https://github.com/PHPOffice/PhpSpreadsheet/pull/2872) [PR #2879](https://github.com/PHPOffice/PhpSpreadsheet/pull/2879) [PR #2898](https://github.com/PHPOffice/PhpSpreadsheet/pull/2898) [PR #2906](https://github.com/PHPOffice/PhpSpreadsheet/pull/2906) [PR #2922](https://github.com/PHPOffice/PhpSpreadsheet/pull/2922) - Calculating Engine regexp for Column/Row references when there are multiple quoted worksheet references in the formula [Issue #2874](https://github.com/PHPOffice/PhpSpreadsheet/issues/2874) [PR #2899](https://github.com/PHPOffice/PhpSpreadsheet/pull/2899) ## 1.23.0 - 2022-04-24 diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 04bdf27339..108836bc88 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1185,46 +1185,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Chart/PlotArea.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getArrayElementsValue\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getArrayElementsValue\\(\\) has parameter \\$elements with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getArrayElementsValue\\(\\) has parameter \\$properties with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getLineStyleArrowSize\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getLineStyleArrowSize\\(\\) has parameter \\$arrayKaySelector with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getLineStyleArrowSize\\(\\) has parameter \\$arraySelector with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getShadowPresetsMap\\(\\) has no return type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Properties\\:\\:getShadowPresetsMap\\(\\) has parameter \\$presetsOption with no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Properties.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#" count: 1 @@ -4020,61 +3980,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Xlsx.php - - - message: "#^Parameter \\#1 \\$plotSeriesValues of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeBubbles\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|null, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|false given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#1 \\$rawTextData of method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\XMLWriter\\:\\:writeRawData\\(\\) expects array\\\\|string\\|null, int given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, float given\\.$#" - count: 6 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, float\\|int given\\.$#" - count: 4 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" - count: 41 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#6 \\$yAxis of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#7 \\$xAxis of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#8 \\$majorGridlines of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#9 \\$minorGridlines of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:\\$calculateCellValues has no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea and null will always evaluate to false\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - message: "#^Parameter \\#1 \\$string of function substr expects string, int given\\.$#" count: 1 diff --git a/samples/Chart/33_Chart_create_bubble.php b/samples/Chart/33_Chart_create_bubble.php index 33feea621c..5efcda7139 100644 --- a/samples/Chart/33_Chart_create_bubble.php +++ b/samples/Chart/33_Chart_create_bubble.php @@ -89,7 +89,8 @@ $series->setPlotBubbleSizes($dataSeriesBubbles); // Set the series in the plot area -$plotArea = new PlotArea(null, [$series]); +$plotArea = new PlotArea(); +$plotArea->setPlotSeries([$series]); // Set the chart legend $legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); diff --git a/samples/templates/32readwriteBarChart4.xlsx b/samples/templates/32readwriteBarChart4.xlsx new file mode 100644 index 0000000000..c785729577 Binary files /dev/null and b/samples/templates/32readwriteBarChart4.xlsx differ diff --git a/samples/templates/32readwriteLineChart4.xlsx b/samples/templates/32readwriteLineChart4.xlsx new file mode 100644 index 0000000000..eb09c784e2 Binary files /dev/null and b/samples/templates/32readwriteLineChart4.xlsx differ diff --git a/src/PhpSpreadsheet/Chart/DataSeriesValues.php b/src/PhpSpreadsheet/Chart/DataSeriesValues.php index d6a8dcca58..bc0e04d193 100644 --- a/src/PhpSpreadsheet/Chart/DataSeriesValues.php +++ b/src/PhpSpreadsheet/Chart/DataSeriesValues.php @@ -85,6 +85,9 @@ class DataSeriesValues extends Properties /** @var bool */ private $bubble3D = false; + /** @var ?Layout */ + private $labelLayout; + /** * Create a new DataSeriesValues object. * @@ -562,4 +565,16 @@ public function setSmoothLine($smoothLine) return $this; } + + public function getLabelLayout(): ?Layout + { + return $this->labelLayout; + } + + public function setLabelLayout(?Layout $labelLayout): self + { + $this->labelLayout = $labelLayout; + + return $this; + } } diff --git a/src/PhpSpreadsheet/Chart/Layout.php b/src/PhpSpreadsheet/Chart/Layout.php index cea96557d8..03a0ca3ec6 100644 --- a/src/PhpSpreadsheet/Chart/Layout.php +++ b/src/PhpSpreadsheet/Chart/Layout.php @@ -57,7 +57,7 @@ class Layout * show legend key * Specifies that legend keys should be shown in data labels. * - * @var bool + * @var ?bool */ private $showLegendKey; @@ -65,7 +65,7 @@ class Layout * show value * Specifies that the value should be shown in a data label. * - * @var bool + * @var ?bool */ private $showVal; @@ -73,7 +73,7 @@ class Layout * show category name * Specifies that the category name should be shown in the data label. * - * @var bool + * @var ?bool */ private $showCatName; @@ -81,7 +81,7 @@ class Layout * show data series name * Specifies that the series name should be shown in the data label. * - * @var bool + * @var ?bool */ private $showSerName; @@ -89,14 +89,14 @@ class Layout * show percentage * Specifies that the percentage should be shown in the data label. * - * @var bool + * @var ?bool */ private $showPercent; /** * show bubble size. * - * @var bool + * @var ?bool */ private $showBubbleSize; @@ -104,10 +104,19 @@ class Layout * show leader lines * Specifies that leader lines should be shown for the data label. * - * @var bool + * @var ?bool */ private $showLeaderLines; + /** @var ?ChartColor */ + private $labelFillColor; + + /** @var ?ChartColor */ + private $labelBorderColor; + + /** @var ?ChartColor */ + private $labelFontColor; + /** * Create a new Layout. */ @@ -134,6 +143,30 @@ public function __construct(array $layout = []) if (isset($layout['h'])) { $this->height = (float) $layout['h']; } + $this->initBoolean($layout, 'showLegendKey'); + $this->initBoolean($layout, 'showVal'); + $this->initBoolean($layout, 'showCatName'); + $this->initBoolean($layout, 'showSerName'); + $this->initBoolean($layout, 'showPercent'); + $this->initBoolean($layout, 'showBubbleSize'); + $this->initBoolean($layout, 'showLeaderLines'); + $this->initColor($layout, 'labelFillColor'); + $this->initColor($layout, 'labelBorderColor'); + $this->initColor($layout, 'labelFontColor'); + } + + private function initBoolean(array $layout, string $name): void + { + if (isset($layout[$name])) { + $this->$name = (bool) $layout[$name]; + } + } + + private function initColor(array $layout, string $name): void + { + if (isset($layout[$name]) && $layout[$name] instanceof ChartColor) { + $this->$name = $layout[$name]; + } } /** @@ -304,12 +337,7 @@ public function setHeight($height) return $this; } - /** - * Get show legend key. - * - * @return bool - */ - public function getShowLegendKey() + public function getShowLegendKey(): ?bool { return $this->showLegendKey; } @@ -317,24 +345,15 @@ public function getShowLegendKey() /** * Set show legend key * Specifies that legend keys should be shown in data labels. - * - * @param bool $showLegendKey Show legend key - * - * @return $this */ - public function setShowLegendKey($showLegendKey) + public function setShowLegendKey(?bool $showLegendKey): self { $this->showLegendKey = $showLegendKey; return $this; } - /** - * Get show value. - * - * @return bool - */ - public function getShowVal() + public function getShowVal(): ?bool { return $this->showVal; } @@ -342,24 +361,15 @@ public function getShowVal() /** * Set show val * Specifies that the value should be shown in data labels. - * - * @param bool $showDataLabelValues Show val - * - * @return $this */ - public function setShowVal($showDataLabelValues) + public function setShowVal(?bool $showDataLabelValues): self { $this->showVal = $showDataLabelValues; return $this; } - /** - * Get show category name. - * - * @return bool - */ - public function getShowCatName() + public function getShowCatName(): ?bool { return $this->showCatName; } @@ -367,115 +377,111 @@ public function getShowCatName() /** * Set show cat name * Specifies that the category name should be shown in data labels. - * - * @param bool $showCategoryName Show cat name - * - * @return $this */ - public function setShowCatName($showCategoryName) + public function setShowCatName(?bool $showCategoryName): self { $this->showCatName = $showCategoryName; return $this; } - /** - * Get show data series name. - * - * @return bool - */ - public function getShowSerName() + public function getShowSerName(): ?bool { return $this->showSerName; } /** - * Set show ser name + * Set show data series name. * Specifies that the series name should be shown in data labels. - * - * @param bool $showSeriesName Show series name - * - * @return $this */ - public function setShowSerName($showSeriesName) + public function setShowSerName(?bool $showSeriesName): self { $this->showSerName = $showSeriesName; return $this; } - /** - * Get show percentage. - * - * @return bool - */ - public function getShowPercent() + public function getShowPercent(): ?bool { return $this->showPercent; } /** - * Set show percentage + * Set show percentage. * Specifies that the percentage should be shown in data labels. - * - * @param bool $showPercentage Show percentage - * - * @return $this */ - public function setShowPercent($showPercentage) + public function setShowPercent(?bool $showPercentage): self { $this->showPercent = $showPercentage; return $this; } - /** - * Get show bubble size. - * - * @return bool - */ - public function getShowBubbleSize() + public function getShowBubbleSize(): ?bool { return $this->showBubbleSize; } /** - * Set show bubble size + * Set show bubble size. * Specifies that the bubble size should be shown in data labels. - * - * @param bool $showBubbleSize Show bubble size - * - * @return $this */ - public function setShowBubbleSize($showBubbleSize) + public function setShowBubbleSize(?bool $showBubbleSize): self { $this->showBubbleSize = $showBubbleSize; return $this; } - /** - * Get show leader lines. - * - * @return bool - */ - public function getShowLeaderLines() + public function getShowLeaderLines(): ?bool { return $this->showLeaderLines; } /** - * Set show leader lines + * Set show leader lines. * Specifies that leader lines should be shown in data labels. - * - * @param bool $showLeaderLines Show leader lines - * - * @return $this */ - public function setShowLeaderLines($showLeaderLines) + public function setShowLeaderLines(?bool $showLeaderLines): self { $this->showLeaderLines = $showLeaderLines; return $this; } + + public function getLabelFillColor(): ?ChartColor + { + return $this->labelFillColor; + } + + public function setLabelFillColor(?ChartColor $chartColor): self + { + $this->labelFillColor = $chartColor; + + return $this; + } + + public function getLabelBorderColor(): ?ChartColor + { + return $this->labelBorderColor; + } + + public function setLabelBorderColor(?ChartColor $chartColor): self + { + $this->labelBorderColor = $chartColor; + + return $this; + } + + public function getLabelFontColor(): ?ChartColor + { + return $this->labelFontColor; + } + + public function setLabelFontColor(?ChartColor $chartColor): self + { + $this->labelFontColor = $chartColor; + + return $this; + } } diff --git a/src/PhpSpreadsheet/Chart/Properties.php b/src/PhpSpreadsheet/Chart/Properties.php index fdc3c12b3f..2ee6572ac1 100644 --- a/src/PhpSpreadsheet/Chart/Properties.php +++ b/src/PhpSpreadsheet/Chart/Properties.php @@ -421,11 +421,19 @@ protected function setColorProperties(?string $color, $alpha, ?string $colorType ], ]; - protected function getShadowPresetsMap($presetsOption) + protected function getShadowPresetsMap(int $presetsOption): array { return self::PRESETS_OPTIONS[$presetsOption] ?? self::PRESETS_OPTIONS[0]; } + /** + * Get value of array element. + * + * @param mixed $properties + * @param mixed $elements + * + * @return mixed + */ protected function getArrayElementsValue($properties, $elements) { $reference = &$properties; @@ -718,6 +726,16 @@ public function getShadowProperty($elements) return $this->getArrayElementsValue($this->shadowProperties, $elements); } + public function getShadowArray(): array + { + $array = $this->shadowProperties; + if ($this->getShadowColorObject()->isUsable()) { + $array['color'] = $this->getShadowProperty('color'); + } + + return $array; + } + /** @var ChartColor */ protected $lineColor; @@ -748,6 +766,10 @@ public function copyLineStyles(self $otherProperties): void { $this->lineStyleProperties = $otherProperties->lineStyleProperties; $this->lineColor = $otherProperties->lineColor; + $this->glowSize = $otherProperties->glowSize; + $this->glowColor = $otherProperties->glowColor; + $this->softEdges = $otherProperties->softEdges; + $this->shadowProperties = $otherProperties->shadowProperties; } public function getLineColor(): ChartColor @@ -875,6 +897,14 @@ public function getLineStyleProperty($elements) 9 => ['w' => 'lg', 'len' => 'lg'], ]; + /** + * Get Line Style Arrow Size. + * + * @param int $arraySelector + * @param string $arrayKaySelector + * + * @return string + */ protected function getLineStyleArrowSize($arraySelector, $arrayKaySelector) { return self::ARROW_SIZES[$arraySelector][$arrayKaySelector] ?? ''; diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index df25dac78a..fd156f135f 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -389,6 +389,7 @@ private function chartDataSeries(SimpleXMLElement $chartDetail, string $plotType $markerFillColor = null; $markerBorderColor = null; $lineStyle = null; + $labelLayout = null; foreach ($seriesDetails as $seriesKey => $seriesDetail) { switch ($seriesKey) { case 'idx': @@ -415,6 +416,12 @@ private function chartDataSeries(SimpleXMLElement $chartDetail, string $plotType $lineStyle = new GridLines(); $this->readLineStyle($seriesDetails, $lineStyle); } + if (isset($children->effectLst)) { + if ($lineStyle === null) { + $lineStyle = new GridLines(); + } + $this->readEffects($seriesDetails, $lineStyle); + } if (isset($children->solidFill)) { $fillColor = new ChartColor($this->readColor($children->solidFill)); } @@ -474,6 +481,21 @@ private function chartDataSeries(SimpleXMLElement $chartDetail, string $plotType $bubble3D = self::getAttribute($seriesDetail, 'val', 'boolean'); break; + case 'dLbls': + $labelLayout = new Layout($this->readChartAttributes($seriesDetails)); + + break; + } + } + if ($labelLayout) { + if (isset($seriesLabel[$seriesIndex])) { + $seriesLabel[$seriesIndex]->setLabelLayout($labelLayout); + } + if (isset($seriesCategory[$seriesIndex])) { + $seriesCategory[$seriesIndex]->setLabelLayout($labelLayout); + } + if (isset($seriesValues[$seriesIndex])) { + $seriesValues[$seriesIndex]->setLabelLayout($labelLayout); } } if ($noFill) { @@ -947,6 +969,21 @@ private function readChartAttributes($chartDetail): array if (isset($chartDetail->dLbls->showLeaderLines)) { $plotAttributes['showLeaderLines'] = self::getAttribute($chartDetail->dLbls->showLeaderLines, 'val', 'string'); } + if (isset($chartDetail->dLbls->spPr)) { + $sppr = $chartDetail->dLbls->spPr->children($this->aNamespace); + if (isset($sppr->solidFill)) { + $plotAttributes['labelFillColor'] = new ChartColor($this->readColor($sppr->solidFill)); + } + if (isset($sppr->ln->solidFill)) { + $plotAttributes['labelBorderColor'] = new ChartColor($this->readColor($sppr->ln->solidFill)); + } + } + if (isset($chartDetail->dLbls->txPr)) { + $txpr = $chartDetail->dLbls->txPr->children($this->aNamespace); + if (isset($txpr->p->pPr->defRPr->solidFill)) { + $plotAttributes['labelFontColor'] = new ChartColor($this->readColor($txpr->p->pPr->defRPr->solidFill)); + } + } } return $plotAttributes; @@ -991,10 +1028,7 @@ private function setChartAttributes(Layout $plotArea, $plotAttributes): void } } - /** - * @param null|Axis|GridLines $chartObject may be extended to include other types - */ - private function readEffects(SimpleXMLElement $chartDetail, $chartObject): void + private function readEffects(SimpleXMLElement $chartDetail, ?Properties $chartObject): void { if (!isset($chartObject, $chartDetail->spPr)) { return; diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php index d242e60202..876e5f0660 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php @@ -17,8 +17,6 @@ class Chart extends WriterPart { - protected $calculateCellValues; - /** * @var int */ @@ -33,8 +31,6 @@ class Chart extends WriterPart */ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calculateCellValues = true) { - $this->calculateCellValues = $calculateCellValues; - // Create XML writer $objWriter = null; if ($this->getParentWriter()->getUseDiskCaching()) { @@ -43,7 +39,7 @@ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calcul $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); } // Ensure that data series values are up-to-date before we save - if ($this->calculateCellValues) { + if ($calculateCellValues) { $chart->refresh(); } @@ -57,13 +53,13 @@ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calcul $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $objWriter->startElement('c:date1904'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->startElement('c:lang'); $objWriter->writeAttribute('val', 'en-GB'); $objWriter->endElement(); $objWriter->startElement('c:roundedCorners'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $this->writeAlternateContent($objWriter); @@ -73,7 +69,7 @@ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calcul $this->writeTitle($objWriter, $chart->getTitle()); $objWriter->startElement('c:autoTitleDeleted'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->startElement('c:view3D'); @@ -108,7 +104,7 @@ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calcul $this->writeLegend($objWriter, $chart->getLegend()); $objWriter->startElement('c:plotVisOnly'); - $objWriter->writeAttribute('val', (int) $chart->getPlotVisibleOnly()); + $objWriter->writeAttribute('val', (string) (int) $chart->getPlotVisibleOnly()); $objWriter->endElement(); $objWriter->startElement('c:dispBlanksAs'); @@ -116,7 +112,7 @@ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calcul $objWriter->endElement(); $objWriter->startElement('c:showDLblsOverMax'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->endElement(); @@ -167,7 +163,7 @@ private function writeTitle(XMLWriter $objWriter, ?Title $title = null): void $this->writeLayout($objWriter, $title->getLayout()); $objWriter->startElement('c:overlay'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->endElement(); @@ -203,7 +199,7 @@ private function writeLegend(XMLWriter $objWriter, ?Legend $legend = null): void $objWriter->startElement('a:p'); $objWriter->startElement('a:pPr'); - $objWriter->writeAttribute('rtl', 0); + $objWriter->writeAttribute('rtl', '0'); $objWriter->startElement('a:defRPr'); $objWriter->endElement(); @@ -222,7 +218,7 @@ private function writeLegend(XMLWriter $objWriter, ?Legend $legend = null): void /** * Write Chart Plot Area. */ - 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 + 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 { if ($plotArea === null) { return; @@ -273,16 +269,16 @@ private function writePlotArea(XMLWriter $objWriter, PlotArea $plotArea, ?Title if ($chartType === DataSeries::TYPE_LINECHART && $plotGroup) { // Line only, Line3D can't be smoothed $objWriter->startElement('c:smooth'); - $objWriter->writeAttribute('val', (int) $plotGroup->getSmoothLine()); + $objWriter->writeAttribute('val', (string) (int) $plotGroup->getSmoothLine()); $objWriter->endElement(); } elseif (($chartType === DataSeries::TYPE_BARCHART) || ($chartType === DataSeries::TYPE_BARCHART_3D)) { $objWriter->startElement('c:gapWidth'); - $objWriter->writeAttribute('val', 150); + $objWriter->writeAttribute('val', '150'); $objWriter->endElement(); if ($plotGroupingType == 'percentStacked' || $plotGroupingType == 'stacked') { $objWriter->startElement('c:overlap'); - $objWriter->writeAttribute('val', 100); + $objWriter->writeAttribute('val', '100'); $objWriter->endElement(); } } elseif ($chartType === DataSeries::TYPE_BUBBLECHART) { @@ -294,7 +290,7 @@ private function writePlotArea(XMLWriter $objWriter, PlotArea $plotArea, ?Title } $objWriter->startElement('c:showNegBubbles'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); } elseif ($chartType === DataSeries::TYPE_STOCKCHART) { $objWriter->startElement('c:hiLowLines'); @@ -303,7 +299,7 @@ private function writePlotArea(XMLWriter $objWriter, PlotArea $plotArea, ?Title $objWriter->startElement('c:upDownBars'); $objWriter->startElement('c:gapWidth'); - $objWriter->writeAttribute('val', 300); + $objWriter->writeAttribute('val', '300'); $objWriter->endElement(); $objWriter->startElement('c:upBars'); @@ -334,12 +330,12 @@ private function writePlotArea(XMLWriter $objWriter, PlotArea $plotArea, ?Title } } else { $objWriter->startElement('c:firstSliceAng'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); if ($chartType === DataSeries::TYPE_DONUTCHART) { $objWriter->startElement('c:holeSize'); - $objWriter->writeAttribute('val', 50); + $objWriter->writeAttribute('val', '50'); $objWriter->endElement(); } } @@ -349,12 +345,12 @@ private function writePlotArea(XMLWriter $objWriter, PlotArea $plotArea, ?Title if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) { if ($chartType === DataSeries::TYPE_BUBBLECHART) { - $this->writeValueAxis($objWriter, $xAxisLabel, $chartType, $id2, $id1, $catIsMultiLevelSeries, $xAxis, $majorGridlines, $minorGridlines); + $this->writeValueAxis($objWriter, $xAxisLabel, $chartType, $id2, $id1, $catIsMultiLevelSeries, $xAxis ?? new Axis(), $majorGridlines, $minorGridlines); } else { - $this->writeCategoryAxis($objWriter, $xAxisLabel, $id1, $id2, $catIsMultiLevelSeries, $xAxis); + $this->writeCategoryAxis($objWriter, $xAxisLabel, $id1, $id2, $catIsMultiLevelSeries, $xAxis ?? new Axis()); } - $this->writeValueAxis($objWriter, $yAxisLabel, $chartType, $id1, $id2, $valIsMultiLevelSeries, $yAxis, $majorGridlines, $minorGridlines); + $this->writeValueAxis($objWriter, $yAxisLabel, $chartType, $id1, $id2, $valIsMultiLevelSeries, $yAxis ?? new Axis(), $majorGridlines, $minorGridlines); if ($chartType === DataSeries::TYPE_SURFACECHART_3D || $chartType === DataSeries::TYPE_SURFACECHART) { $this->writeSerAxis($objWriter, $id2, $id3); } @@ -363,49 +359,75 @@ private function writePlotArea(XMLWriter $objWriter, PlotArea $plotArea, ?Title $objWriter->endElement(); } + private function writeDataLabelsBool(XMLWriter $objWriter, string $name, ?bool $value): void + { + if ($value !== null) { + $objWriter->startElement("c:$name"); + $objWriter->writeAttribute('val', $value ? '1' : '0'); + $objWriter->endElement(); + } + } + /** * Write Data Labels. */ private function writeDataLabels(XMLWriter $objWriter, ?Layout $chartLayout = null): void { + if (!isset($chartLayout)) { + return; + } $objWriter->startElement('c:dLbls'); - $objWriter->startElement('c:showLegendKey'); - $showLegendKey = (empty($chartLayout)) ? 0 : $chartLayout->getShowLegendKey(); - $objWriter->writeAttribute('val', ((empty($showLegendKey)) ? 0 : 1)); - $objWriter->endElement(); - - $objWriter->startElement('c:showVal'); - $showVal = (empty($chartLayout)) ? 0 : $chartLayout->getShowVal(); - $objWriter->writeAttribute('val', ((empty($showVal)) ? 0 : 1)); - $objWriter->endElement(); + $fillColor = $chartLayout->getLabelFillColor(); + $borderColor = $chartLayout->getLabelBorderColor(); + if ($fillColor && $fillColor->isUsable()) { + $objWriter->startElement('c:spPr'); + $this->writeColor($objWriter, $fillColor); + if ($borderColor && $borderColor->isUsable()) { + $objWriter->startElement('a:ln'); + $this->writeColor($objWriter, $borderColor); + $objWriter->endElement(); // a:ln + } + $objWriter->endElement(); // c:spPr + } + $fontColor = $chartLayout->getLabelFontColor(); + if ($fontColor && $fontColor->isUsable()) { + $objWriter->startElement('c:txPr'); - $objWriter->startElement('c:showCatName'); - $showCatName = (empty($chartLayout)) ? 0 : $chartLayout->getShowCatName(); - $objWriter->writeAttribute('val', ((empty($showCatName)) ? 0 : 1)); - $objWriter->endElement(); + $objWriter->startElement('a:bodyPr'); + $objWriter->writeAttribute('wrap', 'square'); + $objWriter->writeAttribute('lIns', '38100'); + $objWriter->writeAttribute('tIns', '19050'); + $objWriter->writeAttribute('rIns', '38100'); + $objWriter->writeAttribute('bIns', '19050'); + $objWriter->writeAttribute('anchor', 'ctr'); + $objWriter->startElement('a:spAutoFit'); + $objWriter->endElement(); // a:spAutoFit + $objWriter->endElement(); // a:bodyPr - $objWriter->startElement('c:showSerName'); - $showSerName = (empty($chartLayout)) ? 0 : $chartLayout->getShowSerName(); - $objWriter->writeAttribute('val', ((empty($showSerName)) ? 0 : 1)); - $objWriter->endElement(); + $objWriter->startElement('a:lstStyle'); + $objWriter->endElement(); // a:lstStyle - $objWriter->startElement('c:showPercent'); - $showPercent = (empty($chartLayout)) ? 0 : $chartLayout->getShowPercent(); - $objWriter->writeAttribute('val', ((empty($showPercent)) ? 0 : 1)); - $objWriter->endElement(); + $objWriter->startElement('a:p'); + $objWriter->startElement('a:pPr'); + $objWriter->startElement('a:defRPr'); + $this->writeColor($objWriter, $fontColor); + $objWriter->endElement(); // a:defRPr + $objWriter->endElement(); // a:pPr + $objWriter->endElement(); // a:p - $objWriter->startElement('c:showBubbleSize'); - $showBubbleSize = (empty($chartLayout)) ? 0 : $chartLayout->getShowBubbleSize(); - $objWriter->writeAttribute('val', ((empty($showBubbleSize)) ? 0 : 1)); - $objWriter->endElement(); + $objWriter->endElement(); // c:txPr + } - $objWriter->startElement('c:showLeaderLines'); - $showLeaderLines = (empty($chartLayout)) ? 1 : $chartLayout->getShowLeaderLines(); - $objWriter->writeAttribute('val', ((empty($showLeaderLines)) ? 0 : 1)); - $objWriter->endElement(); + $this->writeDataLabelsBool($objWriter, 'showLegendKey', $chartLayout->getShowLegendKey()); + $this->writeDataLabelsBool($objWriter, 'showVal', $chartLayout->getShowVal()); + $this->writeDataLabelsBool($objWriter, 'showCatName', $chartLayout->getShowCatName()); + $this->writeDataLabelsBool($objWriter, 'showSerName', $chartLayout->getShowSerName()); + $this->writeDataLabelsBool($objWriter, 'showPercent', $chartLayout->getShowPercent()); + $this->writeDataLabelsBool($objWriter, 'showBubbleSize', $chartLayout->getShowBubbleSize()); + $this->writeDataLabelsBool($objWriter, 'showLeaderLines', $chartLayout->getShowLeaderLines()); - $objWriter->endElement(); + $objWriter->endElement(); // c:dLbls } /** @@ -452,7 +474,7 @@ private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id $objWriter->endElement(); // c:scaling $objWriter->startElement('c:delete'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->startElement('c:axPos'); @@ -486,7 +508,7 @@ private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id $this->writeLayout($objWriter, $layout); $objWriter->startElement('c:overlay'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->endElement(); @@ -517,12 +539,7 @@ private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id $objWriter->startElement('c:spPr'); $this->writeColor($objWriter, $yAxis->getFillColorObject()); - - $objWriter->startElement('a:effectLst'); - $this->writeGlow($objWriter, $yAxis); - $this->writeShadow($objWriter, $yAxis); - $this->writeSoftEdge($objWriter, $yAxis); - $objWriter->endElement(); // effectLst + $this->writeEffects($objWriter, $yAxis); $objWriter->endElement(); // spPr if ($yAxis->getAxisOptionsProperty('major_unit') !== null) { @@ -550,7 +567,7 @@ private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id } $objWriter->startElement('c:auto'); - $objWriter->writeAttribute('val', 1); + $objWriter->writeAttribute('val', '1'); $objWriter->endElement(); $objWriter->startElement('c:lblAlgn'); @@ -558,12 +575,12 @@ private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id $objWriter->endElement(); $objWriter->startElement('c:lblOffset'); - $objWriter->writeAttribute('val', 100); + $objWriter->writeAttribute('val', '100'); $objWriter->endElement(); if ($isMultiLevelSeries) { $objWriter->startElement('c:noMultiLvlLbl'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); } $objWriter->endElement(); @@ -577,7 +594,7 @@ private function writeCategoryAxis(XMLWriter $objWriter, ?Title $xAxisLabel, $id * @param string $id2 * @param bool $isMultiLevelSeries */ - private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $groupType, $id1, $id2, $isMultiLevelSeries, Axis $xAxis, GridLines $majorGridlines, GridLines $minorGridlines): void + private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $groupType, $id1, $id2, $isMultiLevelSeries, Axis $xAxis, ?GridLines $majorGridlines, ?GridLines $minorGridlines): void { $objWriter->startElement('c:valAx'); @@ -610,39 +627,27 @@ private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $group $objWriter->endElement(); // c:scaling $objWriter->startElement('c:delete'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->startElement('c:axPos'); $objWriter->writeAttribute('val', 'l'); $objWriter->endElement(); - $objWriter->startElement('c:majorGridlines'); - $objWriter->startElement('c:spPr'); - - $this->writeLineStyles($objWriter, $majorGridlines); - - $objWriter->startElement('a:effectLst'); - $this->writeGlow($objWriter, $majorGridlines); - $this->writeShadow($objWriter, $majorGridlines); - $this->writeSoftEdge($objWriter, $majorGridlines); - - $objWriter->endElement(); //end effectLst - $objWriter->endElement(); //end spPr - $objWriter->endElement(); //end majorGridLines + if ($majorGridlines !== null) { + $objWriter->startElement('c:majorGridlines'); + $objWriter->startElement('c:spPr'); + $this->writeLineStyles($objWriter, $majorGridlines); + $this->writeEffects($objWriter, $majorGridlines); + $objWriter->endElement(); //end spPr + $objWriter->endElement(); //end majorGridLines + } - if ($minorGridlines->getObjectState()) { + if ($minorGridlines !== null && $minorGridlines->getObjectState()) { $objWriter->startElement('c:minorGridlines'); $objWriter->startElement('c:spPr'); - $this->writeLineStyles($objWriter, $minorGridlines); - - $objWriter->startElement('a:effectLst'); - $this->writeGlow($objWriter, $minorGridlines); - $this->writeShadow($objWriter, $minorGridlines); - $this->writeSoftEdge($objWriter, $minorGridlines); - $objWriter->endElement(); //end effectLst - + $this->writeEffects($objWriter, $minorGridlines); $objWriter->endElement(); //end spPr $objWriter->endElement(); //end minorGridLines } @@ -676,7 +681,7 @@ private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $group } $objWriter->startElement('c:overlay'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); $objWriter->endElement(); @@ -706,17 +711,9 @@ private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $group } $objWriter->startElement('c:spPr'); - $this->writeColor($objWriter, $xAxis->getFillColorObject()); - $this->writeLineStyles($objWriter, $xAxis); - - $objWriter->startElement('a:effectLst'); - $this->writeGlow($objWriter, $xAxis); - $this->writeShadow($objWriter, $xAxis); - $this->writeSoftEdge($objWriter, $xAxis); - $objWriter->endElement(); //effectList - + $this->writeEffects($objWriter, $xAxis); $objWriter->endElement(); //end spPr if ($id1 !== '0') { @@ -760,7 +757,7 @@ private function writeValueAxis(XMLWriter $objWriter, ?Title $yAxisLabel, $group if ($isMultiLevelSeries) { if ($groupType !== DataSeries::TYPE_BUBBLECHART) { $objWriter->startElement('c:noMultiLvlLbl'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); } } @@ -852,11 +849,11 @@ private function writePlotSeriesValuesElement(XMLWriter $objWriter, int $val, ?C $objWriter->startElement('c:dPt'); $objWriter->startElement('c:idx'); - $objWriter->writeAttribute('val', $val); + $objWriter->writeAttribute('val', "$val"); $objWriter->endElement(); // c:idx $objWriter->startElement('c:bubble3D'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); // c:bubble3D $objWriter->startElement('c:spPr'); @@ -901,11 +898,11 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr if ($groupType !== DataSeries::TYPE_LINECHART) { if (($groupType == DataSeries::TYPE_PIECHART) || ($groupType == DataSeries::TYPE_PIECHART_3D) || ($groupType == DataSeries::TYPE_DONUTCHART) || ($plotSeriesCount > 1)) { $objWriter->startElement('c:varyColors'); - $objWriter->writeAttribute('val', 1); + $objWriter->writeAttribute('val', '1'); $objWriter->endElement(); } else { $objWriter->startElement('c:varyColors'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); } } @@ -916,11 +913,11 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr $objWriter->startElement('c:ser'); $objWriter->startElement('c:idx'); - $objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesIdx); + $objWriter->writeAttribute('val', (string) ($this->seriesIndex + $plotSeriesIdx)); $objWriter->endElement(); $objWriter->startElement('c:order'); - $objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesRef); + $objWriter->writeAttribute('val', (string) ($this->seriesIndex + $plotSeriesRef)); $objWriter->endElement(); $plotLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx); @@ -949,6 +946,9 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr } } } + if ($plotSeriesValues !== false && $plotSeriesValues->getLabelLayout()) { + $this->writeDataLabels($objWriter, $plotSeriesValues->getLabelLayout()); + } // Labels $plotSeriesLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx); @@ -980,6 +980,7 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr $nofill = $groupType == DataSeries::TYPE_STOCKCHART || ($groupType === DataSeries::TYPE_SCATTERCHART && !$plotSeriesValues->getScatterLines()); if ($callLineStyles) { $this->writeLineStyles($objWriter, $plotSeriesValues, $nofill); + $this->writeEffects($objWriter, $plotSeriesValues); } $objWriter->endElement(); // c:spPr } @@ -1018,7 +1019,7 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr if (($groupType === DataSeries::TYPE_BARCHART) || ($groupType === DataSeries::TYPE_BARCHART_3D) || ($groupType === DataSeries::TYPE_BUBBLECHART)) { $objWriter->startElement('c:invertIfNegative'); - $objWriter->writeAttribute('val', 0); + $objWriter->writeAttribute('val', '0'); $objWriter->endElement(); } @@ -1032,7 +1033,7 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr $plotStyle = $plotGroup->getPlotStyle(); if ($plotStyle) { $objWriter->startElement('c:explosion'); - $objWriter->writeAttribute('val', 25); + $objWriter->writeAttribute('val', '25'); $objWriter->endElement(); } } @@ -1089,7 +1090,7 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr $objWriter->writeAttribute('val', $plotSeriesValues->getBubble3D() ? '1' : '0'); $objWriter->endElement(); } - } else { + } elseif ($plotSeriesValues !== false) { $this->writeBubbles($plotSeriesValues, $objWriter); } } @@ -1115,7 +1116,7 @@ private function writePlotSeriesLabel(?DataSeriesValues $plotSeriesLabel, XMLWri $objWriter->startElement('c:strCache'); $objWriter->startElement('c:ptCount'); - $objWriter->writeAttribute('val', $plotSeriesLabel->getPointCount()); + $objWriter->writeAttribute('val', (string) $plotSeriesLabel->getPointCount()); $objWriter->endElement(); foreach ($plotSeriesLabel->getDataValues() as $plotLabelKey => $plotLabelValue) { @@ -1154,7 +1155,7 @@ private function writePlotSeriesValues(?DataSeriesValues $plotSeriesValues, XMLW $objWriter->startElement('c:multiLvlStrCache'); $objWriter->startElement('c:ptCount'); - $objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); + $objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointCount()); $objWriter->endElement(); for ($level = 0; $level < $levelCount; ++$level) { @@ -1200,7 +1201,7 @@ private function writePlotSeriesValues(?DataSeriesValues $plotSeriesValues, XMLW } $objWriter->startElement('c:ptCount'); - $objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); + $objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointCount()); $objWriter->endElement(); $dataValues = $plotSeriesValues->getDataValues(); @@ -1250,7 +1251,7 @@ private function writeBubbles(?DataSeriesValues $plotSeriesValues, XMLWriter $ob $objWriter->endElement(); $objWriter->startElement('c:ptCount'); - $objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); + $objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointCount()); $objWriter->endElement(); $dataValues = $plotSeriesValues->getDataValues(); @@ -1260,7 +1261,7 @@ private function writeBubbles(?DataSeriesValues $plotSeriesValues, XMLWriter $ob $objWriter->startElement('c:pt'); $objWriter->writeAttribute('idx', $plotSeriesKey); $objWriter->startElement('c:v'); - $objWriter->writeRawData(1); + $objWriter->writeRawData('1'); $objWriter->endElement(); $objWriter->endElement(); } @@ -1309,28 +1310,28 @@ private function writeLayout(XMLWriter $objWriter, ?Layout $layout = null): void $x = $layout->getXPosition(); if ($x !== null) { $objWriter->startElement('c:x'); - $objWriter->writeAttribute('val', $x); + $objWriter->writeAttribute('val', "$x"); $objWriter->endElement(); } $y = $layout->getYPosition(); if ($y !== null) { $objWriter->startElement('c:y'); - $objWriter->writeAttribute('val', $y); + $objWriter->writeAttribute('val', "$y"); $objWriter->endElement(); } $w = $layout->getWidth(); if ($w !== null) { $objWriter->startElement('c:w'); - $objWriter->writeAttribute('val', $w); + $objWriter->writeAttribute('val', "$w"); $objWriter->endElement(); } $h = $layout->getHeight(); if ($h !== null) { $objWriter->startElement('c:h'); - $objWriter->writeAttribute('val', $h); + $objWriter->writeAttribute('val', "$h"); $objWriter->endElement(); } @@ -1377,12 +1378,12 @@ private function writePrintSettings(XMLWriter $objWriter): void $objWriter->endElement(); $objWriter->startElement('c:pageMargins'); - $objWriter->writeAttribute('footer', 0.3); - $objWriter->writeAttribute('header', 0.3); - $objWriter->writeAttribute('r', 0.7); - $objWriter->writeAttribute('l', 0.7); - $objWriter->writeAttribute('t', 0.75); - $objWriter->writeAttribute('b', 0.75); + $objWriter->writeAttribute('footer', '0.3'); + $objWriter->writeAttribute('header', '0.3'); + $objWriter->writeAttribute('r', '0.7'); + $objWriter->writeAttribute('l', '0.7'); + $objWriter->writeAttribute('t', '0.75'); + $objWriter->writeAttribute('b', '0.75'); $objWriter->endElement(); $objWriter->startElement('c:pageSetup'); @@ -1392,12 +1393,22 @@ private function writePrintSettings(XMLWriter $objWriter): void $objWriter->endElement(); } - /** - * Write shadow properties. - * - * @param Axis|GridLines $xAxis - */ - private function writeShadow(XMLWriter $objWriter, $xAxis): void + private function writeEffects(XMLWriter $objWriter, Properties $yAxis): void + { + if ( + !empty($yAxis->getSoftEdgesSize()) + || !empty($yAxis->getShadowProperty('effect')) + || !empty($yAxis->getGlowProperty('size')) + ) { + $objWriter->startElement('a:effectLst'); + $this->writeGlow($objWriter, $yAxis); + $this->writeShadow($objWriter, $yAxis); + $this->writeSoftEdge($objWriter, $yAxis); + $objWriter->endElement(); // effectLst + } + } + + private function writeShadow(XMLWriter $objWriter, Properties $xAxis): void { if (empty($xAxis->getShadowProperty('effect'))) { return; @@ -1441,12 +1452,7 @@ private function writeShadow(XMLWriter $objWriter, $xAxis): void $objWriter->endElement(); } - /** - * Write glow properties. - * - * @param Axis|GridLines $yAxis - */ - private function writeGlow(XMLWriter $objWriter, $yAxis): void + private function writeGlow(XMLWriter $objWriter, Properties $yAxis): void { $size = $yAxis->getGlowProperty('size'); if (empty($size)) { @@ -1458,12 +1464,7 @@ private function writeGlow(XMLWriter $objWriter, $yAxis): void $objWriter->endElement(); // glow } - /** - * Write soft edge properties. - * - * @param Axis|GridLines $yAxis - */ - private function writeSoftEdge(XMLWriter $objWriter, $yAxis): void + private function writeSoftEdge(XMLWriter $objWriter, Properties $yAxis): void { $softEdgeSize = $yAxis->getSoftEdgesSize(); if (empty($softEdgeSize)) { diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32DsvGlowTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32DsvGlowTest.php new file mode 100644 index 0000000000..da2ad9f69b --- /dev/null +++ b/tests/PhpSpreadsheetTests/Chart/Charts32DsvGlowTest.php @@ -0,0 +1,58 @@ +setIncludeCharts(true); + } + + public function writeCharts(XlsxWriter $writer): void + { + $writer->setIncludeCharts(true); + } + + public function testLine4(): void + { + $file = self::DIRECTORY . '32readwriteLineChart4.xlsx'; + $reader = new XlsxReader(); + $reader->setIncludeCharts(true); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame(1, $sheet->getChartCount()); + /** @var callable */ + $callableReader = [$this, 'readCharts']; + /** @var callable */ + $callableWriter = [$this, 'writeCharts']; + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter); + $spreadsheet->disconnectWorksheets(); + + $sheet = $reloadedSpreadsheet->getActiveSheet(); + $charts = $sheet->getChartCollection(); + self::assertCount(1, $charts); + $chart = $charts[0]; + self::assertNotNull($chart); + + $plotArea = $chart->getPlotArea(); + $dataSeriesArray = $plotArea->getPlotGroup(); + self::assertCount(1, $dataSeriesArray); + $dataSeries = $dataSeriesArray[0]; + $dataSeriesValuesArray = $dataSeries->getPlotValues(); + self::assertCount(3, $dataSeriesValuesArray); + $dataSeriesValues = $dataSeriesValuesArray[1]; + self::assertEquals(5, $dataSeriesValues->getGlowSize()); + self::assertSame('schemeClr', $dataSeriesValues->getGlowProperty(['color', 'type'])); + self::assertSame('accent2', $dataSeriesValues->getGlowProperty(['color', 'value'])); + self::assertSame(60, $dataSeriesValues->getGlowProperty(['color', 'alpha'])); + + $reloadedSpreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32DsvLabelsTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32DsvLabelsTest.php new file mode 100644 index 0000000000..74655a6019 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Chart/Charts32DsvLabelsTest.php @@ -0,0 +1,73 @@ +setIncludeCharts(true); + } + + public function writeCharts(XlsxWriter $writer): void + { + $writer->setIncludeCharts(true); + } + + public function testBar4(): void + { + $file = self::DIRECTORY . '32readwriteBarChart4.xlsx'; + $reader = new XlsxReader(); + $reader->setIncludeCharts(true); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + self::assertSame(1, $sheet->getChartCount()); + /** @var callable */ + $callableReader = [$this, 'readCharts']; + /** @var callable */ + $callableWriter = [$this, 'writeCharts']; + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter); + $spreadsheet->disconnectWorksheets(); + + $sheet = $reloadedSpreadsheet->getActiveSheet(); + $charts = $sheet->getChartCollection(); + self::assertCount(1, $charts); + $chart = $charts[0]; + self::assertNotNull($chart); + + $plotArea = $chart->getPlotArea(); + $dataSeriesArray = $plotArea->getPlotGroup(); + self::assertCount(1, $dataSeriesArray); + $dataSeries = $dataSeriesArray[0]; + $dataSeriesValuesArray = $dataSeries->getPlotValues(); + self::assertCount(1, $dataSeriesValuesArray); + $dataSeriesValues = $dataSeriesValuesArray[0]; + $layout = $dataSeriesValues->getLabelLayout(); + self::assertNotNull($layout); + self::assertTrue($layout->getShowVal()); + $fillColor = $layout->getLabelFillColor(); + self::assertNotNull($fillColor); + self::assertSame('schemeClr', $fillColor->getType()); + self::assertSame('accent1', $fillColor->getValue()); + $borderColor = $layout->getLabelBorderColor(); + self::assertNotNull($borderColor); + self::assertSame('srgbClr', $borderColor->getType()); + self::assertSame('FFC000', $borderColor->getValue()); + $fontColor = $layout->getLabelFontColor(); + self::assertNotNull($fontColor); + self::assertSame('srgbClr', $fontColor->getType()); + self::assertSame('FFFF00', $fontColor->getValue()); + self::assertEquals( + [15, 73, 61, 32], + $dataSeriesValues->getDataValues() + ); + + $reloadedSpreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php b/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php index 04ca7c317c..26e8f1c669 100644 --- a/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php +++ b/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php @@ -129,6 +129,11 @@ public function testGlowY(): void foreach ($expectedShadow as $key => $value) { self::assertEquals($value, $minorGridlines->getShadowProperty($key), $key); } + $testShadow2 = $minorGridlines->getShadowArray(); + self::assertNull($testShadow2['presets']); + self::assertEquals(['sx' => null, 'sy' => null, 'kx' => null, 'ky' => null], $testShadow2['size']); + unset($testShadow2['presets'], $testShadow2['size']); + self::assertEquals($expectedShadow, $testShadow2); // Create the chart $chart = new Chart( diff --git a/tests/PhpSpreadsheetTests/Chart/LayoutTest.php b/tests/PhpSpreadsheetTests/Chart/LayoutTest.php index 8e92798565..fbc878e110 100644 --- a/tests/PhpSpreadsheetTests/Chart/LayoutTest.php +++ b/tests/PhpSpreadsheetTests/Chart/LayoutTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Chart; +use PhpOffice\PhpSpreadsheet\Chart\ChartColor; use PhpOffice\PhpSpreadsheet\Chart\Layout; use PHPUnit\Framework\TestCase; @@ -27,4 +28,37 @@ public function testGetLayoutTarget(): void $result = $testInstance->getLayoutTarget(); self::assertEquals($LayoutTargetValue, $result); } + + public function testConstructorVsMethods(): void + { + $fillColor = new ChartColor('FF0000', 20, 'srgbClr'); + $borderColor = new ChartColor('accent1', 20, 'schemeClr'); + $fontColor = new ChartColor('red', 20, 'prstClr'); + $array = [ + 'xMode' => 'factor', + 'yMode' => 'edge', + 'x' => 1.0, + 'y' => 2.0, + 'w' => 3.0, + 'h' => 4.0, + 'showVal' => true, + 'labelFillColor' => $fillColor, + 'labelBorderColor' => $borderColor, + 'labelFontColor' => $fontColor, + ]; + $layout1 = new Layout($array); + $layout2 = new Layout(); + $layout2 + ->setXMode('factor') + ->setYMode('edge') + ->setXposition(1.0) + ->setYposition(2.0) + ->setWidth(3.0) + ->setHeight(4.0) + ->setShowVal(true) + ->setLabelFillColor($fillColor) + ->setLabelBorderColor($borderColor) + ->setLabelFontColor($fontColor); + self::assertEquals($layout1, $layout2); + } }