<?php
namespace PhpOffice\PhpSpreadsheet\Chart;
use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
< class DataSeriesValues
> class DataSeriesValues extends Properties
{
const DATASERIES_TYPE_STRING = 'String';
const DATASERIES_TYPE_NUMBER = 'Number';
< private static $dataTypeValues = [
> private const DATA_TYPE_VALUES = [
self::DATASERIES_TYPE_STRING,
self::DATASERIES_TYPE_NUMBER,
];
/**
* Series Data Type.
*
* @var string
*/
private $dataType;
/**
* Series Data Source.
*
< * @var string
> * @var ?string
*/
private $dataSource;
/**
* Format Code.
*
* @var string
*/
private $formatCode;
/**
* Series Point Marker.
*
* @var string
*/
private $pointMarker;
> /** @var ChartColor */
/**
> private $markerFillColor;
* Point Count (The number of datapoints in the dataseries).
>
*
> /** @var ChartColor */
* @var int
> private $markerBorderColor;
*/
>
private $pointCount = 0;
> /**
> * Series Point Size.
/**
> *
* Data Values.
> * @var int
*
> */
* @var array of mixed
> private $pointSize = 3;
*/
>
< * @var array of mixed
> * @var mixed[]
/**
* Fill color (can be array with colors if dataseries have custom colors).
*
< * @var string|string[]
> * @var null|ChartColor|ChartColor[]
*/
private $fillColor;
< /**
< * Line Width.
< *
< * @var int
< */
< private $lineWidth = 12700;
> /** @var bool */
> private $scatterLines = true;
>
> /** @var bool */
> private $bubble3D = false;
>
> /** @var ?Layout */
> private $labelLayout;
>
> /** @var TrendLine[] */
> private $trendLines = [];
/**
* Create a new DataSeriesValues object.
*
* @param string $dataType
* @param string $dataSource
* @param null|mixed $formatCode
* @param int $pointCount
* @param mixed $dataValues
* @param null|mixed $marker
< * @param null|string|string[] $fillColor
> * @param null|ChartColor|ChartColor[]|string|string[] $fillColor
> * @param string $pointSize
*/
< public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null)
> public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null, $pointSize = '3')
{
> parent::__construct();
$this->setDataType($dataType);
> $this->markerFillColor = new ChartColor();
$this->dataSource = $dataSource;
> $this->markerBorderColor = new ChartColor();
$this->formatCode = $formatCode;
$this->pointCount = $pointCount;
$this->dataValues = $dataValues;
$this->pointMarker = $marker;
< $this->fillColor = $fillColor;
> if ($fillColor !== null) {
> $this->setFillColor($fillColor);
> }
> if (is_numeric($pointSize)) {
> $this->pointSize = (int) $pointSize;
> }
}
/**
* Get Series Data Type.
*
* @return string
*/
public function getDataType()
{
return $this->dataType;
}
/**
* Set Series Data Type.
*
* @param string $dataType Datatype of this data series
* Typical values are:
* DataSeriesValues::DATASERIES_TYPE_STRING
* Normally used for axis point values
* DataSeriesValues::DATASERIES_TYPE_NUMBER
* Normally used for chart data values
*
* @return $this
*/
public function setDataType($dataType)
{
< if (!in_array($dataType, self::$dataTypeValues)) {
> if (!in_array($dataType, self::DATA_TYPE_VALUES)) {
throw new Exception('Invalid datatype for chart data series values');
}
$this->dataType = $dataType;
return $this;
}
/**
* Get Series Data Source (formula).
*
< * @return string
> * @return ?string
*/
public function getDataSource()
{
return $this->dataSource;
}
/**
* Set Series Data Source (formula).
*
< * @param string $dataSource
> * @param ?string $dataSource
*
* @return $this
*/
public function setDataSource($dataSource)
{
$this->dataSource = $dataSource;
return $this;
}
/**
* Get Point Marker.
*
* @return string
*/
public function getPointMarker()
{
return $this->pointMarker;
}
/**
* Set Point Marker.
*
* @param string $marker
*
* @return $this
*/
public function setPointMarker($marker)
{
$this->pointMarker = $marker;
return $this;
}
> public function getMarkerFillColor(): ChartColor
/**
> {
* Get Series Format Code.
> return $this->markerFillColor;
*
> }
* @return string
>
*/
> public function getMarkerBorderColor(): ChartColor
public function getFormatCode()
> {
{
> return $this->markerBorderColor;
return $this->formatCode;
> }
}
>
> /**
/**
> * Get Point Size.
* Set Series Format Code.
> */
*
> public function getPointSize(): int
* @param string $formatCode
> {
*
> return $this->pointSize;
* @return $this
> }
*/
>
public function setFormatCode($formatCode)
> /**
{
> * Set Point Size.
$this->formatCode = $formatCode;
> *
> * @return $this
return $this;
> */
}
> public function setPointSize(int $size = 3)
> {
/**
> $this->pointSize = $size;
* Get Series Point Count.
>
*
> return $this;
* @return int
> }
*/
>
public function getPointCount()
{
return $this->pointCount;
}
/**
> * Get fill color object.
* Get fill color.
> *
*
> * @return null|ChartColor|ChartColor[]
* @return string|string[] HEX color or array with HEX colors
> */
*/
> public function getFillColorObject()
public function getFillColor()
> {
{
> return $this->fillColor;
return $this->fillColor;
> }
}
>
> private function stringToChartColor(string $fillString): ChartColor
/**
> {
* Set fill color for series.
> $value = $type = '';
*
> if (substr($fillString, 0, 1) === '*') {
* @param string|string[] $color HEX color or array with HEX colors
> $type = 'schemeClr';
*
> $value = substr($fillString, 1);
* @return DataSeriesValues
> } elseif (substr($fillString, 0, 1) === '/') {
*/
> $type = 'prstClr';
public function setFillColor($color)
> $value = substr($fillString, 1);
{
> } elseif ($fillString !== '') {
if (is_array($color)) {
> $type = 'srgbClr';
foreach ($color as $colorValue) {
> $value = $fillString;
$this->validateColor($colorValue);
> $this->validateColor($value);
}
> }
} else {
>
$this->validateColor($color);
> return new ChartColor($value, null, $type);
}
> }
$this->fillColor = $color;
>
> private function chartColorToString(ChartColor $chartColor): string
return $this;
> {
}
> $type = (string) $chartColor->getColorProperty('type');
> $value = (string) $chartColor->getColorProperty('value');
/**
> if ($type === '' || $value === '') {
* Method for validating hex color.
> return '';
*
> }
* @param string $color value for color
> if ($type === 'schemeClr') {
*
> return "*$value";
* @return bool true if validation was successful
> }
*/
> if ($type === 'prstClr') {
private function validateColor($color)
> return "/$value";
{
> }
if (!preg_match('/^[a-f0-9]{6}$/i', $color)) {
>
throw new Exception(sprintf('Invalid hex color for chart series (color: "%s")', $color));
> return $value;
}
> }
>
return true;
> /**
< return $this->fillColor;
> if ($this->fillColor === null) {
> return '';
> }
> if (is_array($this->fillColor)) {
> $array = [];
> foreach ($this->fillColor as $chartColor) {
> $array[] = $this->chartColorToString($chartColor);
> }
>
> return $array;
> }
>
> return $this->chartColorToString($this->fillColor);
< * @param string|string[] $color HEX color or array with HEX colors
> * @param ChartColor|ChartColor[]|string|string[] $color HEX color or array with HEX colors
< foreach ($color as $colorValue) {
< $this->validateColor($colorValue);
< }
> $this->fillColor = [];
> foreach ($color as $fillString) {
> if ($fillString instanceof ChartColor) {
> $this->fillColor[] = $fillString;
< $this->validateColor($color);
> $this->fillColor[] = $this->stringToChartColor($fillString);
*/
> }
public function getLineWidth()
> } elseif ($color instanceof ChartColor) {
{
> } else {
return $this->lineWidth;
> $this->fillColor = $this->stringToChartColor($color);
}
> }
< * @return int
> * @return null|float|int
< return $this->lineWidth;
> return $this->lineStyleProperties['width'];
* Set line width for the series.
*
< * @param int $width
> * @param null|float|int $width
*
* @return $this
*/
public function setLineWidth($width)
{
< $minWidth = 12700;
< $this->lineWidth = max($minWidth, $width);
> $this->lineStyleProperties['width'] = $width;
return $this;
}
/**
* Identify if the Data Series is a multi-level or a simple series.
*
* @return null|bool
*/
public function isMultiLevelSeries()
{
< if (count($this->dataValues) > 0) {
> if (!empty($this->dataValues)) {
return is_array(array_values($this->dataValues)[0]);
}
return null;
}
/**
* Return the level count of a multi-level Data Series.
*
* @return int
*/
public function multiLevelCount()
{
$levelCount = 0;
foreach ($this->dataValues as $dataValueSet) {
$levelCount = max($levelCount, count($dataValueSet));
}
return $levelCount;
}
/**
* Get Series Data Values.
*
< * @return array of mixed
> * @return mixed[]
*/
public function getDataValues()
{
return $this->dataValues;
}
/**
* Get the first Series Data value.
*
* @return mixed
*/
public function getDataValue()
{
$count = count($this->dataValues);
if ($count == 0) {
return null;
} elseif ($count == 1) {
return $this->dataValues[0];
}
return $this->dataValues;
}
/**
* Set Series Data Values.
*
* @param array $dataValues
*
* @return $this
*/
public function setDataValues($dataValues)
{
$this->dataValues = Functions::flattenArray($dataValues);
$this->pointCount = count($dataValues);
return $this;
}
< public function refresh(Worksheet $worksheet, $flatten = true): void
> public function refresh(Worksheet $worksheet, bool $flatten = true): void
{
if ($this->dataSource !== null) {
$calcEngine = Calculation::getInstance($worksheet->getParent());
$newDataValues = Calculation::unwrapResult(
$calcEngine->_calculateFormulaValue(
'=' . $this->dataSource,
null,
$worksheet->getCell('A1')
)
);
if ($flatten) {
$this->dataValues = Functions::flattenArray($newDataValues);
foreach ($this->dataValues as &$dataValue) {
if (is_string($dataValue) && !empty($dataValue) && $dataValue[0] == '#') {
$dataValue = 0.0;
}
}
unset($dataValue);
} else {
[$worksheet, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true);
$dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange));
if (($dimensions[0] == 1) || ($dimensions[1] == 1)) {
$this->dataValues = Functions::flattenArray($newDataValues);
} else {
< $newArray = array_values(array_shift($newDataValues));
> $newArray = array_values(array_shift(/** @scrutinizer ignore-type */ $newDataValues));
foreach ($newArray as $i => $newDataSet) {
$newArray[$i] = [$newDataSet];
}
foreach ($newDataValues as $newDataSet) {
$i = 0;
foreach ($newDataSet as $newDataVal) {
array_unshift($newArray[$i++], $newDataVal);
}
}
$this->dataValues = $newArray;
}
}
$this->pointCount = count($this->dataValues);
}
> }
}
>
}
> public function getScatterLines(): bool
> {
> return $this->scatterLines;
> }
>
> public function setScatterLines(bool $scatterLines): self
> {
> $this->scatterLines = $scatterLines;
>
> return $this;
> }
>
> public function getBubble3D(): bool
> {
> return $this->bubble3D;
> }
>
> public function setBubble3D(bool $bubble3D): self
> {
> $this->bubble3D = $bubble3D;
>
> return $this;
> }
>
> /**
> * Smooth Line. Must be specified for both DataSeries and DataSeriesValues.
> *
> * @var bool
> */
> private $smoothLine;
>
> /**
> * Get Smooth Line.
> *
> * @return bool
> */
> public function getSmoothLine()
> {
> return $this->smoothLine;
> }
>
> /**
> * Set Smooth Line.
> *
> * @param bool $smoothLine
> *
> * @return $this
> */
> public function setSmoothLine($smoothLine)
> {
> $this->smoothLine = $smoothLine;
>
> return $this;
> }
>
> public function getLabelLayout(): ?Layout
> {
> return $this->labelLayout;
> }
>
> public function setLabelLayout(?Layout $labelLayout): self
> {
> $this->labelLayout = $labelLayout;
>
> return $this;
> }
>
> public function setTrendLines(array $trendLines): self
> {
> $this->trendLines = $trendLines;
>
> return $this;
> }
>
> public function getTrendLines(): array
> {
> return $this->trendLines;