Charts - Gradients, Transparency, Hidden Axes (#2950)

Fix #2257. Fix #2929. Fix #2935 (probably in a way that will not satisfy the requester). 2257 and 2929 requested changes that ultimately affect the same section of code, so it's appropriate to deal with them together. 2257 requests the ability to make the chart background transparent (so that the Excel gridlines are visible beneath the chart), and the ability to hide an Axis. 2929 requests the ability to set a gradient background on the chart.
This commit is contained in:
oleibman 2022-07-23 08:06:13 -07:00 committed by GitHub
parent abc1d3db70
commit b8456105dd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 619 additions and 13 deletions

View File

@ -0,0 +1,192 @@
<?php
use PhpOffice\PhpSpreadsheet\Chart\Axis;
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
require __DIR__ . '/../Header.php';
$spreadsheet = new Spreadsheet();
$worksheet = $spreadsheet->getActiveSheet();
// changed data to simulate a trend chart - Xaxis are dates; Yaxis are 3 meausurements from each date
$worksheet->fromArray(
[
['', 'metric1', 'metric2', 'metric3'],
['=DATEVALUE("2021-01-01")', 12.1, 15.1, 21.1],
['=DATEVALUE("2021-01-04")', 56.2, 73.2, 86.2],
['=DATEVALUE("2021-01-07")', 52.2, 61.2, 69.2],
['=DATEVALUE("2021-01-10")', 30.2, 32.2, 0.2],
]
);
$worksheet->getStyle('A2:A5')->getNumberFormat()->setFormatCode(Properties::FORMAT_CODE_DATE_ISO8601);
$worksheet->getColumnDimension('A')->setAutoSize(true);
$worksheet->setSelectedCells('A1');
// Set the Labels for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
$dataSeriesLabels = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$B$1', null, 1), // was 2010
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$C$1', null, 1), // was 2011
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$D$1', null, 1), // was 2012
];
// Set the X-Axis Labels
// changed from STRING to NUMBER
// added 2 additional x-axis values associated with each of the 3 metrics
// added FORMATE_CODE_NUMBER
$xAxisTickValues = [
//new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, 'Worksheet!$A$2:$A$5', null, 4), // Q1 to Q4
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$A$2:$A$5', Properties::FORMAT_CODE_DATE, 4),
];
// Set the Data values for each data series we want to plot
// Datatype
// Cell reference for data
// Format Code
// Number of datapoints in series
// Data values
// Data Marker
// added FORMAT_CODE_NUMBER
$dataSeriesValues = [
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$B$2:$B$5', Properties::FORMAT_CODE_NUMBER, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$C$2:$C$5', Properties::FORMAT_CODE_NUMBER, 4),
new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, 'Worksheet!$D$2:$D$5', Properties::FORMAT_CODE_NUMBER, 4),
];
// series 1
// marker details
$dataSeriesValues[0]
->setPointMarker('diamond')
->setPointSize(5)
->getMarkerFillColor()
->setColorProperties('0070C0', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[0]
->getMarkerBorderColor()
->setColorProperties('002060', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
// line details - smooth line, connected
$dataSeriesValues[0]
->setScatterLines(true)
->setSmoothLine(true)
->setLineColorProperties('accent1', 40, ChartColor::EXCEL_COLOR_TYPE_SCHEME); // value, alpha, type
$dataSeriesValues[0]->setLineStyleProperties(
2.5, // width in points
Properties::LINE_STYLE_COMPOUND_TRIPLE, // compound
Properties::LINE_STYLE_DASH_SQUARE_DOT, // dash
Properties::LINE_STYLE_CAP_SQUARE, // cap
Properties::LINE_STYLE_JOIN_MITER, // join
Properties::LINE_STYLE_ARROW_TYPE_OPEN, // head type
Properties::LINE_STYLE_ARROW_SIZE_4, // head size preset index
Properties::LINE_STYLE_ARROW_TYPE_ARROW, // end type
Properties::LINE_STYLE_ARROW_SIZE_6 // end size preset index
);
// series 2 - straight line - no special effects, connected, straight line
$dataSeriesValues[1] // square fill
->setPointMarker('square')
->setPointSize(6)
->getMarkerBorderColor()
->setColorProperties('accent6', 3, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
$dataSeriesValues[1] // square border
->getMarkerFillColor()
->setColorProperties('0FFF00', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[1]
->setScatterLines(true)
->setSmoothLine(false)
->setLineColorProperties('FF0000', 80, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[1]->setLineWidth(2.0);
// series 3 - markers, no line
$dataSeriesValues[2] // triangle fill
//->setPointMarker('triangle') // let Excel choose shape
->setPointSize(7)
->getMarkerFillColor()
->setColorProperties('FFFF00', null, ChartColor::EXCEL_COLOR_TYPE_RGB);
$dataSeriesValues[2] // triangle border
->getMarkerBorderColor()
->setColorProperties('accent4', null, ChartColor::EXCEL_COLOR_TYPE_SCHEME);
$dataSeriesValues[2]->setScatterLines(false); // points not connected
// Added so that Xaxis shows dates instead of Excel-equivalent-year1900-numbers
$xAxis = new Axis();
//$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE );
$xAxis->setAxisNumberProperties(Properties::FORMAT_CODE_DATE_ISO8601, true);
$xAxis->setAxisOption('textRotation', '45');
$xAxis->setAxisOption('hidden', '1');
$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);
$yAxis->setAxisOption('hidden', '1');
// Build the dataseries
$series = new DataSeries(
DataSeries::TYPE_SCATTERCHART, // plotType
null, // plotGrouping (Scatter charts don't have any grouping)
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues, // plotValues
null, // plotDirection
false, // smooth line
DataSeries::STYLE_SMOOTHMARKER // plotStyle
);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
$plotArea->setNoFill(true);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test Scatter Trend Chart');
//$yAxisLabel = new Title('Value ($k)');
// Create the chart
$chart = new Chart(
'chart1', // name
$title, // title
$legend, // legend
$plotArea, // plotArea
true, // plotVisibleOnly
DataSeries::EMPTY_AS_GAP, // displayBlanksAs
null, // xAxisLabel
null, //$yAxisLabel, // yAxisLabel
// added xAxis for correct date display
$xAxis, // xAxis
$yAxis, // yAxis
);
$chart->setNoFill(true);
// Set the position where the chart should appear in the worksheet
$chart->setTopLeftPosition('A7');
$chart->setBottomRightPosition('P20');
// Add the chart to the worksheet
$worksheet->addChart($chart);
// Save Excel 2007 file
$filename = $helper->getFilename(__FILE__);
$writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
$writer->setIncludeCharts(true);
$callStartTime = microtime(true);
$writer->save($filename);
$spreadsheet->disconnectWorksheets();
$helper->logWrite($writer, $filename, $callStartTime);

View File

@ -0,0 +1,130 @@
<?php
use PhpOffice\PhpSpreadsheet\Chart\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\DataSeries;
use PhpOffice\PhpSpreadsheet\Chart\DataSeriesValues;
use PhpOffice\PhpSpreadsheet\Chart\Legend as ChartLegend;
use PhpOffice\PhpSpreadsheet\Chart\PlotArea;
use PhpOffice\PhpSpreadsheet\Chart\Title;
use PhpOffice\PhpSpreadsheet\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],
]
);
// 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
$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(
DataSeries::TYPE_SCATTERCHART, // plotType
null, // plotGrouping (Scatter charts don't have any grouping)
range(0, count($dataSeriesValues) - 1), // plotOrder
$dataSeriesLabels, // plotLabel
$xAxisTickValues, // plotCategory
$dataSeriesValues, // plotValues
null, // plotDirection
null, // smooth line
DataSeries::STYLE_LINEMARKER // plotStyle
);
// Set the series in the plot area
$plotArea = new PlotArea(null, [$series]);
$pos1 = 0; // pos = 0% (extreme low side or lower left corner)
$brightness1 = 0; // 0%
$gsColor1 = new ChartColor();
$gsColor1->setColorProperties('FF0000', 75, 'srgbClr', $brightness1); // red
$gradientStop1 = [$pos1, $gsColor1];
$pos2 = 0.5; // pos = 50% (middle)
$brightness2 = 0.5; // 50%
$gsColor2 = new ChartColor();
$gsColor2->setColorProperties('FFFF00', 50, 'srgbClr', $brightness2); // yellow
$gradientStop2 = [$pos2, $gsColor2];
$pos3 = 1.0; // pos = 100% (extreme high side or upper right corner)
$brightness3 = 0.5; // 50%
$gsColor3 = new ChartColor();
$gsColor3->setColorProperties('00B050', 50, 'srgbClr', $brightness3); // green
$gradientStop3 = [$pos3, $gsColor3];
$gradientFillStops = [
$gradientStop1,
$gradientStop2,
$gradientStop3,
];
$gradientFillAngle = 315.0; // 45deg above horiz
$plotArea->setGradientFillProperties($gradientFillStops, $gradientFillAngle);
// Set the chart legend
$legend = new ChartLegend(ChartLegend::POSITION_TOPRIGHT, null, false);
$title = new Title('Test Scatter 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);
// 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);

Binary file not shown.

Binary file not shown.

View File

@ -61,6 +61,7 @@ class Axis extends Properties
'horizontal_crosses' => self::HORIZONTAL_CROSSES_AUTOZERO,
'horizontal_crosses_value' => null,
'textRotation' => null,
'hidden' => null,
];
/**
@ -138,7 +139,8 @@ class Axis extends Properties
?string $maximum = null,
?string $majorUnit = null,
?string $minorUnit = null,
?string $textRotation = null
?string $textRotation = null,
?string $hidden = null
): void {
$this->axisOptions['axis_labels'] = $axisLabels;
$this->setAxisOption('horizontal_crosses_value', $horizontalCrossesValue);
@ -151,6 +153,7 @@ class Axis extends Properties
$this->setAxisOption('major_unit', $majorUnit);
$this->setAxisOption('minor_unit', $minorUnit);
$this->setAxisOption('textRotation', $textRotation);
$this->setAxisOption('hidden', $hidden);
}
/**

View File

@ -144,6 +144,9 @@ class Chart
/** @var bool */
private $autoTitleDeleted = false;
/** @var bool */
private $noFill = false;
/**
* Create a new Chart.
* majorGridlines and minorGridlines are deprecated, moved to Axis.
@ -747,4 +750,16 @@ class Chart
return $this;
}
public function getNoFill(): bool
{
return $this->noFill;
}
public function setNoFill(bool $noFill): self
{
$this->noFill = $noFill;
return $this;
}
}

View File

@ -24,15 +24,18 @@ class ChartColor
/** @var ?int */
private $alpha;
/** @var ?int */
private $brightness;
/**
* @param string|string[] $value
*/
public function __construct($value = '', ?int $alpha = null, ?string $type = null)
public function __construct($value = '', ?int $alpha = null, ?string $type = null, ?int $brightness = null)
{
if (is_array($value)) {
$this->setColorPropertiesArray($value);
} else {
$this->setColorProperties($value, $alpha, $type);
$this->setColorProperties($value, $alpha, $type, $brightness);
}
}
@ -72,10 +75,23 @@ class ChartColor
return $this;
}
public function getBrightness(): ?int
{
return $this->brightness;
}
public function setBrightness(?int $brightness): self
{
$this->brightness = $brightness;
return $this;
}
/**
* @param null|float|int|string $alpha
* @param null|float|int|string $brightness
*/
public function setColorProperties(?string $color, $alpha = null, ?string $type = null): self
public function setColorProperties(?string $color, $alpha = null, ?string $type = null, $brightness = null): self
{
if (empty($type) && !empty($color)) {
if (substr($color, 0, 1) === '*') {
@ -99,6 +115,11 @@ class ChartColor
} elseif (is_numeric($alpha)) {
$this->setAlpha((int) $alpha);
}
if ($brightness === null) {
$this->setBrightness(null);
} elseif (is_numeric($brightness)) {
$this->setBrightness((int) $brightness);
}
return $this;
}
@ -108,7 +129,8 @@ class ChartColor
return $this->setColorProperties(
$color['value'] ?? '',
$color['alpha'] ?? null,
$color['type'] ?? null
$color['type'] ?? null,
$color['brightness'] ?? null
);
}
@ -133,6 +155,8 @@ class ChartColor
$retVal = $this->type;
} elseif ($propertyName === 'alpha') {
$retVal = $this->alpha;
} elseif ($propertyName === 'brightness') {
$retVal = $this->brightness;
}
return $retVal;

