Merge branch 'master' into Performance-Refresh-Row/Column-Dimensions

This commit is contained in:
Mark Baker 2022-06-30 17:15:05 +02:00 committed by GitHub
commit 01d2d541c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 1459 additions and 399 deletions

View File

@ -49,7 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
- Time interval formatting [Issue #2768](https://github.com/PHPOffice/PhpSpreadsheet/issues/2768) [PR #2772](https://github.com/PHPOffice/PhpSpreadsheet/pull/2772) - 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) - 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) - 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) - 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 ## 1.23.0 - 2022-04-24

View File

@ -4055,16 +4055,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Writer/Xlsx.php 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\\.$#" 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 count: 1
@ -4087,7 +4077,7 @@ parameters:
- -
message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#" message: "#^Parameter \\#2 \\$value of method XMLWriter\\:\\:writeAttribute\\(\\) expects string, int given\\.$#"
count: 42 count: 41
path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php path: src/PhpSpreadsheet/Writer/Xlsx/Chart.php
- -

View File

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

View File

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

View File

@ -2,6 +2,7 @@
use PhpOffice\PhpSpreadsheet\Chart\Axis; use PhpOffice\PhpSpreadsheet\Chart\Axis;
use PhpOffice\PhpSpreadsheet\Chart\Chart; use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries; use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend; 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!$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), 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 // Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers
$xAxis = new Axis(); $xAxis = new Axis();
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE ); //$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, true); $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 // Build the dataseries
$series = new DataSeries( $series = new DataSeries(
DataSeries::TYPE_SCATTERCHART, // plotType DataSeries::TYPE_SCATTERCHART, // plotType
@ -79,8 +145,7 @@ $series = new DataSeries(
$dataSeriesValues, // plotValues $dataSeriesValues, // plotValues
null, // plotDirection null, // plotDirection
false, // smooth line false, // smooth line
//DataSeries::STYLE_LINEMARKER // plotStyle DataSeries::STYLE_SMOOTHMARKER // plotStyle
DataSeries::STYLE_MARKER // plotStyle
); );
// Set the series in the plot area // Set the series in the plot area
@ -103,6 +168,7 @@ $chart = new Chart(
$yAxisLabel, // yAxisLabel $yAxisLabel, // yAxisLabel
// added xAxis for correct date display // added xAxis for correct date display
$xAxis, // xAxis $xAxis, // xAxis
$yAxis, // yAxis
); );
// Set the position where the chart should appear in the worksheet // Set the position where the chart should appear in the worksheet

Binary file not shown.

View File

