Additional Support for Chart DataSeriesValues (#2906)

* Additional Support for Chart DataSeriesValues

Fix #2863. DataSeriesValues now extends Properties, allowing it to share code in common with Axis and Gridlines. This causes some minor breakages; in particular line width is now initialized to null instead of Excel's default value, and is specified in points, as the user would expect from Excel, rather than the value stored in Xml.

This change:
- adds support for 1 or 2 marker colors.
- adds support for `smoothLine` to DataSeriesValues.
- will determine `catAx` or `valAx` for Axis based on what is read from the Xml when available, rather than guessing based on format. (Another minor break.)
- reads `formatCode` and `sourceLinked` for Axis.
- correct 2 uses of `$plotSeriesRef` to `$plotSeriesIndex` in Writer/Xlsx/Chart.
- pushes coverage over 90% for Chart (88.70% overall).

* Update Change Log

I had updated previously but forgot to stage the member.

* Adopt Some Suggestions

Incorporate some changes suggested by @bridgeplayr.

* Use ChartColor for DSV Fill And Font Text

DataSeriesValues Fill could be a scalar or an array, so I saved it till last.

* Some Final Cleanup

No code changes.

Illustrate even more of the new features in existing sample files.

Deprecate *_ARGB in Properties/ChartColors in favor of *_RGB, because it uses only 6 hex digits. The alpha value is stored separately.
This commit is contained in:
oleibman 2022-06-29 17:52:09 -07:00 committed by GitHub
parent b5b83abc0e
commit 5d5e550342
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1279 additions and 385 deletions

View File

@ -49,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Time interval formatting [Issue #2768](https://github.com/PHPOffice/PhpSpreadsheet/issues/2768) [PR #2772](https://github.com/PHPOffice/PhpSpreadsheet/pull/2772)
- Copy from Xls(x) to Html/Pdf loses drawings [PR #2788](https://github.com/PHPOffice/PhpSpreadsheet/pull/2788)
- Html Reader converting cell containing 0 to null string [Issue #2810](https://github.com/PHPOffice/PhpSpreadsheet/issues/2810) [PR #2813](https://github.com/PHPOffice/PhpSpreadsheet/pull/2813)
- Many fixes for Charts, especially, but not limited to, Scatter, Bubble, and Surface charts. [Issue #2762](https://github.com/PHPOffice/PhpSpreadsheet/issues/2762) [Issue #2299](https://github.com/PHPOffice/PhpSpreadsheet/issues/2299) [Issue #2700](https://github.com/PHPOffice/PhpSpreadsheet/issues/2700) [Issue #2817](https://github.com/PHPOffice/PhpSpreadsheet/issues/2817) [Issue #2763](https://github.com/PHPOffice/PhpSpreadsheet/issues/2763) [Issue #2219](https://github.com/PHPOffice/PhpSpreadsheet/issues/2219) [PR #2828](https://github.com/PHPOffice/PhpSpreadsheet/pull/2828) [PR #2841](https://github.com/PHPOffice/PhpSpreadsheet/pull/2841) [PR #2846](https://github.com/PHPOffice/PhpSpreadsheet/pull/2846) [PR #2852](https://github.com/PHPOffice/PhpSpreadsheet/pull/2852) [PR #2856](https://github.com/PHPOffice/PhpSpreadsheet/pull/2856) [PR #2865](https://github.com/PHPOffice/PhpSpreadsheet/pull/2865) [PR #2872](https://github.com/PHPOffice/PhpSpreadsheet/pull/2872) [PR #2879](https://github.com/PHPOffice/PhpSpreadsheet/pull/2879)
- Many fixes for Charts, especially, but not limited to, Scatter, Bubble, and Surface charts. [Issue #2762](https://github.com/PHPOffice/PhpSpreadsheet/issues/2762) [Issue #2299](https://github.com/PHPOffice/PhpSpreadsheet/issues/2299) [Issue #2700](https://github.com/PHPOffice/PhpSpreadsheet/issues/2700) [Issue #2817](https://github.com/PHPOffice/PhpSpreadsheet/issues/2817) [Issue #2763](https://github.com/PHPOffice/PhpSpreadsheet/issues/2763) [Issue #2219](https://github.com/PHPOffice/PhpSpreadsheet/issues/2219) [Issue #2863](https://github.com/PHPOffice/PhpSpreadsheet/issues/2863) [PR #2828](https://github.com/PHPOffice/PhpSpreadsheet/pull/2828) [PR #2841](https://github.com/PHPOffice/PhpSpreadsheet/pull/2841) [PR #2846](https://github.com/PHPOffice/PhpSpreadsheet/pull/2846) [PR #2852](https://github.com/PHPOffice/PhpSpreadsheet/pull/2852) [PR #2856](https://github.com/PHPOffice/PhpSpreadsheet/pull/2856) [PR #2865](https://github.com/PHPOffice/PhpSpreadsheet/pull/2865) [PR #2872](https://github.com/PHPOffice/PhpSpreadsheet/pull/2872) [PR #2879](https://github.com/PHPOffice/PhpSpreadsheet/pull/2879) [PR #2898](https://github.com/PHPOffice/PhpSpreadsheet/pull/2898) [PR #2906](https://github.com/PHPOffice/PhpSpreadsheet/pull/2906)
- Calculating Engine regexp for Column/Row references when there are multiple quoted worksheet references in the formula [Issue #2874](https://github.com/PHPOffice/PhpSpreadsheet/issues/2874) [PR #2899](https://github.com/PHPOffice/PhpSpreadsheet/pull/2899)
## 1.23.0 - 2022-04-24

View File

@ -4055,16 +4055,6 @@ parameters:
count: 1
path: src/PhpSpreadsheet/Writer/Xlsx.php
-
message: "#^Cannot call method getDataValues\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|false\\.$#"
count: 1
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
-
message: "#^Cannot call method getFillColor\\(\\) on PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|false\\.$#"
count: 1
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
-
message: "#^Parameter \\#1 \\$plotSeriesValues of method PhpOffice\\\\PhpSpreadsheet\\\\Writer\\\\Xlsx\\\\Chart\\:\\:writeBubbles\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|null, PhpOffice\\\\PhpSpreadsheet\\\\Chart\\\\DataSeriesValues\\|false given\\.$#"
count: 1
@ -4087,7 +4077,7 @@ parameters:
-
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#"
count: 42
count: 41
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
-

View File

@ -0,0 +1,183 @@
<?php
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Layout;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
require __DIR__ . '/../Header.php';
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
// Custom colors for dataSeries (gray, blue, red, orange)
$colors = [
'cccccc', '00abb8', 'b8292f', 'eb8500',
];
// 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
$dataSeriesLabels1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// 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
// Custom colors
$dataSeriesValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4, [], null, $colors),
];
// Build the dataseries
$series1 = new DataSeries(
DataSeries::TYPE_BARCHART, // plotType
null, // plotGrouping (Pie charts don't have any grouping)
range(0, count($dataSeriesValues1) - 1), // plotOrder
$dataSeriesLabels1, // plotLabel
$xAxisTickValues1, // plotCategory
$dataSeriesValues1 // plotValues
);
// Set up a layout object for the Pie chart
$layout1 = new Layout();
$layout1->setShowVal(true);
$layout1->setShowPercent(true);
// Set the series in the plot area
$plotArea1 = new PlotArea($layout1, [$series1]);
// Set the chart legend
$legend1 = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false);
$title1 = new Title('Test Bar Chart');
// Create the chart
$chart1 = new Chart(
'chart1', // name
$title1, // title
$legend1, // legend
$plotArea1, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
null // yAxisLabel - Pie charts don't have a Y-Axis
);
// Set the position where the chart should appear in the worksheet
$chart1->setTopLeftPosition('A7');
$chart1->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart1);
// 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
$dataSeriesLabels2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues2 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// 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
// Custom colors
$dataSeriesValues2 = [
$dataSeriesValues2Element = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
];
$dataSeriesValues2Element->setFillColor($colors);
// Build the dataseries
$series2 = new DataSeries(
DataSeries::TYPE_DONUTCHART, // plotType
null, // plotGrouping (Donut charts don't have any grouping)
range(0, count($dataSeriesValues2) - 1), // plotOrder
$dataSeriesLabels2, // plotLabel
$xAxisTickValues2, // plotCategory
$dataSeriesValues2 // plotValues
);
// Set up a layout object for the Pie chart
$layout2 = new Layout();
$layout2->setShowVal(true);
$layout2->setShowCatName(true);
// Set the series in the plot area
$plotArea2 = new PlotArea($layout2, [$series2]);
$title2 = new Title('Test Donut Chart');
// Create the chart
$chart2 = new Chart(
'chart2', // name
$title2, // title
null, // legend
$plotArea2, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
null // yAxisLabel - Like Pie charts, Donut charts don't have a Y-Axis
);
// Set the position where the chart should appear in the worksheet
$chart2->setTopLeftPosition('I7');
$chart2->setBottomRightPosition('P20');
// Add the chart to the worksheet
$worksheet->addChart($chart2);
// Save Excel 2007 file
$filename = $helper->getFilename(__FILE__);
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->setIncludeCharts(true);
$callStartTime = microtime(true);
$writer->save($filename);
$helper->logWrite($writer, $filename, $callStartTime);

View File

@ -5,6 +5,7 @@ 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\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
@ -35,6 +36,7 @@ $dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
$dataSeriesLabels[0]->setFillColor('FF0000');
// Set the X-Axis Labels
// Datatype
// Cell reference for data
@ -57,7 +59,7 @@ $dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
$dataSeriesValues[2]->setLineWidth(60000);
$dataSeriesValues[2]->setLineWidth(60000 / Properties::POINTS_WIDTH_MULTIPLIER);
// Build the dataseries
$series = new DataSeries(

View File

@ -2,6 +2,7 @@
use PhpOffice\PhpSpreadsheet\Chart\Axis;
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;
@ -64,11 +65,76 @@ $dataSeriesValues = [
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
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
);
// 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 Axis();
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, true);
$yAxis = new Axis();
$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);
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_SCATTERCHART, // plotType
@ -79,8 +145,7 @@ $series = new DataSeries(
$dataSeriesValues, // plotValues
null, // plotDirection
false, // smooth line
//DataSeries::STYLE_LINEMARKER // plotStyle
DataSeries::STYLE_MARKER // plotStyle
DataSeries::STYLE_SMOOTHMARKER // plotStyle
);
// Set the series in the plot area
@ -103,6 +168,7 @@ $chart = new Chart(
$yAxisLabel, // yAxisLabel
// added xAxis for correct date display
$xAxis, // xAxis
$yAxis, // yAxis
);
// Set the position where the chart should appear in the worksheet

Binary file not shown.

View File

@ -27,6 +27,9 @@ class Axis extends Properties
'numeric' => null,
];
/** @var string */
private $axisType = '';
/**
* Axis Options.
*
@ -62,11 +65,11 @@ class Axis extends Properties
*
* @param mixed $format_code
*/
public function setAxisNumberProperties($format_code, ?bool $numeric = null): void
public function setAxisNumberProperties($format_code, ?bool $numeric = null, int $sourceLinked = 0): void
{
$format = (string) $format_code;
$this->axisNumber['format'] = $format;
$this->axisNumber['source_linked'] = 0;
$this->axisNumber['source_linked'] = $sourceLinked;
if (is_bool($numeric)) {
$this->axisNumber['numeric'] = $numeric;
} elseif (in_array($format, self::NUMERIC_FORMAT, true)) {
@ -156,6 +159,22 @@ class Axis extends Properties
$this->axisOptions['orientation'] = (string) $orientation;
}
public function getAxisType(): string
{
return $this->axisType;
}
public function setAxisType(string $type): self
{
if ($type === 'catAx' || $type === 'valAx') {
$this->axisType = $type;
} else {
$this->axisType = '';
}
return $this;
}
/**
* Set Fill Property.
*

View File

@ -6,6 +6,8 @@ class ChartColor
{
const EXCEL_COLOR_TYPE_STANDARD = 'prstClr';
const EXCEL_COLOR_TYPE_SCHEME = 'schemeClr';
const EXCEL_COLOR_TYPE_RGB = 'srgbClr';
/** @deprecated 1.24 use EXCEL_COLOR_TYPE_RGB instead */
const EXCEL_COLOR_TYPE_ARGB = 'srgbClr';
const EXCEL_COLOR_TYPES = [
self::EXCEL_COLOR_TYPE_ARGB,
@ -22,6 +24,18 @@ class ChartColor
/** @var ?int */
private $alpha;
/**
* @param string|string[] $value
*/
public function __construct($value = '', ?int $alpha = null, ?string $type = null)
{
if (is_array($value)) {
$this->setColorPropertiesArray($value);
} else {
$this->setColorProperties($value, $alpha, $type);
}
}
public function getValue(): string
{
return $this->value;
@ -61,10 +75,21 @@ class ChartColor
/**
* @param null|float|int|string $alpha
*/
public function setColorProperties(?string $color, $alpha, ?string $type): self
public function setColorProperties(?string $color, $alpha = null, ?string $type = null): self
{
if (empty($type) && !empty($color)) {
if (substr($color, 0, 1) === '*') {
$type = 'schemeClr';
$color = substr($color, 1);
} elseif (substr($color, 0, 1) === '/') {
$type = 'prstClr';
$color = substr($color, 1);
} elseif (preg_match('/^[0-9A-Fa-f]{6}$/', $color) === 1) {
$type = 'srgbClr';
}
}
if ($color !== null) {
$this->setValue($color);
$this->setValue("$color");
}
if ($type !== null) {
$this->setType($type);
@ -80,21 +105,16 @@ class ChartColor
public function setColorPropertiesArray(array $color): self
{
if (array_key_exists('value', $color) && is_string($color['value'])) {
$this->setValue($color['value']);
}
if (array_key_exists('type', $color) && is_string($color['type'])) {
$this->setType($color['type']);
}
if (array_key_exists('alpha', $color)) {
if ($color['alpha'] === null) {
$this->setAlpha(null);
} elseif (is_numeric($color['alpha'])) {
$this->setAlpha((int) $color['alpha']);
}
return $this->setColorProperties(
$color['value'] ?? '',
$color['alpha'] ?? null,
$color['type'] ?? null
);
}
return $this;
public function isUsable(): bool
{
return $this->type !== '' && $this->value !== '';
}
/**

View File

@ -257,8 +257,6 @@ class DataSeries
$keys = array_keys($this->plotLabel);
if (in_array($index, $keys)) {
return $this->plotLabel[$index];
} elseif (isset($keys[$index])) {
return $this->plotLabel[$keys[$index]];
}
return false;
@ -339,8 +337,6 @@ class DataSeries
$keys = array_keys($this->plotValues);
if (in_array($index, $keys)) {
return $this->plotValues[$index];
} elseif (isset($keys[$index])) {
return $this->plotValues[$keys[$index]];
}
return false;

View File

@ -7,7 +7,7 @@ use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class DataSeriesValues
class DataSeriesValues extends Properties
{
const DATASERIES_TYPE_STRING = 'String';
const DATASERIES_TYPE_NUMBER = 'Number';
@ -45,6 +45,12 @@ class DataSeriesValues
*/
private $pointMarker;
/** @var ChartColor */
private $markerFillColor;
/** @var ChartColor */
private $markerBorderColor;
/**
* Series Point Size.
*
@ -69,23 +75,10 @@ class DataSeriesValues
/**
* Fill color (can be array with colors if dataseries have custom colors).
*
* @var null|string|string[]
* @var null|ChartColor|ChartColor[]
*/
private $fillColor;
/** @var string */
private $schemeClr = '';
/** @var string */
private $prstClr = '';
/**
* Line Width.
*
* @var int
*/
private $lineWidth = 12700;
/** @var bool */
private $scatterLines = true;
@ -101,18 +94,23 @@ class DataSeriesValues
* @param int $pointCount
* @param mixed $dataValues
* @param null|mixed $marker
* @param null|string|string[] $fillColor
* @param null|ChartColor|ChartColor[]|string|string[] $fillColor
* @param string $pointSize
*/
public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null, $pointSize = '3')
{
parent::__construct();
$this->markerFillColor = new ChartColor();
$this->markerBorderColor = new ChartColor();
$this->setDataType($dataType);
$this->dataSource = $dataSource;
$this->formatCode = $formatCode;
$this->pointCount = $pointCount;
$this->dataValues = $dataValues;
$this->pointMarker = $marker;
$this->fillColor = $fillColor;
if ($fillColor !== null) {
$this->setFillColor($fillColor);
}
if (is_numeric($pointSize)) {
$this->pointSize = (int) $pointSize;
}
@ -198,6 +196,16 @@ class DataSeriesValues
return $this;
}
public function getMarkerFillColor(): ChartColor
{
return $this->markerFillColor;
}
public function getMarkerBorderColor(): ChartColor
{
return $this->markerBorderColor;
}
/**
* Get Point Size.
*/
@ -252,37 +260,96 @@ class DataSeriesValues
return $this->pointCount;
}
/**
* Get fill color object.
*
* @return null|ChartColor|ChartColor[]
*/
public function getFillColorObject()
{
return $this->fillColor;
}
private function stringToChartColor(string $fillString): ChartColor
{
$value = $type = '';
if (substr($fillString, 0, 1) === '*') {
$type = 'schemeClr';
$value = substr($fillString, 1);
} elseif (substr($fillString, 0, 1) === '/') {
$type = 'prstClr';
$value = substr($fillString, 1);
} elseif ($fillString !== '') {
$type = 'srgbClr';
$value = $fillString;
$this->validateColor($value);
}
return new ChartColor($value, null, $type);
}
private function chartColorToString(ChartColor $chartColor): string
{
$type = (string) $chartColor->getColorProperty('type');
$value = (string) $chartColor->getColorProperty('value');
if ($type === '' || $value === '') {
return '';
}
if ($type === 'schemeClr') {
return "*$value";
}
if ($type === 'prstClr') {
return "/$value";
}
return $value;
}
/**
* Get fill color.
*
* @return null|string|string[] HEX color or array with HEX colors
* @return string|string[] HEX color or array with HEX colors
*/
public function getFillColor()
{
return $this->fillColor;
if ($this->fillColor === null) {
return '';
}
if (is_array($this->fillColor)) {
$array = [];
foreach ($this->fillColor as $chartColor) {
$array[] = self::chartColorToString($chartColor);
}
return $array;
}
return self::chartColorToString($this->fillColor);
}
/**
* Set fill color for series.
*
* @param string|string[] $color HEX color or array with HEX colors
* @param ChartColor|ChartColor[]|string|string[] $color HEX color or array with HEX colors
*
* @return DataSeriesValues
*/
public function setFillColor($color)
{
if (is_array($color)) {
foreach ($color as $colorValue) {
if (substr($colorValue, 0, 1) !== '*' && substr($colorValue, 0, 1) !== '/') {
$this->validateColor($colorValue);
}
}
$this->fillColor = [];
foreach ($color as $fillString) {
if ($fillString instanceof ChartColor) {
$this->fillColor[] = $fillString;
} else {
if (substr($color, 0, 1) !== '*' && substr($color, 0, 1) !== '/') {
$this->validateColor("$color");
$this->fillColor[] = self::stringToChartColor($fillString);
}
}
} elseif ($color instanceof ChartColor) {
$this->fillColor = $color;
} elseif (is_string($color)) {
$this->fillColor = self::stringToChartColor($color);
}
return $this;
}
@ -306,24 +373,23 @@ class DataSeriesValues
/**
* Get line width for series.
*
* @return int
* @return null|float|int
*/
public function getLineWidth()
{
return $this->lineWidth;
return $this->lineStyleProperties['width'];
}
/**
* Set line width for the series.
*
* @param int $width
* @param null|float|int $width
*
* @return $this
*/
public function setLineWidth($width)
{
$minWidth = 12700;
$this->lineWidth = max($minWidth, $width);
$this->lineStyleProperties['width'] = $width;
return $this;
}
@ -466,26 +532,33 @@ class DataSeriesValues
return $this;
}
public function getSchemeClr(): string
/**
* Smooth Line.
*
* @var bool
*/
private $smoothLine;
/**
* Get Smooth Line.
*
* @return bool
*/
public function getSmoothLine()
{
return $this->schemeClr;
return $this->smoothLine;
}
public function setSchemeClr(string $schemeClr): self
/**
* Set Smooth Line.
*
* @param bool $smoothLine
*
* @return $this
*/
public function setSmoothLine($smoothLine)
{
$this->schemeClr = $schemeClr;
return $this;
}
public function getPrstClr(): string
{
return $this->prstClr;
}
public function setPrstClr(string $prstClr): self
{
$this->prstClr = $prstClr;
$this->smoothLine = $smoothLine;
return $this;
}

View File

@ -59,6 +59,8 @@ abstract class Properties
const LINE_STYLE_COMPOUND_TRIPLE = 'tri';
const LINE_STYLE_DASH_SOLID = 'solid';
const LINE_STYLE_DASH_ROUND_DOT = 'sysDot';
const LINE_STYLE_DASH_SQUARE_DOT = 'sysDash';
/** @deprecated 1.24 use LINE_STYLE_DASH_SQUARE_DOT instead */
const LINE_STYLE_DASH_SQUERE_DOT = 'sysDash';
const LINE_STYPE_DASH_DASH = 'dash';
const LINE_STYLE_DASH_DASH_DOT = 'dashDot';
@ -68,7 +70,7 @@ abstract class Properties
const LINE_STYLE_CAP_SQUARE = 'sq';
const LINE_STYLE_CAP_ROUND = 'rnd';
const LINE_STYLE_CAP_FLAT = 'flat';
const LINE_STYLE_JOIN_ROUND = 'bevel';
const LINE_STYLE_JOIN_ROUND = 'round';
const LINE_STYLE_JOIN_MITER = 'miter';
const LINE_STYLE_JOIN_BEVEL = 'bevel';
const LINE_STYLE_ARROW_TYPE_NOARROW = null;
@ -643,30 +645,6 @@ abstract class Properties
return $this;
}
/**
* Set Shadow Color.
*
* @param string $color
* @param int $alpha
* @param string $colorType
*
* @return $this
*/
protected function setShadowColor($color, $alpha, $colorType)
{
if ($color !== null) {
$this->shadowProperties['color']['value'] = (string) $color;
}
if ($alpha !== null) {
$this->shadowProperties['color']['alpha'] = (int) $alpha;
}
if ($colorType !== null) {
$this->shadowProperties['color']['type'] = (string) $colorType;
}
return $this;
}
/**
* Set Shadow Blur.
*
@ -766,6 +744,12 @@ abstract class Properties
],
];
public function copyLineStyles(self $otherProperties): void
{
$this->lineStyleProperties = $otherProperties->lineStyleProperties;
$this->lineColor = $otherProperties->lineColor;
}
public function getLineColor(): ChartColor
{
return $this->lineColor;

View File

@ -14,7 +14,6 @@ use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\Style\Color;
use PhpOffice\PhpSpreadsheet\Style\Font;
use SimpleXMLElement;
@ -90,6 +89,7 @@ class Chart
case 'plotArea':
$plotAreaLayout = $XaxisLabel = $YaxisLabel = null;
$plotSeries = $plotAttributes = [];
$catAxRead = false;
foreach ($chartDetails as $chartDetailKey => $chartDetail) {
switch ($chartDetailKey) {
case 'layout':
@ -97,9 +97,11 @@ class Chart
break;
case 'catAx':
$catAxRead = true;
if (isset($chartDetail->title)) {
$XaxisLabel = $this->chartTitle($chartDetail->title->children($this->cNamespace));
}
$xAxis->setAxisType('catAx');
$this->readEffects($chartDetail, $xAxis);
if (isset($chartDetail->spPr)) {
$sppr = $chartDetail->spPr->children($this->aNamespace);
@ -122,16 +124,22 @@ class Chart
$axPos = null;
if (isset($chartDetail->axPos)) {
$axPos = self::getAttribute($chartDetail->axPos, 'val', 'string');
}
if ($catAxRead) {
$whichAxis = $yAxis;
$yAxis->setAxisType($chartDetailKey);
} elseif (!empty($axPos)) {
switch ($axPos) {
case 't':
case 'b':
$whichAxis = $xAxis;
$xAxis->setAxisType($chartDetailKey);
break;
case 'r':
case 'l':
$whichAxis = $yAxis;
$yAxis->setAxisType($chartDetailKey);
break;
}
@ -373,14 +381,14 @@ class Chart
case 'ser':
$marker = null;
$seriesIndex = '';
$srgbClr = null;
$lineWidth = null;
$fillColor = null;
$pointSize = null;
$noFill = false;
$schemeClr = '';
$prstClr = '';
$bubble3D = false;
$dPtColors = [];
$markerFillColor = null;
$markerBorderColor = null;
$lineStyle = null;
foreach ($seriesDetails as $seriesKey => $seriesDetail) {
switch ($seriesKey) {
case 'idx':
@ -399,12 +407,16 @@ class Chart
case 'spPr':
$children = $seriesDetail->children($this->aNamespace);
$ln = $children->ln;
$lineWidth = self::getAttribute($ln, 'w', 'string');
if (isset($children->ln)) {
$ln = $children->ln;
if (is_countable($ln->noFill) && count($ln->noFill) === 1) {
$noFill = true;
}
$lineStyle = new GridLines();
$this->readLineStyle($seriesDetails, $lineStyle);
}
if (isset($children->solidFill)) {
$this->readColor($children->solidFill, $srgbClr, $schemeClr, $prstClr);
$fillColor = new ChartColor($this->readColor($children->solidFill));
}
break;
@ -414,13 +426,7 @@ class Chart
$children = $seriesDetail->spPr->children($this->aNamespace);
if (isset($children->solidFill)) {
$arrayColors = $this->readColor($children->solidFill);
if ($arrayColors['type'] === 'srgbClr') {
$dptColors[$dptIdx] = $arrayColors['value'];
} elseif ($arrayColors['type'] === 'prstClr') {
$dptColors[$dptIdx] = '/' . $arrayColors['value'];
} else {
$dptColors[$dptIdx] = '*' . $arrayColors['value'];
}
$dptColors[$dptIdx] = new ChartColor($arrayColors);
}
}
@ -429,10 +435,13 @@ class Chart
$marker = self::getAttribute($seriesDetail->symbol, 'val', 'string');
$pointSize = self::getAttribute($seriesDetail->size, 'val', 'string');
$pointSize = is_numeric($pointSize) ? ((int) $pointSize) : null;
if (count($seriesDetail->spPr) === 1) {
$ln = $seriesDetail->spPr->children($this->aNamespace);
if (isset($ln->solidFill)) {
$this->readColor($ln->solidFill, $srgbClr, $schemeClr, $prstClr);
if (isset($seriesDetail->spPr)) {
$children = $seriesDetail->spPr->children($this->aNamespace);
if (isset($children->solidFill)) {
$markerFillColor = $this->readColor($children->solidFill);
}
if (isset($children->ln->solidFill)) {
$markerBorderColor = $this->readColor($children->ln->solidFill);
}
}
@ -446,19 +455,19 @@ class Chart
break;
case 'val':
$seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
$seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
break;
case 'xVal':
$seriesCategory[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
$seriesCategory[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
break;
case 'yVal':
$seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
$seriesValues[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
break;
case 'bubbleSize':
$seriesBubbles[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", "$srgbClr", "$pointSize");
$seriesBubbles[$seriesIndex] = $this->chartDataSeriesValueSet($seriesDetail, "$marker", $fillColor, "$pointSize");
break;
case 'bubble3D':
@ -478,36 +487,15 @@ class Chart
$seriesValues[$seriesIndex]->setScatterLines(false);
}
}
if (is_numeric($lineWidth)) {
if ($lineStyle !== null) {
if (isset($seriesLabel[$seriesIndex])) {
$seriesLabel[$seriesIndex]->setLineWidth((int) $lineWidth);
$seriesLabel[$seriesIndex]->copyLineStyles($lineStyle);
}
if (isset($seriesCategory[$seriesIndex])) {
$seriesCategory[$seriesIndex]->setLineWidth((int) $lineWidth);
$seriesCategory[$seriesIndex]->copyLineStyles($lineStyle);
}
if (isset($seriesValues[$seriesIndex])) {
$seriesValues[$seriesIndex]->setLineWidth((int) $lineWidth);
}
}
if ($schemeClr) {
if (isset($seriesLabel[$seriesIndex])) {
$seriesLabel[$seriesIndex]->setSchemeClr($schemeClr);
}
if (isset($seriesCategory[$seriesIndex])) {
$seriesCategory[$seriesIndex]->setSchemeClr($schemeClr);
}
if (isset($seriesValues[$seriesIndex])) {
$seriesValues[$seriesIndex]->setSchemeClr($schemeClr);
}
} elseif ($prstClr) {
if (isset($seriesLabel[$seriesIndex])) {
$seriesLabel[$seriesIndex]->setPrstClr($prstClr);
}
if (isset($seriesCategory[$seriesIndex])) {
$seriesCategory[$seriesIndex]->setPrstClr($prstClr);
}
if (isset($seriesValues[$seriesIndex])) {
$seriesValues[$seriesIndex]->setPrstClr($prstClr);
$seriesValues[$seriesIndex]->copyLineStyles($lineStyle);
}
}
if ($bubble3D) {
@ -532,6 +520,39 @@ class Chart
$seriesValues[$seriesIndex]->setFillColor($dptColors);
}
}
if ($markerFillColor !== null) {
if (isset($seriesLabel[$seriesIndex])) {
$seriesLabel[$seriesIndex]->getMarkerFillColor()->setColorPropertiesArray($markerFillColor);
}
if (isset($seriesCategory[$seriesIndex])) {
$seriesCategory[$seriesIndex]->getMarkerFillColor()->setColorPropertiesArray($markerFillColor);
}
if (isset($seriesValues[$seriesIndex])) {
$seriesValues[$seriesIndex]->getMarkerFillColor()->setColorPropertiesArray($markerFillColor);
}
}
if ($markerBorderColor !== null) {
if (isset($seriesLabel[$seriesIndex])) {
$seriesLabel[$seriesIndex]->getMarkerBorderColor()->setColorPropertiesArray($markerBorderColor);
}
if (isset($seriesCategory[$seriesIndex])) {
$seriesCategory[$seriesIndex]->getMarkerBorderColor()->setColorPropertiesArray($markerBorderColor);
}
if (isset($seriesValues[$seriesIndex])) {
$seriesValues[$seriesIndex]->getMarkerBorderColor()->setColorPropertiesArray($markerBorderColor);
}
}
if ($smoothLine) {
if (isset($seriesLabel[$seriesIndex])) {
$seriesLabel[$seriesIndex]->setSmoothLine(true);
}
if (isset($seriesCategory[$seriesIndex])) {
$seriesCategory[$seriesIndex]->setSmoothLine(true);
}
if (isset($seriesValues[$seriesIndex])) {
$seriesValues[$seriesIndex]->setSmoothLine(true);
}
}
}
}
/** @phpstan-ignore-next-line */
@ -544,11 +565,11 @@ class Chart
/**
* @return mixed
*/
private function chartDataSeriesValueSet(SimpleXMLElement $seriesDetail, ?string $marker = null, ?string $srgbClr = null, ?string $pointSize = null)
private function chartDataSeriesValueSet(SimpleXMLElement $seriesDetail, ?string $marker = null, ?ChartColor $fillColor = null, ?string $pointSize = null)
{
if (isset($seriesDetail->strRef)) {
$seriesSource = (string) $seriesDetail->strRef->f;
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
if (isset($seriesDetail->strRef->strCache)) {
$seriesData = $this->chartDataSeriesValues($seriesDetail->strRef->strCache->children($this->cNamespace), 's');
@ -560,7 +581,7 @@ class Chart
return $seriesValues;
} elseif (isset($seriesDetail->numRef)) {
$seriesSource = (string) $seriesDetail->numRef->f;
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
if (isset($seriesDetail->numRef->numCache)) {
$seriesData = $this->chartDataSeriesValues($seriesDetail->numRef->numCache->children($this->cNamespace));
$seriesValues
@ -571,7 +592,7 @@ class Chart
return $seriesValues;
} elseif (isset($seriesDetail->multiLvlStrRef)) {
$seriesSource = (string) $seriesDetail->multiLvlStrRef->f;
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
if (isset($seriesDetail->multiLvlStrRef->multiLvlStrCache)) {
$seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlStrRef->multiLvlStrCache->children($this->cNamespace), 's');
@ -583,7 +604,7 @@ class Chart
return $seriesValues;
} elseif (isset($seriesDetail->multiLvlNumRef)) {
$seriesSource = (string) $seriesDetail->multiLvlNumRef->f;
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $srgbClr, "$pointSize");
$seriesValues = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, $seriesSource, null, 0, null, $marker, $fillColor, "$pointSize");
if (isset($seriesDetail->multiLvlNumRef->multiLvlNumCache)) {
$seriesData = $this->chartDataSeriesValuesMultiLevel($seriesDetail->multiLvlNumRef->multiLvlNumCache->children($this->cNamespace), 's');
@ -698,8 +719,7 @@ class Chart
$defaultLatin = null;
$defaultEastAsian = null;
$defaultComplexScript = null;
$defaultSrgbColor = '';
$defaultSchemeColor = '';
$defaultFontColor = null;
if (isset($titleDetailPart->pPr->defRPr)) {
/** @var ?int */
$defaultFontSize = self::getAttribute($titleDetailPart->pPr->defRPr, 'sz', 'integer');
@ -729,7 +749,7 @@ class Chart
$defaultComplexScript = self::getAttribute($titleDetailPart->pPr->defRPr->cs, 'typeface', 'string');
}
if (isset($titleDetailPart->pPr->defRPr->solidFill)) {
$this->readColor($titleDetailPart->pPr->defRPr->solidFill, $defaultSrgbColor, $defaultSchemeClr);
$defaultFontColor = $this->readColor($titleDetailPart->pPr->defRPr->solidFill);
}
}
foreach ($titleDetailPart as $titleDetailElementKey => $titleDetailElement) {
@ -755,8 +775,7 @@ class Chart
$latinName = null;
$eastAsian = null;
$complexScript = null;
$fontSrgbClr = '';
$fontSchemeClr = '';
$fontColor = null;
$underlineColor = null;
if (isset($titleDetailElement->rPr)) {
// not used now, not sure it ever was, grandfathering
@ -781,10 +800,8 @@ class Chart
$fontSize = self::getAttribute($titleDetailElement->rPr, 'sz', 'integer');
// not used now, not sure it ever was, grandfathering
/** @var ?string */
$fontSrgbClr = self::getAttribute($titleDetailElement->rPr, 'color', 'string');
if (isset($titleDetailElement->rPr->solidFill)) {
$this->readColor($titleDetailElement->rPr->solidFill, $fontSrgbClr, $fontSchemeClr);
$fontColor = $this->readColor($titleDetailElement->rPr->solidFill);
}
/** @var ?bool */
@ -834,19 +851,15 @@ class Chart
if (is_int($fontSize)) {
$objText->getFont()->setSize(floor($fontSize / 100));
$fontFound = true;
} else {
$objText->getFont()->setSize(null, true);
}
$fontSrgbClr = $fontSrgbClr ?? $defaultSrgbColor;
if (!empty($fontSrgbClr)) {
$objText->getFont()->setColor(new Color($fontSrgbClr));
$fontColor = $fontColor ?? $defaultFontColor;
if (!empty($fontColor)) {
$objText->getFont()->setChartColor($fontColor);
$fontFound = true;
}
// need to think about what to do here
//$fontSchemeClr = $fontSchemeClr ?? $defaultSchemeColor;
//if (!empty($fontSchemeClr)) {
// $objText->getFont()->setColor(new Color($fontSrgbClr));
// $fontFound = true;
//}
$bold = $bold ?? $defaultBold;
if ($bold !== null) {
@ -1059,7 +1072,7 @@ class Chart
'innerShdw',
];
private function readColor(SimpleXMLElement $colorXml, ?string &$srgbClr = null, ?string &$schemeClr = null, ?string &$prstClr = null): array
private function readColor(SimpleXMLElement $colorXml): array
{
$result = [
'type' => null,
@ -1070,13 +1083,6 @@ class Chart
if (isset($colorXml->$type)) {
$result['type'] = $type;
$result['value'] = self::getAttribute($colorXml->$type, 'val', 'string');
if ($type === Properties::EXCEL_COLOR_TYPE_ARGB) {
$srgbClr = $result['value'];
} elseif ($type === Properties::EXCEL_COLOR_TYPE_SCHEME) {
$schemeClr = $result['value'];
} elseif ($type === Properties::EXCEL_COLOR_TYPE_STANDARD) {
$prstClr = $result['value'];
}
if (isset($colorXml->$type->alpha)) {
/** @var string */
$alpha = self::getAttribute($colorXml->$type->alpha, 'val', 'string');
@ -1092,10 +1098,7 @@ class Chart
return $result;
}
/**
* @param null|GridLines $chartObject may be extended to include other types
*/
private function readLineStyle(SimpleXMLElement $chartDetail, $chartObject): void
private function readLineStyle(SimpleXMLElement $chartDetail, ?Properties $chartObject): void
{
if (!isset($chartObject, $chartDetail->spPr)) {
return;
@ -1164,6 +1167,13 @@ class Chart
if (!isset($whichAxis)) {
return;
}
if (isset($chartDetail->numFmt)) {
$whichAxis->setAxisNumberProperties(
(string) self::getAttribute($chartDetail->numFmt, 'formatCode', 'string'),
null,
(int) self::getAttribute($chartDetail->numFmt, 'sourceLinked', 'int')
);
}
if (isset($chartDetail->crossBetween)) {
$whichAxis->setCrossBetween((string) self::getAttribute($chartDetail->crossBetween, 'val', 'string'));
}

View File

@ -21,7 +21,7 @@ class Font extends Supervisor
protected $name = 'Calibri';
/**
* The following 6 are used only for chart titles, I think.
* The following 7 are used only for chart titles, I think.
*
*@var string
*/
@ -41,6 +41,9 @@ class Font extends Supervisor
/** @var ?ChartColor */
private $underlineColor;
/** @var ?ChartColor */
private $chartColor;
// end of chart title items
/**
@ -371,7 +374,7 @@ class Font extends Supervisor
*
* @return $this
*/
public function setSize($sizeInPoints)
public function setSize($sizeInPoints, bool $nullOk = false)
{
if (is_string($sizeInPoints) || is_int($sizeInPoints)) {
$sizeInPoints = (float) $sizeInPoints; // $pValue = 0 if given string is not numeric
@ -380,8 +383,10 @@ class Font extends Supervisor
// Size must be a positive floating point number
// ECMA-376-1:2016, part 1, chapter 18.4.11 sz (Font Size), p. 1536
if (!is_float($sizeInPoints) || !($sizeInPoints > 0)) {
if (!$nullOk || $sizeInPoints !== null) {
$sizeInPoints = 10.0;
}
}
if ($this->isSupervisor) {
$styleArray = $this->getStyleArray(['size' => $sizeInPoints]);
@ -593,8 +598,7 @@ class Font extends Supervisor
public function setUnderlineColor(array $colorArray): self
{
if (!$this->isSupervisor) {
$this->underlineColor = new ChartColor();
$this->underlineColor->setColorPropertiesArray($colorArray);
$this->underlineColor = new ChartColor($colorArray);
} else {
// should never be true
// @codeCoverageIgnoreStart
@ -606,6 +610,30 @@ class Font extends Supervisor
return $this;
}
public function getChartColor(): ?ChartColor
{
if ($this->isSupervisor) {
return $this->getSharedComponent()->getChartColor();
}
return $this->chartColor;
}
public function setChartColor(array $colorArray): self
{
if (!$this->isSupervisor) {
$this->chartColor = new ChartColor($colorArray);
} else {
// should never be true
// @codeCoverageIgnoreStart
$styleArray = $this->getStyleArray(['chartColor' => $colorArray]);
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
// @codeCoverageIgnoreEnd
}
return $this;
}
/**
* Get Underline.
*
@ -713,6 +741,18 @@ class Font extends Supervisor
return $this;
}
private function hashChartColor(?ChartColor $underlineColor): string
{
if ($this->underlineColor === null) {
return '';
}
return
$this->underlineColor->getValue()
. $this->underlineColor->getType()
. (string) $this->underlineColor->getAlpha();
}
/**
* Get hash code.
*
@ -723,14 +763,6 @@ class Font extends Supervisor
if ($this->isSupervisor) {
return $this->getSharedComponent()->getHashCode();
}
if ($this->underlineColor === null) {
$underlineColor = '';
} else {
$underlineColor =
$this->underlineColor->getValue()
. $this->underlineColor->getType()
. (string) $this->underlineColor->getAlpha();
}
return md5(
$this->name .
@ -749,7 +781,8 @@ class Font extends Supervisor
$this->eastAsian,
$this->complexScript,
$this->strikeType,
$underlineColor,
$this->hashChartColor($this->chartColor),
$this->hashChartColor($this->underlineColor),
(string) $this->baseLine,
]
) .
@ -762,6 +795,7 @@ class Font extends Supervisor
$exportedArray = [];
$this->exportArray2($exportedArray, 'baseLine', $this->getBaseLine());
$this->exportArray2($exportedArray, 'bold', $this->getBold());
$this->exportArray2($exportedArray, 'chartColor', $this->getChartColor());
$this->exportArray2($exportedArray, 'color', $this->getColor());
$this->exportArray2($exportedArray, 'complexScript', $this->getComplexScript());
$this->exportArray2($exportedArray, 'eastAsian', $this->getEastAsian());

View File

@ -419,7 +419,9 @@ class Chart extends WriterPart
{
// N.B. writeCategoryAxis may be invoked with the last parameter($yAxis) using $xAxis for ScatterChart, etc
// In that case, xAxis is NOT a category.
if ($yAxis->getAxisIsNumericFormat()) {
if ($yAxis->getAxisType() !== '') {
$objWriter->startElement('c:' . $yAxis->getAxisType());
} elseif ($yAxis->getAxisIsNumericFormat()) {
$objWriter->startElement('c:valAx');
} else {
$objWriter->startElement('c:catAx');
@ -469,10 +471,6 @@ class Chart extends WriterPart
$objWriter->endElement();
$objWriter->startElement('a:p');
$objWriter->startElement('a:pPr');
$objWriter->startElement('a:defRPr');
$objWriter->endElement();
$objWriter->endElement();
$caption = $xAxisLabel->getCaption();
if (is_array($caption)) {
@ -622,7 +620,7 @@ class Chart extends WriterPart
$objWriter->startElement('c:majorGridlines');
$objWriter->startElement('c:spPr');
$this->writeGridlinesLn($objWriter, $majorGridlines);
$this->writeLineStyles($objWriter, $majorGridlines);
$objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $majorGridlines);
@ -637,7 +635,7 @@ class Chart extends WriterPart
$objWriter->startElement('c:minorGridlines');
$objWriter->startElement('c:spPr');
$this->writeGridlinesLn($objWriter, $minorGridlines);
$this->writeLineStyles($objWriter, $minorGridlines);
$objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $minorGridlines);
@ -661,10 +659,6 @@ class Chart extends WriterPart
$objWriter->endElement();
$objWriter->startElement('a:p');
$objWriter->startElement('a:pPr');
$objWriter->startElement('a:defRPr');
$objWriter->endElement();
$objWriter->endElement();
$caption = $yAxisLabel->getCaption();
if (is_array($caption)) {
@ -715,7 +709,7 @@ class Chart extends WriterPart
$this->writeColor($objWriter, $xAxis->getFillColorObject());
$this->writeGridlinesLn($objWriter, $xAxis);
$this->writeLineStyles($objWriter, $xAxis);
$objWriter->startElement('a:effectLst');
$this->writeGlow($objWriter, $xAxis);
@ -849,40 +843,27 @@ class Chart extends WriterPart
/**
* Method writing plot series values.
*
* @param int $val value for idx (default: 3)
* @param string $fillColor hex color (default: FF9900)
*/
private function writePlotSeriesValuesElement(XMLWriter $objWriter, $val = 3, $fillColor = 'FF9900'): void
private function writePlotSeriesValuesElement(XMLWriter $objWriter, int $val, ?ChartColor $fillColor): void
{
if ($fillColor === '') {
if ($fillColor === null || !$fillColor->isUsable()) {
return;
}
$objWriter->startElement('c:dPt');
$objWriter->startElement('c:idx');
$objWriter->writeAttribute('val', $val);
$objWriter->endElement();
$objWriter->endElement(); // c:idx
$objWriter->startElement('c:bubble3D');
$objWriter->writeAttribute('val', 0);
$objWriter->endElement();
$objWriter->endElement(); // c:bubble3D
$objWriter->startElement('c:spPr');
$objWriter->startElement('a:solidFill');
if (substr($fillColor, 0, 1) === '*') {
$objWriter->startElement('a:schemeClr');
$objWriter->writeAttribute('val', substr($fillColor, 1));
} elseif (substr($fillColor, 0, 1) === '/') {
$objWriter->startElement('a:prstClr');
$objWriter->writeAttribute('val', substr($fillColor, 1));
} else {
$objWriter->startElement('a:srgbClr');
$objWriter->writeAttribute('val', $fillColor);
}
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement();
$this->writeColor($objWriter, $fillColor);
$objWriter->endElement(); // c:spPr
$objWriter->endElement(); // c:dPt
}
/**
@ -934,20 +915,6 @@ class Chart extends WriterPart
foreach ($plotSeriesOrder as $plotSeriesIdx => $plotSeriesRef) {
$objWriter->startElement('c:ser');
$plotLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx);
if ($plotLabel && $groupType !== DataSeries::TYPE_LINECHART) {
$fillColor = $plotLabel->getFillColor();
if ($fillColor !== null && !is_array($fillColor)) {
$objWriter->startElement('c:spPr');
$objWriter->startElement('a:solidFill');
$objWriter->startElement('a:srgbClr');
$objWriter->writeAttribute('val', $fillColor);
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement();
}
}
$objWriter->startElement('c:idx');
$objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesIdx);
$objWriter->endElement();
@ -956,22 +923,35 @@ class Chart extends WriterPart
$objWriter->writeAttribute('val', $this->seriesIndex + $plotSeriesRef);
$objWriter->endElement();
// Values
$plotSeriesValues = $plotGroup->getPlotValuesByIndex($plotSeriesRef);
$plotLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx);
$labelFill = null;
if ($plotLabel && $groupType === DataSeries::TYPE_LINECHART) {
$labelFill = $plotLabel->getFillColorObject();
$labelFill = ($labelFill instanceof ChartColor) ? $labelFill : null;
}
if ($plotLabel && $groupType !== DataSeries::TYPE_LINECHART) {
$fillColor = $plotLabel->getFillColorObject();
if ($fillColor !== null && !is_array($fillColor) && $fillColor->isUsable()) {
$objWriter->startElement('c:spPr');
$this->writeColor($objWriter, $fillColor);
$objWriter->endElement(); // c:spPr
}
}
if (($groupType == DataSeries::TYPE_PIECHART) || ($groupType == DataSeries::TYPE_PIECHART_3D) || ($groupType == DataSeries::TYPE_DONUTCHART)) {
$fillColorValues = $plotSeriesValues->getFillColor();
// Values
$plotSeriesValues = $plotGroup->getPlotValuesByIndex($plotSeriesIdx);
if ($plotSeriesValues !== false && in_array($groupType, self::CUSTOM_COLOR_TYPES, true)) {
$fillColorValues = $plotSeriesValues->getFillColorObject();
if ($fillColorValues !== null && is_array($fillColorValues)) {
foreach ($plotSeriesValues->getDataValues() as $dataKey => $dataValue) {
$this->writePlotSeriesValuesElement($objWriter, $dataKey, $fillColorValues[$dataKey] ?? '');
$this->writePlotSeriesValuesElement($objWriter, $dataKey, $fillColorValues[$dataKey] ?? null);
}
} else {
$this->writePlotSeriesValuesElement($objWriter);
}
}
// Labels
$plotSeriesLabel = $plotGroup->getPlotLabelByIndex($plotSeriesRef);
$plotSeriesLabel = $plotGroup->getPlotLabelByIndex($plotSeriesIdx);
if ($plotSeriesLabel && ($plotSeriesLabel->getPointCount() > 0)) {
$objWriter->startElement('c:tx');
$objWriter->startElement('c:strRef');
@ -982,77 +962,54 @@ class Chart extends WriterPart
// Formatting for the points
if (
$groupType == DataSeries::TYPE_LINECHART
|| $groupType == DataSeries::TYPE_STOCKCHART
|| ($groupType === DataSeries::TYPE_SCATTERCHART && $plotSeriesValues !== false && !$plotSeriesValues->getScatterLines())
|| ($plotSeriesValues !== false && ($plotSeriesValues->getSchemeClr() || $plotSeriesValues->getPrstClr()))
$plotSeriesValues !== false
) {
$plotLineWidth = 12700;
if ($plotSeriesValues) {
$plotLineWidth = $plotSeriesValues->getLineWidth();
}
$objWriter->startElement('c:spPr');
$schemeClr = $typeClr = '';
if ($plotLabel) {
$schemeClr = $plotLabel->getSchemeClr();
if ($schemeClr) {
$typeClr = 'schemeClr';
} else {
$schemeClr = $plotLabel->getPrstClr();
if ($schemeClr) {
$typeClr = 'prstClr';
}
}
}
if ($schemeClr) {
$objWriter->startElement('a:solidFill');
$objWriter->startElement("a:$typeClr");
$objWriter->writeAttribute('val', $schemeClr);
$objWriter->endElement();
$objWriter->endElement();
}
$fillObject = $labelFill ?? $plotSeriesValues->getFillColorObject();
$callLineStyles = true;
if ($fillObject instanceof ChartColor && $fillObject->isUsable()) {
if ($groupType === DataSeries::TYPE_LINECHART) {
$objWriter->startElement('a:ln');
$objWriter->writeAttribute('w', $plotLineWidth);
if ($groupType == DataSeries::TYPE_STOCKCHART || $groupType === DataSeries::TYPE_SCATTERCHART) {
$objWriter->startElement('a:noFill');
$objWriter->endElement();
} elseif ($plotLabel) {
$fillColor = $plotLabel->getFillColor();
if (is_string($fillColor)) {
$objWriter->startElement('a:solidFill');
$objWriter->startElement('a:srgbClr');
$objWriter->writeAttribute('val', $fillColor);
$objWriter->endElement();
$objWriter->endElement();
$callLineStyles = false;
}
$this->writeColor($objWriter, $fillObject);
if (!$callLineStyles) {
$objWriter->endElement(); // a:ln
}
}
$objWriter->endElement();
$objWriter->endElement();
$nofill = $groupType == DataSeries::TYPE_STOCKCHART || ($groupType === DataSeries::TYPE_SCATTERCHART && !$plotSeriesValues->getScatterLines());
if ($callLineStyles) {
$this->writeLineStyles($objWriter, $plotSeriesValues, $nofill);
}
$objWriter->endElement(); // c:spPr
}
if ($plotSeriesValues) {
$plotSeriesMarker = $plotSeriesValues->getPointMarker();
if ($plotSeriesMarker) {
$markerFillColor = $plotSeriesValues->getMarkerFillColor();
$fillUsed = $markerFillColor->IsUsable();
$markerBorderColor = $plotSeriesValues->getMarkerBorderColor();
$borderUsed = $markerBorderColor->isUsable();
if ($plotSeriesMarker || $fillUsed || $borderUsed) {
$objWriter->startElement('c:marker');
$objWriter->startElement('c:symbol');
if ($plotSeriesMarker) {
$objWriter->writeAttribute('val', $plotSeriesMarker);
}
$objWriter->endElement();
if ($plotSeriesMarker !== 'none') {
$objWriter->startElement('c:size');
$objWriter->writeAttribute('val', (string) $plotSeriesValues->getPointSize());
$objWriter->endElement();
$fillColor = $plotSeriesValues->getFillColor();
if (is_string($fillColor) && $fillColor !== '') {
$objWriter->endElement(); // c:size
$objWriter->startElement('c:spPr');
$objWriter->startElement('a:solidFill');
$objWriter->startElement('a:srgbClr');
$objWriter->writeAttribute('val', $fillColor);
$objWriter->endElement(); // srgbClr
$objWriter->endElement(); // solidFill
$objWriter->endElement(); // spPr
$this->writeColor($objWriter, $markerFillColor);
if ($borderUsed) {
$objWriter->startElement('a:ln');
$this->writeColor($objWriter, $markerBorderColor);
$objWriter->endElement(); // a:ln
}
$objWriter->endElement(); // spPr
}
$objWriter->endElement();
@ -1066,7 +1023,7 @@ class Chart extends WriterPart
}
// Category Labels
$plotSeriesCategory = $plotGroup->getPlotCategoryByIndex($plotSeriesRef);
$plotSeriesCategory = $plotGroup->getPlotCategoryByIndex($plotSeriesIdx);
if ($plotSeriesCategory && ($plotSeriesCategory->getPointCount() > 0)) {
$catIsMultiLevelSeries = $catIsMultiLevelSeries || $plotSeriesCategory->isMultiLevelSeries();
@ -1112,7 +1069,7 @@ class Chart extends WriterPart
$objWriter->endElement();
if ($groupType === DataSeries::TYPE_SCATTERCHART && $plotGroup->getPlotStyle() === 'smoothMarker') {
$objWriter->startElement('c:smooth');
$objWriter->writeAttribute('val', '1');
$objWriter->writeAttribute('val', $plotSeriesValues->getSmoothLine() ? '1' : '0');
$objWriter->endElement();
}
}
@ -1268,6 +1225,14 @@ class Chart extends WriterPart
}
}
private const CUSTOM_COLOR_TYPES = [
DataSeries::TYPE_BARCHART,
DataSeries::TYPE_BARCHART_3D,
DataSeries::TYPE_PIECHART,
DataSeries::TYPE_PIECHART_3D,
DataSeries::TYPE_DONUTCHART,
];
/**
* Write Bubble Chart Details.
*/
@ -1384,8 +1349,8 @@ class Chart extends WriterPart
$objWriter->writeAttribute('xmlns:mc', 'http://schemas.openxmlformats.org/markup-compatibility/2006');
$objWriter->startElement('mc:Choice');
$objWriter->writeAttribute('xmlns:c14', 'http://schemas.microsoft.com/office/drawing/2007/8/2/chart');
$objWriter->writeAttribute('Requires', 'c14');
$objWriter->writeAttribute('xmlns:c14', 'http://schemas.microsoft.com/office/drawing/2007/8/2/chart');
$objWriter->startElement('c14:style');
$objWriter->writeAttribute('val', '102');
@ -1509,12 +1474,7 @@ class Chart extends WriterPart
$objWriter->endElement(); //end softEdge
}
/**
* Write Line Style for Gridlines.
*
* @param Axis|GridLines $gridlines
*/
private function writeGridlinesLn(XMLWriter $objWriter, $gridlines): void
private function writeLineStyles(XMLWriter $objWriter, Properties $gridlines, bool $noFill = false): void
{
$objWriter->startElement('a:ln');
$widthTemp = $gridlines->getLineStyleProperty('width');
@ -1523,7 +1483,12 @@ class Chart extends WriterPart
}
$this->writeNotEmpty($objWriter, 'cap', $gridlines->getLineStyleProperty('cap'));
$this->writeNotEmpty($objWriter, 'cmpd', $gridlines->getLineStyleProperty('compound'));
if ($noFill) {
$objWriter->startElement('a:noFill');
$objWriter->endElement();
} else {
$this->writeColor($objWriter, $gridlines->getLineColor());
}
$dash = $gridlines->getLineStyleProperty('dash');
if (!empty($dash)) {
@ -1544,16 +1509,16 @@ class Chart extends WriterPart
if ($gridlines->getLineStyleProperty(['arrow', 'head', 'type'])) {
$objWriter->startElement('a:headEnd');
$objWriter->writeAttribute('type', $gridlines->getLineStyleProperty(['arrow', 'head', 'type']));
$this->writeNotEmpty($objWriter, 'w', $gridlines->getLineStyleArrowParameters('head', 'w'));
$this->writeNotEmpty($objWriter, 'len', $gridlines->getLineStyleArrowParameters('head', 'len'));
$this->writeNotEmpty($objWriter, 'w', $gridlines->getLineStyleArrowWidth('head'));
$this->writeNotEmpty($objWriter, 'len', $gridlines->getLineStyleArrowLength('head'));
$objWriter->endElement();
}
if ($gridlines->getLineStyleProperty(['arrow', 'end', 'type'])) {
$objWriter->startElement('a:tailEnd');
$objWriter->writeAttribute('type', $gridlines->getLineStyleProperty(['arrow', 'end', 'type']));
$this->writeNotEmpty($objWriter, 'w', $gridlines->getLineStyleArrowParameters('end', 'w'));
$this->writeNotEmpty($objWriter, 'len', $gridlines->getLineStyleArrowParameters('end', 'len'));
$this->writeNotEmpty($objWriter, 'w', $gridlines->getLineStyleArrowWidth('end'));
$this->writeNotEmpty($objWriter, 'len', $gridlines->getLineStyleArrowLength('end'));
$objWriter->endElement();
}
$objWriter->endElement(); //end ln

View File

@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\RichText\Run;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
@ -198,7 +199,7 @@ class StringTable extends WriterPart
* @param RichText|string $richText text string or Rich text
* @param string $prefix Optional Namespace prefix
*/
public function writeRichTextForCharts(XMLWriter $objWriter, $richText = null, $prefix = null): void
public function writeRichTextForCharts(XMLWriter $objWriter, $richText = null, $prefix = ''): void
{
if (!$richText instanceof RichText) {
$textRun = $richText;
@ -207,7 +208,7 @@ class StringTable extends WriterPart
$run->setFont(null);
}
if ($prefix !== null) {
if ($prefix !== '') {
$prefix .= ':';
}
@ -249,27 +250,10 @@ class StringTable extends WriterPart
}
// Color
$objWriter->startElement($prefix . 'solidFill');
$objWriter->startElement($prefix . 'srgbClr');
$objWriter->writeAttribute('val', $element->getFont()->getColor()->getRGB());
$objWriter->endElement(); // srgbClr
$objWriter->endElement(); // solidFill
$this->writeChartTextColor($objWriter, $element->getFont()->getChartColor(), $prefix);
// Underscore Color
$underlineColor = $element->getFont()->getUnderlineColor();
if ($underlineColor !== null) {
$type = $underlineColor->getType();
$value = $underlineColor->getValue();
if (!empty($type) && !empty($value)) {
$objWriter->startElement($prefix . 'uFill');
$objWriter->startElement($prefix . 'solidFill');
$objWriter->startElement($prefix . $type);
$objWriter->writeAttribute('val', $value);
$objWriter->endElement(); // schemeClr
$objWriter->endElement(); // solidFill
$objWriter->endElement(); // uFill
}
}
$this->writeChartTextColor($objWriter, $element->getFont()->getUnderlineColor(), $prefix, 'uFill');
// fontName
if ($element->getFont()->getLatin()) {
@ -300,6 +284,33 @@ class StringTable extends WriterPart
}
}
private function writeChartTextColor(XMLWriter $objWriter, ?ChartColor $underlineColor, string $prefix, ?string $openTag = ''): void
{
if ($underlineColor !== null) {
$type = $underlineColor->getType();
$value = $underlineColor->getValue();
if (!empty($type) && !empty($value)) {
if ($openTag !== '') {
$objWriter->startElement($prefix . $openTag);
}
$objWriter->startElement($prefix . 'solidFill');
$objWriter->startElement($prefix . $type);
$objWriter->writeAttribute('val', $value);
$alpha = $underlineColor->getAlpha();
if (is_numeric($alpha)) {
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', ChartColor::alphaToXml((int) $alpha));
$objWriter->endElement();
}
$objWriter->endElement(); // srgbClr/schemeClr/prstClr
$objWriter->endElement(); // solidFill
if ($openTag !== '') {
$objWriter->endElement(); // uFill
}
}
}
}
/**
* Flip string table (for index searching).
*

View File

@ -119,6 +119,7 @@ class AxisGlowTest extends AbstractFunctional
$xAxis->setSoftEdges($softEdgesX);
self::assertEquals($yGlowSize, $yAxis->getGlowProperty('size'));
self::assertEquals($expectedGlowColor, $yAxis->getGlowProperty('color'));
self::assertSame($expectedGlowColor['value'], $yAxis->getGlowProperty(['color', 'value']));
self::assertEquals($softEdgesY, $yAxis->getSoftEdgesSize());
self::assertEquals($softEdgesX, $xAxis->getSoftEdgesSize());

View File

@ -0,0 +1,162 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Layout;
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\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
// based on 33_Chart_create_bar_custom_colors.php
class BarChartCustomColorsTest extends AbstractFunctional
{
public function readCharts(XlsxReader $reader): void
{
$reader->setIncludeCharts(true);
}
public function writeCharts(XlsxWriter $writer): void
{
$writer->setIncludeCharts(true);
}
public function testBarchartColor(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
// Custom colors for dataSeries (gray, blue, red, orange)
$colors = [
'cccccc',
'*accent1', // use schemeClr, was '00abb8',
'/green', // use prstClr, was 'b8292f',
'eb8500',
];
// 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
$dataSeriesLabels1 = [
new DataSeriesValues(
DataSeriesValues::DATASERIES_TYPE_STRING,
'Worksheet!$C$1',
null,
1
), // 2011
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues1 = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// 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
// Custom Colors
$dataSeriesValues1Element = new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4);
$dataSeriesValues1Element->setFillColor($colors);
$dataSeriesValues1 = [$dataSeriesValues1Element];
// Build the dataseries
$series1 = new DataSeries(
DataSeries::TYPE_PIECHART, // plotType
null, // plotGrouping (Pie charts don't have any grouping)
range(0, count($dataSeriesValues1) - 1), // plotOrder
$dataSeriesLabels1, // plotLabel
$xAxisTickValues1, // plotCategory
$dataSeriesValues1 // plotValues
);
// Set up a layout object for the Pie chart
$layout1 = new Layout();
$layout1->setShowVal(true);
$layout1->setShowPercent(true);
// Set the series in the plot area
$plotArea1 = new PlotArea($layout1, [$series1]);
// Set the chart legend
$legend1 = new ChartLegend(ChartLegend::POSITION_RIGHT, null, false);
$title1 = new Title('Test Pie Chart');
// Create the chart
$chart1 = new Chart(
'chart1', // name
$title1, // title
$legend1, // legend
$plotArea1, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
null // no Y-Axis for Pie Chart
);
// Set the position where the chart should appear in the worksheet
$chart1->setTopLeftPosition('A7');
$chart1->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart1);
/** @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);
$plotArea2 = $chart2->getPlotArea();
$dataSeries2 = $plotArea2->getPlotGroup();
self::assertCount(1, $dataSeries2);
$plotValues = $dataSeries2[0]->getPlotValues();
self::assertCount(1, $plotValues);
$fillColors = $plotValues[0]->getFillColor();
self::assertSame($colors, $fillColors);
$writer = new XlsxWriter($reloadedSpreadsheet);
$writer->setIncludeCharts(true);
$writerChart = new XlsxWriter\Chart($writer);
$data = $writerChart->writeChart($chart2);
self::assertSame(1, substr_count($data, '<a:srgbClr val="cccccc"/>'));
self::assertSame(1, substr_count($data, '<a:schemeClr val="accent1"/>'));
self::assertSame(1, substr_count($data, '<a:prstClr val="green"/>'));
self::assertSame(1, substr_count($data, '<a:srgbClr val="eb8500"/>'));
self::assertSame(4, substr_count($data, '<c:dPt>'));
$reloadedSpreadsheet->disconnectWorksheets();
}
}

View File

@ -58,7 +58,10 @@ class Charts32ColoredAxisLabelTest extends AbstractFunctional
self::assertInstanceOf(Run::class, $run);
$font = $run->getFont();
self::assertInstanceOf(Font::class, $font);
self::assertSame('00B050', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('00B050', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
$yAxisLabel = $chart->getYAxisLabel();
$captionArray = $yAxisLabel->getCaption();
@ -73,7 +76,10 @@ class Charts32ColoredAxisLabelTest extends AbstractFunctional
self::assertInstanceOf(Run::class, $run);
$font = $run->getFont();
self::assertInstanceOf(Font::class, $font);
self::assertSame('FF0000', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('FF0000', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
$reloadedSpreadsheet->disconnectWorksheets();
}

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\RichText\Run;
@ -65,7 +66,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline());
self::assertSame('000000', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('000000', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
$plotArea = $chart->getPlotArea();
$plotSeries = $plotArea->getPlotGroup();
@ -75,19 +79,22 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues);
$values = $plotValues[0];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[1];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[2];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(7, $values->getPointSize());
self::assertSame('FFFF00', $values->getFillColor());
// Had been testing for Fill Color, but we actually
// meant to test for marker color, which is now distinct.
self::assertSame('FFFF00', $values->getMarkerFillColor()->getValue());
self::assertSame('srgbClr', $values->getMarkerFillColor()->getType());
$reloadedSpreadsheet->disconnectWorksheets();
}
@ -135,7 +142,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline());
self::assertSame('000000', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('000000', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
$run = $elements[1];
self::assertInstanceOf(Run::class, $run);
@ -149,7 +159,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough());
self::assertSame('single', $font->getUnderline());
self::assertSame('00B0F0', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('00B0F0', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
$run = $elements[2];
self::assertInstanceOf(Run::class, $run);
@ -163,7 +176,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline());
self::assertSame('000000', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('000000', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
$plotArea = $chart->getPlotArea();
$plotSeries = $plotArea->getPlotGroup();
@ -173,19 +189,22 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues);
$values = $plotValues[0];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[1];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[2];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(7, $values->getPointSize());
self::assertSame('FFFF00', $values->getFillColor());
// Had been testing for Fill Color, but we actually
// meant to test for marker color, which is now distinct.
self::assertSame('FFFF00', $values->getMarkerFillColor()->getValue());
self::assertSame('srgbClr', $values->getMarkerFillColor()->getType());
$reloadedSpreadsheet->disconnectWorksheets();
}
@ -232,7 +251,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline());
self::assertSame('000000', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('000000', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
$plotArea = $chart->getPlotArea();
$plotSeries = $plotArea->getPlotGroup();
@ -242,17 +264,19 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues);
$values = $plotValues[0];
self::assertTrue($values->getScatterLines());
self::assertSame(12700, $values->getLineWidth());
// the default value of 1 point is no longer written out
// when not explicitly specified.
self::assertNull($values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[1];
self::assertTrue($values->getScatterLines());
self::assertSame(12700, $values->getLineWidth());
self::assertNull($values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[2];
self::assertTrue($values->getScatterLines());
self::assertSame(12700, $values->getLineWidth());
self::assertNull($values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
@ -303,7 +327,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline());
self::assertSame('000000', $font->getColor()->getRGB());
$chartColor = $font->getChartColor();
self::assertNotNull($chartColor);
self::assertSame('000000', $chartColor->getValue());
self::assertSame('srgbClr', $chartColor->getType());
}
$plotArea = $chart->getPlotArea();
@ -314,19 +341,97 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues);
$values = $plotValues[0];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[1];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor());
$values = $plotValues[2];
self::assertFalse($values->getScatterLines());
self::assertSame(28575, $values->getLineWidth());
self::assertSame(28575 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame(7, $values->getPointSize());
self::assertSame('FFFF00', $values->getFillColor());
// Had been testing for Fill Color, but we actually
// meant to test for marker color, which is now distinct.
self::assertSame('FFFF00', $values->getMarkerFillColor()->getValue());
self::assertSame('srgbClr', $values->getMarkerFillColor()->getType());
$reloadedSpreadsheet->disconnectWorksheets();
}
public function testScatter8(): void
{
$file = self::DIRECTORY . '32readwriteScatterChart8.xlsx';
$reader = new XlsxReader();
$reader->setIncludeCharts(true);
$spreadsheet = $reader->load($file);
$sheet = $spreadsheet->getActiveSheet();
self::assertSame(1, $sheet->getChartCount());
/** @var callable */
$callableReader = [$this, 'readCharts'];
/** @var callable */
$callableWriter = [$this, 'writeCharts'];
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
$spreadsheet->disconnectWorksheets();
$sheet = $reloadedSpreadsheet->getActiveSheet();
self::assertSame('Worksheet', $sheet->getTitle());
$charts = $sheet->getChartCollection();
self::assertCount(1, $charts);
$chart = $charts[0];
self::assertNotNull($chart);
$plotArea = $chart->getPlotArea();
$plotSeries = $plotArea->getPlotGroup();
self::assertCount(1, $plotSeries);
$dataSeries = $plotSeries[0];
$plotValues = $dataSeries->getPlotValues();
self::assertCount(3, $plotValues);
$values = $plotValues[0];
self::assertSame(31750 / Properties::POINTS_WIDTH_MULTIPLIER, $values->getLineWidth());
self::assertSame('sq', $values->getLineStyleProperty('cap'));
self::assertSame('tri', $values->getLineStyleProperty('compound'));
self::assertSame('sysDash', $values->getLineStyleProperty('dash'));
self::assertSame('miter', $values->getLineStyleProperty('join'));
self::assertSame('arrow', $values->getLineStyleProperty(['arrow', 'head', 'type']));
self::assertSame('med', $values->getLineStyleProperty(['arrow', 'head', 'w']));
self::assertSame('sm', $values->getLineStyleProperty(['arrow', 'head', 'len']));
self::assertSame('triangle', $values->getLineStyleProperty(['arrow', 'end', 'type']));
self::assertSame('med', $values->getLineStyleProperty(['arrow', 'end', 'w']));
self::assertSame('lg', $values->getLineStyleProperty(['arrow', 'end', 'len']));
self::assertSame('accent1', $values->getLineColorProperty('value'));
self::assertSame('schemeClr', $values->getLineColorProperty('type'));
self::assertSame(40, $values->getLineColorProperty('alpha'));
self::assertSame('', $values->getFillColor());
self::assertSame(7, $values->getPointSize());
self::assertSame('diamond', $values->getPointMarker());
self::assertSame('0070C0', $values->getMarkerFillColor()->getValue());
self::assertSame('srgbClr', $values->getMarkerFillColor()->getType());
self::assertSame('002060', $values->getMarkerBorderColor()->getValue());
self::assertSame('srgbClr', $values->getMarkerBorderColor()->getType());
$values = $plotValues[1];
self::assertSame(7, $values->getPointSize());
self::assertSame('square', $values->getPointMarker());
self::assertSame('accent6', $values->getMarkerFillColor()->getValue());
self::assertSame('schemeClr', $values->getMarkerFillColor()->getType());
self::assertSame(3, $values->getMarkerFillColor()->getAlpha());
self::assertSame('0FF000', $values->getMarkerBorderColor()->getValue());
self::assertSame('srgbClr', $values->getMarkerBorderColor()->getType());
self::assertNull($values->getMarkerBorderColor()->getAlpha());
$values = $plotValues[2];
self::assertSame(7, $values->getPointSize());
self::assertSame('triangle', $values->getPointMarker());
self::assertSame('FFFF00', $values->getMarkerFillColor()->getValue());
self::assertSame('srgbClr', $values->getMarkerFillColor()->getType());
self::assertNull($values->getMarkerFillColor()->getAlpha());
self::assertSame('accent4', $values->getMarkerBorderColor()->getValue());
self::assertSame('schemeClr', $values->getMarkerBorderColor()->getType());
$reloadedSpreadsheet->disconnectWorksheets();
}

View File

@ -84,12 +84,16 @@ class Charts32XmlTest extends TestCase
$chart = $charts[0];
self::assertNotNull($chart);
$xAxis = $chart->getChartAxisX();
$yAxis = $chart->getChartAxisY();
self::assertSame(Properties::FORMAT_CODE_GENERAL, $xAxis->getAxisNumberFormat());
if (is_bool($numeric)) {
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, true);
}
$yAxis = $chart->getChartAxisY();
self::assertSame('valAx', $yAxis->getAxisType());
self::assertSame('valAx', $xAxis->getAxisType());
self::assertSame(Properties::FORMAT_CODE_GENERAL, $yAxis->getAxisNumberFormat());
$xAxis->setAxisType('');
$yAxis->setAxisType('');
if (is_bool($numeric)) {
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, $numeric);
$yAxis->setAxisNumberProperties(Properties::FORMAT_CODE_GENERAL, $numeric);
@ -119,6 +123,34 @@ class Charts32XmlTest extends TestCase
];
}
public function testCatAxValAxFromRead(): void
{
$file = self::DIRECTORY . '32readwriteScatterChart1.xlsx';
$reader = new XlsxReader();
$reader->setIncludeCharts(true);
$spreadsheet = $reader->load($file);
$sheet = $spreadsheet->getActiveSheet();
$charts = $sheet->getChartCollection();
self::assertCount(1, $charts);
$chart = $charts[0];
self::assertNotNull($chart);
$xAxis = $chart->getChartAxisX();
$yAxis = $chart->getChartAxisY();
self::assertSame(Properties::FORMAT_CODE_GENERAL, $xAxis->getAxisNumberFormat());
self::assertSame('valAx', $yAxis->getAxisType());
self::assertSame('valAx', $xAxis->getAxisType());
self::assertSame(Properties::FORMAT_CODE_GENERAL, $yAxis->getAxisNumberFormat());
$writer = new XlsxWriter($spreadsheet);
$writer->setIncludeCharts(true);
$writerChart = new XlsxWriter\Chart($writer);
$data = $writerChart->writeChart($chart);
$spreadsheet->disconnectWorksheets();
self::assertSame(0, substr_count($data, '<c:catAx>'));
self::assertSame(2, substr_count($data, '<c:valAx>'));
}
public function testAreaPrstClr(): void
{
$file = self::DIRECTORY . '32readwriteAreaChart4.xlsx';

View File

@ -0,0 +1,32 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PHPUnit\Framework\TestCase;
class ColorTest extends TestCase
{
public function testDefaultTypes(): void
{
$color = new ChartColor('800000');
self::assertSame('srgbClr', $color->getType());
self::assertSame('800000', $color->getValue());
$color->setColorProperties('*accent1');
self::assertSame('schemeClr', $color->getType());
self::assertSame('accent1', $color->getValue());
$color->setColorProperties('/red');
self::assertSame('prstClr', $color->getType());
self::assertSame('red', $color->getValue());
}
public function testDataSeriesValues(): void
{
$dsv = new DataSeriesValues();
$dsv->setFillColor([new ChartColor(), new ChartColor()]);
self::assertSame(['', ''], $dsv->getFillColor());
$dsv->setFillColor('cccccc');
self::assertSame('cccccc', $dsv->getFillColor());
}
}

View File

@ -0,0 +1,172 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
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\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class DataSeriesValues2Test extends AbstractFunctional
{
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();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
// 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), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// 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$5', null, 4), // Q1 to Q4
];
// 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$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
$series = new DataSeries(
null, // plotType
null, // plotGrouping
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
self::assertEmpty($series->getPlotType());
self::assertEmpty($series->getPlotGrouping());
self::assertFalse($series->getSmoothLine());
$series->setPlotType(DataSeries::TYPE_AREACHART);
$series->setPlotGrouping(DataSeries::GROUPING_PERCENT_STACKED);
$series->setSmoothLine(true);
self::assertSame(DataSeries::TYPE_AREACHART, $series->getPlotType());
self::assertSame(DataSeries::GROUPING_PERCENT_STACKED, $series->getPlotGrouping());
self::assertTrue($series->getSmoothLine());
// 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 %age-Stacked Area 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
);
// 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);
self::assertSame(1, $chart->getPlotArea()->getPlotGroupCount());
$plotValues = $chart->getPlotArea()->getPlotGroup()[0]->getPlotValues();
self::assertCount(3, $plotValues);
self::assertSame([], $plotValues[1]->getDataValues());
self::assertNull($plotValues[1]->getDataValue());
/** @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);
$plotValues2 = $chart2->getPlotArea()->getPlotGroup()[0]->getPlotValues();
self::assertCount(3, $plotValues2);
self::assertSame([15.0, 73.0, 61.0, 32.0], $plotValues2[1]->getDataValues());
self::assertSame([15.0, 73.0, 61.0, 32.0], $plotValues2[1]->getDataValue());
$labels2 = $chart->getPlotArea()->getPlotGroup()[0]->getPlotLabels();
self::assertCount(3, $labels2);
self::assertSame(2010, $labels2[0]->getDataValue());
$dataSeries = $chart->getPlotArea()->getPlotGroup()[0];
self::assertFalse($dataSeries->getPlotValuesByIndex(99));
self::assertNotFalse($dataSeries->getPlotValuesByIndex(0));
self::assertSame([12, 56, 52, 30], $dataSeries->getPlotValuesByIndex(0)->getDataValues());
self::assertSame(DataSeries::TYPE_AREACHART, $dataSeries->getPlotType());
self::assertSame(DataSeries::GROUPING_PERCENT_STACKED, $dataSeries->getPlotGrouping());
self::assertTrue($dataSeries->getSmoothLine());
$reloadedSpreadsheet->disconnectWorksheets();
}
public function testSomeProperties(): void
{
$dataSeriesValues = new DataSeriesValues();
self::assertNull($dataSeriesValues->getDataSource());
self::assertEmpty($dataSeriesValues->getPointMarker());
self::assertSame(3, $dataSeriesValues->getPointSize());
$dataSeriesValues->setDataSource('Worksheet!$B$1')
->setPointMarker('square')
->setPointSize(6);
self::assertSame('Worksheet!$B$1', $dataSeriesValues->getDataSource());
self::assertSame('square', $dataSeriesValues->getPointMarker());
self::assertSame(6, $dataSeriesValues->getPointSize());
}
}

View File

@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Exception;
use PHPUnit\Framework\TestCase;
@ -51,13 +52,14 @@ class DataSeriesValuesTest extends TestCase
public function testGetLineWidth(): void
{
$testInstance = new DataSeriesValues();
self::assertEquals(12700, $testInstance->getLineWidth(), 'should have default');
// default has changed to null from 1 point (12700)
self::assertNull($testInstance->getLineWidth(), 'should have default');
$testInstance->setLineWidth(40000);
self::assertEquals(40000, $testInstance->getLineWidth());
$testInstance->setLineWidth(40000 / Properties::POINTS_WIDTH_MULTIPLIER);
self::assertEquals(40000 / Properties::POINTS_WIDTH_MULTIPLIER, $testInstance->getLineWidth());
$testInstance->setLineWidth(1);
self::assertEquals(12700, $testInstance->getLineWidth(), 'should enforce minimum width');
self::assertEquals(12700 / Properties::POINTS_WIDTH_MULTIPLIER, $testInstance->getLineWidth(), 'should enforce minimum width');
}
public function testFillColorCorrectInput(): void

View File

@ -1,6 +1,6 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use DOMDocument;
use DOMNode;
@ -108,7 +108,7 @@ class Issue589Test extends TestCase
if ($actualXml === false) {
self::fail('Failure saving the spPr element as xml string!');
} else {
self::assertXmlStringEqualsXmlString('<c:spPr><a:ln w="12700"><a:solidFill><a:srgbClr val="98B954"/></a:solidFill></a:ln></c:spPr>', $actualXml);
self::assertXmlStringEqualsXmlString('<c:spPr><a:ln><a:solidFill><a:srgbClr val="98B954"/></a:solidFill></a:ln></c:spPr>', $actualXml);
}
}
}
@ -153,7 +153,7 @@ class Issue589Test extends TestCase
if ($actualXml === false) {
self::fail('Failure saving the spPr element as xml string!');
} else {
self::assertXmlStringEqualsXmlString('<c:spPr><a:ln w="12700"></a:ln></c:spPr>', $actualXml);
self::assertXmlStringEqualsXmlString('<c:spPr><a:ln/></c:spPr>', $actualXml);
}
}
}

View File

@ -123,6 +123,35 @@ class ShadowPresetsTest extends TestCase
}
}
public function testPreset0(): void
{
$axis = new Axis();
$axis->setShadowProperties(0);
$expectedShadow = [
'presets' => Properties::SHADOW_PRESETS_NOSHADOW,
'effect' => null,
'color' => [
'type' => Properties::EXCEL_COLOR_TYPE_STANDARD,
'value' => 'black',
'alpha' => 40,
],
'size' => [
'sx' => null,
'sy' => null,
'kx' => null,
'ky' => null,
],
'blur' => null,
'direction' => null,
'distance' => null,
'algn' => null,
'rotWithShape' => null,
];
foreach ($expectedShadow as $key => $value) {
self::assertEquals($value, $axis->getShadowProperty($key), $key);
}
}
public function testOutOfRangePresets(): void
{
$axis = new Axis();