View File

@ -94,7 +94,7 @@ class DataSeries
private $plotCategory = [];
/**
* Smooth Line.
* Smooth Line. Must be specified for both DataSeries and DataSeriesValues.
*
* @var bool
*/

View File

@ -536,7 +536,7 @@ class DataSeriesValues extends Properties
}
/**
* Smooth Line.
* Smooth Line. Must be specified for both DataSeries and DataSeriesValues.
*
* @var bool
*/

View File

@ -6,6 +6,30 @@ use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class PlotArea
{
/**
* No fill in plot area (show Excel gridlines through chart).
*
* @var bool
*/
private $noFill = false;
/**
* PlotArea Gradient Stop list.
* Each entry is a 2-element array.
* First is position in %.
* Second is ChartColor.
*
* @var array[]
*/
private $gradientFillStops = [];
/**
* PlotArea Gradient Angle.
*
* @var ?float
*/
private $gradientFillAngle;
/**
* PlotArea Layout.
*
@ -101,4 +125,42 @@ class PlotArea
$plotSeries->refresh($worksheet);
}
}
public function setNoFill(bool $noFill): self
{
$this->noFill = $noFill;
return $this;
}
public function getNoFill(): bool
{
return $this->noFill;
}
public function setGradientFillProperties(array $gradientFillStops, ?float $gradientFillAngle): self
{
$this->gradientFillStops = $gradientFillStops;
$this->gradientFillAngle = $gradientFillAngle;
return $this;
}
/**
* Get gradientFillAngle.
*/
public function getGradientFillAngle(): ?float
{
return $this->gradientFillAngle;
}
/**
* Get gradientFillStops.
*
* @return array
*/
public function getGradientFillStops()
{
return $this->gradientFillStops;
}
}

