Total Complexity | 153 |
Total Lines | 843 |
Duplicated Lines | 8.9 % |
Coverage | 90.78% |
Changes | 1 | ||
Bugs | 0 | Features | 0 |
Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like JpGraph often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use JpGraph, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
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 | 1 | 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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) |
|
562 | 1 | } |
|
563 | |||
564 | 1 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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 | View Code Duplication | 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) |
|
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) |
|
756 | } |
||
757 | |||
758 | 1 | public function render($outputDestination) |
|
759 | { |
||
853 | } |
||
854 | } |
||
855 |
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.