PluginProbe
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin / 6.5.1.7
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin v6.5.1.7
6.5.1.7 6.5.1.6 6.5.1.5 6.5.1.4 6.5.1.3 6.5.1.2 6.5.1.1 6.5.0.9 6.5.0.8 6.5.0.7 6.5.0.6 trunk 3.4.2.40 3.4.2.41 3.4.2.42 3.4.2.43 3.4.2.44 3.4.2.45 3.4.2.46 3.4.2.47 3.4.2.48 3.4.2.49 3.4.2.50 6.3.2 6.3.3.1 All 47 releases
wpdatatables / lib / phpoffice / phpspreadsheet / src / PhpSpreadsheet / Chart / Renderer / JpGraphRendererBase.php

JpGraphRendererBase.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at lib/phpoffice/phpspreadsheet/src/PhpSpreadsheet/Chart/Renderer/JpGraphRendererBase.php

874 lines 31.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace PhpOffice\PhpSpreadsheet\Chart\Renderer;
4
5 use AccBarPlot;
6 use AccLinePlot;
7 use BarPlot;
8 use ContourPlot;
9 use Graph;
10 use GroupBarPlot;
11 use LinePlot;
12 use PhpOffice\PhpSpreadsheet\Chart\Chart;
13 use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
14 use PieGraph;
15 use PiePlot;
16 use PiePlot3D;
17 use PiePlotC;
18 use RadarGraph;
19 use RadarPlot;
20 use ScatterPlot;
21 use Spline;
22 use StockPlot;
23
24 /**
25 * Base class for different Jpgraph implementations as charts renderer.
26 */
27 abstract class JpGraphRendererBase implements IRenderer
28 {
29 private static $width = 640;
30
31 private static $height = 480;
32
33 private static $colourSet = [
34 'mediumpurple1', 'palegreen3', 'gold1', 'cadetblue1',
35 'darkmagenta', 'coral', 'dodgerblue3', 'eggplant',
36 'mediumblue', 'magenta', 'sandybrown', 'cyan',
37 'firebrick1', 'forestgreen', 'deeppink4', 'darkolivegreen',
38 'goldenrod2',
39 ];
40
41 private static $markSet;
42
43 private $chart;
44
45 private $graph;
46
47 private static $plotColour = 0;
48
49 private static $plotMark = 0;
50
51 /**
52 * Create a new jpgraph.
53 */
54 public function __construct(Chart $chart)
55 {
56 static::init();
57 $this->graph = null;
58 $this->chart = $chart;
59
60 self::$markSet = [
61 'diamond' => MARK_DIAMOND,
62 'square' => MARK_SQUARE,
63 'triangle' => MARK_UTRIANGLE,
64 'x' => MARK_X,
65 'star' => MARK_STAR,
66 'dot' => MARK_FILLEDCIRCLE,
67 'dash' => MARK_DTRIANGLE,
68 'circle' => MARK_CIRCLE,
69 'plus' => MARK_CROSS,
70 ];
71 }
72
73 /**
74 * This method should be overriden in descendants to do real JpGraph library initialization.
75 */
76 abstract protected static function init(): void;
77
78 private function formatPointMarker($seriesPlot, $markerID)
79 {
80 $plotMarkKeys = array_keys(self::$markSet);
81 if ($markerID === null) {
82 // Use default plot marker (next marker in the series)
83 self::$plotMark %= count(self::$markSet);
84 $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
85 } elseif ($markerID !== 'none') {
86 // Use specified plot marker (if it exists)
87 if (isset(self::$markSet[$markerID])) {
88 $seriesPlot->mark->SetType(self::$markSet[$markerID]);
89 } else {
90 // If the specified plot marker doesn't exist, use default plot marker (next marker in the series)
91 self::$plotMark %= count(self::$markSet);
92 $seriesPlot->mark->SetType(self::$markSet[$plotMarkKeys[self::$plotMark++]]);
93 }
94 } else {
95 // Hide plot marker
96 $seriesPlot->mark->Hide();
97 }
98 $seriesPlot->mark->SetColor(self::$colourSet[self::$plotColour]);
99 $seriesPlot->mark->SetFillColor(self::$colourSet[self::$plotColour]);
100 $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
101
102 return $seriesPlot;
103 }
104
105 private function formatDataSetLabels($groupID, $datasetLabels, $rotation = '')
106 {
107 $datasetLabelFormatCode = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getFormatCode() ?? '';
108 // Retrieve any label formatting code
109 $datasetLabelFormatCode = stripslashes($datasetLabelFormatCode);
110
111 $testCurrentIndex = 0;
112 foreach ($datasetLabels as $i => $datasetLabel) {
113 if (is_array($datasetLabel)) {
114 if ($rotation == 'bar') {
115 $datasetLabels[$i] = implode(' ', $datasetLabel);
116 } else {
117 $datasetLabel = array_reverse($datasetLabel);
118 $datasetLabels[$i] = implode("\n", $datasetLabel);
119 }
120 } else {
121 // Format labels according to any formatting code
122 if ($datasetLabelFormatCode !== null) {
123 $datasetLabels[$i] = NumberFormat::toFormattedString($datasetLabel, $datasetLabelFormatCode);
124 }
125 }
126 ++$testCurrentIndex;
127 }
128
129 return $datasetLabels;
130 }
131
132 private function percentageSumCalculation($groupID, $seriesCount)
133 {
134 $sumValues = [];
135 // Adjust our values to a percentage value across all series in the group
136 for ($i = 0; $i < $seriesCount; ++$i) {
137 if ($i == 0) {
138 $sumValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
139 } else {
140 $nextValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
141 foreach ($nextValues as $k => $value) {
142 if (isset($sumValues[$k])) {
143 $sumValues[$k] += $value;
144 } else {
145 $sumValues[$k] = $value;
146 }
147 }
148 }
149 }
150
151 return $sumValues;
152 }
153
154 private function percentageAdjustValues($dataValues, $sumValues)
155 {
156 foreach ($dataValues as $k => $dataValue) {
157 $dataValues[$k] = $dataValue / $sumValues[$k] * 100;
158 }
159
160 return $dataValues;
161 }
162
163 private function getCaption($captionElement)
164 {
165 // Read any caption
166 $caption = ($captionElement !== null) ? $captionElement->getCaption() : null;
167 // Test if we have a title caption to display
168 if ($caption !== null) {
169 // If we do, it could be a plain string or an array
170 if (is_array($caption)) {
171 // Implode an array to a plain string
172 $caption = implode('', $caption);
173 }
174 }
175
176 return $caption;
177 }
178
179 private function renderTitle(): void
180 {
181 $title = $this->getCaption($this->chart->getTitle());
182 if ($title !== null) {
183 $this->graph->title->Set($title);
184 }
185 }
186
187 private function renderLegend(): void
188 {
189 $legend = $this->chart->getLegend();
190 if ($legend !== null) {
191 $legendPosition = $legend->getPosition();
192 switch ($legendPosition) {
193 case 'r':
194 $this->graph->legend->SetPos(0.01, 0.5, 'right', 'center'); // right
195 $this->graph->legend->SetColumns(1);
196
197 break;
198 case 'l':
199 $this->graph->legend->SetPos(0.01, 0.5, 'left', 'center'); // left
200 $this->graph->legend->SetColumns(1);
201
202 break;
203 case 't':
204 $this->graph->legend->SetPos(0.5, 0.01, 'center', 'top'); // top
205
206 break;
207 case 'b':
208 $this->graph->legend->SetPos(0.5, 0.99, 'center', 'bottom'); // bottom
209
210 break;
211 default:
212 $this->graph->legend->SetPos(0.01, 0.01, 'right', 'top'); // top-right
213 $this->graph->legend->SetColumns(1);
214
215 break;
216 }
217 } else {
218 $this->graph->legend->Hide();
219 }
220 }
221
222 private function renderCartesianPlotArea($type = 'textlin'): void
223 {
224 $this->graph = new Graph(self::$width, self::$height);
225 $this->graph->SetScale($type);
226
227 $this->renderTitle();
228
229 // Rotate for bar rather than column chart
230 $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotDirection();
231 $reverse = $rotation == 'bar';
232
233 $xAxisLabel = $this->chart->getXAxisLabel();
234 if ($xAxisLabel !== null) {
235 $title = $this->getCaption($xAxisLabel);
236 if ($title !== null) {
237 $this->graph->xaxis->SetTitle($title, 'center');
238 $this->graph->xaxis->title->SetMargin(35);
239 if ($reverse) {
240 $this->graph->xaxis->title->SetAngle(90);
241 $this->graph->xaxis->title->SetMargin(90);
242 }
243 }
244 }
245
246 $yAxisLabel = $this->chart->getYAxisLabel();
247 if ($yAxisLabel !== null) {
248 $title = $this->getCaption($yAxisLabel);
249 if ($title !== null) {
250 $this->graph->yaxis->SetTitle($title, 'center');
251 if ($reverse) {
252 $this->graph->yaxis->title->SetAngle(0);
253 $this->graph->yaxis->title->SetMargin(-55);
254 }
255 }
256 }
257 }
258
259 private function renderPiePlotArea(): void
260 {
261 $this->graph = new PieGraph(self::$width, self::$height);
262
263 $this->renderTitle();
264 }
265
266 private function renderRadarPlotArea(): void
267 {
268 $this->graph = new RadarGraph(self::$width, self::$height);
269 $this->graph->SetScale('lin');
270
271 $this->renderTitle();
272 }
273
274 private function renderPlotLine($groupID, $filled = false, $combination = false): void
275 {
276 $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
277
278 $index = array_keys($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder())[0];
279 $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($index)->getPointCount();
280 if ($labelCount > 0) {
281 $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
282 $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels);
283 $this->graph->xaxis->SetTickLabels($datasetLabels);
284 }
285
286 $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
287 $seriesPlots = [];
288 if ($grouping == 'percentStacked') {
289 $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
290 } else {
291 $sumValues = [];
292 }
293
294 // Loop through each data series in turn
295 for ($i = 0; $i < $seriesCount; ++$i) {
296 $index = array_keys($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder())[$i];
297 $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($index)->getDataValues();
298 $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($index)->getPointMarker();
299
300 if ($grouping == 'percentStacked') {
301 $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
302 }
303
304 // Fill in any missing values in the $dataValues array
305 $testCurrentIndex = 0;
306 foreach ($dataValues as $k => $dataValue) {
307 while ($k != $testCurrentIndex) {
308 $dataValues[$testCurrentIndex] = null;
309 ++$testCurrentIndex;
310 }
311 ++$testCurrentIndex;
312 }
313
314 $seriesPlot = new LinePlot($dataValues);
315 if ($combination) {
316 $seriesPlot->SetBarCenter();
317 }
318
319 if ($filled) {
320 $seriesPlot->SetFilled(true);
321 $seriesPlot->SetColor('black');
322 $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
323 } else {
324 // Set the appropriate plot marker
325 $this->formatPointMarker($seriesPlot, $marker);
326 }
327 $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($index)->getDataValue();
328 $seriesPlot->SetLegend($dataLabel);
329
330 $seriesPlots[] = $seriesPlot;
331 }
332
333 if ($grouping == 'standard') {
334 $groupPlot = $seriesPlots;
335 } else {
336 $groupPlot = new AccLinePlot($seriesPlots);
337 }
338 $this->graph->Add($groupPlot);
339 }
340
341 private function renderPlotBar($groupID, $dimensions = '2d'): void
342 {
343 $rotation = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotDirection();
344 // Rotate for bar rather than column chart
345 if (($groupID == 0) && ($rotation == 'bar')) {
346 $this->graph->Set90AndMargin();
347 }
348 $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
349
350 $index = array_keys($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder())[0];
351 $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($index)->getPointCount();
352 if ($labelCount > 0) {
353 $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
354 $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $rotation);
355 // Rotate for bar rather than column chart
356 if ($rotation == 'bar') {
357 $datasetLabels = array_reverse($datasetLabels);
358 $this->graph->yaxis->SetPos('max');
359 $this->graph->yaxis->SetLabelAlign('center', 'top');
360 $this->graph->yaxis->SetLabelSide(SIDE_RIGHT);
361 }
362 $this->graph->xaxis->SetTickLabels($datasetLabels);
363 }
364
365 $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
366 $seriesPlots = [];
367 if ($grouping == 'percentStacked') {
368 $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
369 } else {
370 $sumValues = [];
371 }
372
373 // Loop through each data series in turn
374 for ($j = 0; $j < $seriesCount; ++$j) {
375 $index = array_keys($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder())[$j];
376 $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($index)->getDataValues();
377 if ($grouping == 'percentStacked') {
378 $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
379 }
380
381 // Fill in any missing values in the $dataValues array
382 $testCurrentIndex = 0;
383 foreach ($dataValues as $k => $dataValue) {
384 while ($k != $testCurrentIndex) {
385 $dataValues[$testCurrentIndex] = null;
386 ++$testCurrentIndex;
387 }
388 ++$testCurrentIndex;
389 }
390
391 // Reverse the $dataValues order for bar rather than column chart
392 if ($rotation == 'bar') {
393 $dataValues = array_reverse($dataValues);
394 }
395 $seriesPlot = new BarPlot($dataValues);
396 $seriesPlot->SetColor('black');
397 $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
398 if ($dimensions == '3d') {
399 $seriesPlot->SetShadow();
400 }
401 if (!$this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)) {
402 $dataLabel = '';
403 } else {
404 $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)->getDataValue();
405 }
406 $seriesPlot->SetLegend($dataLabel);
407
408 $seriesPlots[] = $seriesPlot;
409 }
410 // Reverse the plot order for bar rather than column chart
411 if (($rotation == 'bar') && ($grouping != 'percentStacked')) {
412 $seriesPlots = array_reverse($seriesPlots);
413 }
414
415 if ($grouping == 'clustered') {
416 $groupPlot = new GroupBarPlot($seriesPlots);
417 } elseif ($grouping == 'standard') {
418 $groupPlot = new GroupBarPlot($seriesPlots);
419 } else {
420 $groupPlot = new AccBarPlot($seriesPlots);
421 if ($dimensions == '3d') {
422 $groupPlot->SetShadow();
423 }
424 }
425
426 $this->graph->Add($groupPlot);
427 }
428
429 private function renderPlotScatter($groupID, $bubble): void
430 {
431 $scatterStyle = $bubbleSize = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
432
433 $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
434
435 // Loop through each data series in turn
436 for ($i = 0; $i < $seriesCount; ++$i) {
437 $plotCategoryByIndex = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i);
438 if ($plotCategoryByIndex === false) {
439 $plotCategoryByIndex = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0);
440 }
441 $dataValuesY = $plotCategoryByIndex->getDataValues();
442 $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
443
444 $redoDataValuesY = true;
445 if ($bubble) {
446 if (!$bubbleSize) {
447 $bubbleSize = '10';
448 }
449 $redoDataValuesY = false;
450 foreach ($dataValuesY as $dataValueY) {
451 if (!is_int($dataValueY) && !is_float($dataValueY)) {
452 $redoDataValuesY = true;
453
454 break;
455 }
456 }
457 }
458 if ($redoDataValuesY) {
459 foreach ($dataValuesY as $k => $dataValueY) {
460 $dataValuesY[$k] = $k;
461 }
462 }
463 //var_dump($dataValuesY, $dataValuesX, $bubbleSize);
464
465 $seriesPlot = new ScatterPlot($dataValuesX, $dataValuesY);
466 if ($scatterStyle == 'lineMarker') {
467 $seriesPlot->SetLinkPoints();
468 $seriesPlot->link->SetColor(self::$colourSet[self::$plotColour]);
469 } elseif ($scatterStyle == 'smoothMarker') {
470 $spline = new Spline($dataValuesY, $dataValuesX);
471 [$splineDataY, $splineDataX] = $spline->Get(count($dataValuesX) * self::$width / 20);
472 $lplot = new LinePlot($splineDataX, $splineDataY);
473 $lplot->SetColor(self::$colourSet[self::$plotColour]);
474
475 $this->graph->Add($lplot);
476 }
477
478 if ($bubble) {
479 $this->formatPointMarker($seriesPlot, 'dot');
480 $seriesPlot->mark->SetColor('black');
481 $seriesPlot->mark->SetSize($bubbleSize);
482 } else {
483 $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
484 $this->formatPointMarker($seriesPlot, $marker);
485 }
486 $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
487 $seriesPlot->SetLegend($dataLabel);
488
489 $this->graph->Add($seriesPlot);
490 }
491 }
492
493 private function renderPlotRadar($groupID): void
494 {
495 $radarStyle = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
496
497 $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
498
499 // Loop through each data series in turn
500 for ($i = 0; $i < $seriesCount; ++$i) {
501 $dataValuesY = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex($i)->getDataValues();
502 $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
503 $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
504
505 $dataValues = [];
506 foreach ($dataValuesY as $k => $dataValueY) {
507 $dataValues[$k] = is_array($dataValueY) ? implode(' ', array_reverse($dataValueY)) : $dataValueY;
508 }
509 $tmp = array_shift($dataValues);
510 $dataValues[] = $tmp;
511 $tmp = array_shift($dataValuesX);
512 $dataValuesX[] = $tmp;
513
514 $this->graph->SetTitles(array_reverse($dataValues));
515
516 $seriesPlot = new RadarPlot(array_reverse($dataValuesX));
517
518 $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
519 $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
520 if ($radarStyle == 'filled') {
521 $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour]);
522 }
523 $this->formatPointMarker($seriesPlot, $marker);
524 $seriesPlot->SetLegend($dataLabel);
525
526 $this->graph->Add($seriesPlot);
527 }
528 }
529
530 private function renderPlotContour($groupID): void
531 {
532 $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
533
534 $dataValues = [];
535 // Loop through each data series in turn
536 for ($i = 0; $i < $seriesCount; ++$i) {
537 $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
538
539 $dataValues[$i] = $dataValuesX;
540 }
541 $seriesPlot = new ContourPlot($dataValues);
542
543 $this->graph->Add($seriesPlot);
544 }
545
546 private function renderPlotStock($groupID): void
547 {
548 $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
549 $plotOrder = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotOrder();
550
551 $dataValues = [];
552 // Loop through each data series in turn and build the plot arrays
553 foreach ($plotOrder as $i => $v) {
554 $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($v);
555 if ($dataValuesX === false) {
556 continue;
557 }
558 $dataValuesX = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($v)->getDataValues();
559 foreach ($dataValuesX as $j => $dataValueX) {
560 $dataValues[$plotOrder[$i]][$j] = $dataValueX;
561 }
562 }
563 if (empty($dataValues)) {
564 return;
565 }
566
567 $dataValuesPlot = [];
568 // Flatten the plot arrays to a single dimensional array to work with jpgraph
569 $jMax = count($dataValues[0]);
570 for ($j = 0; $j < $jMax; ++$j) {
571 for ($i = 0; $i < $seriesCount; ++$i) {
572 $dataValuesPlot[] = $dataValues[$i][$j] ?? null;
573 }
574 }
575
576 // Set the x-axis labels
577 $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount();
578 if ($labelCount > 0) {
579 $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
580 $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels);
581 $this->graph->xaxis->SetTickLabels($datasetLabels);
582 }
583
584 $seriesPlot = new StockPlot($dataValuesPlot);
585 $seriesPlot->SetWidth(20);
586
587 $this->graph->Add($seriesPlot);
588 }
589
590 private function renderAreaChart($groupCount): void
591 {
592 $this->renderCartesianPlotArea();
593
594 for ($i = 0; $i < $groupCount; ++$i) {
595 $this->renderPlotLine($i, true, false);
596 }
597 }
598
599 private function renderLineChart($groupCount): void
600 {
601 $this->renderCartesianPlotArea();
602
603 for ($i = 0; $i < $groupCount; ++$i) {
604 $this->renderPlotLine($i, false, false);
605 }
606 }
607
608 private function renderBarChart($groupCount, $dimensions = '2d'): void
609 {
610 $this->renderCartesianPlotArea();
611
612 for ($i = 0; $i < $groupCount; ++$i) {
613 $this->renderPlotBar($i, $dimensions);
614 }
615 }
616
617 private function renderScatterChart($groupCount): void
618 {
619 $this->renderCartesianPlotArea('linlin');
620
621 for ($i = 0; $i < $groupCount; ++$i) {
622 $this->renderPlotScatter($i, false);
623 }
624 }
625
626 private function renderBubbleChart($groupCount): void
627 {
628 $this->renderCartesianPlotArea('linlin');
629
630 for ($i = 0; $i < $groupCount; ++$i) {
631 $this->renderPlotScatter($i, true);
632 }
633 }
634
635 private function renderPieChart($groupCount, $dimensions = '2d', $doughnut = false, $multiplePlots = false): void
636 {
637 $this->renderPiePlotArea();
638
639 $iLimit = ($multiplePlots) ? $groupCount : 1;
640 for ($groupID = 0; $groupID < $iLimit; ++$groupID) {
641 $exploded = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
642 $datasetLabels = [];
643 if ($groupID == 0) {
644 $labelCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount();
645 if ($labelCount > 0) {
646 $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
647 $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels);
648 }
649 }
650
651 $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
652 // For pie charts, we only display the first series: doughnut charts generally display all series
653 $jLimit = ($multiplePlots) ? $seriesCount : 1;
654 // Loop through each data series in turn
655 for ($j = 0; $j < $jLimit; ++$j) {
656 $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
657
658 // Fill in any missing values in the $dataValues array
659 $testCurrentIndex = 0;
660 foreach ($dataValues as $k => $dataValue) {
661 while ($k != $testCurrentIndex) {
662 $dataValues[$testCurrentIndex] = null;
663 ++$testCurrentIndex;
664 }
665 ++$testCurrentIndex;
666 }
667
668 if ($dimensions == '3d') {
669 $seriesPlot = new PiePlot3D($dataValues);
670 } else {
671 if ($doughnut) {
672 $seriesPlot = new PiePlotC($dataValues);
673 } else {
674 $seriesPlot = new PiePlot($dataValues);
675 }
676 }
677
678 if ($multiplePlots) {
679 $seriesPlot->SetSize(($jLimit - $j) / ($jLimit * 4));
680 }
681
682 if ($doughnut && method_exists($seriesPlot, 'SetMidColor')) {
683 $seriesPlot->SetMidColor('white');
684 }
685
686 $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
687 if (count($datasetLabels) > 0) {
688 $seriesPlot->SetLabels(array_fill(0, count($datasetLabels), ''));
689 }
690 if ($dimensions != '3d') {
691 $seriesPlot->SetGuideLines(false);
692 }
693 if ($j == 0) {
694 if ($exploded) {
695 $seriesPlot->ExplodeAll();
696 }
697 $seriesPlot->SetLegends($datasetLabels);
698 }
699
700 $this->graph->Add($seriesPlot);
701 }
702 }
703 }
704
705 private function renderRadarChart($groupCount): void
706 {
707 $this->renderRadarPlotArea();
708
709 for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
710 $this->renderPlotRadar($groupID);
711 }
712 }
713
714 private function renderStockChart($groupCount): void
715 {
716 $this->renderCartesianPlotArea('intint');
717
718 for ($groupID = 0; $groupID < $groupCount; ++$groupID) {
719 $this->renderPlotStock($groupID);
720 }
721 }
722
723 private function renderContourChart($groupCount): void
724 {
725 $this->renderCartesianPlotArea('intint');
726
727 for ($i = 0; $i < $groupCount; ++$i) {
728 $this->renderPlotContour($i);
729 }
730 }
731
732 private function renderCombinationChart($groupCount, $outputDestination)
733 {
734 $this->renderCartesianPlotArea();
735
736 for ($i = 0; $i < $groupCount; ++$i) {
737 $dimensions = null;
738 $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
739 switch ($chartType) {
740 case 'area3DChart':
741 case 'areaChart':
742 $this->renderPlotLine($i, true, true);
743
744 break;
745 case 'bar3DChart':
746 $dimensions = '3d';
747 // no break
748 case 'barChart':
749 $this->renderPlotBar($i, $dimensions);
750
751 break;
752 case 'line3DChart':
753 case 'lineChart':
754 $this->renderPlotLine($i, false, true);
755
756 break;
757 case 'scatterChart':
758 $this->renderPlotScatter($i, false);
759
760 break;
761 case 'bubbleChart':
762 $this->renderPlotScatter($i, true);
763
764 break;
765 default:
766 $this->graph = null;
767
768 return false;
769 }
770 }
771
772 $this->renderLegend();
773
774 $this->graph->Stroke($outputDestination);
775
776 return true;
777 }
778
779 public function render($outputDestination)
780 {
781 self::$plotColour = 0;
782
783 $groupCount = $this->chart->getPlotArea()->getPlotGroupCount();
784
785 $dimensions = null;
786 if ($groupCount == 1) {
787 $chartType = $this->chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType();
788 } else {
789 $chartTypes = [];
790 for ($i = 0; $i < $groupCount; ++$i) {
791 $chartTypes[] = $this->chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType();
792 }
793 $chartTypes = array_unique($chartTypes);
794 if (count($chartTypes) == 1) {
795 $chartType = array_pop($chartTypes);
796 } elseif (count($chartTypes) == 0) {
797 echo 'Chart is not yet implemented<br />';
798
799 return false;
800 } else {
801 return $this->renderCombinationChart($groupCount, $outputDestination);
802 }
803 }
804
805 switch ($chartType) {
806 case 'area3DChart':
807 $dimensions = '3d';
808 // no break
809 case 'areaChart':
810 $this->renderAreaChart($groupCount);
811
812 break;
813 case 'bar3DChart':
814 $dimensions = '3d';
815 // no break
816 case 'barChart':
817 $this->renderBarChart($groupCount, $dimensions);
818
819 break;
820 case 'line3DChart':
821 $dimensions = '3d';
822 // no break
823 case 'lineChart':
824 $this->renderLineChart($groupCount);
825
826 break;
827 case 'pie3DChart':
828 $dimensions = '3d';
829 // no break
830 case 'pieChart':
831 $this->renderPieChart($groupCount, $dimensions, false, false);
832
833 break;
834 case 'doughnut3DChart':
835 $dimensions = '3d';
836 // no break
837 case 'doughnutChart':
838 $this->renderPieChart($groupCount, $dimensions, true, true);
839
840 break;
841 case 'scatterChart':
842 $this->renderScatterChart($groupCount);
843
844 break;
845 case 'bubbleChart':
846 $this->renderBubbleChart($groupCount);
847
848 break;
849 case 'radarChart':
850 $this->renderRadarChart($groupCount);
851
852 break;
853 case 'surface3DChart':
854 case 'surfaceChart':
855 $this->renderContourChart($groupCount);
856
857 break;
858 case 'stockChart':
859 $this->renderStockChart($groupCount);
860
861 break;
862 default:
863 echo $chartType . ' is not yet implemented<br />';
864
865 return false;
866 }
867 $this->renderLegend();
868
869 $this->graph->Stroke($outputDestination);
870
871 return true;
872 }
873 }
874