Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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(/** @scrutinizer ignore-type */ $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
}