diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index ad2777a0..f031bfe6 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -4775,26 +4775,6 @@ parameters: count: 2 path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - message: "#^Parameter \\#3 \\$id1 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects string, int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#4 \\$id1 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects string, int\\|string given\\.$#" - count: 2 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#4 \\$id2 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeCategoryAxis\\(\\) expects string, int\\|string given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php - - - - message: "#^Parameter \\#5 \\$id2 of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeValueAxis\\(\\) expects string, int\\|string given\\.$#" - count: 2 - 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 diff --git a/samples/Chart/33_Chart_create_scatter2.php b/samples/Chart/33_Chart_create_scatter2.php index 59d6bd3b..1d6e331c 100644 --- a/samples/Chart/33_Chart_create_scatter2.php +++ b/samples/Chart/33_Chart_create_scatter2.php @@ -25,7 +25,7 @@ $worksheet->fromArray( ['=DATEVALUE("2021-01-10")', 30.2, 32.2, 0.2], ] ); -$worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode('yyyy-mm-dd'); +$worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601); $worksheet->getColumnDimension('A')->setAutoSize(true); $worksheet->setSelectedCells('A1'); @@ -67,7 +67,7 @@ $dataSeriesValues = [ // Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers $xAxis = new Axis(); //$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE ); -$xAxis->setAxisNumberProperties('yyyy-mm-dd'); +$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, true); // Build the dataseries $series = new DataSeries( @@ -78,7 +78,7 @@ $series = new DataSeries( $xAxisTickValues, // plotCategory $dataSeriesValues, // plotValues null, // plotDirection - null, // smooth line + false, // smooth line //DataSeries::STYLE_LINEMARKER // plotStyle DataSeries::STYLE_MARKER // plotStyle ); @@ -107,7 +107,7 @@ $chart = new Chart( // Set the position where the chart should appear in the worksheet $chart->setTopLeftPosition('A7'); -$chart->setBottomRightPosition('N20'); +$chart->setBottomRightPosition('P20'); // Add the chart to the worksheet $worksheet->addChart($chart); diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php index eeed326d..089ebdb9 100644 --- a/src/PhpSpreadsheet/Chart/Axis.php +++ b/src/PhpSpreadsheet/Chart/Axis.php @@ -18,6 +18,7 @@ class Axis extends Properties private $axisNumber = [ 'format' => self::FORMAT_CODE_GENERAL, 'source_linked' => 1, + 'numeric' => null, ]; /** @@ -131,15 +132,26 @@ class Axis extends Properties 'size' => null, ]; + private const NUMERIC_FORMAT = [ + Properties::FORMAT_CODE_NUMBER, + Properties::FORMAT_CODE_DATE, + ]; + /** * Get Series Data Type. * * @param mixed $format_code */ - public function setAxisNumberProperties($format_code): void + public function setAxisNumberProperties($format_code, ?bool $numeric = null): void { - $this->axisNumber['format'] = (string) $format_code; + $format = (string) $format_code; + $this->axisNumber['format'] = $format; $this->axisNumber['source_linked'] = 0; + if (is_bool($numeric)) { + $this->axisNumber['numeric'] = $numeric; + } elseif (in_array($format, self::NUMERIC_FORMAT, true)) { + $this->axisNumber['numeric'] = true; + } } /** @@ -162,6 +174,11 @@ class Axis extends Properties return (string) $this->axisNumber['source_linked']; } + public function getAxisIsNumericFormat(): bool + { + return (bool) $this->axisNumber['numeric']; + } + /** * Set Axis Options Properties. * diff --git a/src/PhpSpreadsheet/Chart/Chart.php b/src/PhpSpreadsheet/Chart/Chart.php index 2efec5bb..80d3d5f3 100644 --- a/src/PhpSpreadsheet/Chart/Chart.php +++ b/src/PhpSpreadsheet/Chart/Chart.php @@ -140,6 +140,18 @@ class Chart */ private $bottomRightYOffset = 10; + /** @var ?int */ + private $rotX; + + /** @var ?int */ + private $rotY; + + /** @var ?int */ + private $rAngAx; + + /** @var ?int */ + private $perspective; + /** * Create a new Chart. * @@ -351,8 +363,9 @@ class Chart if ($this->yAxis !== null) { return $this->yAxis; } + $this->yAxis = new Axis(); - return new Axis(); + return $this->yAxis; } /** @@ -365,8 +378,9 @@ class Chart if ($this->xAxis !== null) { return $this->xAxis; } + $this->xAxis = new Axis(); - return new Axis(); + return $this->xAxis; } /** @@ -681,4 +695,52 @@ class Chart return $renderer->render($outputDestination); } + + public function getRotX(): ?int + { + return $this->rotX; + } + + public function setRotX(?int $rotX): self + { + $this->rotX = $rotX; + + return $this; + } + + public function getRotY(): ?int + { + return $this->rotY; + } + + public function setRotY(?int $rotY): self + { + $this->rotY = $rotY; + + return $this; + } + + public function getRAngAx(): ?int + { + return $this->rAngAx; + } + + public function setRAngAx(?int $rAngAx): self + { + $this->rAngAx = $rAngAx; + + return $this; + } + + public function getPerspective(): ?int + { + return $this->perspective; + } + + public function setPerspective(?int $perspective): self + { + $this->perspective = $perspective; + + return $this; + } } diff --git a/src/PhpSpreadsheet/Chart/Properties.php b/src/PhpSpreadsheet/Chart/Properties.php index ef22fb52..9f1a5ce0 100644 --- a/src/PhpSpreadsheet/Chart/Properties.php +++ b/src/PhpSpreadsheet/Chart/Properties.php @@ -37,6 +37,7 @@ abstract class Properties const FORMAT_CODE_CURRENCY = '$#,##0.00'; const FORMAT_CODE_ACCOUNTING = '_($* #,##0.00_);_($* (#,##0.00);_($* "-"??_);_(@_)'; const FORMAT_CODE_DATE = 'm/d/yyyy'; + const FORMAT_CODE_DATE_ISO8601 = 'yyyy-mm-dd'; const FORMAT_CODE_TIME = '[$-F400]h:mm:ss AM/PM'; const FORMAT_CODE_PERCENTAGE = '0.00%'; const FORMAT_CODE_FRACTION = '# ?/?'; diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index 4480c6ff..e3498e20 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -55,12 +55,20 @@ class Chart $XaxisLabel = $YaxisLabel = $legend = $title = null; $dispBlanksAs = $plotVisOnly = null; $plotArea = null; + $rotX = $rotY = $rAngAx = $perspective = null; foreach ($chartElementsC as $chartElementKey => $chartElement) { switch ($chartElementKey) { case 'chart': foreach ($chartElement as $chartDetailsKey => $chartDetails) { $chartDetailsC = $chartDetails->children($namespacesChartMeta['c']); switch ($chartDetailsKey) { + case 'view3D': + $rotX = self::getAttribute($chartDetails->rotX, 'val', 'integer'); + $rotY = self::getAttribute($chartDetails->rotY, 'val', 'integer'); + $rAngAx = self::getAttribute($chartDetails->rAngAx, 'val', 'integer'); + $perspective = self::getAttribute($chartDetails->perspective, 'val', 'integer'); + + break; case 'plotArea': $plotAreaLayout = $XaxisLabel = $YaxisLabel = null; $plotSeries = $plotAttributes = []; @@ -220,6 +228,18 @@ class Chart } } $chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, $dispBlanksAs, $XaxisLabel, $YaxisLabel); + if (is_int($rotX)) { + $chart->setRotX($rotX); + } + if (is_int($rotY)) { + $chart->setRotY($rotY); + } + if (is_int($rAngAx)) { + $chart->setRAngAx($rAngAx); + } + if (is_int($perspective)) { + $chart->setPerspective($perspective); + } return $chart; } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php index 0f65ae3b..77cbb872 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php @@ -9,7 +9,6 @@ use PhpOffice\PhpSpreadsheet\Chart\GridLines; use PhpOffice\PhpSpreadsheet\Chart\Layout; use PhpOffice\PhpSpreadsheet\Chart\Legend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; -use PhpOffice\PhpSpreadsheet\Chart\Properties; use PhpOffice\PhpSpreadsheet\Chart\Title; use PhpOffice\PhpSpreadsheet\Shared\XMLWriter; use PhpOffice\PhpSpreadsheet\Writer\Exception as WriterException; @@ -75,6 +74,33 @@ class Chart extends WriterPart $objWriter->writeAttribute('val', 0); $objWriter->endElement(); + $objWriter->startElement('c:view3D'); + $rotX = $chart->getRotX(); + if (is_int($rotX)) { + $objWriter->startElement('c:rotX'); + $objWriter->writeAttribute('val', "$rotX"); + $objWriter->endElement(); + } + $rotY = $chart->getRotY(); + if (is_int($rotY)) { + $objWriter->startElement('c:rotY'); + $objWriter->writeAttribute('val', "$rotY"); + $objWriter->endElement(); + } + $rAngAx = $chart->getRAngAx(); + if (is_int($rAngAx)) { + $objWriter->startElement('c:rAngAx'); + $objWriter->writeAttribute('val', "$rAngAx"); + $objWriter->endElement(); + } + $perspective = $chart->getPerspective(); + if (is_int($perspective)) { + $objWriter->startElement('c:perspective'); + $objWriter->writeAttribute('val', "$perspective"); + $objWriter->endElement(); + } + $objWriter->endElement(); // view3D + $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart->getXAxisLabel(), $chart->getYAxisLabel(), $chart->getChartAxisX(), $chart->getChartAxisY(), $chart->getMajorGridlines(), $chart->getMinorGridlines()); $this->writeLegend($objWriter, $chart->getLegend()); @@ -200,7 +226,7 @@ class Chart extends WriterPart return; } - $id1 = $id2 = 0; + $id1 = $id2 = $id3 = '0'; $this->seriesIndex = 0; $objWriter->startElement('c:plotArea'); @@ -230,6 +256,10 @@ class Chart extends WriterPart $objWriter->startElement('c:scatterStyle'); $objWriter->writeAttribute('val', $plotStyle); $objWriter->endElement(); + } elseif ($groupType === DataSeries::TYPE_SURFACECHART_3D || $groupType === DataSeries::TYPE_SURFACECHART) { + $objWriter->startElement('c:wireframe'); + $objWriter->writeAttribute('val', $plotStyle ? '1' : '0'); + $objWriter->endElement(); } $this->writePlotGroup($plotGroup, $chartType, $objWriter, $catIsMultiLevelSeries, $valIsMultiLevelSeries, $plotGroupingType); @@ -280,9 +310,10 @@ class Chart extends WriterPart $objWriter->endElement(); } - // Generate 2 unique numbers to use for axId values - $id1 = '75091328'; - $id2 = '75089408'; + // Generate 3 unique numbers to use for axId values + $id1 = '110438656'; + $id2 = '110444544'; + $id3 = '110365312'; // used in Surface Chart if (($chartType !== DataSeries::TYPE_PIECHART) && ($chartType !== DataSeries::TYPE_PIECHART_3D) && ($chartType !== DataSeries::TYPE_DONUTCHART)) { $objWriter->startElement('c:axId'); @@ -291,6 +322,11 @@ class Chart extends WriterPart $objWriter->startElement('c:axId'); $objWriter->writeAttribute('val', $id2); $objWriter->endElement(); + if ($chartType === DataSeries::TYPE_SURFACECHART_3D || $chartType === DataSeries::TYPE_SURFACECHART) { + $objWriter->startElement('c:axId'); + $objWriter->writeAttribute('val', $id3); + $objWriter->endElement(); + } } else { $objWriter->startElement('c:firstSliceAng'); $objWriter->writeAttribute('val', 0); @@ -314,6 +350,9 @@ class Chart extends WriterPart } $this->writeValueAxis($objWriter, $yAxisLabel, $chartType, $id1, $id2, $valIsMultiLevelSeries, $yAxis, $majorGridlines, $minorGridlines); + if ($chartType === DataSeries::TYPE_SURFACECHART_3D || $chartType === DataSeries::TYPE_SURFACECHART) { + $this->writeSerAxis($objWriter, $id2, $id3); + } } $objWriter->endElement(); @@ -375,17 +414,13 @@ class Chart extends WriterPart { // N.B. writeCategoryAxis may be invoked with the last parameter($yAxis) using $xAxis for ScatterChart, etc // In that case, xAxis is NOT a category. - $AxisFormat = $yAxis->getAxisNumberFormat(); - if ( - $AxisFormat === Properties::FORMAT_CODE_DATE - || $AxisFormat == Properties::FORMAT_CODE_NUMBER - ) { + if ($yAxis->getAxisIsNumericFormat()) { $objWriter->startElement('c:valAx'); } else { $objWriter->startElement('c:catAx'); } - if ($id1 > 0) { + if ($id1 !== '0') { $objWriter->startElement('c:axId'); $objWriter->writeAttribute('val', $id1); $objWriter->endElement(); @@ -459,7 +494,7 @@ class Chart extends WriterPart $objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('axis_labels')); $objWriter->endElement(); - if ($id2 > 0) { + if ($id2 !== '0') { $objWriter->startElement('c:crossAx'); $objWriter->writeAttribute('val', $id2); $objWriter->endElement(); @@ -501,7 +536,7 @@ class Chart extends WriterPart { $objWriter->startElement('c:valAx'); - if ($id2 > 0) { + if ($id2 !== '0') { $objWriter->startElement('c:axId'); $objWriter->writeAttribute('val', $id2); $objWriter->endElement(); @@ -926,7 +961,7 @@ class Chart extends WriterPart $objWriter->endElement(); //effectList $objWriter->endElement(); //end spPr - if ($id1 > 0) { + if ($id1 !== '0') { $objWriter->startElement('c:crossAx'); $objWriter->writeAttribute('val', $id2); $objWriter->endElement(); @@ -969,6 +1004,54 @@ class Chart extends WriterPart $objWriter->endElement(); } + /** + * Write Ser Axis, for Surface chart. + */ + private function writeSerAxis(XMLWriter $objWriter, string $id2, string $id3): void + { + $objWriter->startElement('c:serAx'); + + $objWriter->startElement('c:axId'); + $objWriter->writeAttribute('val', $id3); + $objWriter->endElement(); // axId + + $objWriter->startElement('c:scaling'); + $objWriter->startElement('c:orientation'); + $objWriter->writeAttribute('val', 'minMax'); + $objWriter->endElement(); // orientation + $objWriter->endElement(); // scaling + + $objWriter->startElement('c:delete'); + $objWriter->writeAttribute('val', '0'); + $objWriter->endElement(); // delete + + $objWriter->startElement('c:axPos'); + $objWriter->writeAttribute('val', 'b'); + $objWriter->endElement(); // axPos + + $objWriter->startElement('c:majorTickMark'); + $objWriter->writeAttribute('val', 'out'); + $objWriter->endElement(); // majorTickMark + + $objWriter->startElement('c:minorTickMark'); + $objWriter->writeAttribute('val', 'none'); + $objWriter->endElement(); // minorTickMark + + $objWriter->startElement('c:tickLblPos'); + $objWriter->writeAttribute('val', 'nextTo'); + $objWriter->endElement(); // tickLblPos + + $objWriter->startElement('c:crossAx'); + $objWriter->writeAttribute('val', $id2); + $objWriter->endElement(); // crossAx + + $objWriter->startElement('c:crosses'); + $objWriter->writeAttribute('val', 'autoZero'); + $objWriter->endElement(); // crosses + + $objWriter->endElement(); //serAx + } + /** * Get the data series type(s) for a chart plot series. * diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/Charts32CatAxValAxTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/Charts32CatAxValAxTest.php new file mode 100644 index 00000000..af33baa1 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/Charts32CatAxValAxTest.php @@ -0,0 +1,171 @@ +outputFileName !== '') { + unlink($this->outputFileName); + $this->outputFileName = ''; + } + } + + /** + * @dataProvider providerCatAxValAx + */ + public function test1CatAx1ValAx(?bool $numeric): void + { + $spreadsheet = new Spreadsheet(); + $worksheet = $spreadsheet->getActiveSheet(); + // changed data to simulate a trend chart - Xaxis are dates; Yaxis are 3 meausurements from each date + $worksheet->fromArray( + [ + ['', 'metric1', 'metric2', 'metric3'], + ['=DATEVALUE("2021-01-01")', 12.1, 15.1, 21.1], + ['=DATEVALUE("2021-01-04")', 56.2, 73.2, 86.2], + ['=DATEVALUE("2021-01-07")', 52.2, 61.2, 69.2], + ['=DATEVALUE("2021-01-10")', 30.2, 32.2, 0.2], + ] + ); + $worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601); + $worksheet->getColumnDimension('A')->setAutoSize(true); + $worksheet->setSelectedCells('A1'); + + // Set the Labels for each data series we want to plot + // Datatype + // Cell reference for data + // Format Code + // Number of datapoints in series + // Data values + // Data Marker + $dataSeriesLabels = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // was 2010 + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // was 2011 + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // was 2012 + ]; + // Set the X-Axis Labels + // changed from STRING to NUMBER + // added 2 additional x-axis values associated with each of the 3 metrics + // added FORMATE_CODE_NUMBER + $xAxisTickValues = [ + //new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4 + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4), + ]; + // Set the Data values for each data series we want to plot + // Datatype + // Cell reference for data + // Format Code + // Number of datapoints in series + // Data values + // Data Marker + // added FORMAT_CODE_NUMBER + $dataSeriesValues = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', Properties::FORMAT_CODE_NUMBER, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', Properties::FORMAT_CODE_NUMBER, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', Properties::FORMAT_CODE_NUMBER, 4), + ]; + // Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers + $xAxis = new Axis(); + //$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE ); + if (is_bool($numeric)) { + $xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, $numeric); + } else { + $xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601); + } + + // Build the dataseries + $series = new DataSeries( + DataSeries::TYPE_SCATTERCHART, // plotType + null, // plotGrouping (Scatter charts don't have any grouping) + range(0, count($dataSeriesValues) - 1), // plotOrder + $dataSeriesLabels, // plotLabel + $xAxisTickValues, // plotCategory + $dataSeriesValues, // plotValues + null, // plotDirection + false, // smooth line + //DataSeries::STYLE_LINEMARKER // plotStyle + DataSeries::STYLE_MARKER // plotStyle + ); + + // Set the series in the plot area + $plotArea = new PlotArea(null, [$series]); + // Set the chart legend + $legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false); + + $title = new Title('Test Scatter Trend Chart'); + $yAxisLabel = new Title('Value ($k)'); + + // Create the chart + $chart = new Chart( + 'chart1', // name + $title, // title + $legend, // legend + $plotArea, // plotArea + true, // plotVisibleOnly + DataSeries::EMPTY_AS_GAP, // displayBlanksAs + null, // xAxisLabel + $yAxisLabel, // yAxisLabel + // added xAxis for correct date display + $xAxis, // xAxis + ); + + // Set the position where the chart should appear in the worksheet + $chart->setTopLeftPosition('A7'); + $chart->setBottomRightPosition('P20'); + // Add the chart to the worksheet + $worksheet->addChart($chart); + + $writer = new XlsxWriter($spreadsheet); + $writer->setIncludeCharts(true); + $this->outputFileName = File::temporaryFilename(); + $writer->save($this->outputFileName); + $spreadsheet->disconnectWorksheets(); + + $file = 'zip://'; + $file .= $this->outputFileName; + $file .= '#xl/charts/chart1.xml'; + $data = file_get_contents($file); + // confirm that file contains expected tags + if ($data === false) { + self::fail('Unable to read file'); + } elseif ($numeric === true) { + self::assertSame(0, substr_count($data, '')); } } + + /** + * @dataProvider providerCatAxValAx + */ + public function testCatAxValAx(?bool $numeric): void + { + $file = self::DIRECTORY . '32readwriteScatterChart1.xlsx'; + $reader = new XlsxReader(); + $reader->setIncludeCharts(true); + $spreadsheet = $reader->load($file); + $sheet = $spreadsheet->getActiveSheet(); + $charts = $sheet->getChartCollection(); + self::assertCount(1, $charts); + $chart = $charts[0]; + self::assertNotNull($chart); + $xAxis = $chart->getChartAxisX(); + self::assertSame(Properties::FORMAT_CODE_GENERAL, $xAxis->getAxisNumberFormat()); + if (is_bool($numeric)) { + $xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, true); + } + $yAxis = $chart->getChartAxisY(); + self::assertSame(Properties::FORMAT_CODE_GENERAL, $yAxis->getAxisNumberFormat()); + if (is_bool($numeric)) { + $xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, $numeric); + $yAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, $numeric); + } + + $writer = new XlsxWriter($spreadsheet); + $writer->setIncludeCharts(true); + $this->outputFileName = File::temporaryFilename(); + $writer->save($this->outputFileName); + $spreadsheet->disconnectWorksheets(); + + $file = 'zip://'; + $file .= $this->outputFileName; + $file .= '#xl/charts/chart2.xml'; + $data = file_get_contents($file); + // confirm that file contains expected tags + if ($data === false) { + self::fail('Unable to read file'); + } elseif ($numeric === true) { + self::assertSame(0, substr_count($data, '')); + self::assertSame(2, substr_count($data, '')); + } else { + self::assertSame(1, substr_count($data, '')); + self::assertSame(1, substr_count($data, '')); + } + } + + public function providerCatAxValAx(): array + { + return [ + [true], + [false], + [null], + ]; + } }