LinePlot   F
last analyzed

Complexity

Total Complexity 89

Size/Duplication

Total Lines 469
Duplicated Lines 0 %

Test Coverage

Coverage 68.48%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 284
c 1
b 0
f 0
dl 0
loc 469
ccs 189
cts 276
cp 0.6848
rs 2
wmc 89

16 Methods

Rating   Name   Duplication   Size   Complexity  
A SetFilled() 0 3 1
A SetStepStyle() 0 3 1
A SetFastStroke() 0 3 1
A SetColor() 0 3 1
A SetFillFromYMin() 0 3 1
A SetStyle() 0 3 1
A AddArea() 0 9 2
B FastStroke() 0 36 7
A Legend() 0 34 5
A PreStrokeAdjust() 0 17 4
A SetFillColor() 0 5 1
A __construct() 0 6 1
F Stroke() 0 266 60
A SetFillGradient() 0 7 1
A SetBarCenter() 0 3 1
A SetFillFromYMax() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like LinePlot 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 LinePlot, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/**
4
 * JPGraph v4.0.3
5
 */
6
7
namespace Amenadiel\JpGraph\Plot;
8
9
use Amenadiel\JpGraph\Util;
10
11
/*
12
 * File:           JPGRAPH_LINE.PHP
13
 * // Description: Line plot extension for JpGraph
14
 * // Created:       2001-01-08
15
 * // Ver:           $Id: jpgraph_line.php 1921 2009-12-11 11:46:39Z ljp $
16
 * //
17
 * // Copyright (c) Asial Corporation. All rights reserved.
18
 */
19
// constants for the (filled) area
20 1
define('LP_AREA_FILLED', true);
21 1
define('LP_AREA_NOT_FILLED', false);
22 1
define('LP_AREA_BORDER', false);
23 1
define('LP_AREA_NO_BORDER', true);
24
25
/**
26
 * @class LinePlot
27
 * // Description:
28
 */
