Failed Conditions
Push — develop ( 0ef1b5...a1e8c8 )
by Mark
34:44
created

JpGraph::renderLegend()   B

Complexity

Conditions 6
Paths 6

Size

Total Lines 30
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 11.1115

Importance

Changes 0
Metric Value
cc 6
eloc 24
nc 6
nop 0
dl 0
loc 30
ccs 11
cts 23
cp 0.4783
crap 11.1115
rs 8.9137
c 0
b 0
f 0
1
<?php
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
    private function formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation = '')
0 ignored issues
show
Unused Code introduced by
The parameter $labelCount is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

106
    private function formatDataSetLabels($groupID, $datasetLabels, /** @scrutinizer ignore-unused */ $labelCount, $rotation = '')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
107
    {
108
        $datasetLabelFormatCode = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getFormatCode();
109
        if ($datasetLabelFormatCode !== null) {
0 ignored issues
show
introduced by
The condition $datasetLabelFormatCode !== null is always true.
Loading history...
110
            //    Retrieve any label formatting code
111
            $datasetLabelFormatCode = stripslashes($datasetLabelFormatCode);
112
        }
113
114
        $testCurrentIndex = 0;
115
        foreach ($datasetLabels as $i => $datasetLabel) {
116
            if (is_array($datasetLabel)) {
117
                if ($rotation == 'bar') {
118
                    $datasetLabels[$i] = implode(' ', $datasetLabel);
119
                } else {
120
                    $datasetLabel = array_reverse($datasetLabel);
121
                    $datasetLabels[$i] = implode("\n", $datasetLabel);
122
                }
123
            } else {
124
                //    Format labels according to any formatting code
125
                if ($datasetLabelFormatCode !== null) {
126
                    $datasetLabels[$i] = NumberFormat::toFormattedString($datasetLabel, $datasetLabelFormatCode);
127
                }
128
            }
129
            ++$testCurrentIndex;
130
        }
131
132
        return $datasetLabels;
133
    }
134
135
    private function percentageSumCalculation($groupID, $seriesCount)
136
    {
137
        //    Adjust our values to a percentage value across all series in the group
138
        for ($i = 0; $i < $seriesCount; ++$i) {
139
            if ($i == 0) {
140
                $sumValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
141
            } else {
142
                $nextValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
143
                foreach ($nextValues as $k => $value) {
144
                    if (isset($sumValues[$k])) {
145
                        $sumValues[$k] += $value;
146
                    } else {
147
                        $sumValues[$k] = $value;
148
                    }
149
                }
150
            }
151
        }
152
153
        return $sumValues;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sumValues does not seem to be defined for all execution paths leading up to this point.
Loading history...
154
    }
155
156
    private function percentageAdjustValues($dataValues, $sumValues)
