1<?php
2
3namespace PhpOffice\PhpSpreadsheet\Chart;
4
5use PhpOffice\PhpSpreadsheet\Settings;
6use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
7
8class Chart
9{
10    /**
11     * Chart Name.
12     *
13     * @var string
14     */
15    private $name = '';
16
17    /**
18     * Worksheet.
19     *
20     * @var Worksheet
21     */
22    private $worksheet;
23
24    /**
25     * Chart Title.
26     *
27     * @var Title
28     */
29    private $title;
30
31    /**
32     * Chart Legend.
33     *
34     * @var Legend
35     */
36    private $legend;
37
38    /**
39     * X-Axis Label.
40     *
41     * @var Title
42     */
43    private $xAxisLabel;
44
45    /**
46     * Y-Axis Label.
47     *
48     * @var Title
49     */
50    private $yAxisLabel;
51
52    /**
53     * Chart Plot Area.
54     *
55     * @var PlotArea
56     */
57    private $plotArea;
58
59    /**
60     * Plot Visible Only.
61     *
62     * @var bool
63     */
64    private $plotVisibleOnly = true;
65
66    /**
67     * Display Blanks as.
68     *
69     * @var string
70     */
71    private $displayBlanksAs = DataSeries::EMPTY_AS_GAP;
72
73    /**
74     * Chart Asix Y as.
75     *
76     * @var Axis
77     */
78    private $yAxis;
79
80    /**
81     * Chart Asix X as.
82     *
83     * @var Axis
84     */
85    private $xAxis;
86
87    /**
88     * Chart Major Gridlines as.
89     *
90     * @var GridLines
91     */
92    private $majorGridlines;
93
94    /**
95     * Chart Minor Gridlines as.
96     *
97     * @var GridLines
98     */
99    private $minorGridlines;
100
101    /**
102     * Top-Left Cell Position.
103     *
104     * @var string
105     */
106    private $topLeftCellRef = 'A1';
107
108    /**
109     * Top-Left X-Offset.
110     *
111     * @var int
112     */
113    private $topLeftXOffset = 0;
114
115    /**
116     * Top-Left Y-Offset.
117     *
118     * @var int
119     */
120    private $topLeftYOffset = 0;
121
122    /**
123     * Bottom-Right Cell Position.
124     *
125     * @var string
126     */
127    private $bottomRightCellRef = 'A1';
128
129    /**
130     * Bottom-Right X-Offset.
131     *
132     * @var int
133     */
134    private $bottomRightXOffset = 10;
135
136    /**
137     * Bottom-Right Y-Offset.
138     *
139     * @var int
140     */
141    private $bottomRightYOffset = 10;
142
143    /**
144     * Create a new Chart.
145     *
146     * @param mixed $name
147     * @param mixed $plotVisibleOnly
148     * @param string $displayBlanksAs
149     */
150    public function __construct($name, ?Title $title = null, ?Legend $legend = null, ?PlotArea $plotArea = null, $plotVisibleOnly = true, $displayBlanksAs = DataSeries::EMPTY_AS_GAP, ?Title $xAxisLabel = null, ?Title $yAxisLabel = null, ?Axis $xAxis = null, ?Axis $yAxis = null, ?GridLines $majorGridlines = null, ?GridLines $minorGridlines = null)
151    {
152        $this->name = $name;
153        $this->title = $title;
154        $this->legend = $legend;
155        $this->xAxisLabel = $xAxisLabel;
156        $this->yAxisLabel = $yAxisLabel;
157        $this->plotArea = $plotArea;
158        $this->plotVisibleOnly = $plotVisibleOnly;
159        $this->displayBlanksAs = $displayBlanksAs;
160        $this->xAxis = $xAxis;
161        $this->yAxis = $yAxis;
162        $this->majorGridlines = $majorGridlines;
163        $this->minorGridlines = $minorGridlines;
164    }
165
166    /**
167     * Get Name.
168     *
169     * @return string
170     */
171    public function getName()
172    {
173        return $this->name;
174    }
175
176    /**
177     * Get Worksheet.
178     *
179     * @return Worksheet
180     */
181    public function getWorksheet()
182    {
183        return $this->worksheet;
184    }
185
186    /**
187     * Set Worksheet.
188     *
189     * @param Worksheet $pValue
190     *
191     * @return $this
192     */
193    public function setWorksheet(?Worksheet $pValue = null)
194    {
195        $this->worksheet = $pValue;
196
197        return $this;
198    }
199
200    /**
201     * Get Title.
202     *
203     * @return Title
204     */
205    public function getTitle()
206    {
207        return $this->title;
208    }
209
210    /**
211     * Set Title.
212     *
213     * @return $this
214     */
215    public function setTitle(Title $title)
216    {
217        $this->title = $title;
218
219        return $this;
220    }
221
222    /**
223     * Get Legend.
224     *
225     * @return Legend
226     */
227    public function getLegend()
228    {
229        return $this->legend;
230    }
231
232    /**
233     * Set Legend.
234     *
235     * @return $this
236     */
237    public function setLegend(Legend $legend)
238    {
239        $this->legend = $legend;
240
241        return $this;
242    }
243
244    /**
245     * Get X-Axis Label.
246     *
247     * @return Title
248     */
249    public function getXAxisLabel()
250    {
251        return $this->xAxisLabel;
252    }
253
254    /**
255     * Set X-Axis Label.
256     *
257     * @return $this
258     */
259    public function setXAxisLabel(Title $label)
260    {
261        $this->xAxisLabel = $label;
262
263        return $this;
264    }
265
266    /**
267     * Get Y-Axis Label.
268     *
269     * @return Title
270     */
271    public function getYAxisLabel()
272    {
273        return $this->yAxisLabel;
274    }
275
276    /**
277     * Set Y-Axis Label.
278     *
279     * @return $this
280     */
281    public function setYAxisLabel(Title $label)
282    {
283        $this->yAxisLabel = $label;
284
285        return $this;
286    }
287
288    /**
289     * Get Plot Area.
290     *
291     * @return PlotArea
292     */
293    public function getPlotArea()
294    {
295        return $this->plotArea;
296    }
297
298    /**
299     * Get Plot Visible Only.
300     *
301     * @return bool
302     */
303    public function getPlotVisibleOnly()
304    {
305        return $this->plotVisibleOnly;
306    }
307
308    /**
309     * Set Plot Visible Only.
310     *
311     * @param bool $plotVisibleOnly
312     *
313     * @return $this
314     */
315    public function setPlotVisibleOnly($plotVisibleOnly)
316    {
317        $this->plotVisibleOnly = $plotVisibleOnly;
318
319        return $this;
320    }
321
322    /**
323     * Get Display Blanks as.
324     *
325     * @return string
326     */
327    public function getDisplayBlanksAs()
328    {
329        return $this->displayBlanksAs;
330    }
331
332    /**
333     * Set Display Blanks as.
334     *
335     * @param string $displayBlanksAs
336     *
337     * @return $this
338     */
339    public function setDisplayBlanksAs($displayBlanksAs)
340    {
341        $this->displayBlanksAs = $displayBlanksAs;
342
343        return $this;
344    }
345
346    /**
347     * Get yAxis.
348     *
349     * @return Axis
350     */
351    public function getChartAxisY()
352    {
353        if ($this->yAxis !== null) {
354            return $this->yAxis;
355        }
356
357        return new Axis();
358    }
359
360    /**
361     * Get xAxis.
362     *
363     * @return Axis
364     */
365    public function getChartAxisX()
366    {
367        if ($this->xAxis !== null) {
368            return $this->xAxis;
369        }
370
371        return new Axis();
372    }
373
374    /**
375     * Get Major Gridlines.
376     *
377     * @return GridLines
378     */
379    public function getMajorGridlines()
380    {
381        if ($this->majorGridlines !== null) {
382            return $this->majorGridlines;
383        }
384
385        return new GridLines();
386    }
387
388    /**
389     * Get Minor Gridlines.
390     *
391     * @return GridLines
392     */
393    public function getMinorGridlines()
394    {
395        if ($this->minorGridlines !== null) {
396            return $this->minorGridlines;
397        }
398
399        return new GridLines();
400    }
401
402    /**
403     * Set the Top Left position for the chart.
404     *
405     * @param string $cell
406     * @param int $xOffset
407     * @param int $yOffset
408     *
409     * @return $this
410     */
411    public function setTopLeftPosition($cell, $xOffset = null, $yOffset = null)
412    {
413        $this->topLeftCellRef = $cell;
414        if ($xOffset !== null) {
415            $this->setTopLeftXOffset($xOffset);
416        }
417        if ($yOffset !== null) {
418            $this->setTopLeftYOffset($yOffset);
419        }
420
421        return $this;
422    }
423
424    /**
425     * Get the top left position of the chart.
426     *
427     * @return array an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
428     */
429    public function getTopLeftPosition()
430    {
431        return [
432            'cell' => $this->topLeftCellRef,
433            'xOffset' => $this->topLeftXOffset,
434            'yOffset' => $this->topLeftYOffset,
435        ];
436    }
437
438    /**
439     * Get the cell address where the top left of the chart is fixed.
440     *
441     * @return string
442     */
443    public function getTopLeftCell()
444    {
445        return $this->topLeftCellRef;
446    }
447
448    /**
449     * Set the Top Left cell position for the chart.
450     *
451     * @param string $cell
452     *
453     * @return $this
454     */
455    public function setTopLeftCell($cell)
456    {
457        $this->topLeftCellRef = $cell;
458
459        return $this;
460    }
461
462    /**
463     * Set the offset position within the Top Left cell for the chart.
464     *
465     * @param int $xOffset
466     * @param int $yOffset
467     *
468     * @return $this
469     */
470    public function setTopLeftOffset($xOffset, $yOffset)
471    {
472        if ($xOffset !== null) {
473            $this->setTopLeftXOffset($xOffset);
474        }
475
476        if ($yOffset !== null) {
477            $this->setTopLeftYOffset($yOffset);
478        }
479
480        return $this;
481    }
482
483    /**
484     * Get the offset position within the Top Left cell for the chart.
485     *
486     * @return int[]
487     */
488    public function getTopLeftOffset()
489    {
490        return [
491            'X' => $this->topLeftXOffset,
492            'Y' => $this->topLeftYOffset,
493        ];
494    }
495
496    public function setTopLeftXOffset($xOffset)
497    {
498        $this->topLeftXOffset = $xOffset;
499
500        return $this;
501    }
502
503    public function getTopLeftXOffset()
504    {
505        return $this->topLeftXOffset;
506    }
507
508    public function setTopLeftYOffset($yOffset)
509    {
510        $this->topLeftYOffset = $yOffset;
511
512        return $this;
513    }
514
515    public function getTopLeftYOffset()
516    {
517        return $this->topLeftYOffset;
518    }
519
520    /**
521     * Set the Bottom Right position of the chart.
522     *
523     * @param string $cell
524     * @param int $xOffset
525     * @param int $yOffset
526     *
527     * @return $this
528     */
529    public function setBottomRightPosition($cell, $xOffset = null, $yOffset = null)
530    {
531        $this->bottomRightCellRef = $cell;
532        if ($xOffset !== null) {
533            $this->setBottomRightXOffset($xOffset);
534        }
535        if ($yOffset !== null) {
536            $this->setBottomRightYOffset($yOffset);
537        }
538
539        return $this;
540    }
541
542    /**
543     * Get the bottom right position of the chart.
544     *
545     * @return array an associative array containing the cell address, X-Offset and Y-Offset from the top left of that cell
546     */
547    public function getBottomRightPosition()
548    {
549        return [
550            'cell' => $this->bottomRightCellRef,
551            'xOffset' => $this->bottomRightXOffset,
552            'yOffset' => $this->bottomRightYOffset,
553        ];
554    }
555
556    public function setBottomRightCell($cell)
557    {
558        $this->bottomRightCellRef = $cell;
559
560        return $this;
561    }
562
563    /**
564     * Get the cell address where the bottom right of the chart is fixed.
565     *
566     * @return string
567     */
568    public function getBottomRightCell()
569    {
570        return $this->bottomRightCellRef;
571    }
572
573    /**
574     * Set the offset position within the Bottom Right cell for the chart.
575     *
576     * @param int $xOffset
577     * @param int $yOffset
578     *
579     * @return $this
580     */
581    public function setBottomRightOffset($xOffset, $yOffset)
582    {
583        if ($xOffset !== null) {
584            $this->setBottomRightXOffset($xOffset);
585        }
586
587        if ($yOffset !== null) {
588            $this->setBottomRightYOffset($yOffset);
589        }
590
591        return $this;
592    }
593
594    /**
595     * Get the offset position within the Bottom Right cell for the chart.
596     *
597     * @return int[]
598     */
599    public function getBottomRightOffset()
600    {
601        return [
602            'X' => $this->bottomRightXOffset,
603            'Y' => $this->bottomRightYOffset,
604        ];
605    }
606
607    public function setBottomRightXOffset($xOffset)
608    {
609        $this->bottomRightXOffset = $xOffset;
610
611        return $this;
612    }
613
614    public function getBottomRightXOffset()
615    {
616        return $this->bottomRightXOffset;
617    }
618
619    public function setBottomRightYOffset($yOffset)
620    {
621        $this->bottomRightYOffset = $yOffset;
622
623        return $this;
624    }
625
626    public function getBottomRightYOffset()
627    {
628        return $this->bottomRightYOffset;
629    }
630
631    public function refresh(): void
632    {
633        if ($this->worksheet !== null) {
634            $this->plotArea->refresh($this->worksheet);
635        }
636    }
637
638    /**
639     * Render the chart to given file (or stream).
640     *
641     * @param string $outputDestination Name of the file render to
642     *
643     * @return bool true on success
644     */
645    public function render($outputDestination = null)
646    {
647        if ($outputDestination == 'php://output') {
648            $outputDestination = null;
649        }
650
651        $libraryName = Settings::getChartRenderer();
652        if ($libraryName === null) {
653            return false;
654        }
655
656        // Ensure that data series values are up-to-date before we render
657        $this->refresh();
658
659        $renderer = new $libraryName($this);
660
661        return $renderer->render($outputDestination);
662    }
663}
664