Charts Additional Support for Layout and DataSeriesValues (#2922)

* Charts Additional Support for Layout and DataSeriesValues

The dLbls tag in more or less the Xml equivalent of the Layout class. It is currently read and written only for the Chart as a whole. It can, however, also be applied to DataSeriesValues. Further it has properties which are currently ignored, namely label fill, border, and font colors. All of these omissions are handled by this PR. There are other properties which can be applied to the labels, but, for now, only the 3 colors are added.

DataSeriesValues can have effects (like glow). Since DSV now descends from Properties, these are already supported, but support needs to be added to the Reader and Writer to handle them. This PR adds the support.

* Add Unit Tests

Based on new samples.

* Minor Improvements

Slight increase to coverage.
This commit is contained in:
oleibman 2022-07-04 08:43:54 -07:00 committed by GitHub
parent faf6d819c6
commit c22c6df5b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 493 additions and 331 deletions

View File

@ -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) - 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) - 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) - 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) - 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 ## 1.23.0 - 2022-04-24

View File

@ -1185,46 +1185,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Chart/PlotArea.php 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\\.$#" message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#"
count: 1 count: 1
@ -4020,61 +3980,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Writer/Xlsx.php 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\\>\\|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\\.$#" message: "#^Parameter \\#1 \\$string of function substr expects string, int given\\.$#"
count: 1 count: 1

View File