View File

@ -73,8 +73,18 @@ class Chart
$xAxis = new Axis();
$yAxis = new Axis();
$autoTitleDeleted = null;
$chartNoFill = false;
$gradientArray = [];
$gradientLin = null;
foreach ($chartElementsC as $chartElementKey => $chartElement) {
switch ($chartElementKey) {
case 'spPr':
$possibleNoFill = $chartElementsC->spPr->children($this->aNamespace);
if (isset($possibleNoFill->noFill)) {
$chartNoFill = true;
}
break;
case 'chart':
foreach ($chartElement as $chartDetailsKey => $chartDetails) {
$chartDetailsC = $chartDetails->children($this->cNamespace);
@ -95,8 +105,29 @@ class Chart
$plotAreaLayout = $XaxisLabel = $YaxisLabel = null;
$plotSeries = $plotAttributes = [];
$catAxRead = false;
$plotNoFill = false;
foreach ($chartDetails as $chartDetailKey => $chartDetail) {
switch ($chartDetailKey) {
case 'spPr':
$possibleNoFill = $chartDetails->spPr->children($this->aNamespace);
if (isset($possibleNoFill->noFill)) {
$plotNoFill = true;
}
if (isset($possibleNoFill->gradFill->gsLst)) {
foreach ($possibleNoFill->gradFill->gsLst->gs as $gradient) {
/** @var float */
$pos = self::getAttribute($gradient, 'pos', 'float');
$gradientArray[] = [
$pos / Properties::PERCENTAGE_MULTIPLIER,
new ChartColor($this->readColor($gradient)),
];
}
}
if (isset($possibleNoFill->gradFill->lin)) {
$gradientLin = Properties::XmlToAngle((string) self::getAttribute($possibleNoFill->gradFill->lin, 'ang', 'string'));
}
break;
case 'layout':
$plotAreaLayout = $this->chartLayoutDetails($chartDetail);
@ -288,6 +319,12 @@ class Chart
}
$plotArea = new PlotArea($plotAreaLayout, $plotSeries);
$this->setChartAttributes($plotAreaLayout, $plotAttributes);
if ($plotNoFill) {
$plotArea->setNoFill(true);
}
if (!empty($gradientArray)) {
$plotArea->setGradientFillProperties($gradientArray, $gradientLin);
}
break;
case 'plotVisOnly':
@ -330,6 +367,9 @@ class Chart
}
}
$chart = new \PhpOffice\PhpSpreadsheet\Chart\Chart($chartName, $title, $legend, $plotArea, $plotVisOnly, (string) $dispBlanksAs, $XaxisLabel, $YaxisLabel, $xAxis, $yAxis);
if ($chartNoFill) {
$chart->setNoFill(true);
}
if (is_bool($autoTitleDeleted)) {
$chart->setAutoTitleDeleted($autoTitleDeleted);
}
@ -1147,6 +1187,7 @@ class Chart
'type' => null,
'value' => null,
'alpha' => null,
'brightness' => null,
];
foreach (ChartColor::EXCEL_COLOR_TYPES as $type) {
if (isset($colorXml->$type)) {
@ -1159,6 +1200,13 @@ class Chart
$result['alpha'] = ChartColor::alphaFromXml($alpha);
}
}
if (isset($colorXml->$type->lumMod)) {
/** @var string */
$brightness = self::getAttribute($colorXml->$type->lumMod, 'val', 'string');
if (is_numeric($brightness)) {
$result['brightness'] = ChartColor::alphaFromXml($brightness);
}
}
break;
}
@ -1236,6 +1284,9 @@ class Chart
if (!isset($whichAxis)) {
return;
}
if (isset($chartDetail->delete)) {
$whichAxis->setAxisOption('hidden', (string) self::getAttribute($chartDetail->delete, 'val', 'string'));
}
if (isset($chartDetail->numFmt)) {
$whichAxis->setAxisNumberProperties(
(string) self::getAttribute($chartDetail->numFmt, 'formatCode', 'string'),

View File

@ -106,11 +106,17 @@ class Chart extends WriterPart
$objWriter->writeAttribute('val', '0');
$objWriter->endElement();
$objWriter->endElement();
$objWriter->endElement(); // c:chart
if ($chart->getNoFill()) {
$objWriter->startElement('c:spPr');
$objWriter->startElement('a:noFill');
$objWriter->endElement(); // a:noFill
$objWriter->endElement(); // c:spPr
}
$this->writePrintSettings($objWriter);
$objWriter->endElement();
$objWriter->endElement(); // c:chartSpace
// Return
return $objWriter->getData();
@ -360,8 +366,35 @@ class Chart extends WriterPart
$this->writeSerAxis($objWriter, $id2, $id3);
}
}
$stops = $plotArea->getGradientFillStops();
if ($plotArea->getNoFill() || !empty($stops)) {
$objWriter->startElement('c:spPr');
if ($plotArea->getNoFill()) {
$objWriter->startElement('a:noFill');
$objWriter->endElement(); // a:noFill
}
if (!empty($stops)) {
$objWriter->startElement('a:gradFill');
$objWriter->startElement('a:gsLst');
foreach ($stops as $stop) {
$objWriter->startElement('a:gs');
$objWriter->writeAttribute('pos', (string) (Properties::PERCENTAGE_MULTIPLIER * (float) $stop[0]));
$this->writeColor($objWriter, $stop[1], false);
$objWriter->endElement(); // a:gs
}
$objWriter->endElement(); // a:gsLst
$angle = $plotArea->getGradientFillAngle();
if ($angle !== null) {
$objWriter->startElement('a:lin');
$objWriter->writeAttribute('ang', Properties::angleToXml($angle));
$objWriter->endElement(); // a:lin
}
$objWriter->endElement(); // a:gradFill
}
$objWriter->endElement(); // c:spPr
}
$objWriter->endElement();
$objWriter->endElement(); // c:plotArea
}
private function writeDataLabelsBool(XMLWriter $objWriter, string $name, ?bool $value): void
@ -492,7 +525,7 @@ class Chart extends WriterPart
$objWriter->endElement(); // c:scaling
$objWriter->startElement('c:delete');
$objWriter->writeAttribute('val', '0');
$objWriter->writeAttribute('val', $yAxis->getAxisOptionsProperty('hidden') ?? '0');
$objWriter->endElement();
$objWriter->startElement('c:axPos');
@ -682,7 +715,7 @@ class Chart extends WriterPart
$objWriter->endElement(); // c:scaling
$objWriter->startElement('c:delete');
$objWriter->writeAttribute('val', '0');
$objWriter->writeAttribute('val', $xAxis->getAxisOptionsProperty('hidden') ?? '0');
$objWriter->endElement();
$objWriter->startElement('c:axPos');
@ -1612,7 +1645,18 @@ class Chart extends WriterPart
if (is_numeric($alpha)) {
$objWriter->startElement('a:alpha');
$objWriter->writeAttribute('val', ChartColor::alphaToXml((int) $alpha));
$objWriter->endElement();
$objWriter->endElement(); // a:alpha
}
$brightness = $chartColor->getBrightness();
if (is_numeric($brightness)) {
$brightness = (int) $brightness;
$lumOff = 100 - $brightness;
$objWriter->startElement('a:lumMod');
$objWriter->writeAttribute('val', ChartColor::alphaToXml($brightness));
$objWriter->endElement(); // a:lumMod
$objWriter->startElement('a:lumOff');
$objWriter->writeAttribute('val', ChartColor::alphaToXml($lumOff));
$objWriter->endElement(); // a:lumOff
}
$objWriter->endElement(); //a:srgbClr/schemeClr/prstClr
if ($solidFill) {

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Chart;
use PhpOffice\PhpSpreadsheet\Chart\ChartColor;
use PhpOffice\PhpSpreadsheet\Chart\Properties;
use PhpOffice\PhpSpreadsheet\Reader\Xlsx as XlsxReader;
use PhpOffice\PhpSpreadsheet\RichText\RichText;
@ -447,4 +448,88 @@ class Charts32ScatterTest extends AbstractFunctional
$reloadedSpreadsheet->disconnectWorksheets();
}
public function testScatter9(): void
{
// gradient testing
$file = self::DIRECTORY . '32readwriteScatterChart9.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);
self::assertFalse($chart->getNoFill());
$plotArea = $chart->getPlotArea();
self::assertNotNull($plotArea);
self::assertFalse($plotArea->getNoFill());
self::assertEquals(315.0, $plotArea->getGradientFillAngle());
$stops = $plotArea->getGradientFillStops();
self::assertCount(3, $stops);
self::assertEquals(0.43808, $stops[0][0]);
self::assertEquals(0, $stops[1][0]);
self::assertEquals(0.91, $stops[2][0]);
$color = $stops[0][1];
self::assertInstanceOf(ChartColor::class, $color);
self::assertSame('srgbClr', $color->getType());
self::assertSame('CDDBEC', $color->getValue());
self::assertNull($color->getAlpha());
self::assertSame(20, $color->getBrightness());
$color = $stops[1][1];
self::assertInstanceOf(ChartColor::class, $color);
self::assertSame('srgbClr', $color->getType());
self::assertSame('FFC000', $color->getValue());
self::assertNull($color->getAlpha());
self::assertNull($color->getBrightness());
$color = $stops[2][1];
self::assertInstanceOf(ChartColor::class, $color);
self::assertSame('srgbClr', $color->getType());
self::assertSame('00B050', $color->getValue());
self::assertNull($color->getAlpha());
self::assertSame(4, $color->getBrightness());
$reloadedSpreadsheet->disconnectWorksheets();
}
public function testScatter10(): void
{
// nofill for Chart and PlotArea, hidden Axis
$file = self::DIRECTORY . '32readwriteScatterChart10.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);
self::assertTrue($chart->getNoFill());
$plotArea = $chart->getPlotArea();
self::assertNotNull($plotArea);
self::assertTrue($plotArea->getNoFill());
$reloadedSpreadsheet->disconnectWorksheets();
}
}