29
class LinePlot extends Plot
30
{
31
    public $mark;
32
    protected $filled             = false;
33
    protected $fill_color         = 'blue';
34
    protected $step_style         = false;
35
    protected $center             = false;
36
    protected $line_style         = 1; // Default to solid
37
    protected $filledAreas        = []; // array of arrays(with min,max,col,filled in them)
38
    public $barcenter             = false; // When we mix line and bar. Should we center the line in the bar.
39
    protected $fillFromMin        = false;
40
    protected $fillFromMax        = false;
41
    protected $fillgrad           = false;
42
    protected $fillgrad_fromcolor = 'navy';
43
    protected $fillgrad_tocolor   = 'silver';
44
    protected $fillgrad_numcolors = 100;
45
    protected $iFastStroke        = false;
46
47
    /**
48
     * CONSTRUCTOR.
49
     *
50
     * @param mixed $datay
51
     * @param mixed $datax
52
     */
53 16
    public function __construct($datay, $datax = false)
54
    {
55 16
        parent::__construct($datay, $datax);
56 16
        $this->mark       = new PlotMark();
57 16
        $this->color      = Util\ColorFactory::getColor();
58 16
        $this->fill_color = $this->color;
59 16
    }
60
61
    /**
62
     * PUBLIC METHODS.
63
     *
64
     * @param mixed $aFlg
65
     */
66
    public function SetFilled($aFlg = true)
67
    {
68
        $this->filled = $aFlg;
69
    }
70
71
    public function SetBarCenter($aFlag = true)
72
    {
73
        $this->barcenter = $aFlag;
74
    }
75
76 2
    public function SetStyle($aStyle)
77
    {
78 2
        $this->line_style = $aStyle;
79 2
    }
80
81 1
    public function SetStepStyle($aFlag = true)
82
    {
83 1
        $this->step_style = $aFlag;
84 1
    }
85
86 15
    public function SetColor($aColor)
87
    {
88 15
        parent::SetColor($aColor);
89 15
    }
90
91 2
    public function SetFillFromYMin($f = true)
92
    {
93 2
        $this->fillFromMin = $f;
94 2
    }
95
96
    public function SetFillFromYMax($f = true)
97
    {
98
        $this->fillFromMax = $f;
99
    }
100
101 5
    public function SetFillColor($aColor, $aFilled = true)
102
    {
103
        //$this->color = $aColor;
104 5
        $this->fill_color = $aColor;
105 5
        $this->filled     = $aFilled;
106 5
    }
107
108
    public function SetFillGradient($aFromColor, $aToColor, $aNumColors = 100, $aFilled = true)
109
    {
110
        $this->fillgrad_fromcolor = $aFromColor;
111
        $this->fillgrad_tocolor   = $aToColor;
112
        $this->fillgrad_numcolors = $aNumColors;
113
        $this->filled             = $aFilled;
114
        $this->fillgrad           = true;
115
    }
116
117 16
    public function Legend($graph)
118
    {
119 16
        if ($this->legend != '') {
120 11
            if ($this->filled && !$this->fillgrad) {
121 2
                $graph->legend->Add(
122 2
                    $this->legend,
123 2
                    $this->fill_color,
124 2
                    $this->mark,
125 2
                    0,
126 2
                    $this->legendcsimtarget,
127 2
                    $this->legendcsimalt,
128 2
                    $this->legendcsimwintarget
129
                );
130 11
            } elseif ($this->fillgrad) {
131
                $color = [$this->fillgrad_fromcolor, $this->fillgrad_tocolor];
132
                // In order to differentiate between gradients and cooors specified as an Image\RGB triple
133
                $graph->legend->Add(
134
                    $this->legend,
135
                    $color,
136
                    '',
137
                    -2/* -GRAD_HOR */,
138
                    $this->legendcsimtarget,
139
                    $this->legendcsimalt,
140
                    $this->legendcsimwintarget
141
                );
142
            } else {
143 11
                $graph->legend->Add(
144 11
                    $this->legend,
145 11
                    $this->color,
146 11
                    $this->mark,
147 11
                    $this->line_style,
148 11
                    $this->legendcsimtarget,
149 11
                    $this->legendcsimalt,
150 11
                    $this->legendcsimwintarget
151
                );
152
            }
153
        }
154 16
    }
155
156 1
    public function AddArea($aMin = 0, $aMax = 0, $aFilled = LP_AREA_NOT_FILLED, $aColor = 'gray9', $aBorder = LP_AREA_BORDER)
157
    {
158 1
        if ($aMin > $aMax) {
159
            // swap
160
            $tmp  = $aMin;
161
            $aMin = $aMax;
162
            $aMax = $tmp;
163
        }
164 1
        $this->filledAreas[] = [$aMin, $aMax, $aColor, $aFilled, $aBorder];
165 1
    }
166
167
    // Gets called before any axis are stroked
168 16
    public function PreStrokeAdjust($graph)
169
    {
170
        // If another plot type have already adjusted the
171
        // offset we don't touch it.
172
        // (We check for empty in case the scale is  a log scale
173
        // and hence doesn't contain any xlabel_offset)
174 16
        if (empty($graph->xaxis->scale->ticks->xlabel_offset) || $graph->xaxis->scale->ticks->xlabel_offset == 0) {
175 15
            if ($this->center) {
176 4
                ++$this->numpoints;
177 4
                $a = 0.5;
178 4
                $b = 0.5;
179
            } else {
180 12
                $a = 0;
181 12
                $b = 0;
182
            }
183 15
            $graph->xaxis->scale->ticks->SetXLabelOffset($a);
184 15
            $graph->SetTextScaleOff($b);
185
            //$graph->xaxis->scale->ticks->SupressMinorTickMarks();
186
        }
187 16
    }
188
189
    public function SetFastStroke($aFlg = true)
190
    {
191
        $this->iFastStroke = $aFlg;
192
    }
193
194
    public function FastStroke($img, $xscale, $yscale, $aStartPoint = 0, $exist_x = true)
195
    {
196
        // An optimized stroke for many data points with no extra
197
        // features but 60% faster. You can't have values or line styles, or null
198
        // values in plots.
199
        $numpoints = safe_count($this->coords[0]);
200
        if ($this->barcenter) {
201
            $textadj = 0.5 - $xscale->text_scale_off;
202
        } else {
203
            $textadj = 0;
204
        }
205
206
        $img->SetColor($this->color);
207
        $img->SetLineWeight($this->weight);
208
        $pnts = $aStartPoint;
209
        while ($pnts < $numpoints) {
210
            if ($exist_x) {
211
                $x = $this->coords[1][$pnts];
212
            } else {
213
                $x = $pnts + $textadj;
214
            }
215
            $xt = $xscale->Translate($x);
216
            $y  = $this->coords[0][$pnts];
217
            $yt = $yscale->Translate($y);
218
            if (is_numeric($y)) {
219
                $cord[] = $xt;
220
                $cord[] = $yt;
221
            } elseif ($y == '-' && $pnts > 0) {
222
                // Just ignore
223
            } else {
224
                Util\JpGraphError::RaiseL(10002); //('Plot too complicated for fast line Stroke. Use standard Stroke()');
225
            }
226
            ++$pnts;
227
        } // WHILE
228
229
        $img->Polygon($cord, false, true);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $cord does not seem to be defined for all execution paths leading up to this point.
Loading history...
230
    }
231
232 16
    public function Stroke($img, $xscale, $yscale)
233
    {
234 16
        $idx       = 0;
235 16
        $numpoints = safe_count($this->coords[0]);
236 16
        if (isset($this->coords[1])) {
237 5
            if (safe_count($this->coords[1]) != $numpoints) {
238
                Util\JpGraphError::RaiseL(2003, safe_count($this->coords[1]), $numpoints);
239
            //("Number of X and Y points are not equal. Number of X-points:". safe_count($this->coords[1])." Number of Y-points:$numpoints");
240
            } else {
241 5
                $exist_x = true;
242
            }
243
        } else {
244 13
            $exist_x = false;
245
        }
246
247 16
        if ($this->barcenter) {
248
            $textadj = 0.5 - $xscale->text_scale_off;
249
        } else {
250 16
            $textadj = 0;
251
        }
252
253
        // Find the first numeric data point
254 16
        $startpoint = 0;
255 16
        while ($startpoint < $numpoints && !is_numeric($this->coords[0][$startpoint])) {
256
            ++$startpoint;
257
        }
258
259
        // Bail out if no data points
260 16
        if ($startpoint == $numpoints) {
261
            return;
262
        }
263
264 16
        if ($this->iFastStroke) {
265
            $this->FastStroke($img, $xscale, $yscale, $startpoint, $exist_x);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $exist_x does not seem to be defined for all execution paths leading up to this point.
Loading history...
266
267
            return;
268
        }
269
270 16
        if ($exist_x) {
271 5
            $xs = $this->coords[1][$startpoint];
272
        } else {
273 13
            $xs = $textadj + $startpoint;
274
        }
275
276 16
        $img->SetStartPoint(
277 16
            $xscale->Translate($xs),
278 16
            $yscale->Translate($this->coords[0][$startpoint])
279
        );
280
281 16
        if ($this->filled) {
282 5
            if ($this->fillFromMax) {
283
                //$max = $yscale->GetMaxVal();
284
                $cord[$idx++] = $xscale->Translate($xs);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$cord was never initialized. Although not strictly required by PHP, it is generally a good practice to add $cord = array(); before regardless.
Loading history...
285
                $cord[$idx++] = $yscale->scale_abs[1];
286
            } else {
287 5
                $min = $yscale->GetMinVal();
288 5
                if ($min > 0 || $this->fillFromMin) {
289 2
                    $fillmin = $yscale->scale_abs[0]; //Translate($min);
290
                } else {
291 4
                    $fillmin = $yscale->Translate(0);
292
                }
293
294 5
                $cord[$idx++] = $xscale->Translate($xs);
295 5
                $cord[$idx++] = $fillmin;
296
            }
297
        }
298 16
        $xt           = $xscale->Translate($xs);
299 16
        $yt           = $yscale->Translate($this->coords[0][$startpoint]);
300 16
        $cord[$idx++] = $xt;
301 16
        $cord[$idx++] = $yt;
302 16
        $yt_old       = $yt;
303 16
        $xt_old       = $xt;
304 16
        $y_old        = $this->coords[0][$startpoint];
305
306 16
        $this->value->Stroke($img, $this->coords[0][$startpoint], $xt, $yt);
307
308 16
        $img->SetColor($this->color);
309 16
        $img->SetLineWeight($this->weight);
310 16
        $img->SetLineStyle($this->line_style);
311 16
        $pnts           = $startpoint + 1;
312 16
        $firstnonumeric = false;
313
314 16
        while ($pnts < $numpoints) {
315 16
            if ($exist_x) {
316 5
                $x = $this->coords[1][$pnts];
317
            } else {
318 13
                $x = $pnts + $textadj;
319
            }
320 16
            $xt = $xscale->Translate($x);
321 16
            $yt = $yscale->Translate($this->coords[0][$pnts]);
322
323 16
            $y = $this->coords[0][$pnts];
324 16
            if ($this->step_style) {
325
                // To handle null values within step style we need to record the
326
                // first non numeric value so we know from where to start if the
327
                // non value is '-'.
328 1
                if (is_numeric($y)) {
329 1
                    $firstnonumeric = false;
330 1
                    if (is_numeric($y_old)) {
331 1
                        $img->StyleLine($xt_old, $yt_old, $xt, $yt_old);
332 1
                        $img->StyleLine($xt, $yt_old, $xt, $yt);
333
                    } elseif ($y_old == '-') {
334
                        $img->StyleLine($xt_first, $yt_first, $xt, $yt_first);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $yt_first does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $xt_first does not seem to be defined for all execution paths leading up to this point.
Loading history...
335
                        $img->StyleLine($xt, $yt_first, $xt, $yt);
336
                    } else {
337
                        $yt_old = $yt;
338
                        $xt_old = $xt;
0 ignored issues
show
Unused Code introduced by
The assignment to $xt_old is dead and can be removed.
Loading history...
339
                    }
340 1
                    $cord[$idx++] = $xt;
341 1
                    $cord[$idx++] = $yt_old;
342 1
                    $cord[$idx++] = $xt;
343 1
                    $cord[$idx++] = $yt;
344
                } elseif ($firstnonumeric == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
345
                    $firstnonumeric = true;
346
                    $yt_first       = $yt_old;
347 1
                    $xt_first       = $xt_old;
348
                }
349
            } else {
350 16
                $tmp1 = $y;
351 16
                $prev = $this->coords[0][$pnts - 1];
352 16
                if ($tmp1 === '' || $tmp1 === null || $tmp1 === 'X') {
353 2
                    $tmp1 = 'x';
354
                }
355
356 16
                if ($prev === '' || $prev === null || $prev === 'X') {
357 2
                    $prev = 'x';
358
                }
359
360 16
                if (is_numeric($y) || (is_string($y) && $y != '-')) {
361 16
                    if (is_numeric($y) && (is_numeric($prev) || $prev === '-')) {
362 16
                        $img->StyleLineTo($xt, $yt);
363
                    } else {
364 2
                        $img->SetStartPoint($xt, $yt);
365
                    }
366
                }
367 16
                if ($this->filled && $tmp1 !== '-') {
368 5
                    if ($tmp1 === 'x') {
369
                        $cord[$idx++] = $cord[$idx - 3];
370
                        $cord[$idx++] = $fillmin;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $fillmin does not seem to be defined for all execution paths leading up to this point.
Loading history...
371 5
                    } elseif ($prev === 'x') {
372
                        $cord[$idx++] = $xt;
373
                        $cord[$idx++] = $fillmin;
374
                        $cord[$idx++] = $xt;
375
                        $cord[$idx++] = $yt;
376
                    } else {
377 5
                        $cord[$idx++] = $xt;
378 5
                        $cord[$idx++] = $yt;
379
                    }
380
                } else {
381 16
                    if (is_numeric($tmp1) && (is_numeric($prev) || $prev === '-')) {
382 16
                        $cord[$idx++] = $xt;
383 16
                        $cord[$idx++] = $yt;
384
                    }
385
                }
386
            }
387 16
            $yt_old = $yt;
388 16
            $xt_old = $xt;
389 16
            $y_old  = $y;
390
391 16
            $this->StrokeDataValue($img, $this->coords[0][$pnts], $xt, $yt);
392
393 16
            ++$pnts;
394
        }
395
396 16
        if ($this->filled) {
397 5
            $cord[$idx++] = $xt;
398 5
            if ($this->fillFromMax) {
399
                $cord[$idx++] = $yscale->scale_abs[1];
400
            } else {
401 5
                if ($min > 0 || $this->fillFromMin) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $min does not seem to be defined for all execution paths leading up to this point.
Loading history...
402 2
                    $cord[$idx++] = $yscale->Translate($min);
403
                } else {
404 4
                    $cord[$idx++] = $yscale->Translate(0);
405
                }
406
            }
407 5
            if ($this->fillgrad) {
408
                $img->SetLineWeight(1);
409
                $grad = new Gradient($img);
410
                $grad->SetNumColors($this->fillgrad_numcolors);
411
                $grad->FilledFlatPolygon($cord, $this->fillgrad_fromcolor, $this->fillgrad_tocolor);
412
                $img->SetLineWeight($this->weight);
413
            } else {
414 5
                $img->SetColor($this->fill_color);
415 5
                $img->FilledPolygon($cord);
416
            }
417 5
            if ($this->weight > 0) {
418 5
                $img->SetLineWeight($this->weight);
419 5
                $img->SetColor($this->color);
420
                // Remove first and last coordinate before drawing the line
421
                // sine we otherwise get the vertical start and end lines which
422
                // doesn't look appropriate
423 5
                $img->Polygon(array_slice($cord, 2, safe_count($cord) - 4));
424
            }
425
        }
426
427 16
        if (!empty($this->filledAreas)) {
428 1
            $minY   = $yscale->Translate($yscale->GetMinVal());
429 1
            $factor = ($this->step_style ? 4 : 2);
430
431 1
            for ($i = 0; $i < safe_count($this->filledAreas); ++$i) {
432
                // go through all filled area elements ordered by insertion
433
                // fill polygon array
434 1
                $areaCoords[] = $cord[$this->filledAreas[$i][0] * $factor];
435 1
                $areaCoords[] = $minY;
436
437
                $areaCoords =
438 1
                    array_merge(
439 1
                        $areaCoords,
440 1
                        array_slice(
441 1
                            $cord,
442 1
                            $this->filledAreas[$i][0] * $factor,
443 1
                            ($this->filledAreas[$i][1] - $this->filledAreas[$i][0] + ($this->step_style ? 0 : 1)) * $factor
444
                        )
445
                    );
446 1
                $areaCoords[] = $areaCoords[safe_count($areaCoords) - 2]; // last x
447 1
                $areaCoords[] = $minY; // last y
448
449 1
                if ($this->filledAreas[$i][3]) {
450 1
                    $img->SetColor($this->filledAreas[$i][2]);
451 1
                    $img->FilledPolygon($areaCoords);
452 1
                    $img->SetColor($this->color);
453
                }
454
                // Check if we should draw the frame.
455
                // If not we still re-draw the line since it might have been
456
                // partially overwritten by the filled area and it doesn't look
457
                // very good.
458 1
                if ($this->filledAreas[$i][4]) {
459
                    $img->Polygon($areaCoords);
460
                } else {
461 1
                    $img->Polygon($cord);
462
                }
463
464 1
                $areaCoords = [];
465
            }
466
        }
467
468 16
        if (!is_object($this->mark) || $this->mark->type == -1 || $this->mark->show == false) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
469 11
            return;
470
        }
