From c82ff2526cec6ab5bea2e4ccf99392ee019e95d0 Mon Sep 17 00:00:00 2001 From: Darren Maczka Date: Sun, 31 Jan 2021 13:13:50 -0500 Subject: [PATCH] Fix/chart axis titles (#1760) * use axPos value to determine whether an axis title is mapped to the XaxisLabel or YaxisLabel * update changelog * Fix php-cs-fixer violations Co-authored-by: Darren Maczka Co-authored-by: Mark Baker --- CHANGELOG.md | 3 +- src/PhpSpreadsheet/Reader/Xlsx/Chart.php | 16 ++++- .../Reader/Xlsx/ChartsTitleTest.php | 64 ++++++++++++++++++ tests/data/Reader/XLSX/excelChartsTest.xlsx | Bin 0 -> 32243 bytes 4 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php create mode 100644 tests/data/Reader/XLSX/excelChartsTest.xlsx diff --git a/CHANGELOG.md b/CHANGELOG.md index d429f0adbc..dc1a809dbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed +- Fix for Xlsx Chart axis titles mapping to correct X or Y axis label when only one is present. +- Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. - Fix For Null Exception on ODS Read of Page Settings. [#1772](https://github.com/PHPOffice/PhpSpreadsheet/issues/1772) - Fix Xlsx reader overriding manually set number format with builtin number format. [PR #1805](https://github.com/PHPOffice/PhpSpreadsheet/pull/1805) - Fix Xlsx reader cell alignment. [PR #1710](https://github.com/PHPOffice/PhpSpreadsheet/pull/1710) @@ -58,7 +60,6 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Resolve Google Sheets Xlsx charts issue. Google Sheets uses oneCellAnchor positioning and does not include *Cache values in the exported Xlsx. - Fix for Xls Reader when SST has a bad length [#1592](https://github.com/PHPOffice/PhpSpreadsheet/issues/1592) - Resolve Xlsx loader issue whe hyperlinks don't have a destination - Resolve issues when printer settings resources IDs clash with drawing IDs diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index 84b2e62b80..5a3439f2fc 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -91,7 +91,21 @@ public static function readChart(SimpleXMLElement $chartElements, $chartName) break; case 'valAx': if (isset($chartDetail->title)) { - $YaxisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); + $axisLabel = self::chartTitle($chartDetail->title->children($namespacesChartMeta['c']), $namespacesChartMeta); + $axPos = self::getAttribute($chartDetail->axPos, 'val', 'string'); + + switch ($axPos) { + case 't': + case 'b': + $XaxisLabel = $axisLabel; + + break; + case 'r': + case 'l': + $YaxisLabel = $axisLabel; + + break; + } } break; diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php new file mode 100644 index 0000000000..5e1711390d --- /dev/null +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/ChartsTitleTest.php @@ -0,0 +1,64 @@ +getCaption()) { + return null; + } + + return implode("\n", array_map(function ($rt) { + return $rt->getPlainText(); + }, $title->getCaption())); +} + +class ChartsTitleTest extends TestCase +{ + public function testChartTitles(): void + { + $filename = 'tests/data/Reader/XLSX/excelChartsTest.xlsx'; + $reader = IOFactory::createReader('Xlsx')->setIncludeCharts(true); + $spreadsheet = $reader->load($filename); + $worksheet = $spreadsheet->getActiveSheet(); + + $charts = $worksheet->getChartCollection(); + self::assertEquals(5, $worksheet->getChartCount()); + self::assertCount(5, $charts); + + // No title or axis labels + $chart1 = $charts[0]; + $title = getTitleText($chart1->getTitle()); + self::assertEmpty($title); + self::assertEmpty(getTitleText($chart1->getXAxisLabel())); + self::assertEmpty(getTitleText($chart1->getYAxisLabel())); + + // Title, no axis labels + $chart2 = $charts[1]; + + self::assertEquals('Chart with Title and no Axis Labels', getTitleText($chart2->getTitle())); + self::assertEmpty(getTitleText($chart2->getXAxisLabel())); + self::assertEmpty(getTitleText($chart2->getYAxisLabel())); + + // No title, only horizontal axis label + $chart3 = $charts[2]; + self::assertEmpty(getTitleText($chart3->getTitle())); + self::assertEquals('Horizontal Axis Title Only', getTitleText($chart3->getXAxisLabel())); + self::assertEmpty(getTitleText($chart3->getYAxisLabel())); + + // No title, only vertical axis label + $chart4 = $charts[3]; + self::assertEmpty(getTitleText($chart4->getTitle())); + self::assertEquals('Vertical Axis Title Only', getTitleText($chart4->getYAxisLabel())); + self::assertEmpty(getTitleText($chart4->getXAxisLabel())); + + // Title and both axis labels + $chart5 = $charts[4]; + self::assertEquals('Complete Annotations', getTitleText($chart5->getTitle())); + self::assertEquals('Horizontal Axis Title', getTitleText($chart5->getXAxisLabel())); + self::assertEquals('Vertical Axis Title', getTitleText($chart5->getYAxisLabel())); + } +} diff --git a/tests/data/Reader/XLSX/excelChartsTest.xlsx b/tests/data/Reader/XLSX/excelChartsTest.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..78cbc8f90250aca9faa05c167fe7e72fb38080c7 GIT binary patch literal 32243 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 P^cNdCQvkdC`0IZFH~@3B literal 0 HcmV?d00001