Basic chart support

This commit is contained in:
Ivan Lanin 2014-06-10 07:11:32 +07:00
parent 4c04071fd5
commit 056ff5e676
14 changed files with 668 additions and 8 deletions

View File

@ -0,0 +1,26 @@
<?php
include_once 'Sample_Header.php';
// New Word document
echo date('H:i:s'), " Create new PhpWord object", EOL;
$phpWord = new \PhpOffice\PhpWord\PhpWord();
$section = $phpWord->addSection(array('colsNum' => 2));
$phpWord->addTitleStyle(1, array('size' => 14, 'bold' => true), array('keepNext' => true, 'spaceBefore' => 240));
$charts = array('pie', 'doughnut', 'line', 'area', 'scatter', 'bar', 'radar');
$labels = array('A', 'B', 'C', 'D', 'E');
$data = array(1, 3, 2, 5, 4);
foreach ($charts as $chart) {
$section->addTitle(ucfirst($chart), 1);
$section->addChart($chart, $labels, $data);
$section->addTextBreak();
}
// Save file
echo write($phpWord, basename(__FILE__, '.php'), $writers);
if (!CLI) {
include_once 'Sample_Footer.php';
}

View File

@ -0,0 +1,27 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt LGPL
*/
namespace PhpOffice\PhpWord\Collection;
/**
* Charts collection
*
* @since 0.12.0
*/
class Charts extends AbstractCollection
{
}

View File

@ -41,6 +41,7 @@ namespace PhpOffice\PhpWord\Element;
* @method Field addField(string $type = null, array $properties = array(), array $options = array())
* @method Line addLine(mixed $lineStyle = null)
* @method Shape addObject(string $type, mixed $style = null)
* @method Chart addChart()
*
* @since 0.10.0
*/
@ -77,7 +78,7 @@ abstract class AbstractContainer extends AbstractElement
$elements = array('Text', 'TextRun', 'Link', 'PreserveText', 'TextBreak',
'ListItem', 'ListItemRun', 'Table', 'Image', 'Object', 'Footnote',
'Endnote', 'CheckBox', 'TextBox', 'Field', 'Line', 'Shape',
'Title', 'TOC', 'PageBreak');
'Title', 'TOC', 'PageBreak', 'Chart');
$functions = array();
for ($i = 0; $i < count($elements); $i++) {
$functions[$i] = 'add' . $elements[$i];
@ -201,6 +202,7 @@ abstract class AbstractContainer extends AbstractElement
'Title' => array('Section'),
'TOC' => array('Section'),
'PageBreak' => array('Section'),
'Chart' => array('Section'),
);
// Special condition, e.g. preservetext can only exists in cell when
// the cell is located in header or footer

View File

@ -109,7 +109,7 @@ abstract class AbstractElement
protected $mediaRelation = false;
/**
* Is part of collection; true for Title, Footnote, and Endnote
* Is part of collection; true for Title, Footnote, Endnote, and Chart
*
* @var bool
*/

View File

@ -0,0 +1,129 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Element;
/**
* Chart element
*
* @since 0.12.0
*/
class Chart extends AbstractElement
{
/**
* Is part of collection
*
* @var bool
*/
protected $collectionRelation = true;
/**
* Type
*
* @var string
*/
private $type = 'pie';
/**
* Labels
*
* @var array
*/
private $labels = array();
/**
* Data
*
* @var array
*/
private $data = array();
/**
* Create new instance
*
* @param string $type
* @param array $labels
* @param array $data
*/
public function __construct($type, $labels, $data)
{
$this->setType($type);
$this->setLabels($labels);
$this->setData($data);
}
/**
* Get type
*
* @return array
*/
public function getType()
{
return $this->type;
}
/**
* Set type
*
* @param array $value
*/
public function setType($value)
{
$enum = array('pie', 'doughnut', 'line', 'bar', 'area', 'radar', 'scatter');
$this->type = $this->setEnumVal($value, $enum, 'pie');
}
/**
* Get labels
*
* @return array
*/
public function getLabels()
{
return $this->labels;
}
/**
* Set labels
*
* @param array $value
*/
public function setLabels($value)
{
$this->labels = $value;
}
/**
* Get data
*
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* Set data
*
* @param array $value
*/
public function setData($value)
{
$this->data = $value;
}
}