471
472 8
        for ($pnts = 0; $pnts < $numpoints; ++$pnts) {
473 8
            if ($exist_x) {
474 2
                $x = $this->coords[1][$pnts];
475
            } else {
476 7
                $x = $pnts + $textadj;
477
            }
478 8
            $xt = $xscale->Translate($x);
479 8
            $yt = $yscale->Translate($this->coords[0][$pnts]);
480
481 8
            if (is_numeric($this->coords[0][$pnts])) {
482 8
                if (!empty($this->csimtargets[$pnts])) {
483
                    if (!empty($this->csimwintargets[$pnts])) {
484
                        $this->mark->SetCSIMTarget($this->csimtargets[$pnts], $this->csimwintargets[$pnts]);
485
                    } else {
486
                        $this->mark->SetCSIMTarget($this->csimtargets[$pnts]);
487
                    }
488
                    $this->mark->SetCSIMAlt($this->csimalts[$pnts]);
489
                }
490 8
                if ($exist_x) {
491 2
                    $x = $this->coords[1][$pnts];
492
                } else {
493 7
                    $x = $pnts;
494
                }
495 8
                $this->mark->SetCSIMAltVal($this->coords[0][$pnts], $x);
496 8
                $this->mark->Stroke($img, $xt, $yt);
497 8
                $this->csimareas .= $this->mark->GetCSIMAreas();
498
            }
499
        }
500 8
    }
501
} // @class
502