Completed
Push — develop ( c96e2d...d2f55f )
by Adrien
48:43 queued 44:11
created

JpGraph::renderPlotLine()   C

Complexity

Conditions 10
Paths 200

Size

Total Lines 61
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 34
CRAP Score 10.0533

Importance

Changes 0
Metric Value
cc 10
eloc 38
nc 200
nop 4
dl 0
loc 61
rs 6.0317
c 0
b 0
f 0
ccs 34
cts 37
cp 0.9189
crap 10.0533

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 10 and the first side effect is on line 8.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

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