From a13e5b20f98969f6e4ca44d8ab8d4e6180c60501 Mon Sep 17 00:00:00 2001 From: Ivan Lanin Date: Sun, 15 Jun 2014 20:48:26 +0700 Subject: [PATCH] #278: 3D charts and ability to set width and height --- CHANGELOG.md | 3 +- samples/Sample_32_Chart.php | 37 ++++- src/PhpWord/Element/Chart.php | 25 +++- src/PhpWord/Shared/Converter.php | 33 +++++ src/PhpWord/Style/AbstractStyle.php | 4 +- src/PhpWord/Style/Chart.php | 127 ++++++++++++++++++ src/PhpWord/Writer/Word2007/Element/Chart.php | 3 +- src/PhpWord/Writer/Word2007/Part/Chart.php | 23 ++-- tests/PhpWord/Tests/Shared/ConverterTest.php | 9 ++ .../Tests/Writer/Word2007/ElementTest.php | 3 +- 10 files changed, 247 insertions(+), 20 deletions(-) create mode 100644 src/PhpWord/Style/Chart.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 28c646ac..155ecb35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,7 +15,8 @@ This release added drawing shapes (arc, curve, line, polyline, rect, oval) and b - Section: Ability to set paper size, e.g. A4, A3, and Legal - @ivanlanin GH-249 - General: New `PhpWord::save()` method to encapsulate `IOFactory` - @ivanlanin - General: New `Shared\Converter` static class - @ivanlanin -- Element: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 +- Chart: Basic 2D chart (pie, doughnut, bar, line, area, scatter, radar) - @ivanlanin GH-278 +- Chart: 3D charts and ability to set width and height - @ivanlanin ### Bugfixes diff --git a/samples/Sample_32_Chart.php b/samples/Sample_32_Chart.php index 26d6c420..5f2188ed 100644 --- a/samples/Sample_32_Chart.php +++ b/samples/Sample_32_Chart.php @@ -1,16 +1,22 @@ addSection(array('colsNum' => 2)); $phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true), array('keepNext' => true, 'spaceBefore' => 240)); +$phpWord->addTitleStyle(2, array('size' => 14, 'bold' => true), array('keepNext' => true, 'spaceBefore' => 240)); -$chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); -$twoSeries = array('bar', 'line', 'area', 'scatter', 'radar'); +// 2D charts +$section = $phpWord->addSection(); +$section->addTitle('2D charts', 1); +$section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); + +$chartTypes = array('pie', 'doughnut', 'bar', 'column', 'line', 'area', 'scatter', 'radar'); +$twoSeries = array('bar', 'column', 'line', 'area', 'scatter', 'radar'); $threeSeries = array('bar', 'line'); $categories = array('A', 'B', 'C', 'D', 'E'); $series1 = array(1, 3, 2, 5, 4); @@ -18,8 +24,11 @@ $series2 = array(3, 1, 7, 2, 6); $series3 = array(8, 3, 2, 5, 4); foreach ($chartTypes as $chartType) { - $section->addTitle(ucfirst($chartType), 1); + $section->addTitle(ucfirst($chartType), 2); $chart = $section->addChart($chartType, $categories, $series1); + $chart->getStyle() + ->setWidth(Converter::inchToEmu(2.5)) + ->setHeight(Converter::inchToEmu(2)); if (in_array($chartType, $twoSeries)) { $chart->addSeries($categories, $series2); } @@ -29,6 +38,24 @@ foreach ($chartTypes as $chartType) { $section->addTextBreak(); } +// 3D charts +$section = $phpWord->addSection(array('breakType' => 'continuous')); +$section->addTitle('3D charts', 1); +$section = $phpWord->addSection(array('colsNum' => 2, 'breakType' => 'continuous')); + +$chartTypes = array('pie', 'bar', 'column', 'line', 'area'); +$multiSeries = array('bar', 'column', 'line', 'area'); +$style = array('width' => Converter::cmToEmu(5), 'height' => Converter::cmToEmu(4), '3d' => true); +foreach ($chartTypes as $chartType) { + $section->addTitle(ucfirst($chartType), 2); + $chart = $section->addChart($chartType, $categories, $series1, $style); + if (in_array($chartType, $multiSeries)) { + $chart->addSeries($categories, $series2); + $chart->addSeries($categories, $series3); + } + $section->addTextBreak(); +} + // Save file echo write($phpWord, basename(__FILE__, '.php'), $writers); if (!CLI) { diff --git a/src/PhpWord/Element/Chart.php b/src/PhpWord/Element/Chart.php index 24f2bb78..629db63b 100644 --- a/src/PhpWord/Element/Chart.php +++ b/src/PhpWord/Element/Chart.php @@ -17,6 +17,9 @@ namespace PhpOffice\PhpWord\Element; +use PhpOffice\PhpWord\Style\Chart as ChartStyle; + + /** * Chart element * @@ -45,6 +48,13 @@ class Chart extends AbstractElement */ private $series = array(); + /** + * Chart style + * + * @var \PhpOffice\PhpWord\Style\Chart + */ + private $style; + /** * Create new instance * @@ -52,10 +62,11 @@ class Chart extends AbstractElement * @param array $categories * @param array $values */ - public function __construct($type, $categories, $values) + public function __construct($type, $categories, $values, $style = null) { $this->setType($type); $this->addSeries($categories, $values); + $this->style = $this->setNewStyle(new ChartStyle(), $style, true); } /** @@ -75,7 +86,7 @@ class Chart extends AbstractElement */ public function setType($value) { - $enum = array('pie', 'doughnut', 'line', 'bar', 'area', 'radar', 'scatter'); + $enum = array('pie', 'doughnut', 'line', 'bar', 'column', 'area', 'radar', 'scatter'); $this->type = $this->setEnumVal($value, $enum, 'pie'); } @@ -99,4 +110,14 @@ class Chart extends AbstractElement { return $this->series; } + + /** + * Get chart style + * + * @return \PhpOffice\PhpWord\Style\Chart + */ + public function getStyle() + { + return $this->style; + } } diff --git a/src/PhpWord/Shared/Converter.php b/src/PhpWord/Shared/Converter.php index 8bc1cecf..c6727edd 100644 --- a/src/PhpWord/Shared/Converter.php +++ b/src/PhpWord/Shared/Converter.php @@ -62,6 +62,28 @@ class Converter return $centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL; } + /** + * Convert centimeter to point + * + * @param int $centimeter + * @return float + */ + public static function cmToPoint($centimeter = 1) + { + return $centimeter / self::INCH_TO_CM * self::INCH_TO_POINT; + } + + /** + * Convert centimeter to EMU + * + * @param int $centimeter + * @return int + */ + public static function cmToEmu($centimeter = 1) + { + return round($centimeter / self::INCH_TO_CM * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU); + } + /** * Convert inch to twip * @@ -106,6 +128,17 @@ class Converter return $inch * self::INCH_TO_POINT; } + /** + * Convert inch to EMU + * + * @param int $inch + * @return int + */ + public static function inchToEmu($inch = 1) + { + return round($inch * self::INCH_TO_PIXEL * self::PIXEL_TO_EMU); + } + /** * Convert pixel to twip * diff --git a/src/PhpWord/Style/AbstractStyle.php b/src/PhpWord/Style/AbstractStyle.php index cc275fc6..6f527210 100644 --- a/src/PhpWord/Style/AbstractStyle.php +++ b/src/PhpWord/Style/AbstractStyle.php @@ -244,8 +244,10 @@ abstract class AbstractStyle if (is_string($value) && (preg_match('/[^\d]/', $value) == 0)) { $value = intval($value); } - if (!is_int($value)) { + if (!is_numeric($value)) { $value = $default; + } else { + $value = intval($value); } return $value; diff --git a/src/PhpWord/Style/Chart.php b/src/PhpWord/Style/Chart.php new file mode 100644 index 00000000..13b72a33 --- /dev/null +++ b/src/PhpWord/Style/Chart.php @@ -0,0 +1,127 @@ +setStyleByArray($style); + } + + /** + * Get width + * + * @return int + */ + public function getWidth() + { + return $this->width; + } + + /** + * Set width + * + * @param int $value + * @return self + */ + public function setWidth($value = null) + { + $this->width = $this->setIntVal($value, $this->width); + + return $this; + } + + /** + * Get height + * + * @return int + */ + public function getHeight() + { + return $this->height; + } + + /** + * Set height + * + * @param int $value + * @return self + */ + public function setHeight($value = null) + { + $this->height = $this->setIntVal($value, $this->height); + + return $this; + } + + /** + * Is 3D + * + * @return bool + */ + public function is3d() + { + return $this->is3d; + } + + /** + * Set 3D + * + * @param bool $value + * @return self + */ + public function set3d($value = true) + { + $this->is3d = $this->setBoolVal($value, $this->is3d); + + return $this; + } +} diff --git a/src/PhpWord/Writer/Word2007/Element/Chart.php b/src/PhpWord/Writer/Word2007/Element/Chart.php index 4330e2fe..e185ee58 100644 --- a/src/PhpWord/Writer/Word2007/Element/Chart.php +++ b/src/PhpWord/Writer/Word2007/Element/Chart.php @@ -38,6 +38,7 @@ class Chart extends AbstractElement } $rId = $element->getRelationId(); + $style = $element->getStyle(); if (!$this->withoutP) { $xmlWriter->startElement('w:p'); @@ -48,7 +49,7 @@ class Chart extends AbstractElement $xmlWriter->startElement('wp:inline'); // EMU - $xmlWriter->writeElementBlock('wp:extent', array('cx' => '2000000', 'cy' => '2000000')); + $xmlWriter->writeElementBlock('wp:extent', array('cx' => $style->getWidth(), 'cy' => $style->getHeight())); $xmlWriter->writeElementBlock('wp:docPr', array('id' => $rId, 'name' => "Chart{$rId}")); $xmlWriter->startElement('a:graphic'); diff --git a/src/PhpWord/Writer/Word2007/Part/Chart.php b/src/PhpWord/Writer/Word2007/Part/Chart.php index 66e43914..0a0ebac6 100644 --- a/src/PhpWord/Writer/Word2007/Part/Chart.php +++ b/src/PhpWord/Writer/Word2007/Part/Chart.php @@ -41,13 +41,14 @@ class Chart extends AbstractPart * @var array */ private $types = array( - 'pie' => array('type' => 'pieChart', 'colors' => 1), - 'doughnut' => array('type' => 'doughnutChart', 'colors' => 1, 'hole' => 75), - 'bar' => array('type' => 'barChart', 'colors' => 0, 'axes' => true, 'bar' => 'col'), - 'line' => array('type' => 'lineChart', 'colors' => 0, 'axes' => true), - 'area' => array('type' => 'areaChart', 'colors' => 0, 'axes' => true), - 'radar' => array('type' => 'radarChart', 'colors' => 0, 'axes' => true, 'radar' => 'standard'), - 'scatter' => array('type' => 'scatterChart', 'colors' => 0, 'axes' => true, 'scatter' => 'marker'), + 'pie' => array('type' => 'pie', 'colors' => 1), + 'doughnut' => array('type' => 'doughnut', 'colors' => 1, 'hole' => 75, 'no3d' => true), + 'bar' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'bar'), + 'column' => array('type' => 'bar', 'colors' => 0, 'axes' => true, 'bar' => 'col'), + 'line' => array('type' => 'line', 'colors' => 0, 'axes' => true), + 'area' => array('type' => 'area', 'colors' => 0, 'axes' => true), + 'radar' => array('type' => 'radar', 'colors' => 0, 'axes' => true, 'radar' => 'standard', 'no3d' => true), + 'scatter' => array('type' => 'scatter', 'colors' => 0, 'axes' => true, 'scatter' => 'marker', 'no3d' => true), ); /** @@ -119,13 +120,17 @@ class Chart extends AbstractPart private function writePlotArea(XMLWriter $xmlWriter) { $type = $this->element->getType(); + $style = $this->element->getStyle(); $this->options = $this->types[$type]; $xmlWriter->startElement('c:plotArea'); $xmlWriter->writeElement('c:layout'); // Chart - $xmlWriter->startElement('c:' . $this->options['type']); + $chartType = $this->options['type']; + $chartType .= $style->is3d() && !isset($this->options['no3d'])? '3D' : ''; + $chartType .= 'Chart'; + $xmlWriter->startElement("c:{$chartType}"); $xmlWriter->writeElementBlock('c:varyColors', 'val', $this->options['colors']); if ($type == 'area') { @@ -136,7 +141,7 @@ class Chart extends AbstractPart } if (isset($this->options['bar'])) { $xmlWriter->writeElementBlock('c:barDir', 'val', $this->options['bar']); // bar|col - $xmlWriter->writeElementBlock('c:grouping', 'val', 'clustered'); + $xmlWriter->writeElementBlock('c:grouping', 'val', 'clustered'); // 3d; standard = percentStacked } if (isset($this->options['radar'])) { $xmlWriter->writeElementBlock('c:radarStyle', 'val', $this->options['radar']); diff --git a/tests/PhpWord/Tests/Shared/ConverterTest.php b/tests/PhpWord/Tests/Shared/ConverterTest.php index 9525148c..002e2e33 100644 --- a/tests/PhpWord/Tests/Shared/ConverterTest.php +++ b/tests/PhpWord/Tests/Shared/ConverterTest.php @@ -45,6 +45,12 @@ class ConverterTest extends \PHPUnit_Framework_TestCase $result = Converter::cmToPixel($value); $this->assertEquals($value / 2.54 * 96, $result); + $result = Converter::cmToPoint($value); + $this->assertEquals($value / 2.54 * 72, $result); + + $result = Converter::cmToEmu($value); + $this->assertEquals(round($value / 2.54 * 96 * 9525), $result); + $result = Converter::inchToTwip($value); $this->assertEquals($value * 1440, $result); @@ -57,6 +63,9 @@ class ConverterTest extends \PHPUnit_Framework_TestCase $result = Converter::inchToPoint($value); $this->assertEquals($value * 72, $result); + $result = Converter::inchToEmu($value); + $this->assertEquals(round($value * 96 * 9525), $result); + $result = Converter::pixelToTwip($value); $this->assertEquals($value / 96 * 1440, $result); diff --git a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php index 0ba29f2f..528cafd5 100644 --- a/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php +++ b/tests/PhpWord/Tests/Writer/Word2007/ElementTest.php @@ -156,12 +156,13 @@ class ElementTest extends \PHPUnit_Framework_TestCase { $phpWord = new PhpWord(); $section = $phpWord->addSection(); + $style = array('width' => 1000000, 'height' => 1000000, '3d' => true); $chartTypes = array('pie', 'doughnut', 'bar', 'line', 'area', 'scatter', 'radar'); $categories = array('A', 'B', 'C', 'D', 'E'); $series1 = array(1, 3, 2, 5, 4); foreach ($chartTypes as $chartType) { - $section->addChart($chartType, $categories, $series1); + $section->addChart($chartType, $categories, $series1, $style); } $doc = TestHelperDOCX::getDocument($phpWord);