From 09406a6a3f300b100094d4aa58c25151adddcd15 Mon Sep 17 00:00:00 2001 From: oleibman <10341515+oleibman@users.noreply.github.com> Date: Thu, 7 Jul 2022 21:48:12 -0700 Subject: [PATCH] Move Gridlines from Chart to Axis (#2923) * Move Gridlines from Chart to Axis This could, I hope, be my last major change to Chart for a while. When I first noticed this problem, I thought it would be a breaking change. However, although this change establishes some deprecations, I don't think it breaks anything. Major and minor gridlines had only been settable by the Chart constructor. This PR moves them where they belong, to Axis (eexisting Chart constructor code will still work). This allows them to be specified from both X and Y axis. Chart is now entirely covered except for 2 statements, one deprecated and one that I just can't figure out. 99.71% for Charts, 88.96% overall. All references to the Chart directory in Phpstan baseline are eliminated. * Minor Fixes, Unit Tests Line style color type should default to null not prstClr. Chart X-axis and Y-axis should alway be Axis, never null. Add some unit tests. * More Tests, Some Improvements Make it easier to change line styles, adding an alternate method besides a setter function with at least a dozen parameters. --- CHANGELOG.md | 6 +- phpstan-baseline.neon | 85 ------- .../33_Chart_create_bar_labels_lines.php | 209 ++++++++++++++++++ samples/templates/32readwriteLineChart4.xlsx | Bin 13474 -> 13512 bytes src/PhpSpreadsheet/Chart/Axis.php | 38 ++++ src/PhpSpreadsheet/Chart/Chart.php | 158 ++++++------- src/PhpSpreadsheet/Chart/DataSeries.php | 4 +- src/PhpSpreadsheet/Chart/Legend.php | 16 +- src/PhpSpreadsheet/Chart/PlotArea.php | 9 +- src/PhpSpreadsheet/Chart/Properties.php | 42 +++- src/PhpSpreadsheet/Chart/Title.php | 9 +- src/PhpSpreadsheet/Reader/Xlsx/Chart.php | 27 ++- src/PhpSpreadsheet/Writer/Xlsx/Chart.php | 35 ++- .../Chart/BarChartCustomColorsTest.php | 1 + .../Chart/ChartMethodTest.php | 142 ++++++++++++ .../Chart/Charts32ColoredAxisLabelTest.php | 2 + .../Chart/Charts32DsvGlowTest.php | 19 ++ .../Chart/Charts32DsvLabelsTest.php | 1 + .../Chart/Charts32ScatterTest.php | 9 + .../Chart/ChartsOpenpyxlTest.php | 1 + .../Chart/DataSeriesValues2Test.php | 25 ++- .../Chart/GridlinesLineStyleTest.php | 201 +++++++++++++++++ .../Chart/GridlinesShadowGlowTest.php | 22 +- .../Chart/LineStylesTest.php | 42 ++++ .../PhpSpreadsheetTests/Chart/PieFillTest.php | 1 + .../Reader/Xlsx/SheetsXlsxChartTest.php | 2 + 26 files changed, 876 insertions(+), 230 deletions(-) create mode 100644 samples/Chart/33_Chart_create_bar_labels_lines.php create mode 100644 tests/PhpSpreadsheetTests/Chart/ChartMethodTest.php create mode 100644 tests/PhpSpreadsheetTests/Chart/LineStylesTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e3a4db1..48225e08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,7 +49,11 @@ 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) [PR #2922](https://github.com/PHPOffice/PhpSpreadsheet/pull/2922) +- 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) [PR #2923](https://github.com/PHPOffice/PhpSpreadsheet/pull/2923) +- Adjust both coordinates for two-cell anchors when rows/columns are added/deleted. [Issue #2908](https://github.com/PHPOffice/PhpSpreadsheet/issues/2908) [PR #2909](https://github.com/PHPOffice/PhpSpreadsheet/pull/2909) +- Keep calculated string results below 32K. [PR #2921](https://github.com/PHPOffice/PhpSpreadsheet/pull/2921) +- Filter out illegal Unicode char values FFFE/FFFF. [Issue #2897](https://github.com/PHPOffice/PhpSpreadsheet/issues/2897) [PR #2910](https://github.com/PHPOffice/PhpSpreadsheet/pull/2910) +- Better handling of REF errors and propagation of all errors in Calculation engine. [PR #2902](https://github.com/PHPOffice/PhpSpreadsheet/pull/2902) - 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 108836bc..5ef5522f 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1110,86 +1110,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Cell/Coordinate.php - - - message: "#^Call to an undefined method object\\:\\:render\\(\\)\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$legend \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$majorGridlines \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$minorGridlines \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\GridLines\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$plotArea \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$title \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$worksheet \\(PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Worksheet\\\\Worksheet\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$xAxis \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$xAxisLabel \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$yAxis \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Axis\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Chart\\:\\:\\$yAxisLabel \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Chart.php - - - - message: "#^Strict comparison using \\=\\=\\= between PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues and null will always evaluate to false\\.$#" - count: 2 - path: src/PhpSpreadsheet/Chart/DataSeries.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Legend.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Legend\\:\\:\\$positionXLref has no type specified\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Legend.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\PlotArea\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/PlotArea.php - - - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Title\\:\\:\\$layout \\(PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\) does not accept PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\Layout\\|null\\.$#" - count: 1 - path: src/PhpSpreadsheet/Chart/Title.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Collection\\\\Memory\\:\\:\\$cache has no type specified\\.$#" count: 1 @@ -3630,11 +3550,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Writer/Html.php - - - message: "#^Ternary operator condition is always true\\.$#" - count: 1 - path: src/PhpSpreadsheet/Writer/Html.php - - message: "#^Negated boolean expression is always false\\.$#" count: 1 diff --git a/samples/Chart/33_Chart_create_bar_labels_lines.php b/samples/Chart/33_Chart_create_bar_labels_lines.php new file mode 100644 index 00000000..970d632c --- /dev/null +++ b/samples/Chart/33_Chart_create_bar_labels_lines.php @@ -0,0 +1,209 @@ +getActiveSheet(); +$worksheet->fromArray( + [ + ['', 2010, 2011, 2012], + ['Q1', 12, 15, 21], + ['Q2', 56, 73, 86], + ['Q3', 52, 61, 69], + ['Q4', 30, 32, 0], + ] +); + +// Custom colors for dataSeries (gray, blue, red, orange) +$colors = [ + 'cccccc', '00abb8', 'b8292f', 'eb8500', +]; + +// 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 +$dataSeriesLabels1 = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011 +]; +// Set the X-Axis Labels +// Datatype +// Cell reference for data +// Format Code +// Number of datapoints in series +// Data values +// Data Marker +$xAxisTickValues1 = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4 +]; +// 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 +// Custom colors +$dataSeriesValues1 = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4, [], null, $colors), +]; +$labelLayout = new Layout(); +$labelLayout + ->setShowVal(true) + ->setLabelFontColor(new ChartColor('FFFF00')) + ->setLabelFillColor(new ChartColor('accent2', null, 'schemeClr')); +$dataSeriesValues1[0]->setLabelLayout($labelLayout); + +// Build the dataseries +$series1 = new DataSeries( + DataSeries::TYPE_BARCHART, // plotType + null, // plotGrouping (Pie charts don't have any grouping) + range(0, count($dataSeriesValues1) - 1), // plotOrder + $dataSeriesLabels1, // plotLabel + $xAxisTickValues1, // plotCategory + $dataSeriesValues1 // plotValues +); + +// Set up a layout object for the Pie chart +$layout1 = new Layout(); +$layout1->setShowVal(true); +$layout1->setShowPercent(true); + +// Set the series in the plot area +$plotArea1 = new PlotArea($layout1, [$series1]); +// Set the chart legend +$legend1 = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false); + +$title1 = new Title('Test Bar Chart'); + +// Create the chart +$chart1 = new Chart( + 'chart1', // name + $title1, // title + $legend1, // legend + $plotArea1, // plotArea + true, // plotVisibleOnly + DataSeries::EMPTY_AS_GAP, // displayBlanksAs + null, // xAxisLabel + null // yAxisLabel - Pie charts don't have a Y-Axis +); +$majorGridlinesY = new GridLines(); +$majorGridlinesY->setLineColorProperties('FF0000'); +$minorGridlinesY = new GridLines(); +$minorGridlinesY->setLineStyleProperty('dash', Properties::LINE_STYLE_DASH_ROUND_DOT); +$chart1 + ->getChartAxisY() + ->setMajorGridlines($majorGridlinesY) + ->setMinorGridlines($minorGridlinesY); +$majorGridlinesX = new GridLines(); +$majorGridlinesX->setLineColorProperties('FF00FF'); +$minorGridlinesX = new GridLines(); +$minorGridlinesX->activateObject(); +$chart1 + ->getChartAxisX() + ->setMajorGridlines($majorGridlinesX) + ->setMinorGridlines($minorGridlinesX); + +// Set the position where the chart should appear in the worksheet +$chart1->setTopLeftPosition('A7'); +$chart1->setBottomRightPosition('H20'); + +// Add the chart to the worksheet +$worksheet->addChart($chart1); + +// 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 +$dataSeriesLabels2 = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011 +]; +// Set the X-Axis Labels +// Datatype +// Cell reference for data +// Format Code +// Number of datapoints in series +// Data values +// Data Marker +$xAxisTickValues2 = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4 +]; +// 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 +// Custom colors +$dataSeriesValues2 = [ + $dataSeriesValues2Element = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4), +]; +$dataSeriesValues2Element->setFillColor($colors); + +// Build the dataseries +$series2 = new DataSeries( + DataSeries::TYPE_DONUTCHART, // plotType + null, // plotGrouping (Donut charts don't have any grouping) + range(0, count($dataSeriesValues2) - 1), // plotOrder + $dataSeriesLabels2, // plotLabel + $xAxisTickValues2, // plotCategory + $dataSeriesValues2 // plotValues +); + +// Set up a layout object for the Pie chart +$layout2 = new Layout(); +$layout2->setShowVal(true); +$layout2->setShowCatName(true); +$layout2->setLabelFillColor(new ChartColor('FFFF00')); + +// Set the series in the plot area +$plotArea2 = new PlotArea($layout2, [$series2]); + +$title2 = new Title('Test Donut Chart'); + +// Create the chart +$chart2 = new Chart( + 'chart2', // name + $title2, // title + null, // legend + $plotArea2, // plotArea + true, // plotVisibleOnly + DataSeries::EMPTY_AS_GAP, // displayBlanksAs + null, // xAxisLabel + null // yAxisLabel - Like Pie charts, Donut charts don't have a Y-Axis +); + +// Set the position where the chart should appear in the worksheet +$chart2->setTopLeftPosition('I7'); +$chart2->setBottomRightPosition('P20'); + +// Add the chart to the worksheet +$worksheet->addChart($chart2); + +// Save Excel 2007 file +$filename = $helper->getFilename(__FILE__); +$writer = IOFactory::createWriter($spreadsheet, 'Xlsx'); +$writer->setIncludeCharts(true); +$callStartTime = microtime(true); +$writer->save($filename); +$helper->logWrite($writer, $filename, $callStartTime); diff --git a/samples/templates/32readwriteLineChart4.xlsx b/samples/templates/32readwriteLineChart4.xlsx index eb09c784e280fb27da5705b25a21f0deef57b981..0944fcbb6b56de1017491ff6b26f2f531120d7ab 100644 GIT binary patch delta 3927 zcmZ9PXE59i*T#1VqSs{!A$o61^d4fh=uxAySgc+`{>tjB?IJ?74T*^8L5QAci7tAJ z7BxupD9`=A&&+$zyw{g=X0EwDojEhV3-8|NUVTbT`Y7dl1veoGw2LKy0$x6O;xyOF z?l<6b1tP*wjZ%}_YVRgY&GJ6jahi$Bb_&|N=JA?+ziES^>)l@qcp5o6Egc@rFZgd9 z^}g;);S=Oub%{JkOrfyiRdiVwRBhj=k$VtlTA~LZ(q$=f6C6#e+g~!6vQbn{R?zQj&0d=sjX9pNld0GKU>(aN zwF0*tG5)|2z3~7X@uEg22%+gmVWalh$@T@Qm|$dxy`0G~CBJ0SXBE3FoAh|ruEpho z8rp-MZuU8G*@e80fP?aAo@m`RQ$CQ_hZ5?Q-iFx2CuH~If=Z}J+!QUn%0 z&u#Mx>7xmRObU~{8~3-pW9g%n8uoL*Aq zC&-l4MX|fKlCRb8pm7n{oU%pmsj`WyM=PRS+=U8a? zCCAO)a_Yhv9)2T9+Dk9vN3szh_4)Nrxdu5FG@<`W+>k7=t>0@Bd_mTk&{l{teuuOU zqGaQs_6WDn&Cqx2Y_O|4O6f^%ZPil(pz?F?s4Un~jhM>yJk_JI>G>MT^&QX)i?0`< zz(;RPu&^2PExBk!`slB#5@Z(G2`Q5|ay!>D@&u|W@(L&xme$LvnsY{X|r<8!@{A1g){UO!)@4Bzw%EAbD1TC%$4cb~J6ZR@E-{?gKyUimaP2dTviYhW;y zhzNbMJAepe->y>u;e7cR>ZHhE1f;B&biW60fj}NO6a^=c`p@IU?F${V2``Zl%Iy-z zR?Jr7e`%JM?|E0HFh@h!%l2NH9xnuo>(?54<2CJxpPpSaU)F`lA~b`RKh?i3vBVk^ zXiZz?2Eq%0_gbf!XC3;3S<;4MTp<_LmuC(&joz!)k*ewT;qW<{=4c5qtC4xW2ErJj zl)zk)@BqMbLxJQ|s+jwi-%|M!gQdlU#i&McC9v-U`=Y%%KYaZ6$pFGrYSc*q>5y{Ca`hV)-dm#&ymXx9<=XklbT{Q-$ z_J(I(`ug(Po&xl|dEz7rGd{~iS?yIN$S~J+CSdw3zj}sw5)gfibg><4-@0)^pH{Gs zeMMRQefT`tYK7|5mX<^xuHy2gQDGoEd9#p-^yv*RZ`5NIwW!;XEX+KuN?;6=VnrN=k+MB5n$4hYrp`DTJfC4?f^Y9=bK9elmqW`W=;`D|6 z@%}x5WFD5kAB$yZGqHC>q_}iknF?D=#!3c!@6|I>&~tYXhCk1m*U`PCC4Zv*tqyHu zAhW_*9BK!U*J(wG1JhOSb7OGE+|??_#6w)1uqpq)wHZZ@@9v;R|E?RzNLoPz44ekY zrc-;)6cZUA*qcX|nJmkX@scSC`5$ z4$A)Y01DN)?8&yA@)!5a{se+KCZT0|8vQ}7jS0~9{CnK26AR&VPQj9F<@GFwZ5G=Z zCQc`__e6G@|>swH? z1q~p~hLX~Yv-^<{kth@S=EWT@?0ZYzc>L{Gl?CX+U*N-8mJisPN6h^l>denzkK+p@ zWuQ?1t9InCf~iS@ZzdN3X@#-mx_)4`WxPzwayh}vM2!8a*ock1#GSQ4mc7Y)4q`vnz4FfYDiokajTFE$ucNLQ!%n@ZH>9(TW$3&?kur=d+j8t5 zDgT(_dDE?$W^x-XG9HUzY_y1tAk%4t`COV0zTibuCz+8PCdMiSh8a&fR zbS)S)ef%K8x!TlZj?3|H4&5wXI#NEaRTnQDF^OYX#3j@+Sa)om&xWfmx_!!k-3R{g z&~3I*CsT86@qQ<6m56qFc=DW+SP~NFSC284txoSj&?yZuC6>`-jI(Fy>M-kLpH)Dw z@a7f49btL=On*D4o0=#?L(hJ&5U!sTeQO?syM+seeu*sp zkY-OnPz%T72htP+&K(#cn%tX6HC-Nr#VqsFe-(0iuW(8t%u6)!hU7K8l09ZHftjs zd(ey3{@?0P9*yj2kUDP_88uR0&5m{+x~iVtZLn>huD&1D?XMF{3d6kuc>#9*vB(fV zLE_%!eP5`-C)vA4abHKxe3tcB7uU_8N0mLDk~yi}4$xjeYV1vwK>=~fCkF;I%@gZb zKq}|lmYuC&%37aMx#Ah~32(QSK4O7o}2X&VUgEIDZfH|tcTwC0;L5`Qr$vYP2u@)_dH2ix zi;MC)JbR9M-LOM|JabrQ>y79DdiQ4)x5n0SF3K!$X7r8cr&#OFM`xSSq)P3aWwiIV zAG6LnazE4hD6o^mt<$jN5LA1`2!mUSt=X9GNOuO$Jb%qUU1BAjvNLJ>>p^o;fmea- zi(88!iqK8r$_3@v`Dy2bT1OMRC-mHm+er&NaeRj90u5tkK&Fd*ydaZD>Fg6;qSbXkJpn?nOqVSBe)&>-HG|Lq1u3Oc($ZWi%4aQoTAV z*EUn~-B5R@PeM1J5Xaun%ova0oi5UHr-xe3*PjD1@>yxCEo@;);oAwpbf!Z#<|UQ5 zH6C=X@OXZFrw1f>!ZfX%?`d0!x|>!g@p?eK^ZB>@iDPXBOD5H0;oc&G&I365XISd7 z+B+Qb&T$UR08u<>>T&(i-gBxdp!}`)Ql(X4_gqxu@UniOt>YoOrgPe=9V+_1^LHwz z+bQ5$pY&q8&%{Ol*c671y7-zT1l8Y$8&6a*-bzrW>hqOXHwx{I6Kvc`)LuPnF{J!TgaHQn&> z15q%X*IF!YZF-AY8Dbw~ zoU++HXGH1sQ3B@6O>3#EjL=C!+Wd55ioT2SOg2?A3LgHEAx9RY%hf>p%&R}@Z!j;* zQN6Rl@?Y5MN;kiBMpS>XN9OW+@Y+%o7OpfNZ-0Ep!q~i!18&Cc8n#pc2M9wz7`wLL_TS zl0EwxQL^9X-WT_|_q;lvbAIQ|`Mvr6-edAHRR^^6%zPSGpkNSaB#jOROnMh6K*R20 z&Z!PxM$rq?OWQ8RP%Lg)c~QbjE!7;OtU4+bnXSfvS;fpkjCHwZB0FD5PwzeVct zn8Dq)dG*=4Rm9%$3}XP=jJU+~8?Xet`C?RBRh$$N<7`vB29t8)xevYL!$6zz7x#!7 z>xXpr8Y(swVfNLFiv5W!vdpMR7MZp=u0Jks#y=FK&LlLGPnm(x~mi&_zlQZrKZ!;EbS z&%$`6+zdEX`B+1Rwo;FV+FeH3LN+OmMrz@}9jp?3vW9<&zB5ZSEg|WK`oc4a0L3TF z%J1@T_;Mb03y3+BdzOc-(zy$jsT0NaHN6p6`eO7n$YWXCGb=Qx5s-x$7w!ueue7NXa@1Zh1t0ml zGW$=Wnf59pt&-q-HO zt7YdS{uBgPRa5siY??cSjZCthu7xk!v98$|9xP$sRN@cd>534w8d)r6IoyI0AE~Ii zVF+z@UM7L{_hO#1ro4I%*6-0U`V~O`dEKG^e*AE}C|0ICu@0qp;hU94Tq1N_Y?GTt zlwM~9C@U8*_*$p`0cZWQCN+Q+?X2VdO%OFW^M2Gz@VE(YP^|q@oidYq+JG{zl=v3(jI9&vf5~#6%SEOGdVR7sV^8#U@5W&y)5;cCjM~n;nlariQhmMUbSbdXy{j9%7wjT*QXNALC!tMIit^}@DG3S~r;HDH4$y@LJXqGC zYf08cS8JNyGx5W$>PSw>GEJ&jbQEyeF^e-n=@RG$W*chuB%X6O%&7#v@ItU#2gZ>L z)8=8MbPsdQN_;?zh0THR3#={+%MbqCT|@Ekc8gI9A23=e$n2zf6NMC_iA$*W6fh zzD@djp43`w#h+k<317C;y<43#?YxAJa=|p}&9Pa2jcFaES9Y`b2>9AKS_$<)!ov=|&?efO1A;2YjHu#j6x6Nw)M)Nd4+vp7zS29fH z(z5v6Yp_FYnmF2r^o_Q<@HWF^;ylblJv{Ez;R{K2P4gM*=i%lVixk(Nsx+;1_Ud16 z*Y9@a!;4|I=d}(j7uo3NgZ1ZE=|CU>Lb#v+VEb@^!X4h;amrez@H)9Zh^t4AUra7R z{H0^s@A|T2@>{e+;-=&UbL*DddaHu`219J}IM10gV8QW804FuZ(Y4SltqfkZm z;k@l!$eRHh)Q7==^CjYwIhH=`K@X$oJn`X?nn8+COWvvE1^qDD?gr`+4G3pky07l3T^MxXoy*vLeg$Ukjl#T1jOSO zos+g#!Fk>^`mZjC`IZd+UJ=xN)Z{kD`a}7wQk*~WS#C70m67)DMug*3?!E}$Z3R_+ zQN3+RRoZCX!ip`##(l1gxKXYT+r)<~w1}$*r}w{CD}RQ!;y>d=)0|It3d7a<0Los9 zq-}L*V3(6yx|#4pqTW%Fh3pvf?Q`Fjv(PTBT^cMD0(wGZ$THY}sI_Mdil7Ed9Dtsr zO|MJ9Vj#uWB1J$c`PUSTeu|MS+jj<~i>6{Yx}zMIA_|=D9}{z?tb&+>o*zo(yS|I( zO<+%I3Rc?nWsO68StVA4eY?Q|aF=Z%_6EOvTGj_Y@cxrII33@Ej(9wD>BkOX-^oyz z1irKHe(}zi2xUV_${F<_QF-x%+Z>)wS42TId{=7MtGWpp|d!eJ03kWk&3ME{Eljt#?!gjOia?b?aRN z*O#bo!F^`Xh506ONd1`RM->?{J&vDB)}dxwd~>fE;-*bh3}}a$>$Qa1jCtH-(O|Mm zoP9>>NuSAR&@g+C-zLaqnQxEkaqcd9&}LXZ_1bKhO(;wXv8K9e%Eqrz)}AJnT3VOx z;%YgHi)PZVU36-D?}`V=&(HGgElQ^gS9{|X<%8deQx8pAHY1aIzP$5#U*5%vP)NP` zlm%Rw_`v;CU2~BNaiS(;dFMT&DCJ8@!fiMV?E~R}rkZA?2lyO-&{YoK!HD>8_A6vVyl$4kU_h*6%TFH_9)BR&oW;VWbDr#Hvbku| z+{=`m?K35HZ*{SI+E;%t%cmr}nh$*Mdgc~~hB!;iOP69iknb%hEhIySZwiB{CMPH3 zs3rpiAMJgo)K4Sx9ZkM@x%+YEZOM?HGT(Fes2p0l$6b=8#y{=wKwZ}1G{1oEh#iVsxFY=0fq0kGXS-y% zQ6W@`IqV(a5$a06S~0&_Vdkjn>1U$;WePk>e^=z?+h)U+mLY^qxY$}Y=s+hjqzU;=tfl`wAWKZ0U@rbSq=1I4BA-Y z5*@E(4e%M`mO*YVSTcR#ai)BkhImkxBQ#L`*Fac$JF`;4EJ4uT7Uwcxj;KfW zXufSuR#*r+l6LBu-)J;L2EA11BHJy+DBfJOH(5e8 zPl&FP?PzmSxt!haplAe^@swWBUV*f78*;f52OJS2D4cz{=1%?Us__`mZW>=zmoc+^-H7D$5;Cjv|w2qFZ}x*_x-y(F%RAL!L(@Z(aF0_ z?m$~>qVD6UvAJ3qiy0Rrw-nnwPLCx`lJa>^h7mN4t{FZCm=?e7Ur#;N{d_#Ma zc(xOfc^XV3?T` z^8lPdA9uk?%|HOx!{w{GY({>?-)WX)udVinQBuJ~-Aq+-TE0g8FWU<*3hOIocmxuH zc*@+h<^5*+6BsDZrITO2a+S-(7>MnW-K#k+nmi9J6f*1nEh*)GR#-~CZ4bI!4p8G5 zIJ;smm}jXC(N&_F)W}iU*eL3&{fmIg*KbxLggMMW!-IDvJCu@Ej-XHWD>mBBo{AJD z`HZ)`RV@W|Uj>q^>CFXInzG2by!tg}fWr!;0HbUee?*MCDON8*bnD5ETjwupKX7)6 zcgIN^Kg257lWVs*(#;|(Qi3`kjw#5Xj2k|!af8pXddcqu@C#H8y1 zmyn+hDdi@Rw=nI@(jS`l%y=|U_^!8=l+DW58&AJ7jvC|?>xI8kU!YXMo>bPO#hQy{01iw%mYQX4JE7eefLeZ`P|Vl^6%p*eYwhxm6o2qeKM=jI3FX zKI&5m`IaBA%sUI+R;|(F(`h~p!8DJ_@d`Gs?Dz~Zulc`DTxG1dRn!L+VB?HrE3$Ma zkTS@?+BkUj*o0o*HbFAy*^SGc9=!bE(jEhBmga! zDjoq29>mC7G5}ex#AQm@E&;VU9a0kPVn1FGJk@jIP%7L`E@!f=T50eVBu|qVMb9{u zse0G9Inh0oPW2tmr?xXnqn&BeK_<2K>X{8Lo;y!l1tE1-Nq65a|Eex7Ne}*oh?IK0 za2z}KcWxnxiW{2rNs~6$V?H(?EFab$n+|yAr3jyi{XG}oMMCLC#*<8FyE%j&`sD)n z6Tbg^l}Sz!{7=jz=qsYA#0f-2S-$@#YS90bEn!;mI+Z&?L`jF~I}8L0@|5@Uf9&Z- zs8-@4@bN<#|Iva8xk|cJjD&e58NUA#96t!e`H$r9&YmEltVfillColor = new ChartColor(); } + /** + * Chart Major Gridlines as. + * + * @var ?GridLines + */ + private $majorGridlines; + + /** + * Chart Minor Gridlines as. + * + * @var ?GridLines + */ + private $minorGridlines; + /** * Axis Number. * @@ -235,4 +249,28 @@ class Axis extends Properties { return $this->crossBetween; } + + public function getMajorGridlines(): ?GridLines + { + return $this->majorGridlines; + } + + public function getMinorGridlines(): ?GridLines + { + return $this->minorGridlines; + } + + public function setMajorGridlines(?GridLines $gridlines): self + { + $this->majorGridlines = $gridlines; + + return $this; + } + + public function setMinorGridlines(?GridLines $gridlines): self + { + $this->minorGridlines = $gridlines; + + return $this; + } } diff --git a/src/PhpSpreadsheet/Chart/Chart.php b/src/PhpSpreadsheet/Chart/Chart.php index ec6342c5..3f4dd2a7 100644 --- a/src/PhpSpreadsheet/Chart/Chart.php +++ b/src/PhpSpreadsheet/Chart/Chart.php @@ -17,42 +17,42 @@ class Chart /** * Worksheet. * - * @var Worksheet + * @var ?Worksheet */ private $worksheet; /** * Chart Title. * - * @var Title + * @var ?Title */ private $title; /** * Chart Legend. * - * @var Legend + * @var ?Legend */ private $legend; /** * X-Axis Label. * - * @var Title + * @var ?Title */ private $xAxisLabel; /** * Y-Axis Label. * - * @var Title + * @var ?Title */ private $yAxisLabel; /** * Chart Plot Area. * - * @var PlotArea + * @var ?PlotArea */ private $plotArea; @@ -84,20 +84,6 @@ class Chart */ private $xAxis; - /** - * Chart Major Gridlines as. - * - * @var GridLines - */ - private $majorGridlines; - - /** - * Chart Minor Gridlines as. - * - * @var GridLines - */ - private $minorGridlines; - /** * Top-Left Cell Position. * @@ -157,6 +143,7 @@ class Chart /** * Create a new Chart. + * majorGridlines and minorGridlines are deprecated, moved to Axis. * * @param mixed $name * @param mixed $plotVisibleOnly @@ -172,10 +159,14 @@ class Chart $this->plotArea = $plotArea; $this->plotVisibleOnly = $plotVisibleOnly; $this->displayBlanksAs = $displayBlanksAs; - $this->xAxis = $xAxis; - $this->yAxis = $yAxis; - $this->majorGridlines = $majorGridlines; - $this->minorGridlines = $minorGridlines; + $this->xAxis = $xAxis ?? new Axis(); + $this->yAxis = $yAxis ?? new Axis(); + if ($majorGridlines !== null) { + $this->yAxis->setMajorGridlines($majorGridlines); + } + if ($minorGridlines !== null) { + $this->yAxis->setMinorGridlines($minorGridlines); + } } /** @@ -190,10 +181,8 @@ class Chart /** * Get Worksheet. - * - * @return Worksheet */ - public function getWorksheet() + public function getWorksheet(): ?Worksheet { return $this->worksheet; } @@ -210,12 +199,7 @@ class Chart return $this; } - /** - * Get Title. - * - * @return Title - */ - public function getTitle() + public function getTitle(): ?Title { return $this->title; } @@ -232,12 +216,7 @@ class Chart return $this; } - /** - * Get Legend. - * - * @return Legend - */ - public function getLegend() + public function getLegend(): ?Legend { return $this->legend; } @@ -254,12 +233,7 @@ class Chart return $this; } - /** - * Get X-Axis Label. - * - * @return Title - */ - public function getXAxisLabel() + public function getXAxisLabel(): ?Title { return $this->xAxisLabel; } @@ -276,12 +250,7 @@ class Chart return $this; } - /** - * Get Y-Axis Label. - * - * @return Title - */ - public function getYAxisLabel() + public function getYAxisLabel(): ?Title { return $this->yAxisLabel; } @@ -298,16 +267,21 @@ class Chart return $this; } - /** - * Get Plot Area. - * - * @return PlotArea - */ - public function getPlotArea() + public function getPlotArea(): ?PlotArea { return $this->plotArea; } + /** + * Set Plot Area. + */ + public function setPlotArea(PlotArea $plotArea): self + { + $this->plotArea = $plotArea; + + return $this; + } + /** * Get Plot Visible Only. * @@ -356,62 +330,58 @@ class Chart return $this; } - /** - * Get yAxis. - * - * @return Axis - */ - public function getChartAxisY() + public function getChartAxisY(): Axis { - if ($this->yAxis !== null) { - return $this->yAxis; - } - $this->yAxis = new Axis(); - return $this->yAxis; } /** - * Get xAxis. - * - * @return Axis + * Set yAxis. */ - public function getChartAxisX() + public function setChartAxisY(?Axis $axis): self { - if ($this->xAxis !== null) { - return $this->xAxis; - } - $this->xAxis = new Axis(); + $this->yAxis = $axis ?? new Axis(); + return $this; + } + + public function getChartAxisX(): Axis + { return $this->xAxis; } + /** + * Set xAxis. + */ + public function setChartAxisX(?Axis $axis): self + { + $this->xAxis = $axis ?? new Axis(); + + return $this; + } + /** * Get Major Gridlines. * - * @return GridLines + * @Deprecated 1.24.0 Use Axis->getMajorGridlines + * + * @codeCoverageIgnore */ - public function getMajorGridlines() + public function getMajorGridlines(): ?GridLines { - if ($this->majorGridlines !== null) { - return $this->majorGridlines; - } - - return new GridLines(); + return $this->yAxis->getMajorGridLines(); } /** * Get Minor Gridlines. * - * @return GridLines + * @Deprecated 1.24.0 Use Axis->getMinorGridlines + * + * @codeCoverageIgnore */ - public function getMinorGridlines() + public function getMinorGridlines(): ?GridLines { - if ($this->minorGridlines !== null) { - return $this->minorGridlines; - } - - return new GridLines(); + return $this->yAxis->getMinorGridLines(); } /** @@ -668,17 +638,21 @@ class Chart public function refresh(): void { - if ($this->worksheet !== null) { + if ($this->worksheet !== null && $this->plotArea !== null) { $this->plotArea->refresh($this->worksheet); } } /** * Render the chart to given file (or stream). + * Unable to cover code until a usable current version of JpGraph + * is made available through Composer. * * @param string $outputDestination Name of the file render to * * @return bool true on success + * + * @codeCoverageIgnore */ public function render($outputDestination = null) { @@ -696,7 +670,7 @@ class Chart $renderer = new $libraryName($this); - return $renderer->render($outputDestination); + return $renderer->render($outputDestination); // @phpstan-ignore-line } public function getRotX(): ?int diff --git a/src/PhpSpreadsheet/Chart/DataSeries.php b/src/PhpSpreadsheet/Chart/DataSeries.php index d27db33e..548145e7 100644 --- a/src/PhpSpreadsheet/Chart/DataSeries.php +++ b/src/PhpSpreadsheet/Chart/DataSeries.php @@ -134,12 +134,12 @@ class DataSeries $this->plotOrder = $plotOrder; $keys = array_keys($plotValues); $this->plotValues = $plotValues; - if ((count($plotLabel) == 0) || ($plotLabel[$keys[0]] === null)) { + if (!isset($plotLabel[$keys[0]])) { $plotLabel[$keys[0]] = new DataSeriesValues(); } $this->plotLabel = $plotLabel; - if ((count($plotCategory) == 0) || ($plotCategory[$keys[0]] === null)) { + if (!isset($plotCategory[$keys[0]])) { $plotCategory[$keys[0]] = new DataSeriesValues(); } $this->plotCategory = $plotCategory; diff --git a/src/PhpSpreadsheet/Chart/Legend.php b/src/PhpSpreadsheet/Chart/Legend.php index 2f003cd8..fc16017c 100644 --- a/src/PhpSpreadsheet/Chart/Legend.php +++ b/src/PhpSpreadsheet/Chart/Legend.php @@ -18,7 +18,7 @@ class Legend const POSITION_TOP = 't'; const POSITION_TOPRIGHT = 'tr'; - private static $positionXLref = [ + const POSITION_XLREF = [ self::XL_LEGEND_POSITION_BOTTOM => self::POSITION_BOTTOM, self::XL_LEGEND_POSITION_CORNER => self::POSITION_TOPRIGHT, self::XL_LEGEND_POSITION_CUSTOM => '??', @@ -44,7 +44,7 @@ class Legend /** * Legend Layout. * - * @var Layout + * @var ?Layout */ private $layout; @@ -80,7 +80,7 @@ class Legend */ public function setPosition($position) { - if (!in_array($position, self::$positionXLref)) { + if (!in_array($position, self::POSITION_XLREF)) { return false; } @@ -92,11 +92,11 @@ class Legend /** * Get legend position as an Excel internal numeric value. * - * @return int + * @return false|int */ public function getPositionXL() { - return array_search($this->position, self::$positionXLref); + return array_search($this->position, self::POSITION_XLREF); } /** @@ -108,11 +108,11 @@ class Legend */ public function setPositionXL($positionXL) { - if (!isset(self::$positionXLref[$positionXL])) { + if (!isset(self::POSITION_XLREF[$positionXL])) { return false; } - $this->position = self::$positionXLref[$positionXL]; + $this->position = self::POSITION_XLREF[$positionXL]; return true; } @@ -140,7 +140,7 @@ class Legend /** * Get Layout. * - * @return Layout + * @return ?Layout */ public function getLayout() { diff --git a/src/PhpSpreadsheet/Chart/PlotArea.php b/src/PhpSpreadsheet/Chart/PlotArea.php index ecb7b6c9..4bd49ece 100644 --- a/src/PhpSpreadsheet/Chart/PlotArea.php +++ b/src/PhpSpreadsheet/Chart/PlotArea.php @@ -9,7 +9,7 @@ class PlotArea /** * PlotArea Layout. * - * @var Layout + * @var ?Layout */ private $layout; @@ -31,12 +31,7 @@ class PlotArea $this->plotSeries = $plotSeries; } - /** - * Get Layout. - * - * @return Layout - */ - public function getLayout() + public function getLayout(): ?Layout { return $this->layout; } diff --git a/src/PhpSpreadsheet/Chart/Properties.php b/src/PhpSpreadsheet/Chart/Properties.php index 2ee6572a..f737ca08 100644 --- a/src/PhpSpreadsheet/Chart/Properties.php +++ b/src/PhpSpreadsheet/Chart/Properties.php @@ -164,7 +164,7 @@ abstract class Properties * * @return $this */ - protected function activateObject() + public function activateObject() { $this->objectState = true; @@ -782,9 +782,9 @@ abstract class Properties * * @param string $value * @param ?int $alpha - * @param string $colorType + * @param ?string $colorType */ - public function setLineColorProperties($value, $alpha = null, $colorType = ChartColor::EXCEL_COLOR_TYPE_STANDARD): void + public function setLineColorProperties($value, $alpha = null, $colorType = null): void { $this->activateObject(); $this->lineColor->setColorPropertiesArray( @@ -873,6 +873,42 @@ abstract class Properties } } + public function getLineStyleArray(): array + { + return $this->lineStyleProperties; + } + + public function setLineStyleArray(array $lineStyleProperties = []): self + { + $this->activateObject(); + $this->lineStyleProperties['width'] = $lineStyleProperties['width'] ?? null; + $this->lineStyleProperties['compound'] = $lineStyleProperties['compound'] ?? ''; + $this->lineStyleProperties['dash'] = $lineStyleProperties['dash'] ?? ''; + $this->lineStyleProperties['cap'] = $lineStyleProperties['cap'] ?? ''; + $this->lineStyleProperties['join'] = $lineStyleProperties['join'] ?? ''; + $this->lineStyleProperties['arrow']['head']['type'] = $lineStyleProperties['arrow']['head']['type'] ?? ''; + $this->lineStyleProperties['arrow']['head']['size'] = $lineStyleProperties['arrow']['head']['size'] ?? ''; + $this->lineStyleProperties['arrow']['head']['w'] = $lineStyleProperties['arrow']['head']['w'] ?? ''; + $this->lineStyleProperties['arrow']['head']['len'] = $lineStyleProperties['arrow']['head']['len'] ?? ''; + $this->lineStyleProperties['arrow']['end']['type'] = $lineStyleProperties['arrow']['end']['type'] ?? ''; + $this->lineStyleProperties['arrow']['end']['size'] = $lineStyleProperties['arrow']['end']['size'] ?? ''; + $this->lineStyleProperties['arrow']['end']['w'] = $lineStyleProperties['arrow']['end']['w'] ?? ''; + $this->lineStyleProperties['arrow']['end']['len'] = $lineStyleProperties['arrow']['end']['len'] ?? ''; + + return $this; + } + + /** + * @param mixed $value + */ + public function setLineStyleProperty(string $propertyName, $value): self + { + $this->activateObject(); + $this->lineStyleProperties[$propertyName] = $value; + + return $this; + } + /** * Get Line Style Property. * diff --git a/src/PhpSpreadsheet/Chart/Title.php b/src/PhpSpreadsheet/Chart/Title.php index 090c4f3f..9b0540d8 100644 --- a/src/PhpSpreadsheet/Chart/Title.php +++ b/src/PhpSpreadsheet/Chart/Title.php @@ -16,7 +16,7 @@ class Title /** * Title Layout. * - * @var Layout + * @var ?Layout */ private $layout; @@ -78,12 +78,7 @@ class Title return $this; } - /** - * Get Layout. - * - * @return Layout - */ - public function getLayout() + public function getLayout(): ?Layout { return $this->layout; } diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php index fd156f13..cf77a7f2 100644 --- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php @@ -72,7 +72,6 @@ class Chart $rotX = $rotY = $rAngAx = $perspective = null; $xAxis = new Axis(); $yAxis = new Axis(); - $majorGridlines = $minorGridlines = null; foreach ($chartElementsC as $chartElementKey => $chartElement) { switch ($chartElementKey) { case 'chart': @@ -110,6 +109,23 @@ class Chart $xAxis->setFillParameters($axisColorArray['value'], $axisColorArray['alpha'], $axisColorArray['type']); } } + if (isset($chartDetail->majorGridlines)) { + $majorGridlines = new GridLines(); + if (isset($chartDetail->majorGridlines->spPr)) { + $this->readEffects($chartDetail->majorGridlines, $majorGridlines); + $this->readLineStyle($chartDetail->majorGridlines, $majorGridlines); + } + $xAxis->setMajorGridlines($majorGridlines); + } + if (isset($chartDetail->minorGridlines)) { + $minorGridlines = new GridLines(); + $minorGridlines->activateObject(); + if (isset($chartDetail->minorGridlines->spPr)) { + $this->readEffects($chartDetail->minorGridlines, $minorGridlines); + $this->readLineStyle($chartDetail->minorGridlines, $minorGridlines); + } + $xAxis->setMinorGridlines($minorGridlines); + } $this->setAxisProperties($chartDetail, $xAxis); break; @@ -168,19 +184,22 @@ class Chart $whichAxis->setFillParameters($axisColorArray['value'], $axisColorArray['alpha'], $axisColorArray['type']); } } - if (isset($chartDetail->majorGridlines)) { + if ($whichAxis !== null && isset($chartDetail->majorGridlines)) { $majorGridlines = new GridLines(); if (isset($chartDetail->majorGridlines->spPr)) { $this->readEffects($chartDetail->majorGridlines, $majorGridlines); $this->readLineStyle($chartDetail->majorGridlines, $majorGridlines); } + $whichAxis->setMajorGridlines($majorGridlines); } - if (isset($chartDetail->minorGridlines)) { + if ($whichAxis !== null && isset($chartDetail->minorGridlines)) { $minorGridlines = new GridLines(); + $minorGridlines->activateObject(); if (isset($chartDetail->minorGridlines->spPr)) { $this->readEffects($chartDetail->minorGridlines, $minorGridlines); $this->readLineStyle($chartDetail->minorGridlines, $minorGridlines); } + $whichAxis->setMinorGridlines($minorGridlines); } $this->setAxisProperties($chartDetail, $whichAxis); @@ -304,7 +323,7 @@ class Chart } } } - $chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, (string) $dispBlanksAs, $XaxisLabel, $YaxisLabel, $xAxis, $yAxis, $majorGridlines, $minorGridlines); + $chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, (string) $dispBlanksAs, $XaxisLabel, $YaxisLabel, $xAxis, $yAxis); if (is_int($rotX)) { $chart->setRotX($rotX); } diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php index 876e5f06..356b44e9 100644 --- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php +++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php @@ -6,7 +6,6 @@ use PhpOffice\PhpSpreadsheet\Chart\Axis; use PhpOffice\PhpSpreadsheet\Chart\ChartColor; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; -use PhpOffice\PhpSpreadsheet\Chart\GridLines; use PhpOffice\PhpSpreadsheet\Chart\Layout; use PhpOffice\PhpSpreadsheet\Chart\Legend; use PhpOffice\PhpSpreadsheet\Chart\PlotArea; @@ -99,7 +98,7 @@ class Chart extends WriterPart } $objWriter->endElement(); // view3D - $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart->getXAxisLabel(), $chart->getYAxisLabel(), $chart->getChartAxisX(), $chart->getChartAxisY(), $chart->getMajorGridlines(), $chart->getMinorGridlines()); + $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart->getXAxisLabel(), $chart->getYAxisLabel(), $chart->getChartAxisX(), $chart->getChartAxisY()); $this->writeLegend($objWriter, $chart->getLegend()); @@ -218,11 +217,13 @@ class Chart extends WriterPart /** * 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): void { if ($plotArea === null) { return; } + $majorGridlines = ($yAxis === null) ? null : $yAxis->getMajorGridlines(); + $minorGridlines = ($yAxis === null) ? null : $yAxis->getMinorGridlines(); $id1 = $id2 = $id3 = '0'; $this->seriesIndex = 0; @@ -345,12 +346,12 @@ class Chart extends WriterPart 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 ?? new Axis(), $majorGridlines, $minorGridlines); + $this->writeValueAxis($objWriter, $xAxisLabel, $chartType, $id2, $id1, $catIsMultiLevelSeries, $xAxis ?? new Axis()); } else { $this->writeCategoryAxis($objWriter, $xAxisLabel, $id1, $id2, $catIsMultiLevelSeries, $xAxis ?? new Axis()); } - $this->writeValueAxis($objWriter, $yAxisLabel, $chartType, $id1, $id2, $valIsMultiLevelSeries, $yAxis ?? new Axis(), $majorGridlines, $minorGridlines); + $this->writeValueAxis($objWriter, $yAxisLabel, $chartType, $id1, $id2, $valIsMultiLevelSeries, $yAxis ?? new Axis()); if ($chartType === DataSeries::TYPE_SURFACECHART_3D || $chartType === DataSeries::TYPE_SURFACECHART) { $this->writeSerAxis($objWriter, $id2, $id3); } @@ -448,6 +449,8 @@ class Chart extends WriterPart } else { $objWriter->startElement('c:catAx'); } + $majorGridlines = $yAxis->getMajorGridlines(); + $minorGridlines = $yAxis->getMinorGridlines(); if ($id1 !== '0') { $objWriter->startElement('c:axId'); @@ -481,6 +484,24 @@ class Chart extends WriterPart $objWriter->writeAttribute('val', 'b'); $objWriter->endElement(); + 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 !== null && $minorGridlines->getObjectState()) { + $objWriter->startElement('c:minorGridlines'); + $objWriter->startElement('c:spPr'); + $this->writeLineStyles($objWriter, $minorGridlines); + $this->writeEffects($objWriter, $minorGridlines); + $objWriter->endElement(); //end spPr + $objWriter->endElement(); //end minorGridLines + } + if ($xAxisLabel !== null) { $objWriter->startElement('c:title'); $objWriter->startElement('c:tx'); @@ -594,9 +615,11 @@ class Chart extends WriterPart * @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): void { $objWriter->startElement('c:valAx'); + $majorGridlines = $xAxis->getMajorGridlines(); + $minorGridlines = $xAxis->getMinorGridlines(); if ($id2 !== '0') { $objWriter->startElement('c:axId'); diff --git a/tests/PhpSpreadsheetTests/Chart/BarChartCustomColorsTest.php b/tests/PhpSpreadsheetTests/Chart/BarChartCustomColorsTest.php index 824e9600..72c541fb 100644 --- a/tests/PhpSpreadsheetTests/Chart/BarChartCustomColorsTest.php +++ b/tests/PhpSpreadsheetTests/Chart/BarChartCustomColorsTest.php @@ -140,6 +140,7 @@ class BarChartCustomColorsTest extends AbstractFunctional $chart2 = $charts2[0]; self::assertNotNull($chart2); $plotArea2 = $chart2->getPlotArea(); + self::assertNotNull($plotArea2); $dataSeries2 = $plotArea2->getPlotGroup(); self::assertCount(1, $dataSeries2); $plotValues = $dataSeries2[0]->getPlotValues(); diff --git a/tests/PhpSpreadsheetTests/Chart/ChartMethodTest.php b/tests/PhpSpreadsheetTests/Chart/ChartMethodTest.php new file mode 100644 index 00000000..027ddc53 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Chart/ChartMethodTest.php @@ -0,0 +1,142 @@ +getActiveSheet(); + $worksheet->fromArray( + [ + ['', 2010, 2011, 2012], + ['Q1', 12, 15, 21], + ['Q2', 56, 73, 86], + ['Q3', 52, 61, 69], + ['Q4', 30, 32, 0], + ] + ); + + // 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), // 2010 + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011 + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012 + ]; + // Set the X-Axis Labels + // Datatype + // Cell reference for data + // Format Code + // Number of datapoints in series + // Data values + // Data Marker + $xAxisTickValues = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4 + ]; + // 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 + $dataSeriesValues = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4), + ]; + + // Build the dataseries + $series = new DataSeries( + DataSeries::TYPE_LINECHART, // plotType + DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping + range(0, count($dataSeriesValues) - 1), // plotOrder + $dataSeriesLabels, // plotLabel + $xAxisTickValues, // plotCategory + $dataSeriesValues // plotValues + ); + + // Set the series in the plot area + $plotArea = new PlotArea(null, [$series]); + $title = new Title('Method vs Constructor test'); + $legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false); + $xAxis = new Axis(); + $yAxis = new Axis(); + $xAxisLabel = new Title('X-Axis label'); + $yAxisLabel = new Title('Y-Axis label'); + $chart1 = new Chart( + 'chart1', // name + $title, // title + $legend, // legend + $plotArea, // plotArea + true, // plotVisibleOnly + DataSeries::EMPTY_AS_GAP, // displayBlanksAs + $xAxisLabel, // xAxisLabel + $yAxisLabel, // yAxisLabel + $xAxis, // xAxis + $yAxis // yAxis + ); + $chart2 = new Chart('chart1'); + $chart2 + ->setLegend($legend) + ->setPlotArea($plotArea) + ->setPlotVisibleOnly(true) + ->setDisplayBlanksAs(DataSeries::EMPTY_AS_GAP) + ->setChartAxisX($xAxis) + ->setChartAxisY($yAxis) + ->setXAxisLabel($xAxisLabel) + ->setYAxisLabel($yAxisLabel) + ->setTitle($title); + self::assertEquals($chart1, $chart2); + $spreadsheet->disconnectWorksheets(); + } + + public function testPositions(): void + { + $chart = new Chart('chart1'); + $chart->setTopLeftPosition('B3', 2, 4); + self::assertSame('B3', $chart->getTopLeftCell()); + self::assertEquals(['X' => 2, 'Y' => 4], $chart->getTopLeftOffset()); + self::assertEquals(2, $chart->getTopLeftXOffset()); + self::assertEquals(4, $chart->getTopLeftYOffset()); + $chart->setTopLeftCell('B5'); + self::assertSame('B5', $chart->getTopLeftCell()); + self::assertEquals(2, $chart->getTopLeftXOffset()); + self::assertEquals(4, $chart->getTopLeftYOffset()); + $chart->setTopLeftOffset(6, 8); + self::assertSame('B5', $chart->getTopLeftCell()); + self::assertEquals(6, $chart->getTopLeftXOffset()); + self::assertEquals(8, $chart->getTopLeftYOffset()); + + $chart->setbottomRightPosition('H9', 3, 5); + self::assertSame('H9', $chart->getBottomRightCell()); + self::assertEquals(['X' => 3, 'Y' => 5], $chart->getBottomRightOffset()); + self::assertEquals(3, $chart->getBottomRightXOffset()); + self::assertEquals(5, $chart->getBottomRightYOffset()); + $chart->setbottomRightCell('H11'); + self::assertSame('H11', $chart->getBottomRightCell()); + self::assertEquals(3, $chart->getBottomRightXOffset()); + self::assertEquals(5, $chart->getBottomRightYOffset()); + $chart->setbottomRightOffset(7, 9); + self::assertSame('H11', $chart->getBottomRightCell()); + self::assertEquals(7, $chart->getBottomRightXOffset()); + self::assertEquals(9, $chart->getBottomRightYOffset()); + } +} diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php index b8041623..f0c84bf0 100644 --- a/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php +++ b/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php @@ -46,6 +46,7 @@ class Charts32ColoredAxisLabelTest extends AbstractFunctional self::assertNotNull($chart); $xAxisLabel = $chart->getXAxisLabel(); + self::assertNotNull($xAxisLabel); $captionArray = $xAxisLabel->getCaption(); self::assertIsArray($captionArray); self::assertCount(1, $captionArray); @@ -64,6 +65,7 @@ class Charts32ColoredAxisLabelTest extends AbstractFunctional self::assertSame('srgbClr', $chartColor->getType()); $yAxisLabel = $chart->getYAxisLabel(); + self::assertNotNull($yAxisLabel); $captionArray = $yAxisLabel->getCaption(); self::assertIsArray($captionArray); self::assertCount(1, $captionArray); diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32DsvGlowTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32DsvGlowTest.php index da2ad9f6..26ef34ee 100644 --- a/tests/PhpSpreadsheetTests/Chart/Charts32DsvGlowTest.php +++ b/tests/PhpSpreadsheetTests/Chart/Charts32DsvGlowTest.php @@ -42,6 +42,7 @@ class Charts32DsvGlowTest extends AbstractFunctional self::assertNotNull($chart); $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $dataSeriesArray = $plotArea->getPlotGroup(); self::assertCount(1, $dataSeriesArray); $dataSeries = $dataSeriesArray[0]; @@ -53,6 +54,24 @@ class Charts32DsvGlowTest extends AbstractFunctional self::assertSame('accent2', $dataSeriesValues->getGlowProperty(['color', 'value'])); self::assertSame(60, $dataSeriesValues->getGlowProperty(['color', 'alpha'])); + $yAxis = $chart->getChartAxisY(); + $majorGridlines = $yAxis->getMajorGridlines(); + self::assertNotNull($majorGridlines); + self::assertSame('triangle', $majorGridlines->getLineStyleProperty(['arrow', 'head', 'type'])); + self::assertSame('triangle', $majorGridlines->getLineStyleProperty(['arrow', 'end', 'type'])); + $minorGridlines = $yAxis->getMinorGridlines(); + self::assertNotNull($minorGridlines); + self::assertSame('sysDot', $minorGridlines->getLineStyleProperty('dash')); + self::assertSame('FFC000', $minorGridlines->getLineColor()->getValue()); + + $xAxis = $chart->getChartAxisX(); + $majorGridlines = $xAxis->getMajorGridlines(); + $minorGridlines = $xAxis->getMinorGridlines(); + self::assertNotNull($majorGridlines); + self::assertSame('7030A0', $majorGridlines->getLineColor()->getValue()); + self::assertNotNull($minorGridlines); + self::assertFalse($minorGridlines->getLineColor()->isUsable()); + $reloadedSpreadsheet->disconnectWorksheets(); } } diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32DsvLabelsTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32DsvLabelsTest.php index 74655a60..b6490776 100644 --- a/tests/PhpSpreadsheetTests/Chart/Charts32DsvLabelsTest.php +++ b/tests/PhpSpreadsheetTests/Chart/Charts32DsvLabelsTest.php @@ -42,6 +42,7 @@ class Charts32DsvLabelsTest extends AbstractFunctional self::assertNotNull($chart); $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $dataSeriesArray = $plotArea->getPlotGroup(); self::assertCount(1, $dataSeriesArray); $dataSeries = $dataSeriesArray[0]; diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php index 38884eaf..b655afc4 100644 --- a/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php +++ b/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php @@ -46,6 +46,7 @@ class Charts32ScatterTest extends AbstractFunctional $chart = $charts[0]; self::assertNotNull($chart); $title = $chart->getTitle(); + self::assertNotNull($title); $captionArray = $title->getCaption(); self::assertIsArray($captionArray); self::assertCount(1, $captionArray); @@ -72,6 +73,7 @@ class Charts32ScatterTest extends AbstractFunctional self::assertSame('srgbClr', $chartColor->getType()); $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $plotSeries = $plotArea->getPlotGroup(); self::assertCount(1, $plotSeries); $dataSeries = $plotSeries[0]; @@ -121,6 +123,7 @@ class Charts32ScatterTest extends AbstractFunctional $chart = $charts[0]; self::assertNotNull($chart); $title = $chart->getTitle(); + self::assertNotNull($title); $captionArray = $title->getCaption(); self::assertIsArray($captionArray); self::assertCount(1, $captionArray); @@ -182,6 +185,7 @@ class Charts32ScatterTest extends AbstractFunctional self::assertSame('srgbClr', $chartColor->getType()); $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $plotSeries = $plotArea->getPlotGroup(); self::assertCount(1, $plotSeries); $dataSeries = $plotSeries[0]; @@ -231,6 +235,7 @@ class Charts32ScatterTest extends AbstractFunctional $chart = $charts[0]; self::assertNotNull($chart); $title = $chart->getTitle(); + self::assertNotNull($title); $captionArray = $title->getCaption(); self::assertIsArray($captionArray); self::assertCount(1, $captionArray); @@ -257,6 +262,7 @@ class Charts32ScatterTest extends AbstractFunctional self::assertSame('srgbClr', $chartColor->getType()); $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $plotSeries = $plotArea->getPlotGroup(); self::assertCount(1, $plotSeries); $dataSeries = $plotSeries[0]; @@ -305,6 +311,7 @@ class Charts32ScatterTest extends AbstractFunctional $chart = $charts[0]; self::assertNotNull($chart); $title = $chart->getTitle(); + self::assertNotNull($title); $captionArray = $title->getCaption(); self::assertIsArray($captionArray); self::assertCount(1, $captionArray); @@ -334,6 +341,7 @@ class Charts32ScatterTest extends AbstractFunctional } $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $plotSeries = $plotArea->getPlotGroup(); self::assertCount(1, $plotSeries); $dataSeries = $plotSeries[0]; @@ -384,6 +392,7 @@ class Charts32ScatterTest extends AbstractFunctional self::assertNotNull($chart); $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $plotSeries = $plotArea->getPlotGroup(); self::assertCount(1, $plotSeries); $dataSeries = $plotSeries[0]; diff --git a/tests/PhpSpreadsheetTests/Chart/ChartsOpenpyxlTest.php b/tests/PhpSpreadsheetTests/Chart/ChartsOpenpyxlTest.php index 7fcc2e90..e6f574fd 100644 --- a/tests/PhpSpreadsheetTests/Chart/ChartsOpenpyxlTest.php +++ b/tests/PhpSpreadsheetTests/Chart/ChartsOpenpyxlTest.php @@ -27,6 +27,7 @@ class ChartsOpenpyxlTest extends TestCase self::assertTrue($chart->getOneCellAnchor()); $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); $plotSeries = $plotArea->getPlotGroup(); self::assertCount(1, $plotSeries); $dataSeries = $plotSeries[0]; diff --git a/tests/PhpSpreadsheetTests/Chart/DataSeriesValues2Test.php b/tests/PhpSpreadsheetTests/Chart/DataSeriesValues2Test.php index a27397f9..bba1c1f1 100644 --- a/tests/PhpSpreadsheetTests/Chart/DataSeriesValues2Test.php +++ b/tests/PhpSpreadsheetTests/Chart/DataSeriesValues2Test.php @@ -120,8 +120,10 @@ class DataSeriesValues2Test extends AbstractFunctional // Add the chart to the worksheet $worksheet->addChart($chart); - self::assertSame(1, $chart->getPlotArea()->getPlotGroupCount()); - $plotValues = $chart->getPlotArea()->getPlotGroup()[0]->getPlotValues(); + $plotArea = $chart->getPlotArea(); + self::assertNotNull($plotArea); + self::assertSame(1, $plotArea->getPlotGroupCount()); + $plotValues = $plotArea->getPlotGroup()[0]->getPlotValues(); self::assertCount(3, $plotValues); self::assertSame([], $plotValues[1]->getDataValues()); self::assertNull($plotValues[1]->getDataValue()); @@ -138,20 +140,27 @@ class DataSeriesValues2Test extends AbstractFunctional self::assertCount(1, $charts2); $chart2 = $charts2[0]; self::assertNotNull($chart2); - $plotValues2 = $chart2->getPlotArea()->getPlotGroup()[0]->getPlotValues(); + $plotArea2 = $chart2->getPlotArea(); + self::assertNotNull($plotArea2); + $plotGroup2 = $plotArea2->getPlotGroup()[0]; + self::assertNotNull($plotGroup2); + $plotValues2 = $plotGroup2->getPlotValues(); self::assertCount(3, $plotValues2); self::assertSame([15.0, 73.0, 61.0, 32.0], $plotValues2[1]->getDataValues()); self::assertSame([15.0, 73.0, 61.0, 32.0], $plotValues2[1]->getDataValue()); - $labels2 = $chart->getPlotArea()->getPlotGroup()[0]->getPlotLabels(); + $labels2 = $plotGroup2->getPlotLabels(); self::assertCount(3, $labels2); - self::assertSame(2010, $labels2[0]->getDataValue()); - $dataSeries = $chart->getPlotArea()->getPlotGroup()[0]; + self::assertEquals(2010, $labels2[0]->getDataValue()); + $dataSeries = $plotArea2->getPlotGroup()[0]; self::assertFalse($dataSeries->getPlotValuesByIndex(99)); self::assertNotFalse($dataSeries->getPlotValuesByIndex(0)); - self::assertSame([12, 56, 52, 30], $dataSeries->getPlotValuesByIndex(0)->getDataValues()); + self::assertEquals([12, 56, 52, 30], $dataSeries->getPlotValuesByIndex(0)->getDataValues()); self::assertSame(DataSeries::TYPE_AREACHART, $dataSeries->getPlotType()); self::assertSame(DataSeries::GROUPING_PERCENT_STACKED, $dataSeries->getPlotGrouping()); - self::assertTrue($dataSeries->getSmoothLine()); + // SmoothLine written out for DataSeries only for LineChart. + // Original test was wrong - used $chart rather than $chart2 + // to retrieve data which was read in. + //self::assertTrue($dataSeries->getSmoothLine()); $reloadedSpreadsheet->disconnectWorksheets(); } diff --git a/tests/PhpSpreadsheetTests/Chart/GridlinesLineStyleTest.php b/tests/PhpSpreadsheetTests/Chart/GridlinesLineStyleTest.php index 997413c5..e13a5840 100644 --- a/tests/PhpSpreadsheetTests/Chart/GridlinesLineStyleTest.php +++ b/tests/PhpSpreadsheetTests/Chart/GridlinesLineStyleTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Chart; +use PhpOffice\PhpSpreadsheet\Chart\Axis; use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; @@ -138,6 +139,202 @@ class GridlinesLineStyleTest extends AbstractFunctional self::assertSame(30, $minorGridlines->getLineColorProperty('alpha')); self::assertSame('srgbClr', $minorGridlines->getLineColorProperty('type')); + // Create the chart + $yAxis = new Axis(); + $yAxis->setMajorGridlines($majorGridlines); + $yAxis->setMinorGridlines($minorGridlines); + $chart = new Chart( + 'chart1', // name + $title, // title + $legend, // legend + $plotArea, // plotArea + true, // plotVisibleOnly + DataSeries::EMPTY_AS_GAP, // displayBlanksAs + null, // xAxisLabel + $yAxisLabel, // yAxisLabel + null, // xAxis + $yAxis // yAxis + ); + $yAxis2 = $chart->getChartAxisY(); + $majorGridlines2 = $yAxis2->getMajorGridlines(); + self::assertNotNull($majorGridlines2); + self::assertEquals($width, $majorGridlines2->getLineStyleProperty('width')); + self::assertEquals($compound, $majorGridlines2->getLineStyleProperty('compound')); + self::assertEquals($dash, $majorGridlines2->getLineStyleProperty('dash')); + self::assertEquals($cap, $majorGridlines2->getLineStyleProperty('cap')); + self::assertEquals($join, $majorGridlines2->getLineStyleProperty('join')); + self::assertEquals($headArrowType, $majorGridlines2->getLineStyleProperty(['arrow', 'head', 'type'])); + self::assertEquals($headArrowSize, $majorGridlines2->getLineStyleProperty(['arrow', 'head', 'size'])); + self::assertEquals($endArrowType, $majorGridlines2->getLineStyleProperty(['arrow', 'end', 'type'])); + self::assertEquals($endArrowSize, $majorGridlines2->getLineStyleProperty(['arrow', 'end', 'size'])); + self::assertEquals('sm', $majorGridlines2->getLineStyleProperty(['arrow', 'head', 'w'])); + self::assertEquals('med', $majorGridlines2->getLineStyleProperty(['arrow', 'head', 'len'])); + self::assertEquals('sm', $majorGridlines2->getLineStyleProperty(['arrow', 'end', 'w'])); + self::assertEquals('lg', $majorGridlines2->getLineStyleProperty(['arrow', 'end', 'len'])); + + $minorGridlines2 = $yAxis2->getMinorGridlines(); + self::assertNotNull($minorGridlines2); + self::assertSame('00FF00', $minorGridlines2->getLineColorProperty('value')); + self::assertSame(30, $minorGridlines2->getLineColorProperty('alpha')); + self::assertSame('srgbClr', $minorGridlines2->getLineColorProperty('type')); + + // Set the position where the chart should appear in the worksheet + $chart->setTopLeftPosition('A7'); + $chart->setBottomRightPosition('H20'); + + // Add the chart to the worksheet + $worksheet->addChart($chart); + + /** @var callable */ + $callableReader = [$this, 'readCharts']; + /** @var callable */ + $callableWriter = [$this, 'writeCharts']; + $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter); + $spreadsheet->disconnectWorksheets(); + + $sheet = $reloadedSpreadsheet->getActiveSheet(); + $charts2 = $sheet->getChartCollection(); + self::assertCount(1, $charts2); + $chart2 = $charts2[0]; + self::assertNotNull($chart2); + self::assertSame('A7', $chart2->getTopLeftCell()); + self::assertSame('H20', $chart2->getBottomRightCell()); + self::assertSame($sheet, $chart2->getWorksheet()); + $yAxis3 = $chart2->getChartAxisY(); + $majorGridlines3 = $yAxis3->getMajorGridlines(); + self::assertNotNull($majorGridlines3); + self::assertEquals($width, $majorGridlines3->getLineStyleProperty('width')); + self::assertEquals($compound, $majorGridlines3->getLineStyleProperty('compound')); + self::assertEquals($dash, $majorGridlines3->getLineStyleProperty('dash')); + self::assertEquals($cap, $majorGridlines3->getLineStyleProperty('cap')); + self::assertEquals($join, $majorGridlines3->getLineStyleProperty('join')); + self::assertEquals($headArrowType, $majorGridlines3->getLineStyleProperty(['arrow', 'head', 'type'])); + self::assertEquals($endArrowType, $majorGridlines3->getLineStyleProperty(['arrow', 'end', 'type'])); + self::assertEquals('sm', $majorGridlines3->getLineStyleProperty(['arrow', 'head', 'w'])); + self::assertEquals('med', $majorGridlines3->getLineStyleProperty(['arrow', 'head', 'len'])); + self::assertEquals('sm', $majorGridlines3->getLineStyleProperty(['arrow', 'end', 'w'])); + self::assertEquals('lg', $majorGridlines3->getLineStyleProperty(['arrow', 'end', 'len'])); + + $minorGridlines3 = $yAxis3->getMinorGridlines(); + self::assertNotNull($minorGridlines3); + self::assertSame('00FF00', $minorGridlines3->getLineColorProperty('value')); + self::assertSame(30, $minorGridlines3->getLineColorProperty('alpha')); + self::assertSame('srgbClr', $minorGridlines3->getLineColorProperty('type')); + + $reloadedSpreadsheet->disconnectWorksheets(); + } + + public function testLineStylesDeprecated(): void + { + $spreadsheet = new Spreadsheet(); + $worksheet = $spreadsheet->getActiveSheet(); + $worksheet->fromArray( + [ + ['', 2010, 2011, 2012], + ['Q1', 12, 15, 21], + ['Q2', 56, 73, 86], + ['Q3', 52, 61, 69], + ['Q4', 30, 32, 0], + ] + ); + + // 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), // 2010 + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011 + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012 + ]; + // Set the X-Axis Labels + // Datatype + // Cell reference for data + // Format Code + // Number of datapoints in series + // Data values + // Data Marker + $xAxisTickValues = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4 + ]; + // 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 + $dataSeriesValues = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4), + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4), + ]; + + // Build the dataseries + $series = new DataSeries( + DataSeries::TYPE_LINECHART, // plotType + DataSeries::GROUPING_PERCENT_STACKED, // plotGrouping + range(0, count($dataSeriesValues) - 1), // plotOrder + $dataSeriesLabels, // plotLabel + $xAxisTickValues, // plotCategory + $dataSeriesValues // plotValues + ); + + // 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 %age-Stacked Area Chart'); + $yAxisLabel = new Title('Value ($k)'); + $majorGridlines = new GridLines(); + $width = 2; + $compound = Properties::LINE_STYLE_COMPOUND_THICKTHIN; + $dash = Properties::LINE_STYLE_DASH_ROUND_DOT; + $cap = Properties::LINE_STYLE_CAP_ROUND; + $join = Properties::LINE_STYLE_JOIN_MITER; + $headArrowType = Properties::LINE_STYLE_ARROW_TYPE_DIAMOND; + $headArrowSize = (string) Properties::LINE_STYLE_ARROW_SIZE_2; + $endArrowType = Properties::LINE_STYLE_ARROW_TYPE_OVAL; + $endArrowSize = (string) Properties::LINE_STYLE_ARROW_SIZE_3; + $majorGridlines->setLineStyleProperties( + $width, + $compound, + $dash, + $cap, + $join, + $headArrowType, + $headArrowSize, + $endArrowType, + $endArrowSize + ); + $minorGridlines = new GridLines(); + $minorGridlines->setLineColorProperties('00FF00', 30, 'srgbClr'); + + self::assertEquals($width, $majorGridlines->getLineStyleProperty('width')); + self::assertEquals($compound, $majorGridlines->getLineStyleProperty('compound')); + self::assertEquals($dash, $majorGridlines->getLineStyleProperty('dash')); + self::assertEquals($cap, $majorGridlines->getLineStyleProperty('cap')); + self::assertEquals($join, $majorGridlines->getLineStyleProperty('join')); + self::assertEquals($headArrowType, $majorGridlines->getLineStyleProperty(['arrow', 'head', 'type'])); + self::assertEquals($headArrowSize, $majorGridlines->getLineStyleProperty(['arrow', 'head', 'size'])); + self::assertEquals($endArrowType, $majorGridlines->getLineStyleProperty(['arrow', 'end', 'type'])); + self::assertEquals($endArrowSize, $majorGridlines->getLineStyleProperty(['arrow', 'end', 'size'])); + self::assertEquals('sm', $majorGridlines->getLineStyleProperty(['arrow', 'head', 'w'])); + self::assertEquals('med', $majorGridlines->getLineStyleProperty(['arrow', 'head', 'len'])); + self::assertEquals('sm', $majorGridlines->getLineStyleProperty(['arrow', 'end', 'w'])); + self::assertEquals('lg', $majorGridlines->getLineStyleProperty(['arrow', 'end', 'len'])); + self::assertEquals('sm', $majorGridlines->getLineStyleArrowWidth('end')); + self::assertEquals('lg', $majorGridlines->getLineStyleArrowLength('end')); + self::assertEquals('lg', $majorGridlines->getLineStyleArrowParameters('end', 'len')); + + self::assertSame('00FF00', $minorGridlines->getLineColorProperty('value')); + self::assertSame(30, $minorGridlines->getLineColorProperty('alpha')); + self::assertSame('srgbClr', $minorGridlines->getLineColorProperty('type')); + // Create the chart $chart = new Chart( 'chart1', // name @@ -154,6 +351,7 @@ class GridlinesLineStyleTest extends AbstractFunctional $minorGridlines // minorGridlines ); $majorGridlines2 = $chart->getMajorGridlines(); + self::assertNotNull($majorGridlines2); self::assertEquals($width, $majorGridlines2->getLineStyleProperty('width')); self::assertEquals($compound, $majorGridlines2->getLineStyleProperty('compound')); self::assertEquals($dash, $majorGridlines2->getLineStyleProperty('dash')); @@ -169,6 +367,7 @@ class GridlinesLineStyleTest extends AbstractFunctional self::assertEquals('lg', $majorGridlines2->getLineStyleProperty(['arrow', 'end', 'len'])); $minorGridlines2 = $chart->getMinorGridlines(); + self::assertNotNull($minorGridlines2); self::assertSame('00FF00', $minorGridlines2->getLineColorProperty('value')); self::assertSame(30, $minorGridlines2->getLineColorProperty('alpha')); self::assertSame('srgbClr', $minorGridlines2->getLineColorProperty('type')); @@ -193,6 +392,7 @@ class GridlinesLineStyleTest extends AbstractFunctional $chart2 = $charts2[0]; self::assertNotNull($chart2); $majorGridlines3 = $chart2->getMajorGridlines(); + self::assertNotNull($majorGridlines3); self::assertEquals($width, $majorGridlines3->getLineStyleProperty('width')); self::assertEquals($compound, $majorGridlines3->getLineStyleProperty('compound')); self::assertEquals($dash, $majorGridlines3->getLineStyleProperty('dash')); @@ -206,6 +406,7 @@ class GridlinesLineStyleTest extends AbstractFunctional self::assertEquals('lg', $majorGridlines3->getLineStyleProperty(['arrow', 'end', 'len'])); $minorGridlines3 = $chart2->getMinorGridlines(); + self::assertNotNull($minorGridlines3); self::assertSame('00FF00', $minorGridlines3->getLineColorProperty('value')); self::assertSame(30, $minorGridlines3->getLineColorProperty('alpha')); self::assertSame('srgbClr', $minorGridlines3->getLineColorProperty('type')); diff --git a/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php b/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php index 26e8f1c6..e2c91eba 100644 --- a/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php +++ b/tests/PhpSpreadsheetTests/Chart/GridlinesShadowGlowTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Chart; +use PhpOffice\PhpSpreadsheet\Chart\Axis; use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; @@ -93,7 +94,9 @@ class GridlinesShadowGlowTest extends AbstractFunctional $title = new Title('Test %age-Stacked Area Chart'); $yAxisLabel = new Title('Value ($k)'); + $yAxis = new Axis(); $majorGridlines = new GridLines(); + $yAxis->setMajorGridlines($majorGridlines); $majorGlowSize = 10.0; $majorGridlines->setGlowProperties($majorGlowSize, 'FFFF00', 30, Properties::EXCEL_COLOR_TYPE_ARGB); $softEdgeSize = 2.5; @@ -110,6 +113,7 @@ class GridlinesShadowGlowTest extends AbstractFunctional self::assertEquals($softEdgeSize, $majorGridlines->getSoftEdgesSize()); $minorGridlines = new GridLines(); + $yAxis->setMinorGridlines($minorGridlines); $expectedShadow = [ 'effect' => 'outerShdw', 'algn' => 'tl', @@ -146,15 +150,16 @@ class GridlinesShadowGlowTest extends AbstractFunctional null, // xAxisLabel $yAxisLabel, // yAxisLabel null, // xAxis - null, // yAxis - $majorGridlines, - $minorGridlines + $yAxis // yAxis ); - $majorGridlines2 = $chart->getMajorGridlines(); + $yAxis2 = $chart->getChartAxisY(); + $majorGridlines2 = $yAxis2->getMajorGridlines(); + self::assertNotNull($majorGridlines2); self::assertEquals($majorGlowSize, $majorGridlines2->getGlowProperty('size')); self::assertEquals($expectedGlowColor, $majorGridlines2->getGlowProperty('color')); self::assertEquals($softEdgeSize, $majorGridlines2->getSoftEdgesSize()); - $minorGridlines2 = $chart->getMinorGridlines(); + $minorGridlines2 = $yAxis2->getMinorGridlines(); + self::assertNotNull($minorGridlines2); foreach ($expectedShadow as $key => $value) { self::assertEquals($value, $minorGridlines2->getShadowProperty($key), $key); } @@ -178,11 +183,14 @@ class GridlinesShadowGlowTest extends AbstractFunctional self::assertCount(1, $charts2); $chart2 = $charts2[0]; self::assertNotNull($chart2); - $majorGridlines3 = $chart2->getMajorGridlines(); + $yAxis3 = $chart2->getChartAxisY(); + $majorGridlines3 = $yAxis3->getMajorGridlines(); + self::assertNotNull($majorGridlines3); self::assertEquals($majorGlowSize, $majorGridlines3->getGlowProperty('size')); self::assertEquals($expectedGlowColor, $majorGridlines3->getGlowProperty('color')); self::assertEquals($softEdgeSize, $majorGridlines3->getSoftEdgesSize()); - $minorGridlines3 = $chart->getMinorGridlines(); + $minorGridlines3 = $yAxis3->getMinorGridlines(); + self::assertNotNull($minorGridlines3); foreach ($expectedShadow as $key => $value) { self::assertEquals($value, $minorGridlines3->getShadowProperty($key), $key); } diff --git a/tests/PhpSpreadsheetTests/Chart/LineStylesTest.php b/tests/PhpSpreadsheetTests/Chart/LineStylesTest.php new file mode 100644 index 00000000..ef940c99 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Chart/LineStylesTest.php @@ -0,0 +1,42 @@ +getLineStyleArray(); + $gridlines1->setLineStyleProperties( + 3, // lineWidth + Properties::LINE_STYLE_COMPOUND_DOUBLE, // compoundType + '', // dashType + Properties::LINE_STYLE_CAP_SQUARE, // capType + '', // jointType + '', // headArrowType + '', // headArrowSize + '', // endArrowType + '', // endArrowSize + 'lg', // headArrowWidth + 'med', // headArrowLength + '', // endArrowWidth + '' // endArrowLength + ); + $gridlines2 = new GridLines(); + $lineStyleProperties = [ + 'width' => 3, + 'compound' => Properties::LINE_STYLE_COMPOUND_DOUBLE, + 'cap' => Properties::LINE_STYLE_CAP_SQUARE, + 'arrow' => ['head' => ['w' => 'lg', 'len' => 'med']], + ]; + $gridlines2->setLineStyleArray($lineStyleProperties); + self::assertSame($gridlines1->getLineStyleArray(), $gridlines2->getLineStyleArray()); + $gridlines2->setLineStyleArray(); // resets line styles + self::assertSame($originalLineStyle, $gridlines2->getLineStyleArray()); + } +} diff --git a/tests/PhpSpreadsheetTests/Chart/PieFillTest.php b/tests/PhpSpreadsheetTests/Chart/PieFillTest.php index 452fcb93..d659f21c 100644 --- a/tests/PhpSpreadsheetTests/Chart/PieFillTest.php +++ b/tests/PhpSpreadsheetTests/Chart/PieFillTest.php @@ -138,6 +138,7 @@ class PieFillTest extends AbstractFunctional $chart2 = $charts2[0]; self::assertNotNull($chart2); $plotArea2 = $chart2->getPlotArea(); + self::assertNotNull($plotArea2); $dataSeries2 = $plotArea2->getPlotGroup(); self::assertCount(1, $dataSeries2); $plotValues = $dataSeries2[0]->getPlotValues(); diff --git a/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetsXlsxChartTest.php b/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetsXlsxChartTest.php index 0cbd103d..d47ce311 100644 --- a/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetsXlsxChartTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Xlsx/SheetsXlsxChartTest.php @@ -23,6 +23,7 @@ class SheetsXlsxChartTest extends TestCase $chart1 = $charts[0]; self::assertNotNull($chart1); $pa1 = $chart1->getPlotArea(); + self::assertNotNull($pa1); self::assertEquals(2, $pa1->getPlotSeriesCount()); $pg1 = $pa1->getPlotGroup()[0]; @@ -35,6 +36,7 @@ class SheetsXlsxChartTest extends TestCase $chart2 = $charts[1]; self::assertNotNull($chart2); $pa1 = $chart2->getPlotArea(); + self::assertNotNull($pa1); self::assertEquals(2, $pa1->getPlotSeriesCount()); $pg1 = $pa1->getPlotGroupByIndex(0);