@ -4834,7 +4834,7 @@ class Calculation
$cell->attach($pCellParent); $cell->attach($pCellParent);
} else { } else {
$cellRef = ($cellSheet !== null) ? "'{$matches[2]}'!{$cellRef}" : $cellRef; $cellRef = ($cellSheet !== null) ? "'{$matches[2]}'!{$cellRef}" : $cellRef;
$cellValue = null; $cellValue = ($cellSheet !== null) ? null : Information\ExcelError::REF();
} }
} else { } else {
return $this->raiseFormulaError('Unable to access Cell Reference'); return $this->raiseFormulaError('Unable to access Cell Reference');

View File

@ -25,6 +25,14 @@ class ExcelError
'spill' => '#SPILL!', 'spill' => '#SPILL!',
]; ];
/**
* @param mixed $value
*/
public static function throwError($value): string
{
return in_array($value, self::$errorCodes, true) ? $value : self::$errorCodes['value'];
}
/** /**
* ERROR_TYPE. * ERROR_TYPE.
* *

View File

@ -38,7 +38,7 @@ class Helpers
return 0 + $number; return 0 + $number;
} }
throw new Exception(ExcelError::VALUE()); throw new Exception(ExcelError::throwError($number));
} }
/** /**
@ -59,7 +59,7 @@ class Helpers
return 0 + $number; return 0 + $number;
} }
throw new Exception(ExcelError::VALUE()); throw new Exception(ExcelError::throwError($number));
} }
/** /**

View File

@ -118,7 +118,7 @@ class Operations
if (is_numeric($arg)) { if (is_numeric($arg)) {
$returnValue *= $arg; $returnValue *= $arg;
} else { } else {
return ExcelError::VALUE(); return ExcelError::throwError($arg);
} }
} }

View File

@ -18,7 +18,11 @@ class Subtotal
return array_filter( return array_filter(
$args, $args,
function ($index) use ($cellReference) { 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(); return $cellReference->getWorksheet()->getRowDimension($row)->getVisible();
}, },
@ -35,7 +39,9 @@ class Subtotal
return array_filter( return array_filter(
$args, $args,
function ($index) use ($cellReference) { function ($index) use ($cellReference) {
[, $row, $column] = explode('.', $index); $explodeArray = explode('.', $index);
$row = $explodeArray[1] ?? '';
$column = $explodeArray[2] ?? '';
$retVal = true; $retVal = true;
if ($cellReference->getWorksheet()->cellExists($column . $row)) { if ($cellReference->getWorksheet()->cellExists($column . $row)) {
//take this cell out if it contains the SUBTOTAL or AGGREGATE functions in a formula //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) public static function evaluate($functionType, ...$args)
{ {
$cellReference = array_pop($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 { try {
$subtotal = (int) Helpers::validateNumericNullBool($functionType); $subtotal = (int) Helpers::validateNumericNullBool($functionType);

View File

@ -27,6 +27,9 @@ class Axis extends Properties
'numeric' => null, 'numeric' => null,
]; ];
/** @var string */
private $axisType = '';
/** /**
* Axis Options. * Axis Options.
* *
@ -62,11 +65,11 @@ class Axis extends Properties
* *
* @param mixed $format_code * @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; $format = (string) $format_code;
$this->axisNumber['format'] = $format; $this->axisNumber['format'] = $format;
$this->axisNumber['source_linked'] = 0; $this->axisNumber['source_linked'] = $sourceLinked;
if (is_bool($numeric)) { if (is_bool($numeric)) {
$this->axisNumber['numeric'] = $numeric; $this->axisNumber['numeric'] = $numeric;
} elseif (in_array($format, self::NUMERIC_FORMAT, true)) { } elseif (in_array($format, self::NUMERIC_FORMAT, true)) {
@ -156,6 +159,22 @@ class Axis extends Properties
$this->axisOptions['orientation'] = (string) $orientation; $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. * Set Fill Property.
* *

View File

@ -6,6 +6,8 @@ class ChartColor
{ {
const EXCEL_COLOR_TYPE_STANDARD = 'prstClr'; const EXCEL_COLOR_TYPE_STANDARD = 'prstClr';
const EXCEL_COLOR_TYPE_SCHEME = 'schemeClr'; 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_TYPE_ARGB = 'srgbClr';
const EXCEL_COLOR_TYPES = [ const EXCEL_COLOR_TYPES = [
self::EXCEL_COLOR_TYPE_ARGB, self::EXCEL_COLOR_TYPE_ARGB,
@ -22,6 +24,18 @@ class ChartColor
/** @var ?int */ /** @var ?int */
private $alpha; 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 public function getValue(): string
{ {
return $this->value; return $this->value;
@ -61,10 +75,21 @@ class ChartColor
/** /**
* @param null|float|int|string $alpha * @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) { if ($color !== null) {
$this->setValue($color); $this->setValue("$color");
} }
if ($type !== null) { if ($type !== null) {
$this->setType($type); $this->setType($type);
@ -80,21 +105,16 @@ class ChartColor
public function setColorPropertiesArray(array $color): self public function setColorPropertiesArray(array $color): self
{ {
if (array_key_exists('value', $color) && is_string($color['value'])) { return $this->setColorProperties(
$this->setValue($color['value']); $color['value'] ?? '',
} $color['alpha'] ?? null,
if (array_key_exists('type', $color) && is_string($color['type'])) { $color['type'] ?? null
$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; public function isUsable(): bool
{
return $this->type !== '' && $this->value !== '';
} }
/** /**

View File

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

View File

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

View File

@ -59,6 +59,8 @@ abstract class Properties
const LINE_STYLE_COMPOUND_TRIPLE = 'tri'; const LINE_STYLE_COMPOUND_TRIPLE = 'tri';
const LINE_STYLE_DASH_SOLID = 'solid'; const LINE_STYLE_DASH_SOLID = 'solid';
const LINE_STYLE_DASH_ROUND_DOT = 'sysDot'; 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_STYLE_DASH_SQUERE_DOT = 'sysDash';
const LINE_STYPE_DASH_DASH = 'dash'; const LINE_STYPE_DASH_DASH = 'dash';
const LINE_STYLE_DASH_DASH_DOT = 'dashDot'; const LINE_STYLE_DASH_DASH_DOT = 'dashDot';
@ -68,7 +70,7 @@ abstract class Properties
const LINE_STYLE_CAP_SQUARE = 'sq'; const LINE_STYLE_CAP_SQUARE = 'sq';
const LINE_STYLE_CAP_ROUND = 'rnd'; const LINE_STYLE_CAP_ROUND = 'rnd';
const LINE_STYLE_CAP_FLAT = 'flat'; 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_MITER = 'miter';
const LINE_STYLE_JOIN_BEVEL = 'bevel'; const LINE_STYLE_JOIN_BEVEL = 'bevel';
const LINE_STYLE_ARROW_TYPE_NOARROW = null; const LINE_STYLE_ARROW_TYPE_NOARROW = null;
@ -643,30 +645,6 @@ abstract class Properties
return $this; 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. * 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 public function getLineColor(): ChartColor
{ {
return $this->lineColor; return $this->lineColor;

View File

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

View File

@ -527,6 +527,12 @@ class ReferenceHelper
if ($objDrawing->getCoordinates() != $newReference) { if ($objDrawing->getCoordinates() != $newReference) {
$objDrawing->setCoordinates($newReference); $objDrawing->setCoordinates($newReference);
} }
if ($objDrawing->getCoordinates2() !== '') {
$newReference = $this->updateCellReference($objDrawing->getCoordinates2());
if ($objDrawing->getCoordinates2() != $newReference) {
$objDrawing->setCoordinates2($newReference);
}
}
} }
// Update workbook: define names // Update workbook: define names

View File

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

View File

@ -9,8 +9,8 @@ use PhpOffice\PhpSpreadsheet\IComparable;
class BaseDrawing implements IComparable class BaseDrawing implements IComparable
{ {
const EDIT_AS_ABSOLUTE = 'absolute'; const EDIT_AS_ABSOLUTE = 'absolute';
const EDIT_AS_ONECELL = 'onecell'; const EDIT_AS_ONECELL = 'oneCell';
const EDIT_AS_TWOCELL = 'twocell'; const EDIT_AS_TWOCELL = 'twoCell';
private const VALID_EDIT_AS = [ private const VALID_EDIT_AS = [
self::EDIT_AS_ABSOLUTE, self::EDIT_AS_ABSOLUTE,
self::EDIT_AS_ONECELL, self::EDIT_AS_ONECELL,
@ -530,6 +530,6 @@ class BaseDrawing implements IComparable
public function validEditAs(): bool public function validEditAs(): bool
{ {
return in_array($this->editAs, self::VALID_EDIT_AS); return in_array($this->editAs, self::VALID_EDIT_AS, true);
} }
} }

View File

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

View File

@ -4,6 +4,7 @@ namespace PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Cell\Cell; use PhpOffice\PhpSpreadsheet\Cell\Cell;
use PhpOffice\PhpSpreadsheet\Cell\DataType; use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\RichText\Run; use PhpOffice\PhpSpreadsheet\RichText\Run;
use PhpOffice\PhpSpreadsheet\Shared\StringHelper; use PhpOffice\PhpSpreadsheet\Shared\StringHelper;
@ -198,7 +199,7 @@ class StringTable extends WriterPart
* @param RichText|string $richText text string or Rich text * @param RichText|string $richText text string or Rich text
* @param string $prefix Optional Namespace prefix * @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) { if (!$richText instanceof RichText) {
$textRun = $richText; $textRun = $richText;
@ -207,7 +208,7 @@ class StringTable extends WriterPart
$run->setFont(null); $run->setFont(null);
} }
if ($prefix !== null) { if ($prefix !== '') {
$prefix .= ':'; $prefix .= ':';
} }
@ -249,27 +250,10 @@ class StringTable extends WriterPart
} }
// Color // Color
$objWriter->startElement($prefix . 'solidFill'); $this->writeChartTextColor($objWriter, $element->getFont()->getChartColor(), $prefix);
$objWriter->startElement($prefix . 'srgbClr');
$objWriter->writeAttribute('val', $element->getFont()->getColor()->getRGB());
$objWriter->endElement(); // srgbClr
$objWriter->endElement(); // solidFill
// Underscore Color // Underscore Color
$underlineColor = $element->getFont()->getUnderlineColor(); $this->writeChartTextColor($objWriter, $element->getFont()->getUnderlineColor(), $prefix, 'uFill');
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
}
}
// fontName // fontName
if ($element->getFont()->getLatin()) { 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). * Flip string table (for index searching).
* *

View File

@ -127,4 +127,32 @@ class SubTotalTest extends AllSetupTeardown
$sheet->getCell('H1')->setValue("=SUBTOTAL(9, A1:$maxCol$maxRow)"); $sheet->getCell('H1')->setValue("=SUBTOTAL(9, A1:$maxCol$maxRow)");
self::assertEquals(362, $sheet->getCell('H1')->getCalculatedValue()); 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());
}
} }

View File

@ -0,0 +1,58 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Calculation;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PHPUnit\Framework\TestCase;
class RefErrorTest extends TestCase
{
/**
* @param mixed $expected
*
* @dataProvider providerRefError
*/
public function testRefError($expected, string $formula): void
{
$spreadsheet = new Spreadsheet();
$sheet1 = $spreadsheet->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)'],
];
}
}