157
    {
158
        foreach ($dataValues as $k => $dataValue) {
159
            $dataValues[$k] = $dataValue / $sumValues[$k] * 100;
160
        }
161
162
        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 1
            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')
0 ignored issues
show
Unused Code introduced by
The parameter $dimensions is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

274
    private function renderPlotLine($groupID, $filled = false, $combination = false, /** @scrutinizer ignore-unused */ $dimensions = '2d')

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
275
    {
276 1
        $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
277
278 1
        $labelCount = count($this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
0 ignored issues
show
Bug introduced by
$this->chart->getPlotAre...dex(0)->getPointCount() of type integer is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

278
        $labelCount = count(/** @scrutinizer ignore-type */ $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
Loading history...
279
        if ($labelCount > 0) {
280
            $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
281
            $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
282
            $this->graph->xaxis->SetTickLabels($datasetLabels);
283
        }
284
285
        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
286
        $seriesPlots = [];
287
        if ($grouping == 'percentStacked') {
288
            $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
289
        }
290
291
        //    Loop through each data series in turn
292
        for ($i = 0; $i < $seriesCount; ++$i) {
293
            $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getDataValues();
294
            $marker = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($i)->getPointMarker();
295
296
            if ($grouping == 'percentStacked') {
297
                $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sumValues does not seem to be defined for all execution paths leading up to this point.
Loading history...
298
            }
299
300
            //    Fill in any missing values in the $dataValues array
301
            $testCurrentIndex = 0;
302
            foreach ($dataValues as $k => $dataValue) {
303
                while ($k != $testCurrentIndex) {
304
                    $dataValues[$testCurrentIndex] = null;
305
                    ++$testCurrentIndex;
306
                }
307
                ++$testCurrentIndex;
308
            }
309
310
            $seriesPlot = new \LinePlot($dataValues);
311
            if ($combination) {
312
                $seriesPlot->SetBarCenter();
313
            }
314
315
            if ($filled) {
316
                $seriesPlot->SetFilled(true);
317
                $seriesPlot->SetColor('black');
318
                $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
319
            } else {
320
                //    Set the appropriate plot marker
321
                $this->formatPointMarker($seriesPlot, $marker);
322
            }
323
            $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($i)->getDataValue();
324
            $seriesPlot->SetLegend($dataLabel);
325
326
            $seriesPlots[] = $seriesPlot;
327
        }
328
329
        if ($grouping == 'standard') {
330
            $groupPlot = $seriesPlots;
331
        } else {
332
            $groupPlot = new \AccLinePlot($seriesPlots);
333
        }
334
        $this->graph->Add($groupPlot);
335
    }
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());
0 ignored issues
show
Bug introduced by
$this->chart->getPlotAre...dex(0)->getPointCount() of type integer is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

346
        $labelCount = count(/** @scrutinizer ignore-type */ $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
Loading history...
347
        if ($labelCount > 0) {
348
            $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
349
            $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount, $rotation);
350
            //    Rotate for bar rather than column chart
351
            if ($rotation == 'bar') {
352
                $datasetLabels = array_reverse($datasetLabels);
353
                $this->graph->yaxis->SetPos('max');
354
                $this->graph->yaxis->SetLabelAlign('center', 'top');
355
                $this->graph->yaxis->SetLabelSide(SIDE_RIGHT);
356
            }
357
            $this->graph->xaxis->SetTickLabels($datasetLabels);
358
        }
359
360
        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
361
        $seriesPlots = [];
362
        if ($grouping == 'percentStacked') {
363
            $sumValues = $this->percentageSumCalculation($groupID, $seriesCount);
364
        }
365
366
        //    Loop through each data series in turn
367
        for ($j = 0; $j < $seriesCount; ++$j) {
368
            $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
369
            if ($grouping == 'percentStacked') {
370
                $dataValues = $this->percentageAdjustValues($dataValues, $sumValues);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $sumValues does not seem to be defined for all execution paths leading up to this point.
Loading history...
371
            }
372
373
            //    Fill in any missing values in the $dataValues array
374
            $testCurrentIndex = 0;
375
            foreach ($dataValues as $k => $dataValue) {
376
                while ($k != $testCurrentIndex) {
377
                    $dataValues[$testCurrentIndex] = null;
378
                    ++$testCurrentIndex;
379
                }
380
                ++$testCurrentIndex;
381
            }
382
383
            //    Reverse the $dataValues order for bar rather than column chart
384
            if ($rotation == 'bar') {
385
                $dataValues = array_reverse($dataValues);
386
            }
387
            $seriesPlot = new \BarPlot($dataValues);
388
            $seriesPlot->SetColor('black');
389
            $seriesPlot->SetFillColor(self::$colourSet[self::$plotColour++]);
390
            if ($dimensions == '3d') {
391
                $seriesPlot->SetShadow();
392
            }
393
            if (!$this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)) {
394
                $dataLabel = '';
395
            } else {
396
                $dataLabel = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotLabelByIndex($j)->getDataValue();
397
            }
398
            $seriesPlot->SetLegend($dataLabel);
399
400
            $seriesPlots[] = $seriesPlot;
401
        }
402
        //    Reverse the plot order for bar rather than column chart
403
        if (($rotation == 'bar') && (!($grouping == 'percentStacked'))) {
404
            $seriesPlots = array_reverse($seriesPlots);
405
        }
406
407
        if ($grouping == 'clustered') {
408
            $groupPlot = new \GroupBarPlot($seriesPlots);
409
        } elseif ($grouping == 'standard') {
410
            $groupPlot = new \GroupBarPlot($seriesPlots);
411
        } else {
412
            $groupPlot = new \AccBarPlot($seriesPlots);
413
            if ($dimensions == '3d') {
414
                $groupPlot->SetShadow();
415
            }
416
        }
417
418
        $this->graph->Add($groupPlot);
419
    }
420
421 1
    private function renderPlotScatter($groupID, $bubble)
422
    {
423 1
        $grouping = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotGrouping();
0 ignored issues
show
Unused Code introduced by
The assignment to $grouping is dead and can be removed.
Loading history...
424 1
        $scatterStyle = $bubbleSize = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotStyle();
425
426 1
        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
427 1
        $seriesPlots = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $seriesPlots is dead and can be removed.
Loading history...
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 = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $seriesPlots is dead and can be removed.
Loading history...
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();
0 ignored issues
show
Unused Code introduced by
The assignment to $contourStyle is dead and can be removed.
Loading history...
507
508 1
        $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
509 1
        $seriesPlots = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $seriesPlots is dead and can be removed.
Loading history...
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();
0 ignored issues
show
Unused Code introduced by
The assignment to $dataValuesY is dead and can be removed.
Loading history...
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());
0 ignored issues
show
Bug introduced by
$this->chart->getPlotAre...dex(0)->getPointCount() of type integer is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

