diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php
index 1f55cf03..222ee8e8 100644
--- a/src/PhpSpreadsheet/Chart/Axis.php
+++ b/src/PhpSpreadsheet/Chart/Axis.php
@@ -144,7 +144,6 @@ class Axis extends Properties
$this->setAxisOption('orientation', $axisOrientation);
$this->setAxisOption('major_tick_mark', $majorTmt);
$this->setAxisOption('minor_tick_mark', $minorTmt);
- $this->setAxisOption('minor_tick_mark', $minorTmt);
$this->setAxisOption('minimum', $minimum);
$this->setAxisOption('maximum', $maximum);
$this->setAxisOption('major_unit', $majorUnit);
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
index 08935721..bfcf91a2 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
@@ -72,30 +72,22 @@ class Chart extends WriterPart
$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();
+ $surface2D = false;
+ $plotArea = $chart->getPlotArea();
+ if ($plotArea !== null) {
+ $seriesArray = $plotArea->getPlotGroup();
+ foreach ($seriesArray as $series) {
+ if ($series->getPlotType() === DataSeries::TYPE_SURFACECHART) {
+ $surface2D = true;
+
+ break;
+ }
+ }
}
+ $this->writeView3D($objWriter, $chart->getRotX(), 'c:rotX', $surface2D, 90);
+ $this->writeView3D($objWriter, $chart->getRotY(), 'c:rotY', $surface2D);
+ $this->writeView3D($objWriter, $chart->getRAngAx(), 'c:rAngAx', $surface2D);
+ $this->writeView3D($objWriter, $chart->getPerspective(), 'c:perspective', $surface2D);
$objWriter->endElement(); // view3D
$this->writePlotArea($objWriter, $chart->getPlotArea(), $chart->getXAxisLabel(), $chart->getYAxisLabel(), $chart->getChartAxisX(), $chart->getChartAxisY());
@@ -124,6 +116,18 @@ class Chart extends WriterPart
return $objWriter->getData();
}
+ private function writeView3D(XMLWriter $objWriter, ?int $value, string $tag, bool $surface2D, int $default = 0): void
+ {
+ if ($value === null && $surface2D) {
+ $value = $default;
+ }
+ if ($value !== null) {
+ $objWriter->startElement($tag);
+ $objWriter->writeAttribute('val', "$value");
+ $objWriter->endElement();
+ }
+ }
+
/**
* Write Chart Title.
*/
@@ -913,8 +917,8 @@ class Chart extends WriterPart
$objWriter->endElement();
}
- if ($plotGroup->getPlotGrouping() !== null) {
- $plotGroupingType = $plotGroup->getPlotGrouping();
+ $plotGroupingType = $plotGroup->getPlotGrouping();
+ if ($plotGroupingType !== null && $groupType !== DataSeries::TYPE_SURFACECHART && $groupType !== DataSeries::TYPE_SURFACECHART_3D) {
$objWriter->startElement('c:grouping');
$objWriter->writeAttribute('val', $plotGroupingType);
$objWriter->endElement();
diff --git a/tests/PhpSpreadsheetTests/Chart/Issue2931Test.php b/tests/PhpSpreadsheetTests/Chart/Issue2931Test.php
new file mode 100644
index 00000000..960eb04e
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Chart/Issue2931Test.php
@@ -0,0 +1,111 @@
+getActiveSheet();
+
+ $dataSeriesLabels = [
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['5-6']),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['6-7']),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, null, null, 1, ['7-8']),
+ ];
+
+ $xAxisTickValues = [
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [1, 2, 3, 4, 5, 6, 7, 8, 9]),
+ ];
+
+ $dataSeriesValues = [
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [6, 6, 6, 6, 6, 6, 5.9, 6, 6]),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [6, 6, 6, 6.5, 7, 7, 7, 7, 7]),
+ new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, null, null, 9, [6, 6, 6, 7, 8, 8, 8, 8, 7.9]),
+ ];
+
+ $series = new DataSeries(
+ DataSeries::TYPE_SURFACECHART,
+ DataSeries::GROUPING_STANDARD, // grouping should not be written for surface chart
+ range(0, count($dataSeriesValues) - 1),
+ $dataSeriesLabels,
+ $xAxisTickValues,
+ $dataSeriesValues,
+ null, // plotDirection
+ false, // smooth line
+ DataSeries::STYLE_LINEMARKER // plotStyle
+ );
+
+ $plotArea = new PlotArea(null, [$series]);
+ $legend = new ChartLegend(ChartLegend::POSITION_BOTTOM, null, false);
+
+ $title = new Title('График распредления температур в пределах кр');
+
+ $chart = new Chart(
+ 'chart2',
+ $title,
+ $legend,
+ $plotArea,
+ true,
+ DataSeries::EMPTY_AS_GAP,
+ );
+
+ $chart->setTopLeftPosition('$A$1');
+ $chart->setBottomRightPosition('$P$20');
+
+ $sheet->addChart($chart);
+
+ $writer = new XlsxWriter($spreadsheet);
+ $writer->setIncludeCharts(true);
+ $writer = new XlsxWriter($spreadsheet);
+ $writer->setIncludeCharts(true);
+ $writerChart = new XlsxWriter\Chart($writer);
+ $data = $writerChart->writeChart($chart);
+
+ // rotX etc. should be generated for surfaceChart 2D
+ // even when unspecified.
+ $expectedXml2D = [
+ '',
+ ];
+ $expectedXml3D = [
+ '',
+ ];
+ $expectedXmlNoX = [
+ 'c:grouping',
+ ];
+
+ // confirm that file contains expected tags
+ foreach ($expectedXml2D as $expected) {
+ self::assertSame(1, substr_count($data, $expected), $expected);
+ }
+ foreach ($expectedXmlNoX as $expected) {
+ self::assertSame(0, substr_count($data, $expected), $expected);
+ }
+
+ $series->setPlotType(DataSeries::TYPE_SURFACECHART_3D);
+ $plotArea = new PlotArea(null, [$series]);
+ $chart->setPlotArea($plotArea);
+ $writerChart = new XlsxWriter\Chart($writer);
+ $data = $writerChart->writeChart($chart);
+ // confirm that file contains expected tags
+ foreach ($expectedXml3D as $expected) {
+ self::assertSame(1, substr_count($data, $expected), $expected);
+ }
+ foreach ($expectedXmlNoX as $expected) {
+ self::assertSame(0, substr_count($data, $expected), $expected);
+ }
+
+ $spreadsheet->disconnectWorksheets();
+ }
+}