View File

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

View File

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

View File

@ -58,7 +58,10 @@ class Charts32ColoredAxisLabelTest extends AbstractFunctional
self::assertInstanceOf(Run::class, $run); self::assertInstanceOf(Run::class, $run);
$font = $run->getFont(); $font = $run->getFont();
self::assertInstanceOf(Font::class, $font); 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(); $yAxisLabel = $chart->getYAxisLabel();
$captionArray = $yAxisLabel->getCaption(); $captionArray = $yAxisLabel->getCaption();
@ -73,7 +76,10 @@ class Charts32ColoredAxisLabelTest extends AbstractFunctional
self::assertInstanceOf(Run::class, $run); self::assertInstanceOf(Run::class, $run);
$font = $run->getFont(); $font = $run->getFont();
self::assertInstanceOf(Font::class, $font); 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(); $reloadedSpreadsheet->disconnectWorksheets();
} }

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Chart; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\RichText;
use PhpOffice\PhpSpreadsheet\RichText\Run; use PhpOffice\PhpSpreadsheet\RichText\Run;
@ -65,7 +66,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript()); self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough()); self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline()); 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(); $plotArea = $chart->getPlotArea();
$plotSeries = $plotArea->getPlotGroup(); $plotSeries = $plotArea->getPlotGroup();
@ -75,19 +79,22 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues); self::assertCount(3, $plotValues);
$values = $plotValues[0]; $values = $plotValues[0];
self::assertFalse($values->getScatterLines()); 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(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[1]; $values = $plotValues[1];
self::assertFalse($values->getScatterLines()); 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(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[2]; $values = $plotValues[2];
self::assertFalse($values->getScatterLines()); 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(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(); $reloadedSpreadsheet->disconnectWorksheets();
} }
@ -135,7 +142,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript()); self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough()); self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline()); 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]; $run = $elements[1];
self::assertInstanceOf(Run::class, $run); self::assertInstanceOf(Run::class, $run);
@ -149,7 +159,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript()); self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough()); self::assertFalse($font->getStrikethrough());
self::assertSame('single', $font->getUnderline()); 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]; $run = $elements[2];
self::assertInstanceOf(Run::class, $run); self::assertInstanceOf(Run::class, $run);
@ -163,7 +176,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript()); self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough()); self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline()); 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(); $plotArea = $chart->getPlotArea();
$plotSeries = $plotArea->getPlotGroup(); $plotSeries = $plotArea->getPlotGroup();
@ -173,19 +189,22 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues); self::assertCount(3, $plotValues);
$values = $plotValues[0]; $values = $plotValues[0];
self::assertFalse($values->getScatterLines()); 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(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[1]; $values = $plotValues[1];
self::assertFalse($values->getScatterLines()); 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(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[2]; $values = $plotValues[2];
self::assertFalse($values->getScatterLines()); 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(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(); $reloadedSpreadsheet->disconnectWorksheets();
} }
@ -232,7 +251,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript()); self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough()); self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline()); 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(); $plotArea = $chart->getPlotArea();
$plotSeries = $plotArea->getPlotGroup(); $plotSeries = $plotArea->getPlotGroup();
@ -242,17 +264,19 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues); self::assertCount(3, $plotValues);
$values = $plotValues[0]; $values = $plotValues[0];
self::assertTrue($values->getScatterLines()); 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(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[1]; $values = $plotValues[1];
self::assertTrue($values->getScatterLines()); self::assertTrue($values->getScatterLines());
self::assertSame(12700, $values->getLineWidth()); self::assertNull($values->getLineWidth());
self::assertSame(3, $values->getPointSize()); self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[2]; $values = $plotValues[2];
self::assertTrue($values->getScatterLines()); self::assertTrue($values->getScatterLines());
self::assertSame(12700, $values->getLineWidth()); self::assertNull($values->getLineWidth());
self::assertSame(3, $values->getPointSize()); self::assertSame(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
@ -303,7 +327,10 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertFalse($font->getSubscript()); self::assertFalse($font->getSubscript());
self::assertFalse($font->getStrikethrough()); self::assertFalse($font->getStrikethrough());
self::assertSame('none', $font->getUnderline()); 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(); $plotArea = $chart->getPlotArea();
@ -314,19 +341,97 @@ class Charts32ScatterTest extends AbstractFunctional
self::assertCount(3, $plotValues); self::assertCount(3, $plotValues);
$values = $plotValues[0]; $values = $plotValues[0];
self::assertFalse($values->getScatterLines()); 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(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[1]; $values = $plotValues[1];
self::assertFalse($values->getScatterLines()); 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(3, $values->getPointSize());
self::assertSame('', $values->getFillColor()); self::assertSame('', $values->getFillColor());
$values = $plotValues[2]; $values = $plotValues[2];
self::assertFalse($values->getScatterLines()); 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(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(); $reloadedSpreadsheet->disconnectWorksheets();
} }

View File

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

View File

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

View File

@ -0,0 +1,172 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx as XlsxWriter;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class DataSeriesValues2Test extends AbstractFunctional
{
public function readCharts(XlsxReader $reader): void
{
$reader->setIncludeCharts(true);
}
public function writeCharts(XlsxWriter $writer): void
{
$writer->setIncludeCharts(true);
}
public function testDataSeriesValues(): void
{
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
$worksheet->fromArray(
[
['', 2010, 2011, 2012],
['Q1', 12, 15, 21],
['Q2', 56, 73, 86],
['Q3', 52, 61, 69],
['Q4', 30, 32, 0],
]
);
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // 2012
];
// Set the X-Axis Labels
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$xAxisTickValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', null, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', null, 4),
];
// Build the dataseries
$series = new DataSeries(
null, // plotType
null, // plotGrouping
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues // plotValues
);
self::assertEmpty($series->getPlotType());
self::assertEmpty($series->getPlotGrouping());
self::assertFalse($series->getSmoothLine());
$series->setPlotType(DataSeries::TYPE_AREACHART);
$series->setPlotGrouping(DataSeries::GROUPING_PERCENT_STACKED);
$series->setSmoothLine(true);
self::assertSame(DataSeries::TYPE_AREACHART, $series->getPlotType());
self::assertSame(DataSeries::GROUPING_PERCENT_STACKED, $series->getPlotGrouping());
self::assertTrue($series->getSmoothLine());
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test %age-Stacked Area Chart');
$yAxisLabel = new Title('Value ($k)');
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
$yAxisLabel // yAxisLabel
);
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('H20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
self::assertSame(1, $chart->getPlotArea()->getPlotGroupCount());
$plotValues = $chart->getPlotArea()->getPlotGroup()[0]->getPlotValues();
self::assertCount(3, $plotValues);
self::assertSame([], $plotValues[1]->getDataValues());
self::assertNull($plotValues[1]->getDataValue());
/** @var callable */
$callableReader = [$this, 'readCharts'];
/** @var callable */
$callableWriter = [$this, 'writeCharts'];
$reloadedSpreadsheet = $this->writeAndReload($spreadsheet, 'Xlsx', $callableReader, $callableWriter);
$spreadsheet->disconnectWorksheets();
$sheet = $reloadedSpreadsheet->getActiveSheet();
$charts2 = $sheet->getChartCollection();
self::assertCount(1, $charts2);
$chart2 = $charts2[0];
self::assertNotNull($chart2);
$plotValues2 = $chart2->getPlotArea()->getPlotGroup()[0]->getPlotValues();
self::assertCount(3, $plotValues2);
self::assertSame([15.0, 73.0, 61.0, 32.0], $plotValues2[1]->getDataValues());
self::assertSame([15.0, 73.0, 61.0, 32.0], $plotValues2[1]->getDataValue());
$labels2 = $chart->getPlotArea()->getPlotGroup()[0]->getPlotLabels();
self::assertCount(3, $labels2);
self::assertSame(2010, $labels2[0]->getDataValue());
$dataSeries = $chart->getPlotArea()->getPlotGroup()[0];
self::assertFalse($dataSeries->getPlotValuesByIndex(99));
self::assertNotFalse($dataSeries->getPlotValuesByIndex(0));
self::assertSame([12, 56, 52, 30], $dataSeries->getPlotValuesByIndex(0)->getDataValues());
self::assertSame(DataSeries::TYPE_AREACHART, $dataSeries->getPlotType());
self::assertSame(DataSeries::GROUPING_PERCENT_STACKED, $dataSeries->getPlotGrouping());
self::assertTrue($dataSeries->getSmoothLine());
$reloadedSpreadsheet->disconnectWorksheets();
}
public function testSomeProperties(): void
{
$dataSeriesValues = new DataSeriesValues();
self::assertNull($dataSeriesValues->getDataSource());
self::assertEmpty($dataSeriesValues->getPointMarker());
self::assertSame(3, $dataSeriesValues->getPointSize());
$dataSeriesValues->setDataSource('Worksheet!$B$1')
->setPointMarker('square')
->setPointSize(6);
self::assertSame('Worksheet!$B$1', $dataSeriesValues->getDataSource());
self::assertSame('square', $dataSeriesValues->getPointMarker());
self::assertSame(6, $dataSeriesValues->getPointSize());
}
}