551
        $labelCount = count(/** @scrutinizer ignore-type */ $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
Loading history...
552
        if ($labelCount > 0) {
553
            $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
554
            $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
555
            $this->graph->xaxis->SetTickLabels($datasetLabels);
556
        }
557
558
        $seriesPlot = new \StockPlot($dataValuesPlot);
559
        $seriesPlot->SetWidth(20);
560
561
        $this->graph->Add($seriesPlot);
562
    }
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
    }
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
    }
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
    }
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();
0 ignored issues
show
Unused Code introduced by
The assignment to $grouping is dead and can be removed.
Loading history...
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());
0 ignored issues
show
Bug introduced by
$this->chart->getPlotAre...dex(0)->getPointCount() of type integer is incompatible with the type Countable|array expected by parameter $var of count(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

618
                $labelCount = count(/** @scrutinizer ignore-type */ $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex(0)->getPointCount());
Loading history...
619
                if ($labelCount > 0) {
620
                    $datasetLabels = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotCategoryByIndex(0)->getDataValues();
621
                    $datasetLabels = $this->formatDataSetLabels($groupID, $datasetLabels, $labelCount);
622
                }
623
            }
624
625
            $seriesCount = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotSeriesCount();
626
            $seriesPlots = [];
0 ignored issues
show
Unused Code introduced by
The assignment to $seriesPlots is dead and can be removed.
Loading history...
627
            //    For pie charts, we only display the first series: doughnut charts generally display all series
628
            $jLimit = ($multiplePlots) ? $seriesCount : 1;
629
            //    Loop through each data series in turn
630
            for ($j = 0; $j < $jLimit; ++$j) {
631
                $dataValues = $this->chart->getPlotArea()->getPlotGroupByIndex($groupID)->getPlotValuesByIndex($j)->getDataValues();
632
633
                //    Fill in any missing values in the $dataValues array
634
                $testCurrentIndex = 0;
635
                foreach ($dataValues as $k => $dataValue) {
636
                    while ($k != $testCurrentIndex) {
637
                        $dataValues[$testCurrentIndex] = null;
638
                        ++$testCurrentIndex;
639
                    }
640
                    ++$testCurrentIndex;
641
                }
642
643
                if ($dimensions == '3d') {
644
                    $seriesPlot = new \PiePlot3D($dataValues);
645
                } else {
646
                    if ($doughnut) {
647
                        $seriesPlot = new \PiePlotC($dataValues);
648
                    } else {
649
                        $seriesPlot = new \PiePlot($dataValues);
650
                    }
651
                }
652
653
                if ($multiplePlots) {
654
                    $seriesPlot->SetSize(($jLimit - $j) / ($jLimit * 4));
655
                }
656
657
                if ($doughnut) {
658
                    $seriesPlot->SetMidColor('white');
0 ignored issues
show
Bug introduced by
The method SetMidColor() does not exist on PiePlot. Did you maybe mean SetColor()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

658
                    $seriesPlot->/** @scrutinizer ignore-call */ 
659
                                 SetMidColor('white');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
Bug introduced by
The method SetMidColor() does not exist on PiePlot3D. Did you maybe mean SetColor()? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

658
                    $seriesPlot->/** @scrutinizer ignore-call */ 
659
                                 SetMidColor('white');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
659
                }
660
661
                $seriesPlot->SetColor(self::$colourSet[self::$plotColour++]);
662
                if (count($datasetLabels) > 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $datasetLabels does not seem to be defined for all execution paths leading up to this point.
Loading history...
663
                    $seriesPlot->SetLabels(array_fill(0, count($datasetLabels), ''));
664
                }
665
                if ($dimensions != '3d') {
666
                    $seriesPlot->SetGuideLines(false);
667
                }
668
                if ($j == 0) {
669
                    if ($exploded) {
670
                        $seriesPlot->ExplodeAll();
671
                    }
672
                    $seriesPlot->SetLegends($datasetLabels);
673
                }
674
675
                $this->graph->Add($seriesPlot);
676
            }
677
        }
678
    }
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
    }
697
698 1
    private function renderContourChart($groupCount, $dimensions)
0 ignored issues
show
Unused Code introduced by
The parameter $dimensions is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

698
    private function renderContourChart($groupCount, /** @scrutinizer ignore-unused */ $dimensions)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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)
0 ignored issues
show
Unused Code introduced by
The parameter $dimensions is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

707
    private function renderCombinationChart($groupCount, /** @scrutinizer ignore-unused */ $dimensions, $outputDestination)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
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 1
            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
                    break;
729
                case 'line3DChart':
730
                    $dimensions = '3d';
731
                // no break
732
                case 'lineChart':
733
                    $this->renderPlotLine($i, false, true, $dimensions);
734
735
                    break;
736
                case 'scatterChart':
737
                    $this->renderPlotScatter($i, false);
738
739
                    break;
740
                case 'bubbleChart':
741
                    $this->renderPlotScatter($i, true);
742
743
                    break;
744
                default:
745
                    $this->graph = null;
746
747
                    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) {
0 ignored issues
show
introduced by
The condition $groupCount == 1 is always false.
Loading history...
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 1
        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
                break;
792 1
            case 'bar3DChart':
793 1
                $dimensions = '3d';
794
            // no break
795 1
            case 'barChart':
796 1
                $this->renderBarChart($groupCount, $dimensions);
797
798
                break;
799 1
            case 'line3DChart':
800 1
                $dimensions = '3d';
801
            // no break
802 1
            case 'lineChart':
803 1
                $this->renderLineChart($groupCount, $dimensions);
804
805
                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
                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
                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
                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