View File

@ -37,7 +37,7 @@ class Footnote extends AbstractContainer
protected $paragraphStyle;
/**
* Is part of collection; true for Title, Footnote, and Endnote
* Is part of collection
*
* @var bool
*/

View File

@ -47,7 +47,7 @@ class Title extends AbstractElement
private $style;
/**
* Is part of collection; true for Title, Footnote, and Endnote
* Is part of collection
*
* @var bool
*/

View File

@ -26,9 +26,11 @@ use PhpOffice\PhpWord\Exception\Exception;
* @method Collection\Titles getTitles()
* @method Collection\Footnotes getFootnotes()
* @method Collection\Endnotes getEndnotes()
* @method Collection\Charts getCharts()
* @method int addTitle(Element\Title $title)
* @method int addFootnote(Element\Footnote $footnote)
* @method int addEndnote(Element\Endnote $endnote)
* @method int addChart(Element\Chart $chart)
*
* @method Style\Paragraph addParagraphStyle(string $styleName, array $styles)
* @method Style\Font addFontStyle(string $styleName, mixed $fontStyle, mixed $paragraphStyle = null)
@ -80,7 +82,7 @@ class PhpWord
{
$this->documentProperties = new DocumentProperties();
$collections = array('Titles', 'Footnotes', 'Endnotes');
$collections = array('Titles', 'Footnotes', 'Endnotes', 'Charts');
foreach ($collections as $collection) {
$class = 'PhpOffice\\PhpWord\\Collection\\' . $collection;
$this->collections[$collection] = new $class();
@ -108,7 +110,7 @@ class PhpWord
$addCollection = array();
$addStyle = array();
$collections = array('Title', 'Footnote', 'Endnote');
$collections = array('Title', 'Footnote', 'Endnote', 'Chart');
foreach ($collections as $collection) {
$getCollection[] = strtolower("get{$collection}s");
$addCollection[] = strtolower("add{$collection}");

View File

@ -139,6 +139,29 @@ class XMLWriter
}
}
/**
* Write simple element and attribute(s) block
*
* There are two options:
* 1. If the `$attributes` is an array, then it's an associative array of attributes
* 2. If not, then it's a simple attribute-value pair
*
* @param string $element
* @param string|array $attributes
* @param string $value
*/
public function writeBlock($element, $attributes, $value = null)
{
$this->xmlWriter->startElement($element);
if (!is_array($attributes)) {
$attributes = array($attributes => $value);
}
foreach ($attributes as $attribute => $value) {
$this->xmlWriter->writeAttribute($attribute, $value);
}
$this->xmlWriter->endElement();
}
/**
* Write element if ...
*

View File

@ -71,6 +71,7 @@ class Word2007 extends AbstractWriter implements WriterInterface
'Footer' => '',
'Footnotes' => '',
'Endnotes' => '',
'Chart' => '',
);
foreach (array_keys($this->parts) as $partName) {
$partClass = get_class($this) . '\\Part\\' . $partName;
@ -127,6 +128,7 @@ class Word2007 extends AbstractWriter implements WriterInterface
$this->addNotes($zip, $rId, 'footnote');
$this->addNotes($zip, $rId, 'endnote');
$this->addChart($zip, $rId);
// Write parts
foreach ($this->parts as $partName => $fileName) {
@ -249,6 +251,40 @@ class Word2007 extends AbstractWriter implements WriterInterface
}
}
/**
* Add chart
*
* @param \PhpOffice\PhpWord\Shared\ZipArchive $zip
* @param integer $rId
*/
private function addChart(ZipArchive $zip, &$rId)
{
$phpWord = $this->getPhpWord();
$collection = $phpWord->getCharts();
$index = 0;
if ($collection->countItems() > 0) {
foreach ($collection->getItems() as $chart) {
$index++;
$rId++;
$filename = "charts/chart{$index}.xml";
// ContentTypes.xml
$this->contentTypes['override']["/word/{$filename}"] = 'chart';
// word/_rels/document.xml.rel
$this->relationships[] = array('target' => $filename, 'type' => 'chart', 'rID' => $rId);
// word/charts/chartN.xml
/** @var \PhpOffice\PhpWord\Element\Chart $chart */
$chart->setRelationId($rId);
$writerPart = $this->getWriterPart('Chart');
$writerPart->setElement($chart);
$zip->addFromString("word/{$filename}", $writerPart->write());
}
}
}
/**
* Register content types for each media
*

View File

@ -0,0 +1,79 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\Word2007\Element;
use PhpOffice\PhpWord\Element\Chart as ChartElement;
/**
* Chart element writer
*
* @since 0.12.0
*/
class Chart extends AbstractElement
{
/**
* Write element
*/
public function write()
{
$xmlWriter = $this->getXmlWriter();
$element = $this->getElement();
if (!$element instanceof ChartElement) {
return;
}
if (!$this->withoutP) {
$xmlWriter->startElement('w:p');
}
$xmlWriter->startElement('w:r');
$xmlWriter->startElement('w:drawing');
$xmlWriter->startElement('wp:inline');
// EMU
$xmlWriter->startElement('wp:extent');
$xmlWriter->writeAttribute('cx', '2000000');
$xmlWriter->writeAttribute('cy', '2000000');
$xmlWriter->endElement(); // wp:extent
$xmlWriter->startElement('wp:docPr');
$xmlWriter->writeAttribute('id', $element->getRelationId());
$xmlWriter->writeAttribute('name', 'Chart'. $element->getRelationId());
$xmlWriter->endElement(); // wp:docPr
$xmlWriter->startElement('a:graphic');
$xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
$xmlWriter->startElement('a:graphicData');
$xmlWriter->writeAttribute('uri', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
$xmlWriter->startElement('c:chart');
$xmlWriter->writeAttribute('r:id', 'rId' . $element->getRelationId());
$xmlWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
$xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$xmlWriter->endElement(); // c:chart
$xmlWriter->endElement(); // a:graphicData
$xmlWriter->endElement(); // a:graphic
$xmlWriter->endElement(); // wp:inline
$xmlWriter->endElement(); // w:drawing
$xmlWriter->endElement(); // w:r
$this->endElementP(); // w:p
}
}

View File

@ -0,0 +1,331 @@
<?php
/**
* This file is part of PHPWord - A pure PHP library for reading and writing
* word processing documents.
*
* PHPWord is free software distributed under the terms of the GNU Lesser
* General Public License version 3 as published by the Free Software Foundation.
*
* For the full copyright and license information, please read the LICENSE
* file that was distributed with this source code. For the full list of
* contributors, visit https://github.com/PHPOffice/PHPWord/contributors.
*
* @link https://github.com/PHPOffice/PHPWord
* @copyright 2010-2014 PHPWord contributors
* @license http://www.gnu.org/licenses/lgpl.txt LGPL version 3
*/
namespace PhpOffice\PhpWord\Writer\Word2007\Part;
use PhpOffice\PhpWord\Shared\XMLWriter;
use PhpOffice\PhpWord\Element\Chart as ChartElement;
/**
* Word2007 chart part writer: word/charts/chartx.xml
*
* @since 0.12.0
* @SuppressWarnings(PHPMD.UnusedPrivateMethod)
*/
class Chart extends AbstractPart
{
/**
* Chart element
*
* @var \PhpOffice\PhpWord\Element\Chart $element
*/
private $element;
/**
* Set chart element
*/
public function setElement(ChartElement $element)
{
$this->element = $element;
}
/**
* Write part
*
* @return string
*/
public function write()
{
$xmlWriter = $this->getXmlWriter();
$xmlWriter->startDocument('1.0', 'UTF-8', 'yes');
$xmlWriter->startElement('c:chartSpace');
$xmlWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
$xmlWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
$xmlWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
$xmlWriter->writeBlock('c:roundedCorners', 'val', '0');
$xmlWriter->startElement('c:chart');
$this->writePlotArea($xmlWriter);
$xmlWriter->endElement(); // c:chart
$xmlWriter->endElement(); // c:chartSpace
return $xmlWriter->getData();
}
/**
* Write plot area
*/
private function writePlotArea(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:plotArea');
$method = "write{$this->element->getType()}Chart";
$this->$method($xmlWriter);
$xmlWriter->endElement(); // c:plotArea
}
/**
* Write pie chart
*
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_PieChart.html
*/
private function writePieChart(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:pieChart');
$xmlWriter->writeBlock('c:varyColors', 'val', '1');
$this->writeSeries($xmlWriter);
$xmlWriter->endElement(); // c:pie3DChart
}
/**
* Write doughnut chart
*
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_DoughnutChart.html
*/
private function writeDoughnutChart(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:doughnutChart');
$xmlWriter->writeBlock('c:varyColors', 'val', '1');
$xmlWriter->writeBlock('c:holeSize', 'val', '75');
$this->writeSeries($xmlWriter);
$xmlWriter->endElement(); // c:doughnutChart
}
/**
* Write bar chart
*
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_BarChart.html
*/
private function writeBarChart(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:barChart');
$xmlWriter->writeBlock('c:varyColors', 'val', '0');
$xmlWriter->writeBlock('c:barDir', 'val', 'col'); // bar|col
$xmlWriter->writeBlock('c:axId', 'val', '1');
$xmlWriter->writeBlock('c:axId', 'val', '2');
$this->writeSeries($xmlWriter);
$xmlWriter->endElement(); // c:barChart
// Axes
$this->writeAxis($xmlWriter, 'cat');
$this->writeAxis($xmlWriter, 'val');
}
/**
* Write line chart
*
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_LineChart.html
*/
private function writeLineChart(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:lineChart');
$xmlWriter->writeBlock('c:varyColors', 'val', '0');
$xmlWriter->writeBlock('c:axId', 'val', '1');
$xmlWriter->writeBlock('c:axId', 'val', '2');
$this->writeSeries($xmlWriter);
$xmlWriter->endElement(); // c:lineChart
// Axes
$this->writeAxis($xmlWriter, 'cat');
$this->writeAxis($xmlWriter, 'val');
}
/**
* Write area chart
*
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_AreaChart.html
*/
private function writeAreaChart(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:areaChart');
$xmlWriter->writeBlock('c:varyColors', 'val', '0');
$xmlWriter->writeBlock('c:axId', 'val', '1');
$xmlWriter->writeBlock('c:axId', 'val', '2');
$this->writeSeries($xmlWriter);
$xmlWriter->endElement(); // c:areaChart
// Axes
$this->writeAxis($xmlWriter, 'cat');
$this->writeAxis($xmlWriter, 'val');
}
/**
* Write radar chart
*
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_RadarChart.html
*/
private function writeRadarChart(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:radarChart');
$xmlWriter->writeBlock('c:varyColors', 'val', '0');
$xmlWriter->writeBlock('c:radarStyle', 'val', 'standard');
$xmlWriter->writeBlock('c:axId', 'val', '1');
$xmlWriter->writeBlock('c:axId', 'val', '2');
$this->writeSeries($xmlWriter);
$xmlWriter->endElement(); // c:radarChart
// Axes
$this->writeAxis($xmlWriter, 'cat');
$this->writeAxis($xmlWriter, 'val');
}
/**
* Write scatter chart
*
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_ScatterChart.html
*/
private function writeScatterChart(XMLWriter $xmlWriter)
{
$xmlWriter->startElement('c:scatterChart');
$xmlWriter->writeBlock('c:varyColors', 'val', '0');
$xmlWriter->writeBlock('c:scatterStyle', 'val', 'lineMarker');
$xmlWriter->writeBlock('c:axId', 'val', '1');
$xmlWriter->writeBlock('c:axId', 'val', '2');
$this->writeSeries($xmlWriter, true);
$xmlWriter->endElement(); // c:scatterChart
// Axes
$this->writeAxis($xmlWriter, 'cat');
$this->writeAxis($xmlWriter, 'val');
}
/**
* Write series
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param bool $scatter
*/
private function writeSeries(XMLWriter $xmlWriter, $scatter = false)
{
$xmlWriter->startElement('c:ser');
$xmlWriter->writeBlock('c:idx', 'val', '0');
$xmlWriter->writeBlock('c:order', 'val', '0');
if ($scatter === true) {
$this->writeSeriesItems($xmlWriter, 'xVal', $this->element->getLabels());
$this->writeSeriesItems($xmlWriter, 'yVal', $this->element->getData());
} else {
$this->writeSeriesItems($xmlWriter, 'cat', $this->element->getLabels());
$this->writeSeriesItems($xmlWriter, 'val', $this->element->getData());
}
$xmlWriter->endElement(); // c:ser
}
/**
* Write series items
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param string $type
* @param array $values
*/
private function writeSeriesItems(XMLWriter $xmlWriter, $type, $values)
{
$types = array(
'cat' => array('c:cat', 'c:strRef', 'c:strCache'),
'val' => array('c:val', 'c:numRef', 'c:numCache'),
'xVal' => array('c:xVal', 'c:strRef', 'c:strCache'),
'yVal' => array('c:yVal', 'c:numRef', 'c:numCache'),
);
list($itemType, $itemRef, $itemCache) = $types[$type];
$xmlWriter->startElement($itemType);
$xmlWriter->startElement($itemRef);
$xmlWriter->startElement($itemCache);
$index = 0;
foreach ($values as $value) {
$xmlWriter->startElement('c:pt');
$xmlWriter->writeAttribute('idx', $index);
$xmlWriter->startElement('c:v');
$xmlWriter->writeRaw($value);
$xmlWriter->endElement(); // c:v
$xmlWriter->endElement(); // c:pt
$index++;
}
$xmlWriter->endElement(); // $itemCache
$xmlWriter->endElement(); // $itemRef
$xmlWriter->endElement(); // $itemType
}
/**
* Write axis
*
* @param \PhpOffice\PhpWord\Shared\XMLWriter $xmlWriter
* @param string $type
* @link http://www.datypic.com/sc/ooxml/t-draw-chart_CT_CatAx.html
*/
private function writeAxis(XMLWriter $xmlWriter, $type)
{
$types = array(
'cat' => array('c:catAx', '1', 'b', '2'),
'val' => array('c:valAx', '2', 'l', '1'),
);
list($axisType, $axisId, $axisPos, $axisCross) = $types[$type];
$xmlWriter->startElement($axisType);
$xmlWriter->writeBlock('c:axId', 'val', $axisId);
$xmlWriter->writeBlock('c:axPos', 'val', $axisPos);
$xmlWriter->writeBlock('c:crossAx', 'val', $axisCross);
$xmlWriter->startElement('c:scaling');
$xmlWriter->writeBlock('c:orientation', 'val', 'minMax');
$xmlWriter->endElement(); // c:scaling
$xmlWriter->startElement('c:spPr');
$xmlWriter->writeElement('a:noFill');
$xmlWriter->startElement('a:ln');
$xmlWriter->startElement('a:solidFill');
$xmlWriter->writeBlock('a:srgbClr', 'val', '0FB7');
$xmlWriter->endElement(); // a:solidFill
$xmlWriter->endElement(); // a:ln
$xmlWriter->endElement(); // c:crossAx
$xmlWriter->endElement(); // $type
}
}

View File

@ -37,6 +37,7 @@ class ContentTypes extends AbstractPart
$openXMLPrefix = 'application/vnd.openxmlformats-';
$wordMLPrefix = $openXMLPrefix . 'officedocument.wordprocessingml.';
$drawingMLPrefix = $openXMLPrefix . 'officedocument.drawingml.';
$overrides = array(
'/docProps/core.xml' => $openXMLPrefix . 'package.core-properties+xml',
'/docProps/app.xml' => $openXMLPrefix . 'officedocument.extended-properties+xml',
@ -53,9 +54,13 @@ class ContentTypes extends AbstractPart
$defaults = $contentTypes['default'];
if (!empty($contentTypes['override'])) {
foreach ($contentTypes['override'] as $key => $val) {
if ($val == 'chart') {
$overrides[$key] = $drawingMLPrefix . $val . '+xml';
} else {
$overrides[$key] = $wordMLPrefix . $val . '+xml';
}
}
}
$xmlWriter = $this->getXmlWriter();

View File

@ -41,7 +41,7 @@ class ElementTest extends \PHPUnit_Framework_TestCase
$elements = array(
'CheckBox', 'Container', 'Footnote', 'Image', 'Link', 'ListItem', 'ListItemRun',
'Object', 'PreserveText', 'Table', 'Text', 'TextBox', 'TextBreak', 'Title', 'TOC',
'Field', 'Line', 'Shape'
'Field', 'Line', 'Shape', 'Chart'
);
foreach ($elements as $element) {
$objectClass = 'PhpOffice\\PhpWord\\Writer\\Word2007\\Element\\' . $element;