@ -89,7 +89,8 @@ $series = new DataSeries(
$series->setPlotBubbleSizes($dataSeriesBubbles); $series->setPlotBubbleSizes($dataSeriesBubbles);
// Set the series in the plot area // Set the series in the plot area
$plotArea = new PlotArea(null, [$series]); $plotArea = new PlotArea();
$plotArea->setPlotSeries([$series]);
// Set the chart legend // Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); $legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false);

Binary file not shown.

Binary file not shown.

View File

@ -85,6 +85,9 @@ class DataSeriesValues extends Properties
/** @var bool */ /** @var bool */
private $bubble3D = false; private $bubble3D = false;
/** @var ?Layout */
private $labelLayout;
/** /**
* Create a new DataSeriesValues object. * Create a new DataSeriesValues object.
* *
@ -562,4 +565,16 @@ class DataSeriesValues extends Properties
return $this; return $this;
} }
public function getLabelLayout(): ?Layout
{
return $this->labelLayout;
}
public function setLabelLayout(?Layout $labelLayout): self
{
$this->labelLayout = $labelLayout;
return $this;
}
} }

View File

@ -57,7 +57,7 @@ class Layout
* show legend key * show legend key
* Specifies that legend keys should be shown in data labels. * Specifies that legend keys should be shown in data labels.
* *
* @var bool * @var ?bool
*/ */
private $showLegendKey; private $showLegendKey;
@ -65,7 +65,7 @@ class Layout
* show value * show value
* Specifies that the value should be shown in a data label. * Specifies that the value should be shown in a data label.
* *
* @var bool * @var ?bool
*/ */
private $showVal; private $showVal;
@ -73,7 +73,7 @@ class Layout
* show category name * show category name
* Specifies that the category name should be shown in the data label. * Specifies that the category name should be shown in the data label.
* *
* @var bool * @var ?bool
*/ */
private $showCatName; private $showCatName;
@ -81,7 +81,7 @@ class Layout
* show data series name * show data series name
* Specifies that the series name should be shown in the data label. * Specifies that the series name should be shown in the data label.
* *
* @var bool * @var ?bool
*/ */
private $showSerName; private $showSerName;
@ -89,14 +89,14 @@ class Layout
* show percentage * show percentage
* Specifies that the percentage should be shown in the data label. * Specifies that the percentage should be shown in the data label.
* *
* @var bool * @var ?bool
*/ */
private $showPercent; private $showPercent;
/** /**
* show bubble size. * show bubble size.
* *
* @var bool * @var ?bool
*/ */
private $showBubbleSize; private $showBubbleSize;
@ -104,10 +104,19 @@ class Layout
* show leader lines * show leader lines
* Specifies that leader lines should be shown for the data label. * Specifies that leader lines should be shown for the data label.
* *
* @var bool * @var ?bool
*/ */
private $showLeaderLines; private $showLeaderLines;
/** @var ?ChartColor */
private $labelFillColor;
/** @var ?ChartColor */
private $labelBorderColor;
/** @var ?ChartColor */
private $labelFontColor;
/** /**
* Create a new Layout. * Create a new Layout.
*/ */
@ -134,6 +143,30 @@ class Layout
if (isset($layout['h'])) { if (isset($layout['h'])) {
$this->height = (float) $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 @@ class Layout
return $this; return $this;
} }
/** public function getShowLegendKey(): ?bool
* Get show legend key.
*
* @return bool
*/
public function getShowLegendKey()
{ {
return $this->showLegendKey; return $this->showLegendKey;
} }
@ -317,24 +345,15 @@ class Layout
/** /**
* Set show legend key * Set show legend key
* Specifies that legend keys should be shown in data labels. * 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; $this->showLegendKey = $showLegendKey;
return $this; return $this;
} }
/** public function getShowVal(): ?bool
* Get show value.
*
* @return bool
*/
public function getShowVal()
{ {
return $this->showVal; return $this->showVal;
} }
@ -342,24 +361,15 @@ class Layout
/** /**
* Set show val * Set show val
* Specifies that the value should be shown in data labels. * 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; $this->showVal = $showDataLabelValues;
return $this; return $this;
} }
/** public function getShowCatName(): ?bool
* Get show category name.
*
* @return bool
*/
public function getShowCatName()
{ {
return $this->showCatName; return $this->showCatName;
} }
@ -367,115 +377,111 @@ class Layout
/** /**
* Set show cat name * Set show cat name
* Specifies that the category name should be shown in data labels. * 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; $this->showCatName = $showCategoryName;
return $this; return $this;
} }
/** public function getShowSerName(): ?bool
* Get show data series name.
*
* @return bool
*/
public function getShowSerName()
{ {
return $this->showSerName; return $this->showSerName;
} }
/** /**
* Set show ser name * Set show data series name.
* Specifies that the series name should be shown in data labels. * 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; $this->showSerName = $showSeriesName;
return $this; return $this;
} }
/** public function getShowPercent(): ?bool
* Get show percentage.
*
* @return bool
*/
public function getShowPercent()
{ {
return $this->showPercent; return $this->showPercent;
} }
/** /**
* Set show percentage * Set show percentage.
* Specifies that the percentage should be shown in data labels. * 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; $this->showPercent = $showPercentage;
return $this; return $this;
} }
/** public function getShowBubbleSize(): ?bool
* Get show bubble size.
*
* @return bool
*/
public function getShowBubbleSize()
{ {
return $this->showBubbleSize; return $this->showBubbleSize;
} }
/** /**
* Set show bubble size * Set show bubble size.
* Specifies that the bubble size should be shown in data labels. * 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; $this->showBubbleSize = $showBubbleSize;
return $this; return $this;
} }
/** public function getShowLeaderLines(): ?bool
* Get show leader lines.
*
* @return bool
*/
public function getShowLeaderLines()
{ {
return $this->showLeaderLines; return $this->showLeaderLines;
} }
/** /**
* Set show leader lines * Set show leader lines.
* Specifies that leader lines should be shown in data labels. * 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; $this->showLeaderLines = $showLeaderLines;
return $this; 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;
}
} }

View File

@ -421,11 +421,19 @@ abstract class Properties
], ],
]; ];
protected function getShadowPresetsMap($presetsOption) protected function getShadowPresetsMap(int $presetsOption): array
{ {
return self::PRESETS_OPTIONS[$presetsOption] ?? self::PRESETS_OPTIONS[0]; 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) protected function getArrayElementsValue($properties, $elements)
{ {
$reference = &$properties; $reference = &$properties;
@ -718,6 +726,16 @@ abstract class Properties
return $this->getArrayElementsValue($this->shadowProperties, $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 */ /** @var ChartColor */
protected $lineColor; protected $lineColor;
@ -748,6 +766,10 @@ abstract class Properties
{ {
$this->lineStyleProperties = $otherProperties->lineStyleProperties; $this->lineStyleProperties = $otherProperties->lineStyleProperties;
$this->lineColor = $otherProperties->lineColor; $this->lineColor = $otherProperties->lineColor;
$this->glowSize = $otherProperties->glowSize;
$this->glowColor = $otherProperties->glowColor;
$this->softEdges = $otherProperties->softEdges;
$this->shadowProperties = $otherProperties->shadowProperties;
} }
public function getLineColor(): ChartColor public function getLineColor(): ChartColor
@ -875,6 +897,14 @@ abstract class Properties
9 => ['w' => 'lg', 'len' => 'lg'], 9 => ['w' => 'lg', 'len' => 'lg'],
]; ];
/**
* Get Line Style Arrow Size.
*
* @param int $arraySelector
* @param string $arrayKaySelector
*
* @return string
*/
protected function getLineStyleArrowSize($arraySelector, $arrayKaySelector) protected function getLineStyleArrowSize($arraySelector, $arrayKaySelector)
{ {
return self::ARROW_SIZES[$arraySelector][$arrayKaySelector] ?? ''; return self::ARROW_SIZES[$arraySelector][$arrayKaySelector] ?? '';

View File

@ -389,6 +389,7 @@ class Chart
$markerFillColor = null; $markerFillColor = null;
$markerBorderColor = null; $markerBorderColor = null;
$lineStyle = null; $lineStyle = null;
$labelLayout = null;
foreach ($seriesDetails as $seriesKey => $seriesDetail) { foreach ($seriesDetails as $seriesKey => $seriesDetail) {
switch ($seriesKey) { switch ($seriesKey) {
case 'idx': case 'idx':
@ -415,6 +416,12 @@ class Chart
$lineStyle = new GridLines(); $lineStyle = new GridLines();
$this->readLineStyle($seriesDetails, $lineStyle); $this->readLineStyle($seriesDetails, $lineStyle);
} }
if (isset($children->effectLst)) {
if ($lineStyle === null) {
$lineStyle = new GridLines();
}
$this->readEffects($seriesDetails, $lineStyle);
}
if (isset($children->solidFill)) { if (isset($children->solidFill)) {
$fillColor = new ChartColor($this->readColor($children->solidFill)); $fillColor = new ChartColor($this->readColor($children->solidFill));
} }
@ -474,6 +481,21 @@ class Chart
$bubble3D = self::getAttribute($seriesDetail, 'val', 'boolean'); $bubble3D = self::getAttribute($seriesDetail, 'val', 'boolean');
break; 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) { if ($noFill) {
@ -947,6 +969,21 @@ class Chart
if (isset($chartDetail->dLbls->showLeaderLines)) { if (isset($chartDetail->dLbls->showLeaderLines)) {
$plotAttributes['showLeaderLines'] = self::getAttribute($chartDetail->dLbls->showLeaderLines, 'val', 'string'); $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; return $plotAttributes;
@ -991,10 +1028,7 @@ class Chart
} }
} }
/** private function readEffects(SimpleXMLElement $chartDetail, ?Properties $chartObject): void
* @param null|Axis|GridLines $chartObject may be extended to include other types
*/
private function readEffects(SimpleXMLElement $chartDetail, $chartObject): void
{ {
if (!isset($chartObject, $chartDetail->spPr)) { if (!isset($chartObject, $chartDetail->spPr)) {
return; return;

View File

@ -17,8 +17,6 @@ use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException;
class Chart extends WriterPart class Chart extends WriterPart
{ {
protected $calculateCellValues;
/** /**
* @var int * @var int
*/ */
@ -33,8 +31,6 @@ class Chart extends WriterPart
*/ */
public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calculateCellValues = true) public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calculateCellValues = true)
{ {
$this->calculateCellValues = $calculateCellValues;
// Create XML writer // Create XML writer
$objWriter = null; $objWriter = null;
if ($this->getParentWriter()->getUseDiskCaching()) { if ($this->getParentWriter()->getUseDiskCaching()) {
@ -43,7 +39,7 @@ class Chart extends WriterPart
$objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY); $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
} }
// Ensure that data series values are up-to-date before we save // Ensure that data series values are up-to-date before we save
if ($this->calculateCellValues) { if ($calculateCellValues) {
$chart->refresh(); $chart->refresh();
} }
@ -57,13 +53,13 @@ class Chart extends WriterPart
$objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships'); $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$objWriter->startElement('c:date1904'); $objWriter->startElement('c:date1904');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:lang'); $objWriter->startElement('c:lang');
$objWriter->writeAttribute('val', 'en-GB'); $objWriter->writeAttribute('val', 'en-GB');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:roundedCorners'); $objWriter->startElement('c:roundedCorners');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$this->writeAlternateContent($objWriter); $this->writeAlternateContent($objWriter);
@ -73,7 +69,7 @@ class Chart extends WriterPart
$this->writeTitle($objWriter, $chart->getTitle()); $this->writeTitle($objWriter, $chart->getTitle());
$objWriter->startElement('c:autoTitleDeleted'); $objWriter->startElement('c:autoTitleDeleted');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:view3D'); $objWriter->startElement('c:view3D');
@ -108,7 +104,7 @@ class Chart extends WriterPart
$this->writeLegend($objWriter, $chart->getLegend()); $this->writeLegend($objWriter, $chart->getLegend());
$objWriter->startElement('c:plotVisOnly'); $objWriter->startElement('c:plotVisOnly');
$objWriter->writeAttribute('val', (int) $chart->getPlotVisibleOnly()); $objWriter->writeAttribute('val', (string) (int) $chart->getPlotVisibleOnly());
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:dispBlanksAs'); $objWriter->startElement('c:dispBlanksAs');
@ -116,7 +112,7 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:showDLblsOverMax'); $objWriter->startElement('c:showDLblsOverMax');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->endElement(); $objWriter->endElement();
@ -167,7 +163,7 @@ class Chart extends WriterPart
$this->writeLayout($objWriter, $title->getLayout()); $this->writeLayout($objWriter, $title->getLayout());
$objWriter->startElement('c:overlay'); $objWriter->startElement('c:overlay');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->endElement(); $objWriter->endElement();
@ -203,7 +199,7 @@ class Chart extends WriterPart
$objWriter->startElement('a:p'); $objWriter->startElement('a:p');
$objWriter->startElement('a:pPr'); $objWriter->startElement('a:pPr');
$objWriter->writeAttribute('rtl', 0); $objWriter->writeAttribute('rtl', '0');
$objWriter->startElement('a:defRPr'); $objWriter->startElement('a:defRPr');
$objWriter->endElement(); $objWriter->endElement();
@ -222,7 +218,7 @@ class Chart extends WriterPart
/** /**
* Write Chart Plot Area. * 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) { if ($plotArea === null) {
return; return;
@ -273,16 +269,16 @@ class Chart extends WriterPart
if ($chartType === DataSeries::TYPE_LINECHART && $plotGroup) { if ($chartType === DataSeries::TYPE_LINECHART && $plotGroup) {
// Line only, Line3D can't be smoothed // Line only, Line3D can't be smoothed
$objWriter->startElement('c:smooth'); $objWriter->startElement('c:smooth');
$objWriter->writeAttribute('val', (int) $plotGroup->getSmoothLine()); $objWriter->writeAttribute('val', (string) (int) $plotGroup->getSmoothLine());
$objWriter->endElement(); $objWriter->endElement();
} elseif (($chartType === DataSeries::TYPE_BARCHART) || ($chartType === DataSeries::TYPE_BARCHART_3D)) { } elseif (($chartType === DataSeries::TYPE_BARCHART) || ($chartType === DataSeries::TYPE_BARCHART_3D)) {
$objWriter->startElement('c:gapWidth'); $objWriter->startElement('c:gapWidth');
$objWriter->writeAttribute('val', 150); $objWriter->writeAttribute('val', '150');
$objWriter->endElement(); $objWriter->endElement();
if ($plotGroupingType == 'percentStacked' || $plotGroupingType == 'stacked') { if ($plotGroupingType == 'percentStacked' || $plotGroupingType == 'stacked') {
$objWriter->startElement('c:overlap'); $objWriter->startElement('c:overlap');
$objWriter->writeAttribute('val', 100); $objWriter->writeAttribute('val', '100');
$objWriter->endElement(); $objWriter->endElement();
} }
} elseif ($chartType === DataSeries::TYPE_BUBBLECHART) { } elseif ($chartType === DataSeries::TYPE_BUBBLECHART) {
@ -294,7 +290,7 @@ class Chart extends WriterPart
} }
$objWriter->startElement('c:showNegBubbles'); $objWriter->startElement('c:showNegBubbles');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
} elseif ($chartType === DataSeries::TYPE_STOCKCHART) { } elseif ($chartType === DataSeries::TYPE_STOCKCHART) {
$objWriter->startElement('c:hiLowLines'); $objWriter->startElement('c:hiLowLines');
@ -303,7 +299,7 @@ class Chart extends WriterPart
$objWriter->startElement('c:upDownBars'); $objWriter->startElement('c:upDownBars');
$objWriter->startElement('c:gapWidth'); $objWriter->startElement('c:gapWidth');
$objWriter->writeAttribute('val', 300); $objWriter->writeAttribute('val', '300');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:upBars'); $objWriter->startElement('c:upBars');
@ -334,12 +330,12 @@ class Chart extends WriterPart
} }
} else { } else {
$objWriter->startElement('c:firstSliceAng'); $objWriter->startElement('c:firstSliceAng');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
if ($chartType === DataSeries::TYPE_DONUTCHART) { if ($chartType === DataSeries::TYPE_DONUTCHART) {
$objWriter->startElement('c:holeSize'); $objWriter->startElement('c:holeSize');
$objWriter->writeAttribute('val', 50); $objWriter->writeAttribute('val', '50');
$objWriter->endElement(); $objWriter->endElement();
} }
} }
@ -349,12 +345,12 @@ class Chart extends WriterPart
if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) { if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) {
if ($chartType === DataSeries::TYPE_BUBBLECHART) { 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 { } 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) { if ($chartType === DataSeries::TYPE_SURFACECHART_3D || $chartType === DataSeries::TYPE_SURFACECHART) {
$this->writeSerAxis($objWriter, $id2, $id3); $this->writeSerAxis($objWriter, $id2, $id3);
} }
@ -363,49 +359,75 @@ class Chart extends WriterPart
$objWriter->endElement(); $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. * Write Data Labels.
*/ */
private function writeDataLabels(XMLWriter $objWriter, ?Layout $chartLayout = null): void private function writeDataLabels(XMLWriter $objWriter, ?Layout $chartLayout = null): void
{ {
if (!isset($chartLayout)) {
return;
}
$objWriter->startElement('c:dLbls'); $objWriter->startElement('c:dLbls');
$objWriter->startElement('c:showLegendKey'); $fillColor = $chartLayout->getLabelFillColor();
$showLegendKey = (empty($chartLayout)) ? 0 : $chartLayout->getShowLegendKey(); $borderColor = $chartLayout->getLabelBorderColor();
$objWriter->writeAttribute('val', ((empty($showLegendKey)) ? 0 : 1)); if ($fillColor && $fillColor->isUsable()) {
$objWriter->endElement(); $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:showVal'); $objWriter->startElement('a:bodyPr');
$showVal = (empty($chartLayout)) ? 0 : $chartLayout->getShowVal(); $objWriter->writeAttribute('wrap', 'square');
$objWriter->writeAttribute('val', ((empty($showVal)) ? 0 : 1)); $objWriter->writeAttribute('lIns', '38100');
$objWriter->endElement(); $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:showCatName'); $objWriter->startElement('a:lstStyle');
$showCatName = (empty($chartLayout)) ? 0 : $chartLayout->getShowCatName(); $objWriter->endElement(); // a:lstStyle
$objWriter->writeAttribute('val', ((empty($showCatName)) ? 0 : 1));
$objWriter->endElement();
$objWriter->startElement('c:showSerName'); $objWriter->startElement('a:p');
$showSerName = (empty($chartLayout)) ? 0 : $chartLayout->getShowSerName(); $objWriter->startElement('a:pPr');
$objWriter->writeAttribute('val', ((empty($showSerName)) ? 0 : 1)); $objWriter->startElement('a:defRPr');
$objWriter->endElement(); $this->writeColor($objWriter, $fontColor);
$objWriter->endElement(); // a:defRPr
$objWriter->endElement(); // a:pPr
$objWriter->endElement(); // a:p
$objWriter->startElement('c:showPercent'); $objWriter->endElement(); // c:txPr
$showPercent = (empty($chartLayout)) ? 0 : $chartLayout->getShowPercent(); }
$objWriter->writeAttribute('val', ((empty($showPercent)) ? 0 : 1));
$objWriter->endElement();
$objWriter->startElement('c:showBubbleSize'); $this->writeDataLabelsBool($objWriter, 'showLegendKey', $chartLayout->getShowLegendKey());
$showBubbleSize = (empty($chartLayout)) ? 0 : $chartLayout->getShowBubbleSize(); $this->writeDataLabelsBool($objWriter, 'showVal', $chartLayout->getShowVal());
$objWriter->writeAttribute('val', ((empty($showBubbleSize)) ? 0 : 1)); $this->writeDataLabelsBool($objWriter, 'showCatName', $chartLayout->getShowCatName());
$objWriter->endElement(); $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->startElement('c:showLeaderLines'); $objWriter->endElement(); // c:dLbls
$showLeaderLines = (empty($chartLayout)) ? 1 : $chartLayout->getShowLeaderLines();
$objWriter->writeAttribute('val', ((empty($showLeaderLines)) ? 0 : 1));
$objWriter->endElement();
$objWriter->endElement();
} }
/** /**
@ -452,7 +474,7 @@ class Chart extends WriterPart
$objWriter->endElement(); // c:scaling $objWriter->endElement(); // c:scaling
$objWriter->startElement('c:delete'); $objWriter->startElement('c:delete');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:axPos'); $objWriter->startElement('c:axPos');
@ -486,7 +508,7 @@ class Chart extends WriterPart
$this->writeLayout($objWriter, $layout); $this->writeLayout($objWriter, $layout);
$objWriter->startElement('c:overlay'); $objWriter->startElement('c:overlay');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->endElement(); $objWriter->endElement();
@ -517,12 +539,7 @@ class Chart extends WriterPart
$objWriter->startElement('c:spPr'); $objWriter->startElement('c:spPr');
$this->writeColor($objWriter, $yAxis->getFillColorObject()); $this->writeColor($objWriter, $yAxis->getFillColorObject());
$this->writeEffects($objWriter, $yAxis);
$objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $yAxis);
$this->writeShadow($objWriter, $yAxis);
$this->writeSoftEdge($objWriter, $yAxis);
$objWriter->endElement(); // effectLst
$objWriter->endElement(); // spPr $objWriter->endElement(); // spPr
if ($yAxis->getAxisOptionsProperty('major_unit') !== null) { if ($yAxis->getAxisOptionsProperty('major_unit') !== null) {
@ -550,7 +567,7 @@ class Chart extends WriterPart
} }
$objWriter->startElement('c:auto'); $objWriter->startElement('c:auto');
$objWriter->writeAttribute('val', 1); $objWriter->writeAttribute('val', '1');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:lblAlgn'); $objWriter->startElement('c:lblAlgn');
@ -558,12 +575,12 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:lblOffset'); $objWriter->startElement('c:lblOffset');
$objWriter->writeAttribute('val', 100); $objWriter->writeAttribute('val', '100');
$objWriter->endElement(); $objWriter->endElement();
if ($isMultiLevelSeries) { if ($isMultiLevelSeries) {
$objWriter->startElement('c:noMultiLvlLbl'); $objWriter->startElement('c:noMultiLvlLbl');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
} }
$objWriter->endElement(); $objWriter->endElement();
@ -577,7 +594,7 @@ class Chart extends WriterPart
* @param string $id2 * @param string $id2
* @param bool $isMultiLevelSeries * @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'); $objWriter->startElement('c:valAx');
@ -610,39 +627,27 @@ class Chart extends WriterPart
$objWriter->endElement(); // c:scaling $objWriter->endElement(); // c:scaling
$objWriter->startElement('c:delete'); $objWriter->startElement('c:delete');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:axPos'); $objWriter->startElement('c:axPos');
$objWriter->writeAttribute('val', 'l'); $objWriter->writeAttribute('val', 'l');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:majorGridlines'); if ($majorGridlines !== null) {
$objWriter->startElement('c:spPr'); $objWriter->startElement('c:majorGridlines');
$objWriter->startElement('c:spPr');
$this->writeLineStyles($objWriter, $majorGridlines);
$this->writeEffects($objWriter, $majorGridlines);
$objWriter->endElement(); //end spPr
$objWriter->endElement(); //end majorGridLines
}
$this->writeLineStyles($objWriter, $majorGridlines); if ($minorGridlines !== null && $minorGridlines->getObjectState()) {
$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 ($minorGridlines->getObjectState()) {
$objWriter->startElement('c:minorGridlines'); $objWriter->startElement('c:minorGridlines');
$objWriter->startElement('c:spPr'); $objWriter->startElement('c:spPr');
$this->writeLineStyles($objWriter, $minorGridlines); $this->writeLineStyles($objWriter, $minorGridlines);
$this->writeEffects($objWriter, $minorGridlines);
$objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $minorGridlines);
$this->writeShadow($objWriter, $minorGridlines);
$this->writeSoftEdge($objWriter, $minorGridlines);
$objWriter->endElement(); //end effectLst
$objWriter->endElement(); //end spPr $objWriter->endElement(); //end spPr
$objWriter->endElement(); //end minorGridLines $objWriter->endElement(); //end minorGridLines
} }
@ -676,7 +681,7 @@ class Chart extends WriterPart
} }
$objWriter->startElement('c:overlay'); $objWriter->startElement('c:overlay');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->endElement(); $objWriter->endElement();
@ -706,17 +711,9 @@ class Chart extends WriterPart
} }
$objWriter->startElement('c:spPr'); $objWriter->startElement('c:spPr');
$this->writeColor($objWriter, $xAxis->getFillColorObject()); $this->writeColor($objWriter, $xAxis->getFillColorObject());
$this->writeLineStyles($objWriter, $xAxis); $this->writeLineStyles($objWriter, $xAxis);
$this->writeEffects($objWriter, $xAxis);
$objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $xAxis);
$this->writeShadow($objWriter, $xAxis);
$this->writeSoftEdge($objWriter, $xAxis);
$objWriter->endElement(); //effectList
$objWriter->endElement(); //end spPr $objWriter->endElement(); //end spPr
if ($id1 !== '0') { if ($id1 !== '0') {
@ -760,7 +757,7 @@ class Chart extends WriterPart
if ($isMultiLevelSeries) { if ($isMultiLevelSeries) {
if ($groupType !== DataSeries::TYPE_BUBBLECHART) { if ($groupType !== DataSeries::TYPE_BUBBLECHART) {
$objWriter->startElement('c:noMultiLvlLbl'); $objWriter->startElement('c:noMultiLvlLbl');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
} }
} }
@ -852,11 +849,11 @@ class Chart extends WriterPart
$objWriter->startElement('c:dPt'); $objWriter->startElement('c:dPt');
$objWriter->startElement('c:idx'); $objWriter->startElement('c:idx');
$objWriter->writeAttribute('val', $val); $objWriter->writeAttribute('val', "$val");
$objWriter->endElement(); // c:idx $objWriter->endElement(); // c:idx
$objWriter->startElement('c:bubble3D'); $objWriter->startElement('c:bubble3D');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); // c:bubble3D $objWriter->endElement(); // c:bubble3D
$objWriter->startElement('c:spPr'); $objWriter->startElement('c:spPr');
@ -901,11 +898,11 @@ class Chart extends WriterPart
if ($groupType !== DataSeries::TYPE_LINECHART) { if ($groupType !== DataSeries::TYPE_LINECHART) {
if (($groupType == DataSeries::TYPE_PIECHART) || ($groupType == DataSeries::TYPE_PIECHART_3D) || ($groupType == DataSeries::TYPE_DONUTCHART) || ($plotSeriesCount > 1)) { if (($groupType == DataSeries::TYPE_PIECHART) || ($groupType == DataSeries::TYPE_PIECHART_3D) || ($groupType == DataSeries::TYPE_DONUTCHART) || ($plotSeriesCount > 1)) {
$objWriter->startElement('c:varyColors'); $objWriter->startElement('c:varyColors');
$objWriter->writeAttribute('val', 1); $objWriter->writeAttribute('val', '1');
$objWriter->endElement(); $objWriter->endElement();
} else { } else {
$objWriter->startElement('c:varyColors'); $objWriter->startElement('c:varyColors');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
} }
} }
@ -916,11 +913,11 @@ class Chart extends WriterPart
$objWriter->startElement('c:ser'); $objWriter->startElement('c:ser');
$objWriter->startElement('c:idx'); $objWriter->startElement('c:idx');
$objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesIdx); $objWriter->writeAttribute('val', (string) ($this->seriesIndex + $plotSeriesIdx));
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:order'); $objWriter->startElement('c:order');
$objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesRef); $objWriter->writeAttribute('val', (string) ($this->seriesIndex + $plotSeriesRef));
$objWriter->endElement(); $objWriter->endElement();
$plotLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx); $plotLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx);
@ -949,6 +946,9 @@ class Chart extends WriterPart
} }
} }
} }
if ($plotSeriesValues !== false && $plotSeriesValues->getLabelLayout()) {
$this->writeDataLabels($objWriter, $plotSeriesValues->getLabelLayout());
}
// Labels // Labels
$plotSeriesLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx); $plotSeriesLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx);
@ -980,6 +980,7 @@ class Chart extends WriterPart
$nofill = $groupType == DataSeries::TYPE_STOCKCHART || ($groupType === DataSeries::TYPE_SCATTERCHART && !$plotSeriesValues->getScatterLines()); $nofill = $groupType == DataSeries::TYPE_STOCKCHART || ($groupType === DataSeries::TYPE_SCATTERCHART && !$plotSeriesValues->getScatterLines());
if ($callLineStyles) { if ($callLineStyles) {
$this->writeLineStyles($objWriter, $plotSeriesValues, $nofill); $this->writeLineStyles($objWriter, $plotSeriesValues, $nofill);
$this->writeEffects($objWriter, $plotSeriesValues);
} }
$objWriter->endElement(); // c:spPr $objWriter->endElement(); // c:spPr
} }
@ -1018,7 +1019,7 @@ class Chart extends WriterPart
if (($groupType === DataSeries::TYPE_BARCHART) || ($groupType === DataSeries::TYPE_BARCHART_3D) || ($groupType === DataSeries::TYPE_BUBBLECHART)) { if (($groupType === DataSeries::TYPE_BARCHART) || ($groupType === DataSeries::TYPE_BARCHART_3D) || ($groupType === DataSeries::TYPE_BUBBLECHART)) {
$objWriter->startElement('c:invertIfNegative'); $objWriter->startElement('c:invertIfNegative');
$objWriter->writeAttribute('val', 0); $objWriter->writeAttribute('val', '0');
$objWriter->endElement(); $objWriter->endElement();
} }
@ -1032,7 +1033,7 @@ class Chart extends WriterPart
$plotStyle = $plotGroup->getPlotStyle(); $plotStyle = $plotGroup->getPlotStyle();
if ($plotStyle) { if ($plotStyle) {
$objWriter->startElement('c:explosion'); $objWriter->startElement('c:explosion');
$objWriter->writeAttribute('val', 25); $objWriter->writeAttribute('val', '25');
$objWriter->endElement(); $objWriter->endElement();
} }
} }
@ -1089,7 +1090,7 @@ class Chart extends WriterPart
$objWriter->writeAttribute('val', $plotSeriesValues->getBubble3D() ? '1' : '0'); $objWriter->writeAttribute('val', $plotSeriesValues->getBubble3D() ? '1' : '0');
$objWriter->endElement(); $objWriter->endElement();
} }
} else { } elseif ($plotSeriesValues !== false) {
$this->writeBubbles($plotSeriesValues, $objWriter); $this->writeBubbles($plotSeriesValues, $objWriter);
} }
} }
@ -1115,7 +1116,7 @@ class Chart extends WriterPart
$objWriter->startElement('c:strCache'); $objWriter->startElement('c:strCache');
$objWriter->startElement('c:ptCount'); $objWriter->startElement('c:ptCount');
$objWriter->writeAttribute('val', $plotSeriesLabel->getPointCount()); $objWriter->writeAttribute('val', (string) $plotSeriesLabel->getPointCount());
$objWriter->endElement(); $objWriter->endElement();
foreach ($plotSeriesLabel->getDataValues() as $plotLabelKey => $plotLabelValue) { foreach ($plotSeriesLabel->getDataValues() as $plotLabelKey => $plotLabelValue) {
@ -1154,7 +1155,7 @@ class Chart extends WriterPart
$objWriter->startElement('c:multiLvlStrCache'); $objWriter->startElement('c:multiLvlStrCache');
$objWriter->startElement('c:ptCount'); $objWriter->startElement('c:ptCount');
$objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); $objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointCount());
$objWriter->endElement(); $objWriter->endElement();
for ($level = 0; $level < $levelCount; ++$level) { for ($level = 0; $level < $levelCount; ++$level) {
@ -1200,7 +1201,7 @@ class Chart extends WriterPart
} }
$objWriter->startElement('c:ptCount'); $objWriter->startElement('c:ptCount');
$objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); $objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointCount());
$objWriter->endElement(); $objWriter->endElement();
$dataValues = $plotSeriesValues->getDataValues(); $dataValues = $plotSeriesValues->getDataValues();
@ -1250,7 +1251,7 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:ptCount'); $objWriter->startElement('c:ptCount');
$objWriter->writeAttribute('val', $plotSeriesValues->getPointCount()); $objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointCount());
$objWriter->endElement(); $objWriter->endElement();
$dataValues = $plotSeriesValues->getDataValues(); $dataValues = $plotSeriesValues->getDataValues();
@ -1260,7 +1261,7 @@ class Chart extends WriterPart
$objWriter->startElement('c:pt'); $objWriter->startElement('c:pt');
$objWriter->writeAttribute('idx', $plotSeriesKey); $objWriter->writeAttribute('idx', $plotSeriesKey);
$objWriter->startElement('c:v'); $objWriter->startElement('c:v');
$objWriter->writeRawData(1); $objWriter->writeRawData('1');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->endElement(); $objWriter->endElement();
} }
@ -1309,28 +1310,28 @@ class Chart extends WriterPart
$x = $layout->getXPosition(); $x = $layout->getXPosition();
if ($x !== null) { if ($x !== null) {
$objWriter->startElement('c:x'); $objWriter->startElement('c:x');
$objWriter->writeAttribute('val', $x); $objWriter->writeAttribute('val', "$x");
$objWriter->endElement(); $objWriter->endElement();
} }
$y = $layout->getYPosition(); $y = $layout->getYPosition();
if ($y !== null) { if ($y !== null) {
$objWriter->startElement('c:y'); $objWriter->startElement('c:y');
$objWriter->writeAttribute('val', $y); $objWriter->writeAttribute('val', "$y");
$objWriter->endElement(); $objWriter->endElement();
} }
$w = $layout->getWidth(); $w = $layout->getWidth();
if ($w !== null) { if ($w !== null) {
$objWriter->startElement('c:w'); $objWriter->startElement('c:w');
$objWriter->writeAttribute('val', $w); $objWriter->writeAttribute('val', "$w");
$objWriter->endElement(); $objWriter->endElement();
} }
$h = $layout->getHeight(); $h = $layout->getHeight();
if ($h !== null) { if ($h !== null) {
$objWriter->startElement('c:h'); $objWriter->startElement('c:h');
$objWriter->writeAttribute('val', $h); $objWriter->writeAttribute('val', "$h");
$objWriter->endElement(); $objWriter->endElement();
} }
@ -1377,12 +1378,12 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:pageMargins'); $objWriter->startElement('c:pageMargins');
$objWriter->writeAttribute('footer', 0.3); $objWriter->writeAttribute('footer', '0.3');
$objWriter->writeAttribute('header', 0.3); $objWriter->writeAttribute('header', '0.3');
$objWriter->writeAttribute('r', 0.7); $objWriter->writeAttribute('r', '0.7');
$objWriter->writeAttribute('l', 0.7); $objWriter->writeAttribute('l', '0.7');
$objWriter->writeAttribute('t', 0.75); $objWriter->writeAttribute('t', '0.75');
$objWriter->writeAttribute('b', 0.75); $objWriter->writeAttribute('b', '0.75');
$objWriter->endElement(); $objWriter->endElement();
$objWriter->startElement('c:pageSetup'); $objWriter->startElement('c:pageSetup');
@ -1392,12 +1393,22 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
} }
/** private function writeEffects(XMLWriter $objWriter, Properties $yAxis): void
* Write shadow properties. {
* if (
* @param Axis|GridLines $xAxis !empty($yAxis->getSoftEdgesSize())
*/ || !empty($yAxis->getShadowProperty('effect'))
private function writeShadow(XMLWriter $objWriter, $xAxis): void || !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'))) { if (empty($xAxis->getShadowProperty('effect'))) {
return; return;
@ -1441,12 +1452,7 @@ class Chart extends WriterPart
$objWriter->endElement(); $objWriter->endElement();
} }
/** private function writeGlow(XMLWriter $objWriter, Properties $yAxis): void
* Write glow properties.
*
* @param Axis|GridLines $yAxis
*/
private function writeGlow(XMLWriter $objWriter, $yAxis): void
{ {
$size = $yAxis->getGlowProperty('size'); $size = $yAxis->getGlowProperty('size');
if (empty($size)) { if (empty($size)) {
@ -1458,12 +1464,7 @@ class Chart extends WriterPart
$objWriter->endElement(); // glow $objWriter->endElement(); // glow
} }
/** private function writeSoftEdge(XMLWriter $objWriter, Properties $yAxis): void
* Write soft edge properties.
*
* @param Axis|GridLines $yAxis
*/
private function writeSoftEdge(XMLWriter $objWriter, $yAxis): void
{ {
$softEdgeSize = $yAxis->getSoftEdgesSize(); $softEdgeSize = $yAxis->getSoftEdgesSize();
if (empty($softEdgeSize)) { if (empty($softEdgeSize)) {

View File

@ -0,0 +1,58 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class Charts32DsvGlowTest extends AbstractFunctional
{
private const DIRECTORY = 'samples' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
public function readCharts(XlsxReader $reader): void
{
$reader->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();
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class Charts32DsvLabelsTest extends AbstractFunctional
{
private const DIRECTORY = 'samples' . DIRECTORY_SEPARATOR . 'templates' . DIRECTORY_SEPARATOR;
public function readCharts(XlsxReader $reader): void
{
$reader->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();
}
}

View File

@ -129,6 +129,11 @@ class GridlinesShadowGlowTest extends AbstractFunctional
foreach ($expectedShadow as $key => $value) { foreach ($expectedShadow as $key => $value) {
self::assertEquals($value, $minorGridlines->getShadowProperty($key), $key); 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 // Create the chart
$chart = new Chart( $chart = new Chart(

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Chart; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\Layout; use PhpOffice\PhpSpreadsheet\Chart\Layout;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -27,4 +28,37 @@ class LayoutTest extends TestCase
$result = $testInstance->getLayoutTarget(); $result = $testInstance->getLayoutTarget();
self::assertEquals($LayoutTargetValue, $result); 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);
}
} }