Skip to content

Commit a062521

Browse files
authored
Fixes for Surface Charts (#2933)
Fix #2931. If surface charts are written with c:grouping tag, Excel will treat them as corrupt. Also, some 3D-ish Xml tags are required when 2D surface charts are written, else they will be treated as 3D. Also eliminate a duplicate line identified by #2932.
1 parent 5de8298 commit a062521

File tree

3 files changed

+140
-26
lines changed

3 files changed

+140
-26
lines changed

src/PhpSpreadsheet/Chart/Axis.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ public function setAxisOptionsProperties(
144144
$this->setAxisOption('orientation', $axisOrientation);
145145
$this->setAxisOption('major_tick_mark', $majorTmt);
146146
$this->setAxisOption('minor_tick_mark', $minorTmt);
147-
$this->setAxisOption('minor_tick_mark', $minorTmt);
148147
$this->setAxisOption('minimum', $minimum);
149148
$this->setAxisOption('maximum', $maximum);
150149
$this->setAxisOption('major_unit', $majorUnit);

src/PhpSpreadsheet/Writer/Xlsx/Chart.php

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -72,30 +72,22 @@ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calcul
7272
$objWriter->endElement();
7373

7474
$objWriter->startElement('c:view3D');
75-
$rotX = $chart->getRotX();
76-
if (is_int($rotX)) {
77-
$objWriter->startElement('c:rotX');
78-
$objWriter->writeAttribute('val', "$rotX");
79-
$objWriter->endElement();
80-
}
81-
$rotY = $chart->getRotY();
82-
if (is_int($rotY)) {
83-
$objWriter->startElement('c:rotY');
84-
$objWriter->writeAttribute('val', "$rotY");
85-
$objWriter->endElement();
86-
}
87-
$rAngAx = $chart->getRAngAx();
88-
if (is_int($rAngAx)) {
89-
$objWriter->startElement('c:rAngAx');
90-
$objWriter->writeAttribute('val', "$rAngAx");
91-
$objWriter->endElement();
92-
}
93-
$perspective = $chart->getPerspective();
94-
if (is_int($perspective)) {
95-
$objWriter->startElement('c:perspective');
96-
$objWriter->writeAttribute('val', "$perspective");
97-
$objWriter->endElement();
75+
$surface2D = false;
76+
$plotArea = $chart->getPlotArea();
77+
if ($plotArea !== null) {
78+
$seriesArray = $plotArea->getPlotGroup();
79+
foreach ($seriesArray as $series) {
80+
if ($series->getPlotType() === DataSeries::TYPE_SURFACECHART) {
81+
$surface2D = true;
82+
83+
break;
84+
}
85+
}
9886
}
87+
$this->writeView3D($objWriter, $chart->getRotX(), 'c:rotX', $surface2D, 90);
88+
$this->writeView3D($objWriter, $chart->getRotY(), 'c:rotY', $surface2D);
89+
$this->writeView3D($objWriter, $chart->getRAngAx(), 'c:rAngAx', $surface2D);
90+
$this->writeView3D($objWriter, $chart->getPerspective(), 'c:perspective', $surface2D);
9991
$objWriter->endElement(); // view3D
10092

10193
$this->writePlotArea($objWriter, $chart->getPlotArea(), $chart->getXAxisLabel(), $chart->getYAxisLabel(), $chart->getChartAxisX(), $chart->getChartAxisY());
@@ -124,6 +116,18 @@ public function writeChart(\PhpOffice\PhpSpreadsheet\Chart\Chart $chart, $calcul
124116
return $objWriter->getData();
125117
}
126118

119+
private function writeView3D(XMLWriter $objWriter, ?int $value, string $tag, bool $surface2D, int $default = 0): void
120+
{
121+
if ($value === null && $surface2D) {
122+
$value = $default;
123+
}
124+
if ($value !== null) {
125+
$objWriter->startElement($tag);
126+
$objWriter->writeAttribute('val', "$value");
127+
$objWriter->endElement();
128+
}
129+
}
130+
127131
/**
128132
* Write Chart Title.
129133
*/
@@ -913,8 +917,8 @@ private function writePlotGroup(?DataSeries $plotGroup, string $groupType, XMLWr
913917
$objWriter->endElement();
914918
}
915919

916-
if ($plotGroup->getPlotGrouping() !== null) {
917-
$plotGroupingType = $plotGroup->getPlotGrouping();
920+
$plotGroupingType = $plotGroup->getPlotGrouping();
921+
if ($plotGroupingType !== null && $groupType !== DataSeries::TYPE_SURFACECHART && $groupType !== DataSeries::TYPE_SURFACECHART_3D) {
918922
$objWriter->startElement('c:grouping');
919923
$objWriter->writeAttribute('val', $plotGroupingType);
920924
$objWriter->endElement();
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheetTests\Chart;
4+
5+
use PhpOffice\PhpSpreadsheet\Chart\Chart;
6+
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
7+
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
8+
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
9+
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
10+
use PhpOffice\PhpSpreadsheet\Chart\Title;
11+
use PhpOffice\PhpSpreadsheet\Spreadsheet;
12+
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
13+
use PHPUnit\Framework\TestCase;
14+
15+
class Issue2931Test extends TestCase
16+
{
17+
public function testSurface(): void
18+
{
19+
$spreadsheet = new Spreadsheet();
20+
$sheet = $spreadsheet->getActiveSheet();
21+
22+
$dataSeriesLabels = [
23+
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['5-6']),
24+
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['6-7']),
25+
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['7-8']),
26+
];
27+
28+
$xAxisTickValues = [
29+
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]),
30+
];
31+
32+
$dataSeriesValues = [
33+
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [6, 6, 6, 6, 6, 6, 5.9, 6, 6]),
34+
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [6, 6, 6, 6.5, 7, 7, 7, 7, 7]),
35+
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [6, 6, 6, 7, 8, 8, 8, 8, 7.9]),
36+
];
37+
38+
$series = new DataSeries(
39+
DataSeries::TYPE_SURFACECHART,
40+
DataSeries::GROUPING_STANDARD, // grouping should not be written for surface chart
41+
range(0, count($dataSeriesValues) - 1),
42+
$dataSeriesLabels,
43+
$xAxisTickValues,
44+
$dataSeriesValues,
45+
null, // plotDirection
46+
false, // smooth line
47+
DataSeries::STYLE_LINEMARKER // plotStyle
48+
);
49+
50+
$plotArea = new PlotArea(null, [$series]);
51+
$legend = new ChartLegend(ChartLegend::POSITION_BOTTOM, null, false);
52+
53+
$title = new Title('График распредления температур в пределах кр');
54+
55+
$chart = new Chart(
56+
'chart2',
57+
$title,
58+
$legend,
59+
$plotArea,
60+
true,
61+
DataSeries::EMPTY_AS_GAP,
62+
);
63+
64+
$chart->setTopLeftPosition('$A$1');
65+
$chart->setBottomRightPosition('$P$20');
66+
67+
$sheet->addChart($chart);
68+
69+
$writer = new XlsxWriter($spreadsheet);
70+
$writer->setIncludeCharts(true);
71+
$writer = new XlsxWriter($spreadsheet);
72+
$writer->setIncludeCharts(true);
73+
$writerChart = new XlsxWriter\Chart($writer);
74+
$data = $writerChart->writeChart($chart);
75+
76+
// rotX etc. should be generated for surfaceChart 2D
77+
// even when unspecified.
78+
$expectedXml2D = [
79+
'<c:view3D><c:rotX val="90"/><c:rotY val="0"/><c:rAngAx val="0"/><c:perspective val="0"/></c:view3D>',
80+
];
81+
$expectedXml3D = [
82+
'<c:view3D/>',
83+
];
84+
$expectedXmlNoX = [
85+
'c:grouping',
86+
];
87+
88+
// confirm that file contains expected tags
89+
foreach ($expectedXml2D as $expected) {
90+
self::assertSame(1, substr_count($data, $expected), $expected);
91+
}
92+
foreach ($expectedXmlNoX as $expected) {
93+
self::assertSame(0, substr_count($data, $expected), $expected);
94+
}
95+
96+
$series->setPlotType(DataSeries::TYPE_SURFACECHART_3D);
97+
$plotArea = new PlotArea(null, [$series]);
98+
$chart->setPlotArea($plotArea);
99+
$writerChart = new XlsxWriter\Chart($writer);
100+
$data = $writerChart->writeChart($chart);
101+
// confirm that file contains expected tags
102+
foreach ($expectedXml3D as $expected) {
103+
self::assertSame(1, substr_count($data, $expected), $expected);
104+
}
105+
foreach ($expectedXmlNoX as $expected) {
106+
self::assertSame(0, substr_count($data, $expected), $expected);
107+
}
108+
109+
$spreadsheet->disconnectWorksheets();
110+
}
111+
}

0 commit comments

Comments
 (0)