AccBarPlot::Min()   B
last analyzed

Complexity

Conditions 7
Paths 28

Size

Total Lines 36
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 20
nc 28
nop 0
dl 0
loc 36
ccs 0
cts 28
cp 0
crap 56
rs 8.6666
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * JPGraph v4.0.3
5
 */
6
7
namespace Amenadiel\JpGraph\Plot;
8
9
use Amenadiel\JpGraph\Graph;
10
use Amenadiel\JpGraph\Util;
11
12
/**
13
 * @class AccBarPlot
14
 * // Description: Produce accumulated bar plots
15
 */
16
class AccBarPlot extends BarPlot
17
{
18
    public $plots;
19
    private $nbrplots = 0;
20
21
    /**
22
     * CONSTRUCTOR.
23
     *
24
     * @param mixed $plots
25
     */
26
    public function __construct($plots)
27
    {
28
        $this->plots    = $plots;
29
        $this->nbrplots = safe_count($plots);
30
        if ($this->nbrplots < 1) {
31
            Util\JpGraphError::RaiseL(2010); //('Cannot create AccBarPlot from empty plot array.');
32
        }
33
        for ($i = 0; $i < $this->nbrplots; ++$i) {
34
            if (empty($this->plots[$i]) || !isset($this->plots[$i])) {
35
                Util\JpGraphError::RaiseL(2011, $i); //("Acc bar plot element nbr $i is undefined or empty.");
36
            }
37
        }
38
39
        // We can only allow individual plost which do not have specified X-positions
40
        for ($i = 0; $i < $this->nbrplots; ++$i) {
41
            if (!empty($this->plots[$i]->coords[1])) {
42
                Util\JpGraphError::RaiseL(2015);
43
                //'Individual bar plots in an AccBarPlot or GroupBarPlot can not have specified X-positions.');
44
            }
45
        }
46
47
        // Use 0 weight by default which means that the individual bar
48
        // weights will be used per part n the accumulated bar
49
        $this->SetWeight(0);
50
51
        $this->numpoints = $plots[0]->numpoints;
52
        $this->value     = new DisplayValue();
53
    }
54
55
    /**
56
     * PUBLIC METHODS.
57
     *
58
     * @param mixed $graph
59
     */
60
    public function Legend($graph)
61
    {
62
        $n = safe_count($this->plots);
63
        for ($i = $n - 1; $i >= 0; --$i) {
64
            $c = get_class($this->plots[$i]);
65
            if (!($this->plots[$i] instanceof BarPlot)) {
66
                Util\JpGraphError::RaiseL(2012, $c);
67
                //('One of the objects submitted to AccBar is not a BarPlot. Make sure that you create the AccBar plot from an array of BarPlot objects.(Class='.$c.')');
68
            }
69
            $this->plots[$i]->DoLegend($graph);
70
        }
71
    }
72
73
    public function Max()
74
    {
75
        list($xmax) = $this->plots[0]->Max();
76
        $nmax       = 0;
77
        for ($i = 0; $i < safe_count($this->plots); ++$i) {
78
            $n       = safe_count($this->plots[$i]->coords[0]);
79
            $nmax    = max($nmax, $n);
80
            list($x) = $this->plots[$i]->Max();
81
            $xmax    = max($xmax, $x);
82
        }
83
        for ($i = 0; $i < $nmax; ++$i) {
84
            // Get y-value for bar $i by adding the
85
            // individual bars from all the plots added.
86
            // It would be wrong to just add the
87
            // individual plots max y-value since that
88
            // would in most cases give to large y-value.
89
            $y = 0;
90
            if (!isset($this->plots[0]->coords[0][$i])) {
91
                Util\JpGraphError::RaiseL(2014);
92
            }
93
            if ($this->plots[0]->coords[0][$i] > 0) {
94
                $y = $this->plots[0]->coords[0][$i];
95
            }
96
97
            for ($j = 1; $j < $this->nbrplots; ++$j) {
98
                if (!isset($this->plots[$j]->coords[0][$i])) {
99
                    Util\JpGraphError::RaiseL(2014);
100
                }
101
                if ($this->plots[$j]->coords[0][$i] > 0) {
102
                    $y += $this->plots[$j]->coords[0][$i];
103
                }
104
            }
105
            $ymax[$i] = $y;
106
        }
107
        $ymax = max($ymax);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ymax does not seem to be defined for all execution paths leading up to this point.
Loading history...
108
109
        // Bar always start at baseline
110
        if ($ymax <= $this->ybase) {
111
            $ymax = $this->ybase;
112
        }
113
114
        return [$xmax, $ymax];
115
    }
116
117
    public function Min()
118
    {
119
        $nmax                 = 0;
120
        list($xmin, $ysetmin) = $this->plots[0]->Min();
121
        for ($i = 0; $i < safe_count($this->plots); ++$i) {
122
            $n           = safe_count($this->plots[$i]->coords[0]);
123
            $nmax        = max($nmax, $n);
124
            list($x, $y) = $this->plots[$i]->Min();
125
            $xmin        = min($xmin, $x);
126
            $ysetmin     = min($y, $ysetmin);
127
        }
128
        for ($i = 0; $i < $nmax; ++$i) {
129
            // Get y-value for bar $i by adding the
130
            // individual bars from all the plots added.
131
            // It would be wrong to just add the
132
            // individual plots max y-value since that
133
            // would in most cases give to large y-value.
134
            $y = 0;
135
            if ($this->plots[0]->coords[0][$i] < 0) {
136
                $y = $this->plots[0]->coords[0][$i];
137
            }
138
139
            for ($j = 1; $j < $this->nbrplots; ++$j) {
140
                if ($this->plots[$j]->coords[0][$i] < 0) {
141
                    $y += $this->plots[$j]->coords[0][$i];
142
                }
143
            }
144
            $ymin[$i] = $y;
145
        }
146
        $ymin = min($ysetmin, min($ymin));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ymin does not seem to be defined for all execution paths leading up to this point.
Loading history...
147
        // Bar always start at baseline
148
        if ($ymin >= $this->ybase) {
149
            $ymin = $this->ybase;
150
        }
151
152
        return [$xmin, $ymin];
153
    }
154
155
    // Stroke acc bar plot
156
    public function Stroke($img, $xscale, $yscale)
157
    {
158
        $pattern = null;
159
        $img->SetLineWeight($this->weight);
160
        $grad = null;
161
        for ($i = 0; $i < $this->numpoints - 1; ++$i) {
162
            $accy     = 0;
163
            $accy_neg = 0;
164
            for ($j = 0; $j < $this->nbrplots; ++$j) {
165
                $img->SetColor($this->plots[$j]->color);
166
167
                if ($this->plots[$j]->coords[0][$i] >= 0) {
168
                    $yt    = $yscale->Translate($this->plots[$j]->coords[0][$i] + $accy);
169
                    $accyt = $yscale->Translate($accy);
170
                    $accy += $this->plots[$j]->coords[0][$i];
171
                } else {
172
                    //if ( $this->plots[$j]->coords[0][$i] < 0 || $accy_neg < 0 ) {
173
                    $yt    = $yscale->Translate($this->plots[$j]->coords[0][$i] + $accy_neg);
174
                    $accyt = $yscale->Translate($accy_neg);
175
                    $accy_neg += $this->plots[$j]->coords[0][$i];
176
                }
177
178
                $xt = $xscale->Translate($i);
179
180
                if ($this->abswidth > -1) {
181
                    $abswidth = $this->abswidth;
182
                } else {
183
                    $abswidth = round($this->width * $xscale->scale_factor, 0);
184
                }
185
186
                $pts = [$xt, $accyt, $xt, $yt, $xt + $abswidth, $yt, $xt + $abswidth, $accyt];
187
188
                if ($this->bar_shadow) {
189
                    $ssh = $this->bar_shadow_hsize;
190
                    $ssv = $this->bar_shadow_vsize;
191
192
                    // We must also differ if we are a positive or negative bar.
193
                    if ($j === 0) {
194
                        // This gets extra complicated since we have to
195
                        // see all plots to see if we are negative. It could
196
                        // for example be that all plots are 0 until the very
197
                        // last one. We therefore need to save the initial setup
198
                        // for both the negative and positive case
199
200
                        // In case the final bar is positive
201
                        $sp[0] = $pts[6] + 1;
202
                        $sp[1] = $pts[7];
203
                        $sp[2] = $pts[6] + $ssh;
204
                        $sp[3] = $pts[7] - $ssv;
205
206
                        // In case the final bar is negative
207
                        $nsp[0]  = $pts[0];
208
                        $nsp[1]  = $pts[1];
209
                        $nsp[2]  = $pts[0] + $ssh;
210
                        $nsp[3]  = $pts[1] - $ssv;
211
                        $nsp[4]  = $pts[6] + $ssh;
212
                        $nsp[5]  = $pts[7] - $ssv;
213
                        $nsp[10] = $pts[6] + 1;
214
                        $nsp[11] = $pts[7];
215
                    }
216
217
                    if ($j === $this->nbrplots - 1) {
218
                        // If this is the last plot of the bar and
219
                        // the total value is larger than 0 then we
220
                        // add the shadow.
221
                        if (is_array($this->bar_shadow_color)) {
222
                            $numcolors = safe_count($this->bar_shadow_color);
223
                            if ($numcolors == 0) {
224
                                Util\JpGraphError::RaiseL(2013); //('You have specified an empty array for shadow colors in the bar plot.');
225
                            }
226
                            $img->PushColor($this->bar_shadow_color[$i % $numcolors]);
227
                        } else {
228
                            $img->PushColor($this->bar_shadow_color);
229
                        }
230
231
                        if ($accy > 0) {
232
                            $sp[4]  = $pts[4] + $ssh;
233
                            $sp[5]  = $pts[5] - $ssv;
234
                            $sp[6]  = $pts[2] + $ssh;
235
                            $sp[7]  = $pts[3] - $ssv;
236
                            $sp[8]  = $pts[2];
237
                            $sp[9]  = $pts[3] - 1;
238
                            $sp[10] = $pts[4] + 1;
239
                            $sp[11] = $pts[5];
240
                            $img->FilledPolygon($sp, 4);
241
                        } elseif ($accy_neg < 0) {
242
                            $nsp[6] = $pts[4] + $ssh;
243
                            $nsp[7] = $pts[5] - $ssv;
244
                            $nsp[8] = $pts[4] + 1;
245
                            $nsp[9] = $pts[5];
246
                            $img->FilledPolygon($nsp, 4);
247
                        }
248
                        $img->PopColor();
249
                    }
250
                }
251
252
                // If value is NULL or 0, then don't draw a bar at all
253
                if ($this->plots[$j]->coords[0][$i] == 0) {
254
                    continue;
255
                }
256
257
                if ($this->plots[$j]->grad) {
258
                    if ($grad === null) {
259
                        $grad = new Gradient($img);
260
                    }
261
                    if (is_array($this->plots[$j]->grad_fromcolor)) {
262
                        // The first argument (grad_fromcolor) can be either an array or a single color. If it is an array
263
                        // then we have two choices. It can either a) be a single color specified as an Image\RGB triple or it can be
264
                        // an array to specify both (from, to style) for each individual bar. The way to know the difference is
265
                        // to investgate the first element. If this element is an integer [0,255] then we assume it is an Image\RGB
266
                        // triple.
267
                        $ng = safe_count($this->plots[$j]->grad_fromcolor);
268
                        if ($ng === 3) {
269
                            if (is_numeric($this->plots[$j]->grad_fromcolor[0]) && $this->plots[$j]->grad_fromcolor[0] > 0 &&
270
                                $this->plots[$j]->grad_fromcolor[0] < 256) {
271
                                // Image\RGB Triple
272
                                $fromcolor = $this->plots[$j]->grad_fromcolor;
273
                                $tocolor   = $this->plots[$j]->grad_tocolor;
274
                                $style     = $this->plots[$j]->grad_style;
275
                            } else {
276
                                $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0];
277
                                $tocolor   = $this->plots[$j]->grad_fromcolor[$i % $ng][1];
278
                                $style     = $this->plots[$j]->grad_fromcolor[$i % $ng][2];
279
                            }
280
                        } else {
281
                            $fromcolor = $this->plots[$j]->grad_fromcolor[$i % $ng][0];
282
                            $tocolor   = $this->plots[$j]->grad_fromcolor[$i % $ng][1];
283
                            $style     = $this->plots[$j]->grad_fromcolor[$i % $ng][2];
284
                        }
285
                        $grad->FilledRectangle(
286
                            $pts[2],
287
                            $pts[3],
288
                            $pts[6],
289
                            $pts[7],
290
                            $fromcolor,
291
                            $tocolor,
292
                            $style
293
                        );
294
                    } else {
295
                        $grad->FilledRectangle(
296
                            $pts[2],
297
                            $pts[3],
298
                            $pts[6],
299
                            $pts[7],
300
                            $this->plots[$j]->grad_fromcolor,
301
                            $this->plots[$j]->grad_tocolor,
302
                            $this->plots[$j]->grad_style
303
                        );
304
                    }
305
                } else {
306
                    if (is_array($this->plots[$j]->fill_color)) {
307
                        $numcolors = safe_count($this->plots[$j]->fill_color);
308
                        $fillcolor = $this->plots[$j]->fill_color[$i % $numcolors];
309
                        // If the bar is specified to be non filled then the fill color is false
310
                        if ($fillcolor !== false) {
311
                            $img->SetColor($this->plots[$j]->fill_color[$i % $numcolors]);
312
                        }
313
                    } else {
314
                        $fillcolor = $this->plots[$j]->fill_color;
315
                        if ($fillcolor !== false) {
316
                            $img->SetColor($this->plots[$j]->fill_color);
317
                        }
318
                    }
319
                    if ($fillcolor !== false) {
320
                        $img->FilledPolygon($pts);
321
                    }
322
                }
323
324
                $img->SetColor($this->plots[$j]->color);
325
326
                // Stroke the pattern
327
                if ($this->plots[$j]->iPattern > -1) {
328
                    if ($pattern === null) {
329
                        $pattern = new Graph\RectPatternFactory();
330
                    }
331
332
                    $prect = $pattern->Create($this->plots[$j]->iPattern, $this->plots[$j]->iPatternColor, 1);
333
                    $prect->SetDensity($this->plots[$j]->iPatternDensity);
334
                    if ($this->plots[$j]->coords[0][$i] < 0) {
335
                        $rx = $pts[0];
336
                        $ry = $pts[1];
337
                    } else {
338
                        $rx = $pts[2];
339
                        $ry = $pts[3];
340
                    }
341
                    $width  = abs($pts[4] - $pts[0]) + 1;
342
                    $height = abs($pts[1] - $pts[3]) + 1;
343
                    $prect->SetPos(new Util\Rectangle($rx, $ry, $width, $height));
344
                    $prect->Stroke($img);
345
                }
346
347
                // CSIM array
348
349
                if ($i < safe_count($this->plots[$j]->csimtargets)) {
350
                    // Create the client side image map
351
                    $rpts      = $img->ArrRotate($pts);
352
                    $csimcoord = round($rpts[0]) . ', ' . round($rpts[1]);
353
                    for ($k = 1; $k < 4; ++$k) {
354
                        $csimcoord .= ', ' . round($rpts[2 * $k]) . ', ' . round($rpts[2 * $k + 1]);
355
                    }
356
                    if (!empty($this->plots[$j]->csimtargets[$i])) {
357
                        $this->csimareas .= '<area shape="poly" coords="' . $csimcoord . '" ';
358
                        $this->csimareas .= ' href="' . $this->plots[$j]->csimtargets[$i] . '" ';
359
360
                        if (!empty($this->plots[$j]->csimwintargets[$i])) {
361
                            $this->csimareas .= ' target="' . $this->plots[$j]->csimwintargets[$i] . '" ';
362
                        }
363
364
                        $sval = '';
365
                        if (!empty($this->plots[$j]->csimalts[$i])) {
366
                            $sval = sprintf($this->plots[$j]->csimalts[$i], $this->plots[$j]->coords[0][$i]);
367
                            $this->csimareas .= " title=\"${sval}\" ";
368
                        }
369
                        $this->csimareas .= " alt=\"${sval}\" />\n";
370
                    }
371
                }
372
373
                $pts[] = $pts[0];
374
                $pts[] = $pts[1];
375
                $img->SetLineWeight($this->plots[$j]->weight);
376
                $img->Polygon($pts);
377
                $img->SetLineWeight(1);
378
            }
379
380
            // Daw potential bar around the entire accbar bar
381
            if ($this->weight > 0) {
382
                $y = $yscale->Translate(0);
383
                $img->SetColor($this->color);
384
                $img->SetLineWeight($this->weight);
385
                $img->Rectangle($pts[0], $y, $pts[6], $pts[5]);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pts does not seem to be defined for all execution paths leading up to this point.
Loading history...
386
            }
387
388
            // Draw labels for each acc.bar
389
390
            $x = $pts[2] + ($pts[4] - $pts[2]) / 2;
391
            if ($this->bar_shadow) {
392
                $x += $ssh;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ssh does not seem to be defined for all execution paths leading up to this point.
Loading history...
393
            }
394
395
            // First stroke the accumulated value for the entire bar
396
            // This value is always placed at the top/bottom of the bars
397
            if ($accy_neg < 0) {
398
                $y = $yscale->Translate($accy_neg);
399
                $this->value->Stroke($img, $accy_neg, $x, $y);
400
            } else {
401
                $y = $yscale->Translate($accy);
402
                $this->value->Stroke($img, $accy, $x, $y);
403
            }
404
405
            $accy     = 0;
406
            $accy_neg = 0;
407
            for ($j = 0; $j < $this->nbrplots; ++$j) {
408
                // We don't print 0 values in an accumulated bar plot
409
                if ($this->plots[$j]->coords[0][$i] == 0) {
410
                    continue;
411
                }
412
413
                if ($this->plots[$j]->coords[0][$i] > 0) {
414
                    $yt    = $yscale->Translate($this->plots[$j]->coords[0][$i] + $accy);
415
                    $accyt = $yscale->Translate($accy);
416
                    if ($this->plots[$j]->valuepos == 'center') {
417
                        $y = $accyt - ($accyt - $yt) / 2;
418
                    } elseif ($this->plots[$j]->valuepos == 'bottom') {
419
                        $y = $accyt;
420
                    } else {
421
                        // top or max
422
                        $y = $accyt - ($accyt - $yt);
423
                    }
424
                    $accy += $this->plots[$j]->coords[0][$i];
425
                    if ($this->plots[$j]->valuepos == 'center') {
426
                        $this->plots[$j]->value->SetAlign('center', 'center');
427
                        $this->plots[$j]->value->SetMargin(0);
428
                    } elseif ($this->plots[$j]->valuepos == 'bottom') {
429
                        $this->plots[$j]->value->SetAlign('center', 'bottom');
430
                        $this->plots[$j]->value->SetMargin(2);
431
                    } else {
432
                        $this->plots[$j]->value->SetAlign('center', 'top');
433
                        $this->plots[$j]->value->SetMargin(1);
434
                    }
435
                } else {
436
                    $yt    = $yscale->Translate($this->plots[$j]->coords[0][$i] + $accy_neg);
437
                    $accyt = $yscale->Translate($accy_neg);
438
                    $accy_neg += $this->plots[$j]->coords[0][$i];
439
                    if ($this->plots[$j]->valuepos == 'center') {
440
                        $y = $accyt - ($accyt - $yt) / 2;
441
                    } elseif ($this->plots[$j]->valuepos == 'bottom') {
442
                        $y = $accyt;
443
                    } else {
444
                        $y = $accyt - ($accyt - $yt);
445
                    }
446
                    if ($this->plots[$j]->valuepos == 'center') {
447
                        $this->plots[$j]->value->SetAlign('center', 'center');
448
                        $this->plots[$j]->value->SetMargin(0);
449
                    } elseif ($this->plots[$j]->valuepos == 'bottom') {
450
                        $this->plots[$j]->value->SetAlign('center', $j == 0 ? 'bottom' : 'top');
451
                        $this->plots[$j]->value->SetMargin(-2);
452
                    } else {
453
                        $this->plots[$j]->value->SetAlign('center', 'bottom');
454
                        $this->plots[$j]->value->SetMargin(-1);
455
                    }
456
                }
457
                $this->plots[$j]->value->Stroke($img, $this->plots[$j]->coords[0][$i], $x, $y);
458
            }
459
        }
460
461
        return true;
462
    }
463
} // @class
464