diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9148425d..b7d55bbe 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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
diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index d1f2a03b..858502fd 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -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
-
diff --git a/samples/Chart/33_Chart_create_bar_custom_colors.php b/samples/Chart/33_Chart_create_bar_custom_colors.php
new file mode 100644
index 00000000..75f2306b
--- /dev/null
+++ b/samples/Chart/33_Chart_create_bar_custom_colors.php
@@ -0,0 +1,183 @@
+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);
diff --git a/samples/Chart/33_Chart_create_line.php b/samples/Chart/33_Chart_create_line.php
index fee2a284..8cb87e30 100644
--- a/samples/Chart/33_Chart_create_line.php
+++ b/samples/Chart/33_Chart_create_line.php
@@ -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(
diff --git a/samples/Chart/33_Chart_create_scatter2.php b/samples/Chart/33_Chart_create_scatter2.php
index 1d6e331c..ef6353bb 100644
--- a/samples/Chart/33_Chart_create_scatter2.php
+++ b/samples/Chart/33_Chart_create_scatter2.php
@@ -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
diff --git a/samples/templates/32readwriteScatterChart8.xlsx b/samples/templates/32readwriteScatterChart8.xlsx
new file mode 100644
index 00000000..fdd85b0e
Binary files /dev/null and b/samples/templates/32readwriteScatterChart8.xlsx differ
diff --git a/src/PhpSpreadsheet/Calculation/Calculation.php b/src/PhpSpreadsheet/Calculation/Calculation.php
index 516faa86..4e3a7c53 100644
--- a/src/PhpSpreadsheet/Calculation/Calculation.php
+++ b/src/PhpSpreadsheet/Calculation/Calculation.php
@@ -4834,7 +4834,7 @@ class Calculation
$cell->attach($pCellParent);
} else {
$cellRef = ($cellSheet !== null) ? "'{$matches[2]}'!{$cellRef}" : $cellRef;
- $cellValue = null;
+ $cellValue = ($cellSheet !== null) ? null : Information\ExcelError::REF();
}
} else {
return $this->raiseFormulaError('Unable to access Cell Reference');
diff --git a/src/PhpSpreadsheet/Calculation/Information/ExcelError.php b/src/PhpSpreadsheet/Calculation/Information/ExcelError.php
index 88de7e54..6305e502 100644
--- a/src/PhpSpreadsheet/Calculation/Information/ExcelError.php
+++ b/src/PhpSpreadsheet/Calculation/Information/ExcelError.php
@@ -25,6 +25,14 @@ class ExcelError
'spill' => '#SPILL!',
];
+ /**
+ * @param mixed $value
+ */
+ public static function throwError($value): string
+ {
+ return in_array($value, self::$errorCodes, true) ? $value : self::$errorCodes['value'];
+ }
+
/**
* ERROR_TYPE.
*
diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php
index 348aa5b3..f34f159b 100644
--- a/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php
+++ b/src/PhpSpreadsheet/Calculation/MathTrig/Helpers.php
@@ -38,7 +38,7 @@ class Helpers
return 0 + $number;
}
- throw new Exception(ExcelError::VALUE());
+ throw new Exception(ExcelError::throwError($number));
}
/**
@@ -59,7 +59,7 @@ class Helpers
return 0 + $number;
}
- throw new Exception(ExcelError::VALUE());
+ throw new Exception(ExcelError::throwError($number));
}
/**
diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php b/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php
index f26da389..06258451 100644
--- a/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php
+++ b/src/PhpSpreadsheet/Calculation/MathTrig/Operations.php
@@ -118,7 +118,7 @@ class Operations
if (is_numeric($arg)) {
$returnValue *= $arg;
} else {
- return ExcelError::VALUE();
+ return ExcelError::throwError($arg);
}
}
diff --git a/src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php b/src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php
index 336bc690..6d8f4723 100644
--- a/src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php
+++ b/src/PhpSpreadsheet/Calculation/MathTrig/Subtotal.php
@@ -18,7 +18,11 @@ class Subtotal
return array_filter(
$args,
function ($index) use ($cellReference) {
- [, $row, ] = explode('.', $index);
+ $explodeArray = explode('.', $index);
+ $row = $explodeArray[1] ?? '';
+ if (!is_numeric($row)) {
+ return true;
+ }
return $cellReference->getWorksheet()->getRowDimension($row)->getVisible();
},
@@ -35,7 +39,9 @@ class Subtotal
return array_filter(
$args,
function ($index) use ($cellReference) {
- [, $row, $column] = explode('.', $index);
+ $explodeArray = explode('.', $index);
+ $row = $explodeArray[1] ?? '';
+ $column = $explodeArray[2] ?? '';
$retVal = true;
if ($cellReference->getWorksheet()->cellExists($column . $row)) {
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula
@@ -87,7 +93,22 @@ class Subtotal
public static function evaluate($functionType, ...$args)
{
$cellReference = array_pop($args);
- $aArgs = Functions::flattenArrayIndexed($args);
+ $bArgs = Functions::flattenArrayIndexed($args);
+ $aArgs = [];
+ // int keys must come before string keys for PHP 8.0+
+ // Otherwise, PHP thinks positional args follow keyword
+ // in the subsequent call to call_user_func_array.
+ // Fortunately, order of args is unimportant to Subtotal.
+ foreach ($bArgs as $key => $value) {
+ if (is_int($key)) {
+ $aArgs[$key] = $value;
+ }
+ }
+ foreach ($bArgs as $key => $value) {
+ if (!is_int($key)) {
+ $aArgs[$key] = $value;
+ }
+ }
try {
$subtotal = (int) Helpers::validateNumericNullBool($functionType);
diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php
index 69a25d92..72438891 100644
--- a/src/PhpSpreadsheet/Chart/Axis.php
+++ b/src/PhpSpreadsheet/Chart/Axis.php
@@ -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.
*
diff --git a/src/PhpSpreadsheet/Chart/ChartColor.php b/src/PhpSpreadsheet/Chart/ChartColor.php
index 05c1bb9a..7f87e391 100644
--- a/src/PhpSpreadsheet/Chart/ChartColor.php
+++ b/src/PhpSpreadsheet/Chart/ChartColor.php
@@ -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 !== '';
}
/**
diff --git a/src/PhpSpreadsheet/Chart/DataSeries.php b/src/PhpSpreadsheet/Chart/DataSeries.php
index dca1186e..d27db33e 100644
--- a/src/PhpSpreadsheet/Chart/DataSeries.php
+++ b/src/PhpSpreadsheet/Chart/DataSeries.php
@@ -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;
diff --git a/src/PhpSpreadsheet/Chart/DataSeriesValues.php b/src/PhpSpreadsheet/Chart/DataSeriesValues.php
index 0a2f5a85..d6a8dcca 100644
--- a/src/PhpSpreadsheet/Chart/DataSeriesValues.php
+++ b/src/PhpSpreadsheet/Chart/DataSeriesValues.php
@@ -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 {
+ $this->fillColor[] = self::stringToChartColor($fillString);
}
}
- } else {
- if (substr($color, 0, 1) !== '*' && substr($color, 0, 1) !== '/') {
- $this->validateColor("$color");
- }
+ } elseif ($color instanceof ChartColor) {
+ $this->fillColor = $color;
+ } elseif (is_string($color)) {
+ $this->fillColor = self::stringToChartColor($color);
}
- $this->fillColor = $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;
}
diff --git a/src/PhpSpreadsheet/Chart/Properties.php b/src/PhpSpreadsheet/Chart/Properties.php
index a64a826f..fdc3c12b 100644
--- a/src/PhpSpreadsheet/Chart/Properties.php
+++ b/src/PhpSpreadsheet/Chart/Properties.php
@@ -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;
diff --git a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
index 2c060d07..df25dac7 100644
--- a/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
+++ b/src/PhpSpreadsheet/Reader/Xlsx/Chart.php
@@ -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 (is_countable($ln->noFill) && count($ln->noFill) === 1) {
- $noFill = true;
+ 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'));
}
diff --git a/src/PhpSpreadsheet/ReferenceHelper.php b/src/PhpSpreadsheet/ReferenceHelper.php
index a6b82015..08a38b3b 100644
--- a/src/PhpSpreadsheet/ReferenceHelper.php
+++ b/src/PhpSpreadsheet/ReferenceHelper.php
@@ -527,6 +527,12 @@ class ReferenceHelper
if ($objDrawing->getCoordinates() != $newReference) {
$objDrawing->setCoordinates($newReference);
}
+ if ($objDrawing->getCoordinates2() !== '') {
+ $newReference = $this->updateCellReference($objDrawing->getCoordinates2());
+ if ($objDrawing->getCoordinates2() != $newReference) {
+ $objDrawing->setCoordinates2($newReference);
+ }
+ }
}
// Update workbook: define names
diff --git a/src/PhpSpreadsheet/Style/Font.php b/src/PhpSpreadsheet/Style/Font.php
index 4dbe7272..19d67563 100644
--- a/src/PhpSpreadsheet/Style/Font.php
+++ b/src/PhpSpreadsheet/Style/Font.php
@@ -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,7 +383,9 @@ 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)) {
- $sizeInPoints = 10.0;
+ if (!$nullOk || $sizeInPoints !== null) {
+ $sizeInPoints = 10.0;
+ }
}
if ($this->isSupervisor) {
@@ -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());
diff --git a/src/PhpSpreadsheet/Worksheet/BaseDrawing.php b/src/PhpSpreadsheet/Worksheet/BaseDrawing.php
index 815536b5..369e4162 100644
--- a/src/PhpSpreadsheet/Worksheet/BaseDrawing.php
+++ b/src/PhpSpreadsheet/Worksheet/BaseDrawing.php
@@ -9,8 +9,8 @@ use PhpOffice\PhpSpreadsheet\IComparable;
class BaseDrawing implements IComparable
{
const EDIT_AS_ABSOLUTE = 'absolute';
- const EDIT_AS_ONECELL = 'onecell';
- const EDIT_AS_TWOCELL = 'twocell';
+ const EDIT_AS_ONECELL = 'oneCell';
+ const EDIT_AS_TWOCELL = 'twoCell';
private const VALID_EDIT_AS = [
self::EDIT_AS_ABSOLUTE,
self::EDIT_AS_ONECELL,
@@ -530,6 +530,6 @@ class BaseDrawing implements IComparable
public function validEditAs(): bool
{
- return in_array($this->editAs, self::VALID_EDIT_AS);
+ return in_array($this->editAs, self::VALID_EDIT_AS, true);
}
}
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
index acc6f3af..d242e602 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/Chart.php
@@ -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';
- }
+ $fillObject = $labelFill ?? $plotSeriesValues->getFillColorObject();
+ $callLineStyles = true;
+ if ($fillObject instanceof ChartColor && $fillObject->isUsable()) {
+ if ($groupType === DataSeries::TYPE_LINECHART) {
+ $objWriter->startElement('a:ln');
+ $callLineStyles = false;
+ }
+ $this->writeColor($objWriter, $fillObject);
+ if (!$callLineStyles) {
+ $objWriter->endElement(); // a:ln
}
}
- if ($schemeClr) {
- $objWriter->startElement('a:solidFill');
- $objWriter->startElement("a:$typeClr");
- $objWriter->writeAttribute('val', $schemeClr);
- $objWriter->endElement();
- $objWriter->endElement();
+ $nofill = $groupType == DataSeries::TYPE_STOCKCHART || ($groupType === DataSeries::TYPE_SCATTERCHART && !$plotSeriesValues->getScatterLines());
+ if ($callLineStyles) {
+ $this->writeLineStyles($objWriter, $plotSeriesValues, $nofill);
}
- $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();
- }
- }
- $objWriter->endElement();
- $objWriter->endElement();
+ $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');
- $objWriter->writeAttribute('val', $plotSeriesMarker);
+ 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->startElement('c:spPr');
- $objWriter->startElement('a:solidFill');
- $objWriter->startElement('a:srgbClr');
- $objWriter->writeAttribute('val', $fillColor);
- $objWriter->endElement(); // srgbClr
- $objWriter->endElement(); // solidFill
- $objWriter->endElement(); // spPr
+ $objWriter->endElement(); // c:size
+ $objWriter->startElement('c: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'));
- $this->writeColor($objWriter, $gridlines->getLineColor());
+ 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
diff --git a/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php b/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
index 8a376df4..8b293bc1 100644
--- a/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
+++ b/src/PhpSpreadsheet/Writer/Xlsx/StringTable.php
@@ -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).
*
diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php
index cf79ac0b..43156182 100644
--- a/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php
+++ b/tests/PhpSpreadsheetTests/Calculation/Functions/MathTrig/SubTotalTest.php
@@ -127,4 +127,32 @@ class SubTotalTest extends AllSetupTeardown
$sheet->getCell('H1')->setValue("=SUBTOTAL(9, A1:$maxCol$maxRow)");
self::assertEquals(362, $sheet->getCell('H1')->getCalculatedValue());
}
+
+ public function testRefError(): void
+ {
+ $sheet = $this->getSheet();
+ $sheet->getCell('A1')->setValue('=SUBTOTAL(9, #REF!)');
+ self::assertEquals('#REF!', $sheet->getCell('A1')->getCalculatedValue());
+ }
+
+ public function testSecondaryRefError(): void
+ {
+ $sheet = $this->getSheet();
+ $sheet->getCell('A1')->setValue('=SUBTOTAL(9, B1:B9,#REF!,C1:C9)');
+ self::assertEquals('#REF!', $sheet->getCell('A1')->getCalculatedValue());
+ }
+
+ public function testNonStringSingleCellRefError(): void
+ {
+ $sheet = $this->getSheet();
+ $sheet->getCell('A1')->setValue('=SUBTOTAL(9, 1, C1, Sheet99!A11)');
+ self::assertEquals('#REF!', $sheet->getCell('A1')->getCalculatedValue());
+ }
+
+ public function testNonStringCellRangeRefError(): void
+ {
+ $sheet = $this->getSheet();
+ $sheet->getCell('A1')->setValue('=SUBTOTAL(9, Sheet99!A1)');
+ self::assertEquals('#REF!', $sheet->getCell('A1')->getCalculatedValue());
+ }
}
diff --git a/tests/PhpSpreadsheetTests/Calculation/RefErrorTest.php b/tests/PhpSpreadsheetTests/Calculation/RefErrorTest.php
new file mode 100644
index 00000000..ffdfc2fa
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Calculation/RefErrorTest.php
@@ -0,0 +1,58 @@
+getActiveSheet();
+ $sheet1->setTitle('Sheet1');
+ $sheet2 = $spreadsheet->createSheet();
+ $sheet2->setTitle('Sheet2');
+ $sheet2->getCell('A1')->setValue(5);
+ $sheet1->getCell('A1')->setValue(9);
+ $sheet1->getCell('A2')->setValue(2);
+ $sheet1->getCell('A3')->setValue(4);
+ $sheet1->getCell('A4')->setValue(6);
+ $sheet1->getCell('A5')->setValue(7);
+ $sheet1->getRowDimension(5)->setVisible(false);
+ $sheet1->getCell('B1')->setValue('=1/0');
+ $sheet1->getCell('C1')->setValue('=Sheet99!A1');
+ $sheet1->getCell('C2')->setValue('=Sheet2!A1');
+ $sheet1->getCell('C3')->setValue('=Sheet2!A2');
+ $sheet1->getCell('H1')->setValue($formula);
+ self::assertSame($expected, $sheet1->getCell('H1')->getCalculatedValue());
+ $spreadsheet->disconnectWorksheets();
+ }
+
+ public function providerRefError(): array
+ {
+ return [
+ 'Subtotal9 Ok' => [12, '=SUBTOTAL(A1,A2:A4)'],
+ 'Subtotal9 REF' => ['#REF!', '=SUBTOTAL(A1,A2:A4,C1)'],
+ 'Subtotal9 with literal and cells' => [111, '=SUBTOTAL(A1,A2:A4,99)'],
+ 'Subtotal9 with literal no rows hidden' => [111, '=SUBTOTAL(109,A2:A4,99)'],
+ 'Subtotal9 with literal ignoring hidden row' => [111, '=SUBTOTAL(109,A2:A5,99)'],
+ 'Subtotal9 with literal using hidden row' => [118, '=SUBTOTAL(9,A2:A5,99)'],
+ 'Subtotal9 with Null same sheet' => [12, '=SUBTOTAL(A1,A2:A4,A99)'],
+ 'Subtotal9 with Null Different sheet' => [12, '=SUBTOTAL(A1,A2:A4,C3)'],
+ 'Subtotal9 with NonNull Different sheet' => [17, '=SUBTOTAL(A1,A2:A4,C2)'],
+ 'Product DIV0' => ['#DIV/0!', '=PRODUCT(2, 3, B1)'],
+ 'Sqrt REF' => ['#REF!', '=SQRT(C1)'],
+ 'Sum NUM' => ['#NUM!', '=SUM(SQRT(-1), A2:A4)'],
+ 'Sum with literal and cells' => [111, '=SUM(A2:A4, 99)'],
+ 'Sum REF' => ['#REF!', '=SUM(A2:A4, C1)'],
+ 'Tan DIV0' => ['#DIV/0!', '=TAN(B1)'],
+ ];
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Chart/AxisGlowTest.php b/tests/PhpSpreadsheetTests/Chart/AxisGlowTest.php
index ad7fc776..0ed4a1b4 100644
--- a/tests/PhpSpreadsheetTests/Chart/AxisGlowTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/AxisGlowTest.php
@@ -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());
diff --git a/tests/PhpSpreadsheetTests/Chart/BarChartCustomColorsTest.php b/tests/PhpSpreadsheetTests/Chart/BarChartCustomColorsTest.php
new file mode 100644
index 00000000..824e9600
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Chart/BarChartCustomColorsTest.php
@@ -0,0 +1,162 @@
+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, ''));
+ self::assertSame(1, substr_count($data, ''));
+ self::assertSame(1, substr_count($data, ''));
+ self::assertSame(1, substr_count($data, ''));
+ self::assertSame(4, substr_count($data, ''));
+
+ $reloadedSpreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php
index 71cda504..b8041623 100644
--- a/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/Charts32ColoredAxisLabelTest.php
@@ -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();
}
diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php
index d79cba6f..38884eaf 100644
--- a/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/Charts32ScatterTest.php
@@ -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();
}
diff --git a/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php b/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php
index 3123278f..6a4673fd 100644
--- a/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/Charts32XmlTest.php
@@ -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, ''));
+ self::assertSame(2, substr_count($data, ''));
+ }
+
public function testAreaPrstClr(): void
{
$file = self::DIRECTORY . '32readwriteAreaChart4.xlsx';
diff --git a/tests/PhpSpreadsheetTests/Chart/ColorTest.php b/tests/PhpSpreadsheetTests/Chart/ColorTest.php
new file mode 100644
index 00000000..e8326e52
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Chart/ColorTest.php
@@ -0,0 +1,32 @@
+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());
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Chart/DataSeriesValues2Test.php b/tests/PhpSpreadsheetTests/Chart/DataSeriesValues2Test.php
new file mode 100644
index 00000000..a27397f9
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Chart/DataSeriesValues2Test.php
@@ -0,0 +1,172 @@
+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());
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Chart/DataSeriesValuesTest.php b/tests/PhpSpreadsheetTests/Chart/DataSeriesValuesTest.php
index c34ca697..47c2fb89 100644
--- a/tests/PhpSpreadsheetTests/Chart/DataSeriesValuesTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/DataSeriesValuesTest.php
@@ -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
diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue589Test.php b/tests/PhpSpreadsheetTests/Chart/Issue589Test.php
similarity index 96%
rename from tests/PhpSpreadsheetTests/Writer/Xlsx/Issue589Test.php
rename to tests/PhpSpreadsheetTests/Chart/Issue589Test.php
index 82478fb9..747cba74 100644
--- a/tests/PhpSpreadsheetTests/Writer/Xlsx/Issue589Test.php
+++ b/tests/PhpSpreadsheetTests/Chart/Issue589Test.php
@@ -1,6 +1,6 @@
', $actualXml);
+ self::assertXmlStringEqualsXmlString('', $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('', $actualXml);
+ self::assertXmlStringEqualsXmlString('', $actualXml);
}
}
}
diff --git a/tests/PhpSpreadsheetTests/Chart/ShadowPresetsTest.php b/tests/PhpSpreadsheetTests/Chart/ShadowPresetsTest.php
index 58c024c1..e96d6c14 100644
--- a/tests/PhpSpreadsheetTests/Chart/ShadowPresetsTest.php
+++ b/tests/PhpSpreadsheetTests/Chart/ShadowPresetsTest.php
@@ -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();
diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsInsertRowsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsInsertRowsTest.php
new file mode 100644
index 00000000..e2cbbff3
--- /dev/null
+++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsInsertRowsTest.php
@@ -0,0 +1,45 @@
+load($inputFilename);
+ $sheet = $spreadsheet->getActiveSheet();
+ $drawingCollection = $sheet->getDrawingCollection();
+ self::assertCount(1, $drawingCollection);
+ $drawing = $drawingCollection[0];
+ self::assertNotNull($drawing);
+ self::assertSame('D10', $drawing->getCoordinates());
+ self::assertSame('F11', $drawing->getCoordinates2());
+ self::assertSame('oneCell', $drawing->getEditAs());
+
+ $sheet->insertNewRowBefore(5);
+ $sheet->insertNewRowBefore(6);
+
+ // Save spreadsheet to file and read it back
+ $reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx');
+ $spreadsheet->disconnectWorksheets();
+ $rsheet = $reloadedSpreadsheet->getActiveSheet();
+ $drawingCollection2 = $rsheet->getDrawingCollection();
+ self::assertCount(1, $drawingCollection2);
+ $drawing2 = $drawingCollection2[0];
+ self::assertNotNull($drawing2);
+ self::assertSame('D12', $drawing2->getCoordinates());
+ self::assertSame('F13', $drawing2->getCoordinates2());
+ self::assertSame('oneCell', $drawing2->getEditAs());
+
+ $reloadedSpreadsheet->disconnectWorksheets();
+ }
+}
diff --git a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php
index f089b9ee..14b816d2 100644
--- a/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php
+++ b/tests/PhpSpreadsheetTests/Writer/Xlsx/DrawingsTest.php
@@ -554,10 +554,10 @@ class DrawingsTest extends AbstractFunctional
{
return [
'absolute' => ['absolute'],
- 'onecell' => ['onecell'],
- 'twocell' => ['twocell'],
- 'unset (will be treated as twocell)' => [''],
- 'unknown (will be treated as twocell)' => ['unknown', ''],
+ 'onecell' => ['oneCell'],
+ 'twocell' => ['twoCell'],
+ 'unset (will be treated as twoCell)' => [''],
+ 'unknown (will be treated as twoCell)' => ['unknown', ''],
];
}
diff --git a/tests/data/Writer/XLSX/issue.2908.xlsx b/tests/data/Writer/XLSX/issue.2908.xlsx
new file mode 100644
index 00000000..3dcd7923
Binary files /dev/null and b/tests/data/Writer/XLSX/issue.2908.xlsx differ