More Display Options for Chart Axis and Legend (#3434)

* Allow Color and Effects on Data Points on Chart Axis

Fix #3414. There had been no way to do this. It is now supported via a new AxisText class, which derives from Properties, and has FillColor and effects (glow/shadow/softEdges) properties. The code changes in chart sample 33_Chart_create_scatter2 illustrate usage.

* Minor Performance Improvement

May also get rid of Scrutinizer complaint.

* Eliminate New Spacing Patch

No need for it.

* Add Legend Formatting to Change

Much in common with Data Point formatting.
This commit is contained in:
oleibman
2023-03-09 10:15:24 -08:00
committed by GitHub
parent 64f32d8c75
commit 20348642ed
9 changed files with 617 additions and 18 deletions
+10 -3
View File
@@ -1,6 +1,7 @@
<?php
use PhpOffice\PhpSpreadsheet\Chart\Axis as ChartAxis;
use PhpOffice\PhpSpreadsheet\Chart\AxisText;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
@@ -89,9 +90,9 @@ $dataSeriesValues[0]->setLineStyleProperties(
Properties::LINE_STYLE_CAP_SQUARE, // cap
Properties::LINE_STYLE_JOIN_MITER, // join
Properties::LINE_STYLE_ARROW_TYPE_OPEN, // head type
Properties::LINE_STYLE_ARROW_SIZE_4, // head size preset index
(string) Properties::LINE_STYLE_ARROW_SIZE_4, // head size preset index
Properties::LINE_STYLE_ARROW_TYPE_ARROW, // end type
Properties::LINE_STYLE_ARROW_SIZE_6 // end size preset index
(string) Properties::LINE_STYLE_ARROW_SIZE_6 // end size preset index
);
// series 2 - straight line - no special effects, connected, straight line
@@ -124,7 +125,10 @@ $dataSeriesValues[2]->setScatterLines(false); // points not connected
$xAxis = new ChartAxis();
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, true);
$xAxis->setAxisOption('textRotation', '45');
//$xAxis->setAxisOption('textRotation', '45');
$xAxisText = new AxisText();
$xAxisText->setRotation(45)->getFillColorObject()->setValue('00FF00')->setType(ChartColor::EXCEL_COLOR_TYPE_RGB);
$xAxis->setAxisText($xAxisText);
$yAxis = new ChartAxis();
$yAxis->setLineStyleProperties(
@@ -135,6 +139,9 @@ $yAxis->setLineStyleProperties(
Properties::LINE_STYLE_JOIN_BEVEL
);
$yAxis->setLineColorProperties('ffc000', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$yAxisText = new AxisText();
$yAxisText->setGlowProperties(20.0, 'accent1', 20, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
$yAxis->setAxisText($yAxisText);
// Build the dataseries
$series = new DataSeries(
+9
View File
@@ -1,6 +1,8 @@
<?php
use PhpOffice\PhpSpreadsheet\Chart\AxisText;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
@@ -80,6 +82,12 @@ $series = new DataSeries(
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false);
$legend->getBorderColor()->setColorProperties('ffc000');
$legend->getFillColor()->setColorProperties('cccccc');
$legendText = new AxisText();
$legendText->getFillColorObject()->setValue('008080')->setType(ChartColor::EXCEL_COLOR_TYPE_RGB);
$legendText->setShadowProperties(1);
$legend->setLegendText($legendText);
$title = new Title('Test Stock Chart');
$xAxisLabel = new Title('Counts');
@@ -103,6 +111,7 @@ $chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
$worksheet->setSelectedCells('G2');
// Save Excel 2007 file
$filename = $helper->getFilename(__FILE__);
+23
View File
@@ -52,6 +52,9 @@ class Axis extends Properties
/** @var string */
private $axisType = '';
/** @var ?AxisText */
private $axisText;
/**
* Axis Options.
*
@@ -183,6 +186,14 @@ class Axis extends Properties
*/
public function getAxisOptionsProperty($property)
{
if ($property === 'textRotation') {
if ($this->axisText !== null) {
if ($this->axisText->getRotation() !== null) {
return (string) $this->axisText->getRotation();
}
}
}
return $this->axisOptions[$property];
}
@@ -295,4 +306,16 @@ class Axis extends Properties
return $this;
}
public function getAxisText(): ?AxisText
{
return $this->axisText;
}
public function setAxisText(?AxisText $axisText): self
{
$this->axisText = $axisText;
return $this;
}
}
+35
View File
@@ -0,0 +1,35 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Chart;
class AxisText extends Properties
{
/** @var ?int */
private $rotation;
/** @var ChartColor */
private $fillColor;
public function __construct()
{
parent::__construct();
$this->fillColor = new ChartColor();
}
public function setRotation(?int $rotation): self
{
$this->rotation = $rotation;
return $this;
}
public function getRotation(): ?int
{
return $this->rotation;
}
public function getFillColorObject(): ChartColor
{
return $this->fillColor;
}
}
+33
View File
@@ -48,6 +48,15 @@ class Legend
*/
private $layout;
/** @var ChartColor */
private $borderColor;
/** @var ChartColor */
private $fillColor;
/** @var ?AxisText */
private $legendText;
/**
* Create a new Legend.
*
@@ -60,6 +69,18 @@ class Legend
$this->setPosition($position);
$this->layout = $layout;
$this->setOverlay($overlay);
$this->borderColor = new ChartColor();
$this->fillColor = new ChartColor();
}
public function getBorderColor(): ChartColor
{
return $this->borderColor;
}
public function getFillColor(): ChartColor
{
return $this->fillColor;
}
/**
@@ -148,4 +169,16 @@ class Legend
{
return $this->layout;
}
public function getLegendText(): ?AxisText
{
return $this->legendText;
}
public function setLegendText(?AxisText $legendText): self
{
$this->legendText = $legendText;
return $this;
}
}
+65 -5
View File
@@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
use PhpOffice\PhpSpreadsheet\Chart\Axis;
use PhpOffice\PhpSpreadsheet\Chart\AxisText;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
@@ -350,6 +351,10 @@ class Chart
$legendPos = 'r';
$legendLayout = null;
$legendOverlay = false;
$legendBorderColor = null;
$legendFillColor = null;
$legendText = null;
$addLegendText = false;
foreach ($chartDetails as $chartDetailKey => $chartDetail) {
$chartDetail = Xlsx::testSimpleXml($chartDetail);
switch ($chartDetailKey) {
@@ -364,10 +369,44 @@ class Chart
case 'layout':
$legendLayout = $this->chartLayoutDetails($chartDetail);
break;
case 'spPr':
$children = $chartDetails->spPr->children($this->aNamespace);
if (isset($children->solidFill)) {
$legendFillColor = $this->readColor($children->solidFill);
}
if (isset($children->ln->solidFill)) {
$legendBorderColor = $this->readColor($children->ln->solidFill);
}
break;
case 'txPr':
$children = $chartDetails->txPr->children($this->aNamespace);
$addLegendText = false;
$legendText = new AxisText();
if (isset($children->p->pPr->defRPr->solidFill)) {
$colorArray = $this->readColor($children->p->pPr->defRPr->solidFill);
$legendText->getFillColorObject()->setColorPropertiesArray($colorArray);
$addLegendText = true;
}
if (isset($children->p->pPr->defRPr->effectLst)) {
$this->readEffects($children->p->pPr->defRPr, $legendText, false);
$addLegendText = true;
}
break;
}
}
$legend = new Legend("$legendPos", $legendLayout, (bool) $legendOverlay);
if ($legendFillColor !== null) {
$legend->getFillColor()->setColorPropertiesArray($legendFillColor);
}
if ($legendBorderColor !== null) {
$legend->getBorderColor()->setColorPropertiesArray($legendBorderColor);
}
if ($addLegendText) {
$legend->setLegendText($legendText);
}
break;
}
@@ -1176,13 +1215,19 @@ class Chart
}
}
private function readEffects(SimpleXMLElement $chartDetail, ?ChartProperties $chartObject): void
private function readEffects(SimpleXMLElement $chartDetail, ?ChartProperties $chartObject, bool $getSppr = true): void
{
if (!isset($chartObject, $chartDetail->spPr)) {
if (!isset($chartObject)) {
return;
}
$sppr = $chartDetail->spPr->children($this->aNamespace);
if ($getSppr) {
if (!isset($chartDetail->spPr)) {
return;
}
$sppr = $chartDetail->spPr->children($this->aNamespace);
} else {
$sppr = $chartDetail;
}
if (isset($sppr->effectLst->glow)) {
$axisGlowSize = (float) self::getAttribute($sppr->effectLst->glow, 'rad', 'integer') / ChartProperties::POINTS_WIDTH_MULTIPLIER;
if ($axisGlowSize != 0.0) {
@@ -1412,13 +1457,28 @@ class Chart
}
if (isset($chartDetail->txPr)) {
$children = $chartDetail->txPr->children($this->aNamespace);
$addAxisText = false;
$axisText = new AxisText();
if (isset($children->bodyPr)) {
/** @var string */
$textRotation = self::getAttribute($children->bodyPr, 'rot', 'string');
if (is_numeric($textRotation)) {
$whichAxis->setAxisOption('textRotation', (string) ChartProperties::xmlToAngle($textRotation));
$axisText->setRotation((int) ChartProperties::xmlToAngle($textRotation));
$addAxisText = true;
}
}
if (isset($children->p->pPr->defRPr->solidFill)) {
$colorArray = $this->readColor($children->p->pPr->defRPr->solidFill);
$axisText->getFillColorObject()->setColorPropertiesArray($colorArray);
$addAxisText = true;
}
if (isset($children->p->pPr->defRPr->effectLst)) {
$this->readEffects($children->p->pPr->defRPr, $axisText, false);
$addAxisText = true;
}
if ($addAxisText) {
$whichAxis->setAxisText($axisText);
}
}
}
}
+46 -10
View File
@@ -201,6 +201,22 @@ class Chart extends WriterPart
$objWriter->writeAttribute('val', ($legend->getOverlay()) ? '1' : '0');
$objWriter->endElement();
$fillColor = $legend->getFillColor();
$borderColor = $legend->getBorderColor();
if ($fillColor->isUsable() || $borderColor->isUsable()) {
$objWriter->startElement('c:spPr');
if ($fillColor->isUsable()) {
$this->writeColor($objWriter, $fillColor);
}
if ($borderColor->isUsable()) {
$objWriter->startElement('a:ln');
$this->writeColor($objWriter, $borderColor);
$objWriter->endElement(); // a:ln
}
$objWriter->endElement(); // c:spPr
}
$legendText = $legend->getLegendText();
$objWriter->startElement('c:txPr');
$objWriter->startElement('a:bodyPr');
$objWriter->endElement();
@@ -213,17 +229,21 @@ class Chart extends WriterPart
$objWriter->writeAttribute('rtl', '0');
$objWriter->startElement('a:defRPr');
$objWriter->endElement();
$objWriter->endElement();
if ($legendText !== null) {
$this->writeColor($objWriter, $legendText->getFillColorObject());
$this->writeEffects($objWriter, $legendText);
}
$objWriter->endElement(); // a:defRpr
$objWriter->endElement(); // a:pPr
$objWriter->startElement('a:endParaRPr');
$objWriter->writeAttribute('lang', 'en-US');
$objWriter->endElement();
$objWriter->endElement(); // a:endParaRPr
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement(); // a:p
$objWriter->endElement(); // c:txPr
$objWriter->endElement();
$objWriter->endElement(); // c:legend
}
/**
@@ -608,16 +628,24 @@ class Chart extends WriterPart
}
$textRotation = $yAxis->getAxisOptionsProperty('textRotation');
if (is_numeric($textRotation)) {
$axisText = $yAxis->getAxisText();
if ($axisText !== null || is_numeric($textRotation)) {
$objWriter->startElement('c:txPr');
$objWriter->startElement('a:bodyPr');
$objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation));
if (is_numeric($textRotation)) {
$objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation));
}
$objWriter->endElement(); // a:bodyPr
$objWriter->startElement('a:lstStyle');
$objWriter->endElement(); // a:lstStyle
$objWriter->startElement('a:p');
$objWriter->startElement('a:pPr');
$objWriter->startElement('a:defRPr');
if ($axisText !== null) {
$this->writeColor($objWriter, $axisText->getFillColorObject());
$this->writeEffects($objWriter, $axisText);
}
$objWriter->endElement(); // a:defRPr
$objWriter->endElement(); // a:pPr
$objWriter->endElement(); // a:p
@@ -826,16 +854,24 @@ class Chart extends WriterPart
}
$textRotation = $xAxis->getAxisOptionsProperty('textRotation');
if (is_numeric($textRotation)) {
$axisText = $xAxis->getAxisText();
if ($axisText !== null || is_numeric($textRotation)) {
$objWriter->startElement('c:txPr');
$objWriter->startElement('a:bodyPr');
$objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation));
if (is_numeric($textRotation)) {
$objWriter->writeAttribute('rot', Properties::angleToXml((float) $textRotation));
}
$objWriter->endElement(); // a:bodyPr
$objWriter->startElement('a:lstStyle');
$objWriter->endElement(); // a:lstStyle
$objWriter->startElement('a:p');
$objWriter->startElement('a:pPr');
$objWriter->startElement('a:defRPr');
if ($axisText !== null) {
$this->writeColor($objWriter, $axisText->getFillColorObject());
$this->writeEffects($objWriter, $axisText);
}
$objWriter->endElement(); // a:defRPr
$objWriter->endElement(); // a:pPr
$objWriter->endElement(); // a:p
@@ -0,0 +1,232 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Axis as ChartAxis;
use PhpOffice\PhpSpreadsheet\Chart\AxisText;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class DataSeriesColorTest extends AbstractFunctional
{
// based on 33_Char_create_scatter2
public function readCharts(XlsxReader $reader): void
{
$reader->setIncludeCharts(true);
}
public function writeCharts(XlsxWriter $writer): void
{
$writer->setIncludeCharts(true);
}
public function testDataSeriesValues(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
// changed data to simulate a trend chart - Xaxis are dates; Yaxis are 3 measurements from each date
$worksheet->fromArray(
[
['', 'metric1', 'metric2', 'metric3'],
['=DATEVALUE("2021-01-01")', 12.1, 15.1, 21.1],
['=DATEVALUE("2021-01-04")', 56.2, 73.2, 86.2],
['=DATEVALUE("2021-01-07")', 52.2, 61.2, 69.2],
['=DATEVALUE("2021-01-10")', 30.2, 32.2, 0.2],
]
);
$worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601);
$worksheet->getColumnDimension('A')->setAutoSize(true);
$worksheet->setSelectedCells('A1');
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // was 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // was 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // was 2012
];
// Set the X-Axis Labels
// changed from STRING to NUMBER
// added 2 additional x-axis values associated with each of the 3 metrics
// added FORMATE_CODE_NUMBER
$xAxisTickValues = [
//new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// added FORMAT_CODE_NUMBER
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', Properties::FORMAT_CODE_NUMBER, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', Properties::FORMAT_CODE_NUMBER, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', Properties::FORMAT_CODE_NUMBER, 4),
];
// series 1
// marker details
$dataSeriesValues[0]
->setPointMarker('diamond')
->setPointSize(5)
->getMarkerFillColor()
->setColorProperties('0070C0', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[0]
->getMarkerBorderColor()
->setColorProperties('002060', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
// line details - smooth line, connected
$dataSeriesValues[0]
->setScatterLines(true)
->setSmoothLine(true)
->setLineColorProperties('accent1', 40, ChartColor::EXCEL_COLOR_TYPE_SCHEME); // value, alpha, type
$dataSeriesValues[0]->setLineStyleProperties(
2.5, // width in points
Properties::LINE_STYLE_COMPOUND_TRIPLE, // compound
Properties::LINE_STYLE_DASH_SQUARE_DOT, // dash
Properties::LINE_STYLE_CAP_SQUARE, // cap
Properties::LINE_STYLE_JOIN_MITER, // join
Properties::LINE_STYLE_ARROW_TYPE_OPEN, // head type
(string) Properties::LINE_STYLE_ARROW_SIZE_4, // head size preset index
Properties::LINE_STYLE_ARROW_TYPE_ARROW, // end type
(string) Properties::LINE_STYLE_ARROW_SIZE_6 // end size preset index
);
// series 2 - straight line - no special effects, connected, straight line
$dataSeriesValues[1] // square fill
->setPointMarker('square')
->setPointSize(6)
->getMarkerBorderColor()
->setColorProperties('accent6', 3, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
$dataSeriesValues[1] // square border
->getMarkerFillColor()
->setColorProperties('0FFF00', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[1]
->setScatterLines(true)
->setSmoothLine(false)
->setLineColorProperties('FF0000', 80, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[1]->setLineWidth(2.0);
// series 3 - markers, no line
$dataSeriesValues[2] // triangle fill
//->setPointMarker('triangle') // let Excel choose shape
->setPointSize(7)
->getMarkerFillColor()
->setColorProperties('FFFF00', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[2] // triangle border
->getMarkerBorderColor()
->setColorProperties('accent4', null, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
$dataSeriesValues[2]->setScatterLines(false); // points not connected
// Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers
$xAxis = new ChartAxis();
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, true);
//$xAxis->setAxisOption('textRotation', '45');
$xAxisText = new AxisText();
$xAxisText->setRotation(45)->getFillColorObject()->setValue('00FF00')->setType(ChartColor::EXCEL_COLOR_TYPE_RGB);
$xAxis->setAxisText($xAxisText);
$yAxis = new ChartAxis();
$yAxis->setLineStyleProperties(
2.5, // width in points
Properties::LINE_STYLE_COMPOUND_SIMPLE,
Properties::LINE_STYLE_DASH_DASH_DOT,
Properties::LINE_STYLE_CAP_FLAT,
Properties::LINE_STYLE_JOIN_BEVEL
);
$yAxis->setLineColorProperties('ffc000', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$yAxisText = new AxisText();
$yAxisText->setGlowProperties(20.0, 'accent1', 20, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
$yAxis->setAxisText($yAxisText);
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_SCATTERCHART, // plotType
null, // plotGrouping (Scatter charts don't have any grouping)
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues, // plotValues
null, // plotDirection
false, // smooth line
DataSeries::STYLE_SMOOTHMARKER // plotStyle
);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test Scatter Trend Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel, // yAxisLabel
// added xAxis for correct date display
$xAxis, // xAxis
$yAxis, // yAxis
);
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('P20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
/** @var callable */
$callableReader = [$this, 'readCharts'];
/** @var callable */
$callableWriter = [$this, 'writeCharts'];
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
$spreadsheet->disconnectWorksheets();
$sheet = $reloadedSpreadsheet->getActiveSheet();
$charts2 = $sheet->getChartCollection();
self::assertCount(1, $charts2);
$chart2 = $charts2[0];
self::assertNotNull($chart2);
$xAxisText = $chart2->getChartAxisX()->getAxisText();
$yAxisText = $chart2->getChartAxisY()->getAxisText();
if ($xAxisText === null || $yAxisText === null) {
self::fail('Unexpected null x-axis or y-axis');
} else {
self::assertSame(45, $xAxisText->getRotation());
self::assertSame('00FF00', $xAxisText->getFillColorObject()->getValue());
self::assertSame(ChartColor::EXCEL_COLOR_TYPE_RGB, $xAxisText->getFillColorObject()->getType());
self::assertSame(20.0, $yAxisText->getGlowProperty('size'));
self::assertSame(['value' => 'accent1', 'type' => 'schemeClr', 'alpha' => 20], $yAxisText->getGlowProperty('color'));
}
$reloadedSpreadsheet->disconnectWorksheets();
}
}
@@ -0,0 +1,164 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\AxisText;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class LegendColorTest extends AbstractFunctional
{
// based on 33_Chart_create_stock
public function readCharts(XlsxReader $reader): void
{
$reader->setIncludeCharts(true);
}
public function writeCharts(XlsxWriter $writer): void
{
$writer->setIncludeCharts(true);
}
public function testLegend(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['Counts', 'Max', 'Min', 'Min Threshold', 'Max Threshold'],
[10, 10, 5, 0, 50],
[30, 20, 10, 0, 50],
[20, 30, 15, 0, 50],
[40, 10, 0, 0, 50],
[100, 40, 5, 0, 50],
],
null,
'A1',
true
);
$worksheet->getStyle('B2:E6')->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_NUMBER_00);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), //Max / Open
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), //Min / Close
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), //Min Threshold / Min
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$E$1', null, 1), //Max Threshold / Max
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$6', null, 5), // Counts
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$6', null, 5),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$6', null, 5),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$6', null, 5),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$E$2:$E$6', null, 5),
];
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_STOCKCHART, // plotType
null, // plotGrouping - if we set this to not null, then xlsx throws error
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false);
$legend->getBorderColor()->setColorProperties('ffc000');
$legend->getFillColor()->setColorProperties('cccccc');
$legendText = new AxisText();
$legendText->getFillColorObject()->setValue('008080')->setType(ChartColor::EXCEL_COLOR_TYPE_RGB);
$legendText->setShadowProperties(1);
$legend->setLegendText($legendText);
$title = new Title('Test Stock Chart');
$xAxisLabel = new Title('Counts');
$yAxisLabel = new Title('Values');
// Create the chart
$chart = new Chart(
'stock-chart', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
$xAxisLabel, // xAxisLabel
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
$worksheet->setSelectedCells('G2');
/** @var callable */
$callableReader = [$this, 'readCharts'];
/** @var callable */
$callableWriter = [$this, 'writeCharts'];
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
$spreadsheet->disconnectWorksheets();
$sheet = $reloadedSpreadsheet->getActiveSheet();
$charts2 = $sheet->getChartCollection();
self::assertCount(1, $charts2);
$chart2 = $charts2[0];
self::assertNotNull($chart2);
$legend2 = $chart2->getLegend();
if ($legend2 === null) {
self::fail('Unexpected null legend');
} else {
self::assertSame('ffc000', $legend2->getBorderColor()->getValue());
self::assertSame('cccccc', $legend2->getFillColor()->getValue());
$legendText2 = $legend2->getLegendText();
if ($legendText2 === null) {
self::fail('Unexpected null legendText');
} else {
self::assertSame('008080', $legendText2->getFillColorObject()->getValue());
self::assertSame('outerShdw', $legendText2->getShadowProperty('effect'));
self::assertSame(4.0, (float) $legendText2->getShadowProperty('blur'));
self::assertSame(45.0, (float) $legendText2->getShadowProperty('direction'));
}
}
$reloadedSpreadsheet->disconnectWorksheets();
}
}