See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 3 namespace PhpOffice\PhpSpreadsheet\Chart; 4 5 use PhpOffice\PhpSpreadsheet\Calculation\Calculation; 6 use PhpOffice\PhpSpreadsheet\Calculation\Functions; 7 use PhpOffice\PhpSpreadsheet\Cell\Coordinate; 8 use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; 9 10 class DataSeriesValues extends Properties 11 { 12 const DATASERIES_TYPE_STRING = 'String'; 13 const DATASERIES_TYPE_NUMBER = 'Number'; 14 15 private const DATA_TYPE_VALUES = [ 16 self::DATASERIES_TYPE_STRING, 17 self::DATASERIES_TYPE_NUMBER, 18 ]; 19 20 /** 21 * Series Data Type. 22 * 23 * @var string 24 */ 25 private $dataType; 26 27 /** 28 * Series Data Source. 29 * 30 * @var ?string 31 */ 32 private $dataSource; 33 34 /** 35 * Format Code. 36 * 37 * @var string 38 */ 39 private $formatCode; 40 41 /** 42 * Series Point Marker. 43 * 44 * @var string 45 */ 46 private $pointMarker; 47 48 /** @var ChartColor */ 49 private $markerFillColor; 50 51 /** @var ChartColor */ 52 private $markerBorderColor; 53 54 /** 55 * Series Point Size. 56 * 57 * @var int 58 */ 59 private $pointSize = 3; 60 61 /** 62 * Point Count (The number of datapoints in the dataseries). 63 * 64 * @var int 65 */ 66 private $pointCount = 0; 67 68 /** 69 * Data Values. 70 * 71 * @var mixed[] 72 */ 73 private $dataValues = []; 74 75 /** 76 * Fill color (can be array with colors if dataseries have custom colors). 77 * 78 * @var null|ChartColor|ChartColor[] 79 */ 80 private $fillColor; 81 82 /** @var bool */ 83 private $scatterLines = true; 84 85 /** @var bool */ 86 private $bubble3D = false; 87 88 /** @var ?Layout */ 89 private $labelLayout; 90 91 /** @var TrendLine[] */ 92 private $trendLines = []; 93 94 /** 95 * Create a new DataSeriesValues object. 96 * 97 * @param string $dataType 98 * @param string $dataSource 99 * @param null|mixed $formatCode 100 * @param int $pointCount 101 * @param mixed $dataValues 102 * @param null|mixed $marker 103 * @param null|ChartColor|ChartColor[]|string|string[] $fillColor 104 * @param string $pointSize 105 */ 106 public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null, $pointSize = '3') 107 { 108 parent::__construct(); 109 $this->markerFillColor = new ChartColor(); 110 $this->markerBorderColor = new ChartColor(); 111 $this->setDataType($dataType); 112 $this->dataSource = $dataSource; 113 $this->formatCode = $formatCode; 114 $this->pointCount = $pointCount; 115 $this->dataValues = $dataValues; 116 $this->pointMarker = $marker; 117 if ($fillColor !== null) { 118 $this->setFillColor($fillColor); 119 } 120 if (is_numeric($pointSize)) { 121 $this->pointSize = (int) $pointSize; 122 } 123 } 124 125 /** 126 * Get Series Data Type. 127 * 128 * @return string 129 */ 130 public function getDataType() 131 { 132 return $this->dataType; 133 } 134 135 /** 136 * Set Series Data Type. 137 * 138 * @param string $dataType Datatype of this data series 139 * Typical values are: 140 * DataSeriesValues::DATASERIES_TYPE_STRING 141 * Normally used for axis point values 142 * DataSeriesValues::DATASERIES_TYPE_NUMBER 143 * Normally used for chart data values 144 * 145 * @return $this 146 */ 147 public function setDataType($dataType) 148 { 149 if (!in_array($dataType, self::DATA_TYPE_VALUES)) { 150 throw new Exception('Invalid datatype for chart data series values'); 151 } 152 $this->dataType = $dataType; 153 154 return $this; 155 } 156 157 /** 158 * Get Series Data Source (formula). 159 * 160 * @return ?string 161 */ 162 public function getDataSource() 163 { 164 return $this->dataSource; 165 } 166 167 /** 168 * Set Series Data Source (formula). 169 * 170 * @param ?string $dataSource 171 * 172 * @return $this 173 */ 174 public function setDataSource($dataSource) 175 { 176 $this->dataSource = $dataSource; 177 178 return $this; 179 } 180 181 /** 182 * Get Point Marker. 183 * 184 * @return string 185 */ 186 public function getPointMarker() 187 { 188 return $this->pointMarker; 189 } 190 191 /** 192 * Set Point Marker. 193 * 194 * @param string $marker 195 * 196 * @return $this 197 */ 198 public function setPointMarker($marker) 199 { 200 $this->pointMarker = $marker; 201 202 return $this; 203 } 204 205 public function getMarkerFillColor(): ChartColor 206 { 207 return $this->markerFillColor; 208 } 209 210 public function getMarkerBorderColor(): ChartColor 211 { 212 return $this->markerBorderColor; 213 } 214 215 /** 216 * Get Point Size. 217 */ 218 public function getPointSize(): int 219 { 220 return $this->pointSize; 221 } 222 223 /** 224 * Set Point Size. 225 * 226 * @return $this 227 */ 228 public function setPointSize(int $size = 3) 229 { 230 $this->pointSize = $size; 231 232 return $this; 233 } 234 235 /** 236 * Get Series Format Code. 237 * 238 * @return string 239 */ 240 public function getFormatCode() 241 { 242 return $this->formatCode; 243 } 244 245 /** 246 * Set Series Format Code. 247 * 248 * @param string $formatCode 249 * 250 * @return $this 251 */ 252 public function setFormatCode($formatCode) 253 { 254 $this->formatCode = $formatCode; 255 256 return $this; 257 } 258 259 /** 260 * Get Series Point Count. 261 * 262 * @return int 263 */ 264 public function getPointCount() 265 { 266 return $this->pointCount; 267 } 268 269 /** 270 * Get fill color object. 271 * 272 * @return null|ChartColor|ChartColor[] 273 */ 274 public function getFillColorObject() 275 { 276 return $this->fillColor; 277 } 278 279 private function stringToChartColor(string $fillString): ChartColor 280 { 281 $value = $type = ''; 282 if (substr($fillString, 0, 1) === '*') { 283 $type = 'schemeClr'; 284 $value = substr($fillString, 1); 285 } elseif (substr($fillString, 0, 1) === '/') { 286 $type = 'prstClr'; 287 $value = substr($fillString, 1); 288 } elseif ($fillString !== '') { 289 $type = 'srgbClr'; 290 $value = $fillString; 291 $this->validateColor($value); 292 } 293 294 return new ChartColor($value, null, $type); 295 } 296 297 private function chartColorToString(ChartColor $chartColor): string 298 { 299 $type = (string) $chartColor->getColorProperty('type'); 300 $value = (string) $chartColor->getColorProperty('value'); 301 if ($type === '' || $value === '') { 302 return ''; 303 } 304 if ($type === 'schemeClr') { 305 return "*$value"; 306 } 307 if ($type === 'prstClr') { 308 return "/$value"; 309 } 310 311 return $value; 312 } 313 314 /** 315 * Get fill color. 316 * 317 * @return string|string[] HEX color or array with HEX colors 318 */ 319 public function getFillColor() 320 { 321 if ($this->fillColor === null) { 322 return ''; 323 } 324 if (is_array($this->fillColor)) { 325 $array = []; 326 foreach ($this->fillColor as $chartColor) { 327 $array[] = $this->chartColorToString($chartColor); 328 } 329 330 return $array; 331 } 332 333 return $this->chartColorToString($this->fillColor); 334 } 335 336 /** 337 * Set fill color for series. 338 * 339 * @param ChartColor|ChartColor[]|string|string[] $color HEX color or array with HEX colors 340 * 341 * @return DataSeriesValues 342 */ 343 public function setFillColor($color) 344 { 345 if (is_array($color)) { 346 $this->fillColor = []; 347 foreach ($color as $fillString) { 348 if ($fillString instanceof ChartColor) { 349 $this->fillColor[] = $fillString; 350 } else { 351 $this->fillColor[] = $this->stringToChartColor($fillString); 352 } 353 } 354 } elseif ($color instanceof ChartColor) { 355 $this->fillColor = $color; 356 } else { 357 $this->fillColor = $this->stringToChartColor($color); 358 } 359 360 return $this; 361 } 362 363 /** 364 * Method for validating hex color. 365 * 366 * @param string $color value for color 367 * 368 * @return bool true if validation was successful 369 */ 370 private function validateColor($color) 371 { 372 if (!preg_match('/^[a-f0-9]{6}$/i', $color)) { 373 throw new Exception(sprintf('Invalid hex color for chart series (color: "%s")', $color)); 374 } 375 376 return true; 377 } 378 379 /** 380 * Get line width for series. 381 * 382 * @return null|float|int 383 */ 384 public function getLineWidth() 385 { 386 return $this->lineStyleProperties['width']; 387 } 388 389 /** 390 * Set line width for the series. 391 * 392 * @param null|float|int $width 393 * 394 * @return $this 395 */ 396 public function setLineWidth($width) 397 { 398 $this->lineStyleProperties['width'] = $width; 399 400 return $this; 401 } 402 403 /** 404 * Identify if the Data Series is a multi-level or a simple series. 405 * 406 * @return null|bool 407 */ 408 public function isMultiLevelSeries() 409 { 410 if (!empty($this->dataValues)) { 411 return is_array(array_values($this->dataValues)[0]); 412 } 413 414 return null; 415 } 416 417 /** 418 * Return the level count of a multi-level Data Series. 419 * 420 * @return int 421 */ 422 public function multiLevelCount() 423 { 424 $levelCount = 0; 425 foreach ($this->dataValues as $dataValueSet) { 426 $levelCount = max($levelCount, count($dataValueSet)); 427 } 428 429 return $levelCount; 430 } 431 432 /** 433 * Get Series Data Values. 434 * 435 * @return mixed[] 436 */ 437 public function getDataValues() 438 { 439 return $this->dataValues; 440 } 441 442 /** 443 * Get the first Series Data value. 444 * 445 * @return mixed 446 */ 447 public function getDataValue() 448 { 449 $count = count($this->dataValues); 450 if ($count == 0) { 451 return null; 452 } elseif ($count == 1) { 453 return $this->dataValues[0]; 454 } 455 456 return $this->dataValues; 457 } 458 459 /** 460 * Set Series Data Values. 461 * 462 * @param array $dataValues 463 * 464 * @return $this 465 */ 466 public function setDataValues($dataValues) 467 { 468 $this->dataValues = Functions::flattenArray($dataValues); 469 $this->pointCount = count($dataValues); 470 471 return $this; 472 } 473 474 public function refresh(Worksheet $worksheet, bool $flatten = true): void 475 { 476 if ($this->dataSource !== null) { 477 $calcEngine = Calculation::getInstance($worksheet->getParent()); 478 $newDataValues = Calculation::unwrapResult( 479 $calcEngine->_calculateFormulaValue( 480 '=' . $this->dataSource, 481 null, 482 $worksheet->getCell('A1') 483 ) 484 ); 485 if ($flatten) { 486 $this->dataValues = Functions::flattenArray($newDataValues); 487 foreach ($this->dataValues as &$dataValue) { 488 if (is_string($dataValue) && !empty($dataValue) && $dataValue[0] == '#') { 489 $dataValue = 0.0; 490 } 491 } 492 unset($dataValue); 493 } else { 494 [$worksheet, $cellRange] = Worksheet::extractSheetTitle($this->dataSource, true); 495 $dimensions = Coordinate::rangeDimension(str_replace('$', '', $cellRange)); 496 if (($dimensions[0] == 1) || ($dimensions[1] == 1)) { 497 $this->dataValues = Functions::flattenArray($newDataValues); 498 } else { 499 $newArray = array_values(array_shift($newDataValues)); 500 foreach ($newArray as $i => $newDataSet) { 501 $newArray[$i] = [$newDataSet]; 502 } 503 504 foreach ($newDataValues as $newDataSet) { 505 $i = 0; 506 foreach ($newDataSet as $newDataVal) { 507 array_unshift($newArray[$i++], $newDataVal); 508 } 509 } 510 $this->dataValues = $newArray; 511 } 512 } 513 $this->pointCount = count($this->dataValues); 514 } 515 } 516 517 public function getScatterLines(): bool 518 { 519 return $this->scatterLines; 520 } 521 522 public function setScatterLines(bool $scatterLines): self 523 { 524 $this->scatterLines = $scatterLines; 525 526 return $this; 527 } 528 529 public function getBubble3D(): bool 530 { 531 return $this->bubble3D; 532 } 533 534 public function setBubble3D(bool $bubble3D): self 535 { 536 $this->bubble3D = $bubble3D; 537 538 return $this; 539 } 540 541 /** 542 * Smooth Line. Must be specified for both DataSeries and DataSeriesValues. 543 * 544 * @var bool 545 */ 546 private $smoothLine; 547 548 /** 549 * Get Smooth Line. 550 * 551 * @return bool 552 */ 553 public function getSmoothLine() 554 { 555 return $this->smoothLine; 556 } 557 558 /** 559 * Set Smooth Line. 560 * 561 * @param bool $smoothLine 562 * 563 * @return $this 564 */ 565 public function setSmoothLine($smoothLine) 566 { 567 $this->smoothLine = $smoothLine; 568 569 return $this; 570 } 571 572 public function getLabelLayout(): ?Layout 573 { 574 return $this->labelLayout; 575 } 576 577 public function setLabelLayout(?Layout $labelLayout): self 578 { 579 $this->labelLayout = $labelLayout; 580 581 return $this; 582 } 583 584 public function setTrendLines(array $trendLines): self 585 { 586 $this->trendLines = $trendLines; 587 588 return $this; 589 } 590 591 public function getTrendLines(): array 592 { 593 return $this->trendLines; 594 } 595 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body