From 72d48a44b70cff3e9901980fb7473fee31a9c379 Mon Sep 17 00:00:00 2001 From: Progi1984 Date: Thu, 29 Jul 2021 22:39:17 +0200 Subject: [PATCH] Support for line smooth for line and scatter chart --- docs/changes/1.0.0.md | 3 + docs/usage/shapes/chart.md | 34 ++++++++- samples/Sample_05_Chart.php | 1 + .../Shape/Chart/Type/AbstractTypeLine.php | 63 ++++++++++++++++ src/PhpPresentation/Shape/Chart/Type/Line.php | 7 +- .../Shape/Chart/Type/Scatter.php | 7 +- .../Writer/ODPresentation/ObjectsChart.php | 3 + .../Writer/PowerPoint2007/PptCharts.php | 12 +-- .../Tests/Shape/Chart/Type/LineTest.php | 26 +++++-- .../Tests/Shape/Chart/Type/ScatterTest.php | 26 +++++-- .../ODPresentation/ObjectsChartTest.php | 62 ++++++++++++++++ .../Writer/PowerPoint2007/PptChartsTest.php | 74 +++++++++++++++++++ 12 files changed, 286 insertions(+), 32 deletions(-) create mode 100644 src/PhpPresentation/Shape/Chart/Type/AbstractTypeLine.php diff --git a/docs/changes/1.0.0.md b/docs/changes/1.0.0.md index 828751b69..62fb51c96 100644 --- a/docs/changes/1.0.0.md +++ b/docs/changes/1.0.0.md @@ -49,6 +49,9 @@ - Support for interval unit for Chart's Axis - @Progi1984 GH-546 - ODPresentation Writer - PowerPoint2007 Writer +- Support for line smooth for line and scatter chart - @ksmeeks0001 GH-626 & @Progi1984 GH-662 + - ODPresentation Writer + - PowerPoint2007 Writer ## Project Management - Migrated from Travis CI to Github Actions - @Progi1984 GH-635 diff --git a/docs/usage/shapes/chart.md b/docs/usage/shapes/chart.md index 0e9590da6..4fadfcb45 100644 --- a/docs/usage/shapes/chart.md +++ b/docs/usage/shapes/chart.md @@ -364,7 +364,22 @@ $barChart->setBarGrouping(Bar::GROUPING_PERCENTSTACKED); ### Line -TODO +#### Smooth line + +You can enable or disable the smooth line with `setIsSmooth` method from `AbstractTypeLine`. +By default, smooth line is disabled. + +``` php +setIsSmooth(true); +// Disable the smooth line +$chart->setIsSmooth(false); +// Get status of smooth line +$chart->isSmooth(); +``` ### Pie & Pie3D @@ -372,5 +387,20 @@ TODO ### Scatter -TODO +#### Smooth line + +You can enable or disable the smooth line with `setIsSmooth` method from `AbstractTypeLine`. +By default, smooth line is disabled. + +``` php +setIsSmooth(true); +// Disable the smooth line +$chart->setIsSmooth(false); +// Get status of smooth line +$chart->isSmooth(); +``` diff --git a/samples/Sample_05_Chart.php b/samples/Sample_05_Chart.php index c004af2c1..a7cf89f47 100644 --- a/samples/Sample_05_Chart.php +++ b/samples/Sample_05_Chart.php @@ -562,6 +562,7 @@ function fnSlide_Scatter(PhpPresentation $objPHPPresentation) // Create a scatter chart (that should be inserted in a shape) echo date('H:i:s') . ' Create a scatter chart (that should be inserted in a chart shape)' . EOL; $lineChart = new Scatter(); + $lineChart->setIsSmooth(true); $series = new Series('Downloads', $seriesData); $series->setShowSeriesName(true); $series->getMarker()->setSymbol(\PhpOffice\PhpPresentation\Shape\Chart\Marker::SYMBOL_CIRCLE); diff --git a/src/PhpPresentation/Shape/Chart/Type/AbstractTypeLine.php b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeLine.php new file mode 100644 index 000000000..32c5e7f0e --- /dev/null +++ b/src/PhpPresentation/Shape/Chart/Type/AbstractTypeLine.php @@ -0,0 +1,63 @@ +isSmooth; + } + + /** + * Set Line Smoothness + * + * @param bool $value + * + * @return AbstractTypeLine + */ + public function setIsSmooth(bool $value = true): AbstractTypeLine + { + $this->isSmooth = $value; + + return $this; + } + + /** + * Get hash code. + * + * @return string Hash code + */ + public function getHashCode(): string + { + return md5($this->isSmooth() ? '1' : '0'); + } +} diff --git a/src/PhpPresentation/Shape/Chart/Type/Line.php b/src/PhpPresentation/Shape/Chart/Type/Line.php index 0d49ef4b9..4d1f07cad 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Line.php +++ b/src/PhpPresentation/Shape/Chart/Type/Line.php @@ -20,10 +20,7 @@ use PhpOffice\PhpPresentation\ComparableInterface; -/** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Line. - */ -class Line extends AbstractType implements ComparableInterface +class Line extends AbstractTypeLine implements ComparableInterface { /** * Get hash code. @@ -37,6 +34,6 @@ public function getHashCode(): string $hash .= $series->getHashCode(); } - return md5($hash . __CLASS__); + return md5(parent::getHashCode() . $hash . __CLASS__); } } diff --git a/src/PhpPresentation/Shape/Chart/Type/Scatter.php b/src/PhpPresentation/Shape/Chart/Type/Scatter.php index 441e3c57e..3cb2bba43 100644 --- a/src/PhpPresentation/Shape/Chart/Type/Scatter.php +++ b/src/PhpPresentation/Shape/Chart/Type/Scatter.php @@ -20,10 +20,7 @@ use PhpOffice\PhpPresentation\ComparableInterface; -/** - * \PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter. - */ -class Scatter extends AbstractType implements ComparableInterface +class Scatter extends AbstractTypeLine implements ComparableInterface { /** * Get hash code. @@ -37,6 +34,6 @@ public function getHashCode(): string $hash .= $series->getHashCode(); } - return md5($hash . __CLASS__); + return md5(parent::getHashCode() . $hash . __CLASS__); } } diff --git a/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php b/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php index 13759a560..806c1a673 100644 --- a/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php +++ b/src/PhpPresentation/Writer/ODPresentation/ObjectsChart.php @@ -10,6 +10,7 @@ use PhpOffice\PhpPresentation\Shape\Chart\Axis; use PhpOffice\PhpPresentation\Shape\Chart\Title; use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeBar; +use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypeLine; use PhpOffice\PhpPresentation\Shape\Chart\Type\AbstractTypePie; use PhpOffice\PhpPresentation\Shape\Chart\Type\Area; use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar; @@ -560,6 +561,8 @@ private function writePlotAreaStyle(Chart $chart): void } elseif ($chartType instanceof Pie3D) { $this->xmlContent->writeAttribute('chart:three-dimensional', 'true'); $this->xmlContent->writeAttribute('chart:right-angled-axes', 'true'); + } elseif ($chartType instanceof AbstractTypeLine) { + $this->xmlContent->writeAttributeIf($chartType->isSmooth(), 'chart:interpolation', 'cubic-spline'); } switch ($chart->getDisplayBlankAs()) { case Chart::BLANKAS_ZERO: diff --git a/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php b/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php index ada5fb77b..66641a8c4 100644 --- a/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php +++ b/src/PhpPresentation/Writer/PowerPoint2007/PptCharts.php @@ -1826,6 +1826,11 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $incl $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords); $objWriter->endElement(); + // c:smooth + $objWriter->startElement('c:smooth'); + $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0'); + $objWriter->endElement(); + $objWriter->endElement(); ++$seriesIndex; @@ -1836,11 +1841,6 @@ protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $incl $objWriter->writeAttribute('val', '1'); $objWriter->endElement(); - // c:smooth - $objWriter->startElement('c:smooth'); - $objWriter->writeAttribute('val', '0'); - $objWriter->endElement(); - // c:axId $objWriter->startElement('c:axId'); $objWriter->writeAttribute('val', '52743552'); @@ -2012,7 +2012,7 @@ protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool // c:smooth $objWriter->startElement('c:smooth'); - $objWriter->writeAttribute('val', '0'); + $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0'); $objWriter->endElement(); $objWriter->endElement(); diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php index 77a9adbd5..043b5d79c 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/LineTest.php @@ -41,27 +41,39 @@ public function testData(): void new Series(), ]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Line', $object->setSeries()); + $this->assertInstanceOf(Line::class, $object->setSeries()); $this->assertEmpty($object->getSeries()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Line', $object->setSeries($array)); + $this->assertInstanceOf(Line::class, $object->setSeries($array)); $this->assertCount(count($array), $object->getSeries()); } - public function testSerties(): void + public function testSeries(): void { $object = new Line(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Line', $object->addSeries(new Series())); + $this->assertInstanceOf(Line::class, $object->addSeries(new Series())); $this->assertCount(1, $object->getSeries()); } + public function testSmooth(): void + { + $object = new Line(); + + $this->assertFalse($object->isSmooth()); + $this->assertInstanceOf(Line::class, $object->setIsSmooth(true)); + $this->assertTrue($object->isSmooth()); + } + public function testHashCode(): void { - $oSeries = new Series(); + $series = new Series(); $object = new Line(); - $object->addSeries($oSeries); + $object->addSeries($series); - $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); + $this->assertEquals( + md5(md5($object->isSmooth() ? '1' : '0') . $series->getHashCode() . get_class($object)), + $object->getHashCode() + ); } } diff --git a/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php b/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php index fd64afad1..bb430770c 100644 --- a/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php +++ b/tests/PhpPresentation/Tests/Shape/Chart/Type/ScatterTest.php @@ -41,27 +41,39 @@ public function testData(): void new Series(), ]; - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Scatter', $object->setSeries()); + $this->assertInstanceOf(Scatter::class, $object->setSeries()); $this->assertEmpty($object->getSeries()); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Scatter', $object->setSeries($array)); + $this->assertInstanceOf(Scatter::class, $object->setSeries($array)); $this->assertCount(count($array), $object->getSeries()); } - public function testSerties(): void + public function testSeries(): void { $object = new Scatter(); - $this->assertInstanceOf('PhpOffice\\PhpPresentation\\Shape\\Chart\\Type\\Scatter', $object->addSeries(new Series())); + $this->assertInstanceOf(Scatter::class, $object->addSeries(new Series())); $this->assertCount(1, $object->getSeries()); } + public function testSmooth(): void + { + $object = new Scatter(); + + $this->assertFalse($object->isSmooth()); + $this->assertInstanceOf(Scatter::class, $object->setIsSmooth(true)); + $this->assertTrue($object->isSmooth()); + } + public function testHashCode(): void { - $oSeries = new Series(); + $series = new Series(); $object = new Scatter(); - $object->addSeries($oSeries); + $object->addSeries($series); - $this->assertEquals(md5($oSeries->getHashCode() . get_class($object)), $object->getHashCode()); + $this->assertEquals( + md5(md5($object->isSmooth() ? '1' : '0') . $series->getHashCode() . get_class($object)), + $object->getHashCode() + ); } } diff --git a/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php b/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php index ef3d266d3..2b87e169d 100644 --- a/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php +++ b/tests/PhpPresentation/Tests/Writer/ODPresentation/ObjectsChartTest.php @@ -1021,6 +1021,37 @@ public function testTypeLineSeriesOutline(): void $this->assertIsSchemaOpenDocumentNotValid('1.2'); } + public function testTypeLineSmooth(): void + { + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePlotArea\']/style:chart-properties'; + + $oSeries = new Series('Downloads', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + $oLine->setIsSmooth(false); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interpolation'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $oLine->setIsSmooth(true); + $oShape->getPlotArea()->setType($oLine); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interpolation'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interpolation', 'cubic-spline'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } + public function testTypePie(): void { $oSeries = new Series('Series', ['Jan' => '1', 'Feb' => '5', 'Mar' => '2']); @@ -1225,4 +1256,35 @@ public function testTypeScatterSeriesOutline(): void // chart:title : Element chart failed to validate attributes $this->assertIsSchemaOpenDocumentNotValid('1.2'); } + + public function testTypeScatterSmooth(): void + { + $element = '/office:document-content/office:automatic-styles/style:style[@style:name=\'stylePlotArea\']/style:chart-properties'; + + $oSeries = new Series('Downloads', $this->seriesData); + + $scatter = new Scatter(); + $scatter->addSeries($oSeries); + $scatter->setIsSmooth(false); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->getPlotArea()->setType($scatter); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeNotExists('Object 1/content.xml', $element, 'chart:interpolation'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + + $this->resetPresentationFile(); + $scatter->setIsSmooth(true); + $oShape->getPlotArea()->setType($scatter); + + $this->assertZipFileExists('Object 1/content.xml'); + $this->assertZipXmlElementExists('Object 1/content.xml', $element); + $this->assertZipXmlAttributeExists('Object 1/content.xml', $element, 'chart:interpolation'); + $this->assertZipXmlAttributeEquals('Object 1/content.xml', $element, 'chart:interpolation', 'cubic-spline'); + // chart:title : Element chart failed to validate attributes + $this->assertIsSchemaOpenDocumentNotValid('1.2'); + } } diff --git a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php index 0df4119b8..8dbac33ba 100644 --- a/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php +++ b/tests/PhpPresentation/Tests/Writer/PowerPoint2007/PptChartsTest.php @@ -959,6 +959,43 @@ public function testTypeLineSeriesOutline(): void $this->assertIsSchemaECMA376Valid(); } + public function testTypeLineSmooth(): void + { + $oSeries = new Series('Downloads', $this->seriesData); + + $oLine = new Line(); + $oLine->addSeries($oSeries); + $oLine->setIsSmooth(false); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oShape->getPlotArea()->setType($oLine); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oLine->setIsSmooth(true); + $oShape->getPlotArea()->setType($oLine); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:lineChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '1'); + } + public function testTypeLineSubScript(): void { $oSlide = $this->oPresentation->getActiveSlide(); @@ -1308,6 +1345,43 @@ public function testTypeScatterSeriesOutline(): void $this->assertIsSchemaECMA376Valid(); } + public function testTypeScatterSmooth(): void + { + $oSeries = new Series('Downloads', $this->seriesData); + + $oScatter = new Scatter(); + $oScatter->addSeries($oSeries); + $oScatter->setIsSmooth(false); + + $oShape = $this->oPresentation->getActiveSlide()->createChartShape(); + $oShape->setResizeProportional(false)->setHeight(550)->setWidth(700)->setOffsetX(120)->setOffsetY(80); + $oShape->getPlotArea()->setType($oScatter); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '0'); + + $this->assertIsSchemaECMA376Valid(); + + $this->resetPresentationFile(); + $oScatter->setIsSmooth(true); + $oShape->getPlotArea()->setType($oScatter); + + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $element = '/c:chartSpace/c:chart/c:plotArea/c:scatterChart/c:ser/c:smooth'; + $this->assertZipXmlElementExists('ppt/charts/' . $oShape->getIndexedFilename(), $element); + $this->assertZipXmlAttributeExists('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val'); + $this->assertZipXmlAttributeEquals('ppt/charts/' . $oShape->getIndexedFilename(), $element, 'val', '1'); + } + public function testTypeScatterSubScript(): void { $oSlide = $this->oPresentation->getActiveSlide();