View File

@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Chart; namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues; use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Exception; use PhpOffice\PhpSpreadsheet\Exception;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -51,13 +52,14 @@ class DataSeriesValuesTest extends TestCase
public function testGetLineWidth(): void public function testGetLineWidth(): void
{ {
$testInstance = new DataSeriesValues(); $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); $testInstance->setLineWidth(40000 / Properties::POINTS_WIDTH_MULTIPLIER);
self::assertEquals(40000, $testInstance->getLineWidth()); self::assertEquals(40000 / Properties::POINTS_WIDTH_MULTIPLIER, $testInstance->getLineWidth());
$testInstance->setLineWidth(1); $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 public function testFillColorCorrectInput(): void

View File

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

View File

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

View File

@ -0,0 +1,45 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Writer\Xlsx;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheetTests\Functional\AbstractFunctional;
class DrawingsInsertRowsTest extends AbstractFunctional
{
/**
* Test save and load XLSX file with drawing on 2nd worksheet.
*/
public function testSaveAfterInsertingRows(): void
{
// Read spreadsheet from file
$inputFilename = 'tests/data/Writer/XLSX/issue.2908.xlsx';
$reader = new Xlsx();
$spreadsheet = $reader->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();
}
}

View File

@ -554,10 +554,10 @@ class DrawingsTest extends AbstractFunctional
{ {
return [ return [
'absolute' => ['absolute'], 'absolute' => ['absolute'],
'onecell' => ['onecell'], 'onecell' => ['oneCell'],
'twocell' => ['twocell'], 'twocell' => ['twoCell'],
'unset (will be treated as twocell)' => [''], 'unset (will be treated as twoCell)' => [''],
'unknown (will be treated as twocell)' => ['unknown', ''], 'unknown (will be treated as twoCell)' => ['unknown', ''],
]; ];
} }

Binary file not shown.