Passed
Push — master ( 3dc74f...81d6e9 )
by Felipe
04:17
created

Graph   F

Complexity

Total Complexity 564

Size/Duplication

Total Lines 2903
Duplicated Lines 0 %

Test Coverage

Coverage 67.58%

Importance

Changes 0
Metric Value
dl 0
loc 2903
ccs 1080
cts 1598
cp 0.6758
rs 0.6314
c 0
b 0
f 0
wmc 564

92 Methods

Rating   Name   Duplication   Size   Complexity  
D SetTickDensity() 0 43 9
A SetGridDepth() 0 3 1
C CheckCSIMCache() 0 48 8
A InitializeFrameAndMargin() 0 21 1
A SetYDeltaDist() 0 3 1
C GetTextsYMinMax() 0 25 7
A SetIconDepth() 0 3 1
A SetImgFormat() 0 3 1
C AddLine() 0 25 7
A SetupCache() 0 4 1
B SetBackgroundImage() 0 21 5
B Set90AndMargin() 0 16 7
A SetY2OrderBack() 0 3 1
A SetFrameBevel() 0 10 1
A SetMargin() 0 3 1
A SetCSIMImgAlt() 0 3 1
A SetBox() 0 5 1
A StrokeStore() 0 12 1
A SetBackgroundCFlag() 0 5 1
A SetAxisStyle() 0 3 1
A SetUserFont2() 0 3 1
A SetAngle() 0 3 1
A SetBackgroundImageMix() 0 3 1
D AdjustMarginsForTitles() 0 65 13
C GetXMinMax() 0 47 12
A SetFrame() 0 5 1
B SetYScale() 0 19 5
A SetClipping() 0 3 1
A SetColor() 0 3 1
A AddTable() 0 8 3
A GetCSIMImgHTML() 0 8 2
A Set3DPerspective() 0 11 1
A SetBackgroundGradient() 0 6 1
C GetURLArguments() 0 35 8
A SetMarginColor() 0 3 1
A SetUserFont1() 0 3 1
A SetUserFont() 0 3 1
C StrokeCSIM() 0 65 9
B SetY2Scale() 0 24 5
A SetBackgroundImagePos() 0 4 1
C GetTextsXMinMax() 0 25 7
A SetShadow() 0 7 1
A SetPlotGradient() 0 5 1
A SetUserFont3() 0 3 1
B AddText() 0 20 7
A GetHTMLImageMap() 0 7 1
A StrokeCSIMImage() 0 4 2
F GetCSIMareas() 0 58 15
C __construct() 0 70 10
A SetTextScaleOff() 0 4 1
A StrokePlotGrad() 0 12 2
B StrokeBands() 0 17 10
C GetLinesXMinMax() 0 25 7
C LoadBkgImage() 0 52 19
B ClearTheme() 0 27 3
C StrokeAxis() 0 85 10
A StrokePlotBox() 0 13 3
F Stroke() 0 284 58
C StrokeFrameBackground() 0 144 12
A SetTheme() 0 13 4
D doAutoScaleYnAxis() 0 81 22
A SetAxisLabelBackground() 0 7 1
C StrokeAxisLabelBackground() 0 78 20
D doPrestrokeAdjustments() 0 31 10
A SetTextScaleAbsCenterOff() 0 3 1
B hasLinePlotAndBarPlot() 0 19 6
B StrokePlotArea() 0 22 6
F StrokeTitles() 0 167 34
C GetLinesYMinMax() 0 29 8
B InitScaleConstants() 0 19 6
C doAutoScaleYAxis() 0 47 11
B StrokeTexts() 0 12 6
F GetPlotsYMinMax() 0 50 16
C DisplayClientSideaImageMapAreas() 0 26 7
A FillPlotArea() 0 10 1
A StrokeTables() 0 6 3
F doAutoscaleXAxis() 0 126 30
A SetTitleBackground() 0 9 1
A SetTitleBackgroundFillStyle() 0 5 1
B FillMarginArea() 0 25 2
C StrokeFrame() 0 49 11
A SetSupersampling() 0 7 2
A AddIcon() 0 8 3
A SetBackgroundCountryFlag() 0 5 1
A StrokeIcons() 0 5 2
B StrokeBackgroundGrad() 0 31 5
B AddBand() 0 21 7
C SetScale() 0 54 13
C Add() 0 31 11
A SetAlphaBlending() 0 3 1
C AddY2() 0 24 8
C AddY() 0 22 8

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
/**
4
 * JPGraph v3.6.15
5
 */
6
7
namespace Amenadiel\JpGraph\Graph;
8
9 1
require_once __DIR__ . '/../config.inc.php';
10
11
use Amenadiel\JpGraph\Image;
12
use Amenadiel\JpGraph\Plot;
13
use Amenadiel\JpGraph\Text;
14
use Amenadiel\JpGraph\Util;
15
16
/**
17
 * @class Graph
18
 * // Description: Main class to handle graphs
19
 */
20
class Graph
21
{
22
    public $gDateLocale;
23
    public $gJpgDateLocale;
24
    public $cache; // Cache object (singleton)
25
    public $img; // Img object (singleton)
26
    public $plots   = []; // Array of all plot object in the graph (for Y 1 axis)
27
    public $y2plots = []; // Array of all plot object in the graph (for Y 2 axis)
28
    public $ynplots = [];
29
    public $xscale; // X Scale object (could be instance of LinearScale or LogScale
30
    public $yscale;
31
    public $y2scale;
32
    public $ynscale = [];
33
    public $iIcons  = []; // Array of Icons to add to
34
    public $cache_name; // File name to be used for the current graph in the cache directory
35
    public $xgrid; // X Grid object (linear or logarithmic)
36
    public $ygrid;
37
    public $y2grid; //dito for Y
38
    public $doframe;
39
    public $frame_color;
40
    public $frame_weight; // Frame around graph
41
    public $boxed        = false;
42
    public $box_color    = 'black';
43
    public $box_weight   = 1; // Box around plot area
44
    public $doshadow     = false;
45
    public $shadow_width = 4;
46
    public $shadow_color = '[email protected]'; // Shadow for graph
47
    public $xaxis; // X-axis (instane of Axis class)
48
    public $yaxis;
49
    public $y2axis;
50
    public $ynaxis = []; // Y axis (instance of Axis class)
51
    public $margin_color; // Margin color of graph
52
    public $plotarea_color = [255, 255, 255]; // Plot area color
53
    public $title;
54
    public $subtitle;
55
    public $subsubtitle; // Title and subtitle(s) text object
56
    public $axtype = 'linlin'; // Type of axis
57
    public $xtick_factor;
58
    public $ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width
59
    public $texts;
60
    public $y2texts; // Text object to ge shown in the graph
61
    public $lines;
62
    public $y2lines;
63
    public $bands;
64
    public $y2bands;
65
    public $text_scale_off          = 0;
66
    public $text_scale_abscenteroff = -1; // Text scale in fractions and for centering bars
67
    public $background_image        = '';
68
    public $background_image_type   = -1;
69
    public $background_image_format = 'png';
70
    public $background_image_bright = 0;
71
    public $background_image_contr  = 0;
72
    public $background_image_sat    = 0;
73
    public $background_image_xpos   = 0;
74
    public $background_image_ypos   = 0;
75
    public $image_bright            = 0;
76
    public $image_contr             = 0;
77
    public $image_sat               = 0;
78
    public $inline;
79
    public $showcsim     = 0;
80
    public $csimcolor    = 'red'; //debug stuff, draw the csim boundaris on the image if <>0
81
    public $grid_depth   = DEPTH_BACK; // Draw grid under all plots as default
82
    public $iAxisStyle   = AXSTYLE_SIMPLE;
83
    public $iCSIMdisplay = false;
84
    public $iHasStroked  = false;
85
    public $footer;
86
    public $csimcachename    = '';
87
    public $csimcachetimeout = 0;
88
    public $iCSIMImgAlt      = '';
89
    public $iDoClipping      = false;
90
    public $y2orderback      = true;
91
    public $tabtitle;
92
    public $bkg_gradtype   = -1;
93
    public $bkg_gradstyle  = BGRAD_MARGIN;
94
    public $bkg_gradfrom   = 'navy';
95
    public $bkg_gradto     = 'silver';
96
    public $plot_gradtype  = -1;
97
    public $plot_gradstyle = BGRAD_MARGIN;
98
    public $plot_gradfrom  = 'silver';
99
    public $plot_gradto    = 'navy';
100
101
    public $titlebackground       = false;
102
    public $titlebackground_color = 'lightblue';
103
    public $titlebackground_style = 1;
104
    public $titlebackground_framecolor;
105
    public $titlebackground_framestyle;
106
    public $titlebackground_frameweight;
107
    public $titlebackground_bevelheight;
108
    public $titlebkg_fillstyle = TITLEBKG_FILLSTYLE_SOLID;
109
    public $titlebkg_scolor1   = 'black';
110
    public $titlebkg_scolor2   = 'white';
111
    public $framebevel;
112
    public $framebeveldepth;
113
    public $framebevelborder;
114
    public $framebevelbordercolor;
115
    public $framebevelcolor1;
116
    public $framebevelcolor2;
117
    public $background_image_mix  = 100;
118
    public $background_cflag      = '';
119
    public $background_cflag_type = BGIMG_FILLPLOT;
120
    public $background_cflag_mix  = 100;
121
    public $iImgTrans             = false;
122
    public $iImgTransHorizon      = 100;
123
    public $iImgTransSkewDist     = 150;
124
    public $iImgTransDirection    = 1;
125
    public $iImgTransMinSize      = true;
126
    public $iImgTransFillColor    = 'white';
127
    public $iImgTransHighQ        = false;
128
    public $iImgTransBorder       = false;
129
    public $iImgTransHorizonPos   = 0.5;
130
    public $legend;
131
    public $graph_theme;
132
    protected $iYAxisDeltaPos       = 50;
133
    protected $iIconDepth           = DEPTH_BACK;
134
    protected $iAxisLblBgType       = 0;
135
    protected $iXAxisLblBgFillColor = 'lightgray';
136
    protected $iXAxisLblBgColor     = 'black';
137
    protected $iYAxisLblBgFillColor = 'lightgray';
138
    protected $iYAxisLblBgColor     = 'black';
139
    protected $iTables;
140
141
    protected $isRunningClear = false;
142
    protected $inputValues;
143
    protected $isAfterSetScale = false;
144
145
    // aWIdth   Width in pixels of image
146
    // aHeight   Height in pixels of image
147
    // aCachedName Name for image file in cache directory
148
    // aTimeOut  Timeout in minutes for image in cache
149
    // aInline  If true the image is streamed back in the call to Stroke()
150
    //   If false the image is just created in the cache
151 18
    public function __construct($aWidth = 300, $aHeight = 200, $aCachedName = '', $aTimeout = 0, $aInline = true)
152
    {
153 18
        $this->gDateLocale    = new Util\DateLocale();
154 18
        $this->gJpgDateLocale = new Util\DateLocale();
155 18
        if (!is_numeric($aWidth) || !is_numeric($aHeight)) {
156
            Util\JpGraphError::RaiseL(25008); //('Image width/height argument in Graph::Graph() must be numeric');
157
        }
158
159
        // Initialize frame and margin
160 18
        $this->InitializeFrameAndMargin();
161
162
        // Automatically generate the image file name based on the name of the script that
163
        // generates the graph
164 18
        if ($aCachedName == 'auto') {
165 2
            $aCachedName = Util\Helper::GenImgName();
166
        }
167
168
        // Should the image be streamed back to the browser or only to the cache?
169 18
        $this->inline = $aInline;
170
171 18
        $this->img   = new Image\RotImage($aWidth, $aHeight);
172 18
        $this->cache = new Image\ImgStreamCache();
173
174
        // Window doesn't like '?' in the file name so replace it with an '_'
175 18
        $aCachedName = str_replace('?', '_', $aCachedName);
176 18
        $this->SetupCache($aCachedName, $aTimeout);
177
178 18
        $this->title = new Text\Text();
179 18
        $this->title->ParagraphAlign('center');
180 18
        $this->title->SetFont(FF_DEFAULT, FS_NORMAL); //FF_FONT2, FS_BOLD
181 18
        $this->title->SetMargin(5);
182 18
        $this->title->SetAlign('center');
183
184 18
        $this->subtitle = new Text\Text();
185 18
        $this->subtitle->ParagraphAlign('center');
186 18
        $this->subtitle->SetMargin(3);
187 18
        $this->subtitle->SetAlign('center');
188
189 18
        $this->subsubtitle = new Text\Text();
190 18
        $this->subsubtitle->ParagraphAlign('center');
191 18
        $this->subsubtitle->SetMargin(3);
192 18
        $this->subsubtitle->SetAlign('center');
193
194 18
        $this->legend = new Legend();
195 18
        $this->footer = new Image\Footer();
196
197
        // If the cached version exist just read it directly from the
198
        // cache, stream it back to browser and exit
199 18
        if ($aCachedName != '' && READ_CACHE && $aInline) {
200 2
            if ($this->cache->GetAndStream($this->img, $aCachedName)) {
201
                exit();
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
202
            }
203
        }
204
205 18
        $this->SetTickDensity(); // Normal density
206
207 18
        $this->tabtitle = new Text\GraphTabTitle();
208
209 18
        if (!$this->isRunningClear) {
210 18
            $this->inputValues                = [];
211 18
            $this->inputValues['aWidth']      = $aWidth;
212 18
            $this->inputValues['aHeight']     = $aHeight;
213 18
            $this->inputValues['aCachedName'] = $aCachedName;
214 18
            $this->inputValues['aTimeout']    = $aTimeout;
215 18
            $this->inputValues['aInline']     = $aInline;
216
217 18
            $theme_class = '\Amenadiel\JpGraph\Themes\\' . DEFAULT_THEME_CLASS;
218
219 18
            if (class_exists($theme_class)) {
220 18
                $this->graph_theme = new $theme_class();
221
            }
222
        }
223 18
    }
224
225 18
    public function InitializeFrameAndMargin()
226
    {
227 18
        $this->doframe      = true;
228 18
        $this->frame_color  = 'black';
229 18
        $this->frame_weight = 1;
230
231 18
        $this->titlebackground_framecolor  = 'blue';
232 18
        $this->titlebackground_framestyle  = 2;
233 18
        $this->titlebackground_frameweight = 1;
234 18
        $this->titlebackground_bevelheight = 3;
235 18
        $this->titlebkg_fillstyle          = TITLEBKG_FILLSTYLE_SOLID;
236 18
        $this->titlebkg_scolor1            = 'black';
237 18
        $this->titlebkg_scolor2            = 'white';
238 18
        $this->framebevel                  = false;
239 18
        $this->framebeveldepth             = 2;
240 18
        $this->framebevelborder            = false;
241 18
        $this->framebevelbordercolor       = 'black';
242 18
        $this->framebevelcolor1            = '[email protected]';
243 18
        $this->framebevelcolor2            = '[email protected]';
244
245 18
        $this->margin_color = [250, 250, 250];
246 18
    }
247
248 18
    public function SetupCache($aFilename, $aTimeout = 60)
249
    {
250 18
        $this->cache_name = $aFilename;
251 18
        $this->cache->SetTimeOut($aTimeout);
252 18
    }
253
254
    // Enable final image perspective transformation
255
    public function Set3DPerspective($aDir = 1, $aHorizon = 100, $aSkewDist = 120, $aQuality = false, $aFillColor = '#FFFFFF', $aBorder = false, $aMinSize = true, $aHorizonPos = 0.5)
256
    {
257
        $this->iImgTrans           = true;
258
        $this->iImgTransHorizon    = $aHorizon;
259
        $this->iImgTransSkewDist   = $aSkewDist;
260
        $this->iImgTransDirection  = $aDir;
261
        $this->iImgTransMinSize    = $aMinSize;
262
        $this->iImgTransFillColor  = $aFillColor;
263
        $this->iImgTransHighQ      = $aQuality;
264
        $this->iImgTransBorder     = $aBorder;
265
        $this->iImgTransHorizonPos = $aHorizonPos;
266
    }
267
268
    public function SetUserFont($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
269
    {
270
        $this->img->ttf->SetUserFont($aNormal, $aBold, $aItalic, $aBoldIt);
271
    }
272
273
    public function SetUserFont1($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
274
    {
275
        $this->img->ttf->SetUserFont1($aNormal, $aBold, $aItalic, $aBoldIt);
276
    }
277
278
    public function SetUserFont2($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
279
    {
280
        $this->img->ttf->SetUserFont2($aNormal, $aBold, $aItalic, $aBoldIt);
281
    }
282
283
    public function SetUserFont3($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
284
    {
285
        $this->img->ttf->SetUserFont3($aNormal, $aBold, $aItalic, $aBoldIt);
286
    }
287
288
    // Set Image format and optional quality
289
    public function SetImgFormat($aFormat, $aQuality = 75)
290
    {
291
        $this->img->SetImgFormat($aFormat, $aQuality);
292
    }
293
294
    // Should the grid be in front or back of the plot?
295 2
    public function SetGridDepth($aDepth)
296
    {
297 2
        $this->grid_depth = $aDepth;
298 2
    }
299
300
    public function SetIconDepth($aDepth)
301
    {
302
        $this->iIconDepth = $aDepth;
303
    }
304
305
    // Specify graph angle 0-360 degrees.
306 3
    public function SetAngle($aAngle)
307
    {
308 3
        $this->img->SetAngle($aAngle);
309 3
    }
310
311 1
    public function SetAlphaBlending($aFlg = true)
312
    {
313 1
        $this->img->SetAlphaBlending($aFlg);
314 1
    }
315
316
    // Shortcut to image margin
317 15
    public function SetMargin($lm, $rm, $tm, $bm)
318
    {
319 15
        $this->img->SetMargin($lm, $rm, $tm, $bm);
320 15
    }
321
322
    public function SetY2OrderBack($aBack = true)
323
    {
324
        $this->y2orderback = $aBack;
325
    }
326
327
    // Rotate the graph 90 degrees and set the margin
328
    // when we have done a 90 degree rotation
329 2
    public function Set90AndMargin($lm = 0, $rm = 0, $tm = 0, $bm = 0)
330
    {
331 2
        $lm = $lm == 0 ? floor(0.2 * $this->img->width) : $lm;
332 2
        $rm = $rm == 0 ? floor(0.1 * $this->img->width) : $rm;
333 2
        $tm = $tm == 0 ? floor(0.2 * $this->img->height) : $tm;
334 2
        $bm = $bm == 0 ? floor(0.1 * $this->img->height) : $bm;
335
336 2
        $adj = ($this->img->height - $this->img->width) / 2;
337 2
        $this->img->SetMargin($tm - $adj, $bm - $adj, $rm + $adj, $lm + $adj);
338 2
        $this->img->SetCenter(floor($this->img->width / 2), floor($this->img->height / 2));
339 2
        $this->SetAngle(90);
340 2
        if (empty($this->yaxis) || empty($this->xaxis)) {
341
            Util\JpGraphError::RaiseL(25009); //('You must specify what scale to use with a call to Graph::SetScale()');
342
        }
343 2
        $this->xaxis->SetLabelAlign('right', 'center');
344 2
        $this->yaxis->SetLabelAlign('center', 'bottom');
345 2
    }
346
347 2
    public function SetClipping($aFlg = true)
348
    {
349 2
        $this->iDoClipping = $aFlg;
350 2
    }
351
352
    // Add a plot object to the graph
353 14
    public function Add($aPlot)
354
    {
355 14
        if ($aPlot == null) {
356
            Util\JpGraphError::RaiseL(25010); //("Graph::Add() You tried to add a null plot to the graph.");
357
        }
358 14
        if (is_array($aPlot) && count($aPlot) > 0) {
359 3
            $cl = $aPlot[0];
360
        } else {
361 14
            $cl = $aPlot;
362
        }
363
364 14
        if ($cl instanceof Text) {
365
            $this->AddText($aPlot);
366 14
        } elseif (($cl instanceof Plot\PlotLine)) {
367 2
            $this->AddLine($aPlot);
368 14
        } elseif (($cl instanceof Plot\PlotBand)) {
369 1
            $this->AddBand($aPlot);
370 14
        } elseif (($cl instanceof Plot\IconPlot)) {
371
            $this->AddIcon($aPlot);
372 14
        } elseif (($cl instanceof Text\GTextTable)) {
373
            $this->AddTable($aPlot);
374
        } else {
375 14
            if (is_array($aPlot)) {
376 2
                $this->plots = array_merge($this->plots, $aPlot);
377
            } else {
378 14
                $this->plots[] = $aPlot;
379
            }
380
        }
381
382 14
        if ($this->graph_theme) {
383 14
            $this->graph_theme->SetupPlot($aPlot);
384
        }
385 14
    }
386
387
    public function AddTable($aTable)
388
    {
389
        if (is_array($aTable)) {
390
            for ($i = 0; $i < count($aTable); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
391
                $this->iTables[] = $aTable[$i];
392
            }
393
        } else {
394
            $this->iTables[] = $aTable;
395
        }
396
    }
397
398 1
    public function AddIcon($aIcon)
399
    {
400 1
        if (is_array($aIcon)) {
401
            for ($i = 0; $i < count($aIcon); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
402
                $this->iIcons[] = $aIcon[$i];
403
            }
404
        } else {
405 1
            $this->iIcons[] = $aIcon;
406
        }
407 1
    }
408
409
    // Add plot to second Y-scale
410 5
    public function AddY2($aPlot)
411
    {
412 5
        if ($aPlot == null) {
413
            Util\JpGraphError::RaiseL(25011); //("Graph::AddY2() You tried to add a null plot to the graph.");
414
        }
415
416 5
        if (is_array($aPlot) && count($aPlot) > 0) {
417
            $cl = $aPlot[0];
418
        } else {
419 5
            $cl = $aPlot;
420
        }
421
422 5
        if ($cl instanceof Text) {
423
            $this->AddText($aPlot, true);
424 5
        } elseif (($cl instanceof Plot\PlotLine)) {
425
            $this->AddLine($aPlot, true);
426 5
        } elseif (($cl instanceof Plot\PlotBand)) {
427
            $this->AddBand($aPlot, true);
428
        } else {
429 5
            $this->y2plots[] = $aPlot;
430
        }
431
432 5
        if ($this->graph_theme) {
433 5
            $this->graph_theme->SetupPlot($aPlot);
434
        }
435 5
    }
436
437
    // Add plot to the extra Y-axises
438 1
    public function AddY($aN, $aPlot)
439
    {
440 1
        if ($aPlot == null) {
441
            Util\JpGraphError::RaiseL(25012); //("Graph::AddYN() You tried to add a null plot to the graph.");
442
        }
443
444 1
        if (is_array($aPlot) && count($aPlot) > 0) {
445
            $cl = $aPlot[0];
446
        } else {
447 1
            $cl = $aPlot;
448
        }
449
450 1
        if (($cl instanceof Text\Text) ||
451 1
            ($cl instanceof Plot\PlotLine) ||
452 1
            ($cl instanceof Plot\PlotBand)) {
453
            JpGraph::RaiseL(25013); //('You can only add standard plots to multiple Y-axis');
1 ignored issue
show
Bug introduced by
The type Amenadiel\JpGraph\Graph\JpGraph was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
454
        } else {
455 1
            $this->ynplots[$aN][] = $aPlot;
456
        }
457
458 1
        if ($this->graph_theme) {
459 1
            $this->graph_theme->SetupPlot($aPlot);
460
        }
461 1
    }
462
463
    // Add text object to the graph
464 2
    public function AddText($aTxt, $aToY2 = false)
465
    {
466 2
        if ($aTxt == null) {
467
            Util\JpGraphError::RaiseL(25014); //("Graph::AddText() You tried to add a null text to the graph.");
468
        }
469 2
        if ($aToY2) {
470
            if (is_array($aTxt)) {
471
                for ($i = 0; $i < count($aTxt); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
472
                    $this->y2texts[] = $aTxt[$i];
473
                }
474
            } else {
475
                $this->y2texts[] = $aTxt;
476
            }
477
        } else {
478 2
            if (is_array($aTxt)) {
479
                for ($i = 0; $i < count($aTxt); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
480
                    $this->texts[] = $aTxt[$i];
481
                }
482
            } else {
483 2
                $this->texts[] = $aTxt;
484
            }
485
        }
486 2
    }
487
488
    // Add a line object (class PlotLine) to the graph
489 3
    public function AddLine($aLine, $aToY2 = false)
490
    {
491 3
        if ($aLine == null) {
492
            Util\JpGraphError::RaiseL(25015); //("Graph::AddLine() You tried to add a null line to the graph.");
493
        }
494
495 3
        if ($aToY2) {
496
            if (is_array($aLine)) {
497
                for ($i = 0; $i < count($aLine); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
498
                    //$this->y2lines[]=$aLine[$i];
499
                    $this->y2plots[] = $aLine[$i];
500
                }
501
            } else {
502
                //$this->y2lines[] = $aLine;
503
                $this->y2plots[] = $aLine;
504
            }
505
        } else {
506 3
            if (is_array($aLine)) {
507
                for ($i = 0; $i < count($aLine); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
508
                    //$this->lines[]=$aLine[$i];
509
                    $this->plots[] = $aLine[$i];
510
                }
511
            } else {
512
                //$this->lines[] = $aLine;
513 3
                $this->plots[] = $aLine;
514
            }
515
        }
516 3
    }
517
518
    // Add vertical or horizontal band
519 2
    public function AddBand($aBand, $aToY2 = false)
520
    {
521 2
        if ($aBand == null) {
522
            Util\JpGraphError::RaiseL(25016); //(" Graph::AddBand() You tried to add a null band to the graph.");
523
        }
524
525 2
        if ($aToY2) {
526
            if (is_array($aBand)) {
527
                for ($i = 0; $i < count($aBand); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
528
                    $this->y2bands[] = $aBand[$i];
529
                }
530
            } else {
531
                $this->y2bands[] = $aBand;
532
            }
533
        } else {
534 2
            if (is_array($aBand)) {
535 1
                for ($i = 0; $i < count($aBand); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
536 1
                    $this->bands[] = $aBand[$i];
537
                }
538
            } else {
539 2
                $this->bands[] = $aBand;
540
            }
541
        }
542 2
    }
543
544 1
    public function SetPlotGradient($aFrom = 'navy', $aTo = 'silver', $aGradType = 2)
545
    {
546 1
        $this->plot_gradtype = $aGradType;
547 1
        $this->plot_gradfrom = $aFrom;
548 1
        $this->plot_gradto   = $aTo;
549 1
    }
550
551 4
    public function SetBackgroundGradient($aFrom = 'navy', $aTo = 'silver', $aGradType = 2, $aStyle = BGRAD_FRAME)
552
    {
553 4
        $this->bkg_gradtype  = $aGradType;
554 4
        $this->bkg_gradstyle = $aStyle;
555 4
        $this->bkg_gradfrom  = $aFrom;
556 4
        $this->bkg_gradto    = $aTo;
557 4
    }
558
559
    // Set a country flag in the background
560 1
    public function SetBackgroundCFlag($aName, $aBgType = BGIMG_FILLPLOT, $aMix = 100)
561
    {
562 1
        $this->background_cflag      = $aName;
563 1
        $this->background_cflag_type = $aBgType;
564 1
        $this->background_cflag_mix  = $aMix;
565 1
    }
566
567
    // Alias for the above method
568 1
    public function SetBackgroundCountryFlag($aName, $aBgType = BGIMG_FILLPLOT, $aMix = 100)
569
    {
570 1
        $this->background_cflag      = $aName;
571 1
        $this->background_cflag_type = $aBgType;
572 1
        $this->background_cflag_mix  = $aMix;
573 1
    }
574
575
    // Specify a background image
576 5
    public function SetBackgroundImage($aFileName, $aBgType = BGIMG_FILLPLOT, $aImgFormat = 'auto')
577
    {
578
        // Get extension to determine image type
579 5
        if ($aImgFormat == 'auto') {
580 5
            $e = explode('.', $aFileName);
581 5
            if (!$e) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $e of type string[] is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
582
                Util\JpGraphError::RaiseL(25018, $aFileName); //('Incorrect file name for Graph::SetBackgroundImage() : '.$aFileName.' Must have a valid image extension (jpg,gif,png) when using autodetection of image type');
583
            }
584
585 5
            $valid_formats = ['png', 'jpg', 'gif'];
586 5
            $aImgFormat    = strtolower($e[count($e) - 1]);
587 5
            if ($aImgFormat == 'jpeg') {
588
                $aImgFormat = 'jpg';
589 5
            } elseif (!in_array($aImgFormat, $valid_formats, true)) {
590
                Util\JpGraphError::RaiseL(25019, $aImgFormat); //('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
591
            }
592
        }
593
594 5
        $this->background_image        = $aFileName;
595 5
        $this->background_image_type   = $aBgType;
596 5
        $this->background_image_format = $aImgFormat;
597 5
    }
598
599 1
    public function SetBackgroundImageMix($aMix)
600
    {
601 1
        $this->background_image_mix = $aMix;
602 1
    }
603
604
    // Adjust background image position
605
    public function SetBackgroundImagePos($aXpos, $aYpos)
606
    {
607
        $this->background_image_xpos = $aXpos;
608
        $this->background_image_ypos = $aYpos;
609
    }
610
611
    // Specify axis style (boxed or single)
612 4
    public function SetAxisStyle($aStyle)
613
    {
614 4
        $this->iAxisStyle = $aStyle;
615 4
    }
616
617
    // Set a frame around the plot area
618 15
    public function SetBox($aDrawPlotFrame = true, $aPlotFrameColor = [0, 0, 0], $aPlotFrameWeight = 1)
619
    {
620 15
        $this->boxed      = $aDrawPlotFrame;
621 15
        $this->box_weight = $aPlotFrameWeight;
622 15
        $this->box_color  = $aPlotFrameColor;
623 15
    }
624
625
    // Specify color for the plotarea (not the margins)
626 6
    public function SetColor($aColor)
627
    {
628 6
        $this->plotarea_color = $aColor;
629 6
    }
630
631
    // Specify color for the margins (all areas outside the plotarea)
632 18
    public function SetMarginColor($aColor)
633
    {
634 18
        $this->margin_color = $aColor;
635 18
    }
636
637
    // Set a frame around the entire image
638 17
    public function SetFrame($aDrawImgFrame = true, $aImgFrameColor = [0, 0, 0], $aImgFrameWeight = 1)
639
    {
640 17
        $this->doframe      = $aDrawImgFrame;
641 17
        $this->frame_color  = $aImgFrameColor;
642 17
        $this->frame_weight = $aImgFrameWeight;
643 17
    }
644
645
    public function SetFrameBevel($aDepth = 3, $aBorder = false, $aBorderColor = 'black', $aColor1 = '[email protected]', $aColor2 = '[email protected]', $aFlg = true)
646
    {
647
        $this->framebevel            = $aFlg;
648
        $this->framebeveldepth       = $aDepth;
649
        $this->framebevelborder      = $aBorder;
650
        $this->framebevelbordercolor = $aBorderColor;
651
        $this->framebevelcolor1      = $aColor1;
652
        $this->framebevelcolor2      = $aColor2;
653
654
        $this->doshadow = false;
655
    }
656
657
    // Set the shadow around the whole image
658 12
    public function SetShadow($aShowShadow = true, $aShadowWidth = 5, $aShadowColor = 'darkgray')
659
    {
660 12
        $this->doshadow     = $aShowShadow;
661 12
        $this->shadow_color = $aShadowColor;
662 12
        $this->shadow_width = $aShadowWidth;
663 12
        $this->footer->iBottomMargin += $aShadowWidth;
664 12
        $this->footer->iRightMargin += $aShadowWidth;
665 12
    }
666
667
    // Specify x,y scale. Note that if you manually specify the scale
668
    // you must also specify the tick distance with a call to Ticks::Set()
669 14
    public function SetScale($aAxisType, $aYMin = 1, $aYMax = 1, $aXMin = 1, $aXMax = 1)
670
    {
671 14
        $this->axtype = $aAxisType;
672
673 14
        if ($aYMax < $aYMin || $aXMax < $aXMin) {
674
            Util\JpGraphError::RaiseL(25020); //('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
675
        }
676
677 14
        $yt = substr($aAxisType, -3, 3);
678 14
        if ($yt == 'lin') {
679 13
            $this->yscale = new LinearScale($aYMin, $aYMax);
680 5
        } elseif ($yt == 'int') {
681 3
            $this->yscale = new LinearScale($aYMin, $aYMax);
682 3
            $this->yscale->SetIntScale();
683 3
        } elseif ($yt == 'log') {
684 3
            $this->yscale = new LogScale($aYMin, $aYMax);
685
        } else {
686
            Util\JpGraphError::RaiseL(25021, $aAxisType); //("Unknown scale specification for Y-scale. ($aAxisType)");
687
        }
688
689 14
        $xt = substr($aAxisType, 0, 3);
690 14
        if ($xt == 'lin' || $xt == 'tex') {
691 13
            $this->xscale            = new LinearScale($aXMin, $aXMax, 'x');
692 13
            $this->xscale->textscale = ($xt == 'tex');
693 7
        } elseif ($xt == 'int') {
694 7
            $this->xscale = new LinearScale($aXMin, $aXMax, 'x');
695 7
            $this->xscale->SetIntScale();
696 2
        } elseif ($xt == 'dat') {
697 1
            $this->xscale = new DateScale($aXMin, $aXMax, 'x');
698 1
        } elseif ($xt == 'log') {
699 1
            $this->xscale = new LogScale($aXMin, $aXMax, 'x');
700
        } else {
701
            Util\JpGraphError::RaiseL(25022, $aAxisType); //(" Unknown scale specification for X-scale. ($aAxisType)");
702
        }
703
704 14
        $this->xaxis = new Axis($this->img, $this->xscale);
705 14
        $this->yaxis = new Axis($this->img, $this->yscale);
706 14
        $this->xgrid = new Grid($this->xaxis);
707 14
        $this->ygrid = new Grid($this->yaxis);
708 14
        $this->ygrid->Show();
709
710 14
        if (!$this->isRunningClear) {
711 14
            $this->inputValues['aAxisType'] = $aAxisType;
712 14
            $this->inputValues['aYMin']     = $aYMin;
713 14
            $this->inputValues['aYMax']     = $aYMax;
714 14
            $this->inputValues['aXMin']     = $aXMin;
715 14
            $this->inputValues['aXMax']     = $aXMax;
716
717 14
            if ($this->graph_theme) {
718 14
                $this->graph_theme->ApplyGraph($this);
719
            }
720
        }
721
722 14
        $this->isAfterSetScale = true;
723 14
    }
724
725
    // Specify secondary Y scale
726 5
    public function SetY2Scale($aAxisType = 'lin', $aY2Min = 1, $aY2Max = 1)
727
    {
728 5
        if ($aAxisType == 'lin') {
729 5
            $this->y2scale = new LinearScale($aY2Min, $aY2Max);
730 1
        } elseif ($aAxisType == 'int') {
731
            $this->y2scale = new LinearScale($aY2Min, $aY2Max);
732
            $this->y2scale->SetIntScale();
733 1
        } elseif ($aAxisType == 'log') {
734 1
            $this->y2scale = new LogScale($aY2Min, $aY2Max);
735
        } else {
736
            Util\JpGraphError::RaiseL(25023, $aAxisType); //("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)");
737
        }
738
739 5
        $this->y2axis = new Axis($this->img, $this->y2scale);
740 5
        $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
741 5
        $this->y2axis->SetLabelSide(SIDE_RIGHT);
742 5
        $this->y2axis->SetPos('max');
743 5
        $this->y2axis->SetTitleSide(SIDE_RIGHT);
744
745
        // Deafult position is the max x-value
746 5
        $this->y2grid = new Grid($this->y2axis);
747
748 5
        if ($this->graph_theme) {
749 5
            $this->graph_theme->ApplyGraph($this);
750
        }
751 5
    }
752
753
    // Set the delta position (in pixels) between the multiple Y-axis
754
    public function SetYDeltaDist($aDist)
755
    {
756
        $this->iYAxisDeltaPos = $aDist;
757
    }
758
759
    // Specify secondary Y scale
760 1
    public function SetYScale($aN, $aAxisType = 'lin', $aYMin = 1, $aYMax = 1)
761
    {
762 1
        if ($aAxisType == 'lin') {
763 1
            $this->ynscale[$aN] = new LinearScale($aYMin, $aYMax);
764
        } elseif ($aAxisType == 'int') {
765
            $this->ynscale[$aN] = new LinearScale($aYMin, $aYMax);
766
            $this->ynscale[$aN]->SetIntScale();
767
        } elseif ($aAxisType == 'log') {
768
            $this->ynscale[$aN] = new LogScale($aYMin, $aYMax);
769
        } else {
770
            Util\JpGraphError::RaiseL(25024, $aAxisType); //("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)");
771
        }
772
773 1
        $this->ynaxis[$aN] = new Axis($this->img, $this->ynscale[$aN]);
774 1
        $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT);
775 1
        $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT);
776
777 1
        if ($this->graph_theme) {
778 1
            $this->graph_theme->ApplyGraph($this);
779
        }
780 1
    }
781
782
    // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'
783
    // The dividing factor have been determined heuristically according to my aesthetic
784
    // sense (or lack off) y.m.m.v !
785 18
    public function SetTickDensity($aYDensity = TICKD_NORMAL, $aXDensity = TICKD_NORMAL)
786
    {
787 18
        $this->xtick_factor = 30;
788 18
        $this->ytick_factor = 25;
789
        switch ($aYDensity) {
790 18
            case TICKD_DENSE:
791 1
                $this->ytick_factor = 12;
792
793 1
                break;
794 18
            case TICKD_NORMAL:
795 18
                $this->ytick_factor = 25;
796
797 18
                break;
798
            case TICKD_SPARSE:
799
                $this->ytick_factor = 40;
800
801
                break;
802
            case TICKD_VERYSPARSE:
803
                $this->ytick_factor = 100;
804
805
                break;
806
            default:
807
                Util\JpGraphError::RaiseL(25025, $densy); //("JpGraph: Unsupported Tick density: $densy");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $densy seems to be never defined.
Loading history...
808
        }
809
        switch ($aXDensity) {
810 18
            case TICKD_DENSE:
811
                $this->xtick_factor = 15;
812
813
                break;
814 18
            case TICKD_NORMAL:
815 18
                $this->xtick_factor = 30;
816
817 18
                break;
818
            case TICKD_SPARSE:
819
                $this->xtick_factor = 45;
820
821
                break;
822
            case TICKD_VERYSPARSE:
823
                $this->xtick_factor = 60;
824
825
                break;
826
            default:
827
                Util\JpGraphError::RaiseL(25025, $densx); //("JpGraph: Unsupported Tick density: $densx");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $densx seems to be never defined.
Loading history...
828
        }
829 18
    }
830
831
    // Get a string of all image map areas
832
    public function GetCSIMareas()
833
    {
834
        if (!$this->iHasStroked) {
835
            $this->Stroke(_CSIM_SPECIALFILE);
836
        }
837
838
        $csim = $this->title->GetCSIMAreas();
839
        $csim .= $this->subtitle->GetCSIMAreas();
840
        $csim .= $this->subsubtitle->GetCSIMAreas();
841
        $csim .= $this->legend->GetCSIMAreas();
842
843
        if ($this->y2axis != null) {
844
            $csim .= $this->y2axis->title->GetCSIMAreas();
845
        }
846
847
        if ($this->texts != null) {
848
            $n = count($this->texts);
849
            for ($i = 0; $i < $n; ++$i) {
850
                $csim .= $this->texts[$i]->GetCSIMAreas();
851
            }
852
        }
853
854
        if ($this->y2texts != null && $this->y2scale != null) {
855
            $n = count($this->y2texts);
856
            for ($i = 0; $i < $n; ++$i) {
857
                $csim .= $this->y2texts[$i]->GetCSIMAreas();
858
            }
859
        }
860
861
        if ($this->yaxis != null && $this->xaxis != null) {
862
            $csim .= $this->yaxis->title->GetCSIMAreas();
863
            $csim .= $this->xaxis->title->GetCSIMAreas();
864
        }
865
866
        $n = count($this->plots);
867
        for ($i = 0; $i < $n; ++$i) {
868
            $csim .= $this->plots[$i]->GetCSIMareas();
869
        }
870
871
        $n = count($this->y2plots);
872
        for ($i = 0; $i < $n; ++$i) {
873
            $csim .= $this->y2plots[$i]->GetCSIMareas();
874
        }
875
876
        $n = count($this->ynaxis);
877
        for ($i = 0; $i < $n; ++$i) {
878
            $m = count($this->ynplots[$i]);
879
            for ($j = 0; $j < $m; ++$j) {
880
                $csim .= $this->ynplots[$i][$j]->GetCSIMareas();
881
            }
882
        }
883
884
        $n = count($this->iTables);
885
        for ($i = 0; $i < $n; ++$i) {
886
            $csim .= $this->iTables[$i]->GetCSIMareas();
887
        }
888
889
        return $csim;
890
    }
891
892
    // Get a complete <MAP>..</MAP> tag for the final image map
893
    public function GetHTMLImageMap($aMapName)
894
    {
895
        $im = "<map name=\"${aMapName}\" id=\"${aMapName}\" >\n";
896
        $im .= $this->GetCSIMareas();
897
        $im .= '</map>';
898
899
        return $im;
900
    }
901
902
    public function CheckCSIMCache($aCacheName, $aTimeOut = 60)
903
    {
904
        global $_SERVER;
905
906
        if ($aCacheName == 'auto') {
907
            $aCacheName = basename($_SERVER['PHP_SELF']);
908
        }
909
910
        $urlarg                 = $this->GetURLArguments();
911
        $this->csimcachename    = CSIMCACHE_DIR . $aCacheName . $urlarg;
912
        $this->csimcachetimeout = $aTimeOut;
913
914
        // First determine if we need to check for a cached version
915
        // This differs from the standard cache in the sense that the
916
        // image and CSIM map HTML file is written relative to the directory
917
        // the script executes in and not the specified cache directory.
918
        // The reason for this is that the cache directory is not necessarily
919
        // accessible from the HTTP server.
920
        if ($this->csimcachename != '') {
921
            $dir      = dirname($this->csimcachename);
922
            $base     = basename($this->csimcachename);
923
            $base     = strtok($base, '.');
924
            $suffix   = strtok('.');
0 ignored issues
show
Unused Code introduced by
The assignment to $suffix is dead and can be removed.
Loading history...
925
            $basecsim = $dir . '/' . $base . '?' . $urlarg . '_csim_.html';
926
            $baseimg  = $dir . '/' . $base . '?' . $urlarg . '.' . $this->img->img_format;
927
928
            $timedout = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $timedout is dead and can be removed.
Loading history...
929
            // Does it exist at all ?
930
931
            if (file_exists($basecsim) && file_exists($baseimg)) {
932
                // Check that it hasn't timed out
933
                $diff = time() - filemtime($basecsim);
934
                if ($this->csimcachetimeout > 0 && ($diff > $this->csimcachetimeout * 60)) {
935
                    $timedout = true;
936
                    @unlink($basecsim);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition for unlink(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

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

936
                    /** @scrutinizer ignore-unhandled */ @unlink($basecsim);

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
937
                    @unlink($baseimg);
938
                } else {
939
                    if ($fh = @fopen($basecsim, 'r')) {
940
                        fpassthru($fh);
941
942
                        return true;
943
                    }
944
                    Util\JpGraphError::RaiseL(25027, $basecsim); //(" Can't open cached CSIM \"$basecsim\" for reading.");
945
                }
946
            }
947
        }
948
949
        return false;
950
    }
951
952
    // Build the argument string to be used with the csim images
953
    public static function GetURLArguments($aAddRecursiveBlocker = false)
954
    {
955
        if ($aAddRecursiveBlocker) {
956
            // This is a JPGRAPH internal defined that prevents
957
            // us from recursively coming here again
958
            $urlarg = _CSIM_DISPLAY . '=1';
959
        }
960
961
        // Now reconstruct any user URL argument
962
        reset($_GET);
963
        while (list($key, $value) = each($_GET)) {
0 ignored issues
show
Deprecated Code introduced by
The function each() has been deprecated: 7.2 ( Ignorable by Annotation )

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

963
        while (list($key, $value) = /** @scrutinizer ignore-deprecated */ each($_GET)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
964
            if (is_array($value)) {
965
                foreach ($value as $k => $v) {
966
                    $urlarg .= '&amp;' . $key . '%5B' . $k . '%5D=' . urlencode($v);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $urlarg does not seem to be defined for all execution paths leading up to this point.
Loading history...
967
                }
968
            } else {
969
                $urlarg .= '&amp;' . $key . '=' . urlencode($value);
970
            }
971
        }
972
973
        // It's not ideal to convert POST argument to GET arguments
974
        // but there is little else we can do. One idea for the
975
        // future might be recreate the POST header in case.
976
        reset($_POST);
977
        while (list($key, $value) = each($_POST)) {
0 ignored issues
show
Deprecated Code introduced by
The function each() has been deprecated: 7.2 ( Ignorable by Annotation )

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

977
        while (list($key, $value) = /** @scrutinizer ignore-deprecated */ each($_POST)) {

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
978
            if (is_array($value)) {
979
                foreach ($value as $k => $v) {
980
                    $urlarg .= '&amp;' . $key . '%5B' . $k . '%5D=' . urlencode($v);
981
                }
982
            } else {
983
                $urlarg .= '&amp;' . $key . '=' . urlencode($value);
984
            }
985
        }
986
987
        return $urlarg;
988
    }
989
990
    public function SetCSIMImgAlt($aAlt)
991
    {
992
        $this->iCSIMImgAlt = $aAlt;
993
    }
994
995
    public function StrokeCSIM($aScriptName = 'auto', $aCSIMName = '', $aBorder = 0)
996
    {
997
        if ($aCSIMName == '') {
998
            // create a random map name
999
            srand((float) microtime() * 1000000);
0 ignored issues
show
Bug introduced by
(double)microtime() * 1000000 of type double is incompatible with the type integer expected by parameter $seed of srand(). ( Ignorable by Annotation )

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

999
            srand(/** @scrutinizer ignore-type */ (float) microtime() * 1000000);
Loading history...
1000
            $r         = rand(0, 100000);
1001
            $aCSIMName = '__mapname' . $r . '__';
1002
        }
1003
1004
        if ($aScriptName == 'auto') {
1005
            $aScriptName = basename($_SERVER['PHP_SELF']);
1006
        }
1007
1008
        $urlarg = $this->GetURLArguments(true);
1009
1010
        if (empty($_GET[_CSIM_DISPLAY])) {
1011
            // First determine if we need to check for a cached version
1012
            // This differs from the standard cache in the sense that the
1013
            // image and CSIM map HTML file is written relative to the directory
1014
            // the script executes in and not the specified cache directory.
1015
            // The reason for this is that the cache directory is not necessarily
1016
            // accessible from the HTTP server.
1017
            if ($this->csimcachename != '') {
1018
                $dir      = dirname($this->csimcachename);
1019
                $base     = basename($this->csimcachename);
1020
                $base     = strtok($base, '.');
1021
                $suffix   = strtok('.');
0 ignored issues
show
Unused Code introduced by
The assignment to $suffix is dead and can be removed.
Loading history...
1022
                $basecsim = $dir . '/' . $base . '?' . $urlarg . '_csim_.html';
1023
                $baseimg  = $base . '?' . $urlarg . '.' . $this->img->img_format;
1024
1025
                // Check that apache can write to directory specified
1026
1027
                if (file_exists($dir) && !is_writeable($dir)) {
1028
                    Util\JpGraphError::RaiseL(25028, $dir); //('Apache/PHP does not have permission to write to the CSIM cache directory ('.$dir.'). Check permissions.');
1029
                }
1030
1031
                // Make sure directory exists
1032
                $this->cache->MakeDirs($dir);
1033
1034
                // Write the image file
1035
                $this->Stroke(CSIMCACHE_DIR . $baseimg);
1036
1037
                // Construct wrapper HTML and write to file and send it back to browser
1038
1039
                // In the src URL we must replace the '?' with its encoding to prevent the arguments
1040
                // to be converted to real arguments.
1041
                $tmp      = str_replace('?', '%3f', $baseimg);
1042
                $htmlwrap = $this->GetHTMLImageMap($aCSIMName) . "\n" .
1043
                '<img src="' . CSIMCACHE_HTTP_DIR . $tmp . '" ismap="ismap" usemap="#' . $aCSIMName . ' width="' . $this->img->width . '" height="' . $this->img->height . '" alt="' . $this->iCSIMImgAlt . "\" />\n";
1044
1045
                if ($fh = @fopen($basecsim, 'w')) {
1046
                    fwrite($fh, $htmlwrap);
1047
                    fclose($fh);
1048
                    echo $htmlwrap;
1049
                } else {
1050
                    Util\JpGraphError::RaiseL(25029, $basecsim); //(" Can't write CSIM \"$basecsim\" for writing. Check free space and permissions.");
1051
                }
1052
            } else {
1053
                if ($aScriptName == '') {
1054
                    Util\JpGraphError::RaiseL(25030); //('Missing script name in call to StrokeCSIM(). You must specify the name of the actual image script as the first parameter to StrokeCSIM().');
1055
                }
1056
                echo $this->GetHTMLImageMap($aCSIMName) . $this->GetCSIMImgHTML($aCSIMName, $aScriptName, $aBorder);
1057
            }
1058
        } else {
1059
            $this->Stroke();
1060
        }
1061
    }
1062
1063
    public function StrokeCSIMImage()
1064
    {
1065
        if (@$_GET[_CSIM_DISPLAY] == 1) {
1066
            $this->Stroke();
1067
        }
1068
    }
1069
1070
    public function GetCSIMImgHTML($aCSIMName, $aScriptName = 'auto', $aBorder = 0)
0 ignored issues
show
Unused Code introduced by
The parameter $aBorder 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

1070
    public function GetCSIMImgHTML($aCSIMName, $aScriptName = 'auto', /** @scrutinizer ignore-unused */ $aBorder = 0)

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...
1071
    {
1072
        if ($aScriptName == 'auto') {
1073
            $aScriptName = basename($_SERVER['PHP_SELF']);
1074
        }
1075
        $urlarg = $this->GetURLArguments(true);
1076
1077
        return '<img src="' . $aScriptName . '?' . $urlarg . '" ismap="ismap" usemap="#' . $aCSIMName . '" height="' . $this->img->height . '" alt="' . $this->iCSIMImgAlt . "\" />\n";
1078
    }
1079
1080
    public function GetTextsYMinMax($aY2 = false)
1081
    {
1082 13
        if ($aY2) {
1083 5
            $txts = $this->y2texts;
1084
        } else {
1085 13
            $txts = $this->texts;
1086
        }
1087 13
        $n   = count($txts);
1088 13
        $min = null;
1089 13
        $max = null;
1090 13
        for ($i = 0; $i < $n; ++$i) {
1091 1
            if ($txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null) {
1092
                if ($min === null) {
1093
                    $min = $max = $txts[$i]->iScalePosY;
1094
                } else {
1095
                    $min = min($min, $txts[$i]->iScalePosY);
1096
                    $max = max($max, $txts[$i]->iScalePosY);
1097
                }
1098
            }
1099
        }
1100 13
        if ($min !== null) {
1101
            return [$min, $max];
1102
        }
1103
1104 13
        return null;
1105
    }
1106
1107
    public function GetTextsXMinMax($aY2 = false)
1108
    {
1109 6
        if ($aY2) {
1110 6
            $txts = $this->y2texts;
1111
        } else {
1112 6
            $txts = $this->texts;
1113
        }
1114 6
        $n   = count($txts);
1115 6
        $min = null;
1116 6
        $max = null;
1117 6
        for ($i = 0; $i < $n; ++$i) {
1118
            if ($txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null) {
1119
                if ($min === null) {
1120
                    $min = $max = $txts[$i]->iScalePosX;
1121
                } else {
1122
                    $min = min($min, $txts[$i]->iScalePosX);
1123
                    $max = max($max, $txts[$i]->iScalePosX);
1124
                }
1125
            }
1126
        }
1127 6
        if ($min !== null) {
1128
            return [$min, $max];
1129
        }
1130
1131 6
        return null;
1132
    }
1133
1134
    public function GetXMinMax()
1135
    {
1136 6
        list($min, $ymin) = $this->plots[0]->Min();
1137 6
        list($max, $ymax) = $this->plots[0]->Max();
1138
1139 6
        $i = 0;
1140
        // Some plots, e.g. PlotLine should not affect the scale
1141
        // and will return (null,null). We should ignore those
1142
        // values.
1143 6
        while (($min === null || $max === null) && ($i < count($this->plots) - 1)) {
1144 1
            ++$i;
1145 1
            list($min, $ymin) = $this->plots[$i]->Min();
1146 1
            list($max, $ymax) = $this->plots[$i]->Max();
1147
        }
1148
1149 6
        foreach ($this->plots as $p) {
1150 6
            list($xmin, $ymin) = $p->Min();
1151 6
            list($xmax, $ymax) = $p->Max();
1152
1153 6
            if ($xmin !== null && $xmax !== null) {
1154 6
                $min = min($xmin, $min);
1155 6
                $max = max($xmax, $max);
1156
            }
1157
        }
1158
1159 6
        if ($this->y2axis != null) {
1160 2
            foreach ($this->y2plots as $p) {
1161 2
                list($xmin, $ymin) = $p->Min();
1162 2
                list($xmax, $ymax) = $p->Max();
1163 2
                $min               = min($xmin, $min);
1164 2
                $max               = max($xmax, $max);
1165
            }
1166
        }
1167
1168 6
        $n = count($this->ynaxis);
1169 6
        for ($i = 0; $i < $n; ++$i) {
1170 1
            if ($this->ynaxis[$i] != null) {
1171 1
                foreach ($this->ynplots[$i] as $p) {
1172 1
                    list($xmin, $ymin) = $p->Min();
1173 1
                    list($xmax, $ymax) = $p->Max();
1174 1
                    $min               = min($xmin, $min);
1175 1
                    $max               = max($xmax, $max);
1176
                }
1177
            }
1178
        }
1179
1180 6
        return [$min, $max];
1181
    }
1182
1183
    public function AdjustMarginsForTitles()
1184
    {
1185
        $totrequired =
1186 14
            ($this->title->t != ''
1187 13
            ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * SUPERSAMPLING_SCALE
1188 6
            : 0) +
1189 14
            ($this->subtitle->t != ''
1190 8
            ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * SUPERSAMPLING_SCALE
1191 14
            : 0) +
1192 14
            ($this->subsubtitle->t != ''
1193 1
            ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * SUPERSAMPLING_SCALE
1194 14
            : 0);
1195
1196 14
        $btotrequired = 0;
1197 14
        if ($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels) {
1198
            // Minimum bottom margin
1199 14
            if ($this->xaxis->title->t != '') {
1200 7
                if ($this->img->a == 90) {
1201 1
                    $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7;
1202
                } else {
1203 7
                    $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7;
1204
                }
1205
            } else {
1206 12
                $btotrequired = 0;
1207
            }
1208
1209 14
            if ($this->img->a == 90) {
1210 3
                $this->img->SetFont(
1211 3
                    $this->yaxis->font_family,
1212 3
                    $this->yaxis->font_style,
1213 3
                    $this->yaxis->font_size
1214
                );
1215 3
                $lh = $this->img->GetTextHeight('Mg', $this->yaxis->label_angle);
1216
            } else {
1217 14
                $this->img->SetFont(
1218 14
                    $this->xaxis->font_family,
1219 14
                    $this->xaxis->font_style,
1220 14
                    $this->xaxis->font_size
1221
                );
1222 14
                $lh = $this->img->GetTextHeight('Mg', $this->xaxis->label_angle);
1223
            }
1224
1225 14
            $btotrequired += $lh + 6;
1226
        }
1227
1228 14
        if ($this->img->a == 90) {
1229
            // DO Nothing. It gets too messy to do this properly for 90 deg...
1230
        } else {
1231
            // need more top margin
1232 14
            if ($this->img->top_margin < $totrequired) {
1233 8
                $this->SetMargin(
1234 8
                    $this->img->raw_left_margin,
1 ignored issue
show
Bug Best Practice introduced by
The property raw_left_margin does not exist on Amenadiel\JpGraph\Image\RotImage. Since you implemented __get, consider adding a @property annotation.
Loading history...
1235 8
                    $this->img->raw_right_margin,
1 ignored issue
show
Bug Best Practice introduced by
The property raw_right_margin does not exist on Amenadiel\JpGraph\Image\RotImage. Since you implemented __get, consider adding a @property annotation.
Loading history...
1236 8
                    $totrequired / SUPERSAMPLING_SCALE,
1237 8
                    $this->img->raw_bottom_margin
1 ignored issue
show
Bug Best Practice introduced by
The property raw_bottom_margin does not exist on Amenadiel\JpGraph\Image\RotImage. Since you implemented __get, consider adding a @property annotation.
Loading history...
1238
                );
1239
            }
1240
1241
            // need more bottom margin
1242 14
            if ($this->img->bottom_margin < $btotrequired) {
1243 2
                $this->SetMargin(
1244 2
                    $this->img->raw_left_margin,
1245 2
                    $this->img->raw_right_margin,
1246 2
                    $this->img->raw_top_margin,
1 ignored issue
show
Bug Best Practice introduced by
The property raw_top_margin does not exist on Amenadiel\JpGraph\Image\RotImage. Since you implemented __get, consider adding a @property annotation.
Loading history...
1247 2
                    $btotrequired / SUPERSAMPLING_SCALE
1248
                );
1249
            }
1250
        }
1251 14
    }
1252
1253
    public function StrokeStore($aStrokeFileName)
1254
    {
1255
        // Get the handler to prevent the library from sending the
1256
        // image to the browser
1257
        $ih = $this->Stroke(_IMG_HANDLER);
0 ignored issues
show
Unused Code introduced by
The assignment to $ih is dead and can be removed.
Loading history...
1258
1259
        // Stroke it to a file
1260
        $this->img->Stream($aStrokeFileName);
1261
1262
        // Send it back to browser
1263
        $this->img->Headers();
1264
        $this->img->Stream();
1265
    }
1266
1267
    public function doAutoscaleXAxis()
1268
    {
1269
        $aPlots = array_filter($this->plots, function ($plot) {
1270
            //\Kint::dump($plot, $plot instanceof Plot\Plot);
1271 14
            return $plot instanceof Plot\Plot;
1272 14
        });
1273
1274
        //Check if we should autoscale x-axis
1275 14
        if (!$this->xscale->IsSpecified()) {
1276 12
            if (substr($this->axtype, 0, 4) == 'text') {
1277 11
                $max = 0;
1278 11
                $n   = count($aPlots);
1279
1280 11
                for ($i = 0; $i < $n; ++$i) {
1281 11
                    $p = $aPlots[$i];
1282
1283
                    // We need some unfortunate sub class knowledge here in order
1284
                    // to increase number of data points in case it is a line plot
1285
                    // which has the barcenter set. If not it could mean that the
1286
                    // last point of the data is outside the scale since the barcenter
1287
                    // settings means that we will shift the entire plot half a tick step
1288
                    // to the right in oder to align with the center of the bars.
1289
1290 11
                    $cl = strtolower(get_class($p));
0 ignored issues
show
Unused Code introduced by
The assignment to $cl is dead and can be removed.
Loading history...
1291 11
                    if (empty($p->barcenter)) {
1292 11
                        $max = max($max, $p->numpoints - 1);
1293
                    } else {
1294 2
                        $max = max($max, $p->numpoints);
1295
                    }
1296
                }
1297 11
                $min = 0;
1298 11
                if ($this->y2axis != null) {
1299 3
                    foreach ($this->y2plots as $p) {
1300 3
                        $max = max($max, $p->numpoints - 1);
1301
                    }
1302
                }
1303 11
                $n = count($this->ynaxis);
1304 11
                for ($i = 0; $i < $n; ++$i) {
1305
                    if ($this->ynaxis[$i] != null) {
1306
                        foreach ($this->ynplots[$i] as $p) {
1307
                            $max = max($max, $p->numpoints - 1);
1308
                        }
1309
                    }
1310
                }
1311
1312 11
                $this->xscale->Update($this->img, $min, $max);
1313 11
                $this->xscale->ticks->Set($this->xaxis->tick_step, 1);
1314 11
                $this->xscale->ticks->SupressMinorTickMarks();
1315
            } else {
1316 6
                list($min, $max) = $this->GetXMinMax();
1317
1318 6
                $lres = $this->GetLinesXMinMax($this->lines);
1319 6
                if ($lres) {
0 ignored issues
show
introduced by
The condition $lres is always false.
Loading history...
1320
                    list($linmin, $linmax) = $lres;
1321
                    $min                   = min($min, $linmin);
1322
                    $max                   = max($max, $linmax);
1323
                }
1324
1325 6
                $lres = $this->GetLinesXMinMax($this->y2lines);
1326 6
                if ($lres) {
0 ignored issues
show
introduced by
The condition $lres is always false.
Loading history...
1327
                    list($linmin, $linmax) = $lres;
1328
                    $min                   = min($min, $linmin);
1329
                    $max                   = max($max, $linmax);
1330
                }
1331
1332 6
                $tres = $this->GetTextsXMinMax();
1333 6
                if ($tres) {
1334
                    list($tmin, $tmax) = $tres;
1335
                    $min               = min($min, $tmin);
1336
                    $max               = max($max, $tmax);
1337
                }
1338
1339 6
                $tres = $this->GetTextsXMinMax(true);
1340 6
                if ($tres) {
1341
                    list($tmin, $tmax) = $tres;
1342
                    $min               = min($min, $tmin);
1343
                    $max               = max($max, $tmax);
1344
                }
1345
1346 6
                $this->xscale->AutoScale($this->img, $min, $max, round($this->img->plotwidth / $this->xtick_factor));
1347
            }
1348
1349
            //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale
1350 12
            if (!is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos)) {
1351 12
                $this->yaxis->SetPos($this->xscale->GetMinVal());
1352
            }
1353 5
        } elseif ($this->xscale->IsSpecified() &&
1354 5
            ($this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified())) {
1355
            // The tick calculation will use the user suplied min/max values to determine
1356
            // the ticks. If auto_ticks is false the exact user specifed min and max
1357
            // values will be used for the scale.
1358
            // If auto_ticks is true then the scale might be slightly adjusted
1359
            // so that the min and max values falls on an even major step.
1360 4
            $min = $this->xscale->scale[0];
1361 4
            $max = $this->xscale->scale[1];
1362 4
            $this->xscale->AutoScale($this->img, $min, $max, round($this->img->plotwidth / $this->xtick_factor), false);
1363
1364
            // Now make sure we show enough precision to accurate display the
1365
            // labels. If this is not done then the user might end up with
1366
            // a scale that might actually start with, say 13.5, butdue to rounding
1367
            // the scale label will ony show 14.
1368 4
            if (abs(floor($min) - $min) > 0) {
1369
                // If the user has set a format then we bail out
1370
                if ($this->xscale->ticks->label_formatstr == '' && $this->xscale->ticks->label_dateformatstr == '') {
1371
                    $this->xscale->ticks->precision = abs(floor(log10(abs(floor($min) - $min)))) + 1;
1372
                }
1373
            }
1374
        }
1375
1376
        // Position the optional Y2 and Yn axis to the rightmost position of the x-axis
1377 14
        if ($this->y2axis != null) {
1378 5
            if (!is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos)) {
1379
                $this->y2axis->SetPos($this->xscale->GetMaxVal());
1380
            }
1381 5
            $this->y2axis->SetTitleSide(SIDE_RIGHT);
1382
        }
1383
1384 14
        $n      = count($this->ynaxis);
1385 14
        $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0;
1386 14
        for ($i = 0; $i < $n; ++$i) {
1387 1
            if ($this->ynaxis[$i] != null) {
1388 1
                if (!is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos)) {
1389 1
                    $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal());
1390 1
                    $this->ynaxis[$i]->SetPosAbsDelta($i * $this->iYAxisDeltaPos + $nY2adj);
1391
                }
1392 1
                $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT);
1393
            }
1394
        }
1395 14
    }
1396
1397
    public function doAutoScaleYnAxis()
1398
    {
1399 14
        if ($this->y2scale != null) {
1400 5
            if (!$this->y2scale->IsSpecified() && count($this->y2plots) > 0) {
1401 5
                list($min, $max) = $this->GetPlotsYMinMax($this->y2plots);
1402
1403 5
                $lres = $this->GetLinesYMinMax($this->y2lines);
1404 5
                if (is_array($lres)) {
0 ignored issues
show
introduced by
The condition is_array($lres) is always false.
Loading history...
1405
                    list($linmin, $linmax) = $lres;
1406
                    $min                   = min($min, $linmin);
1407
                    $max                   = max($max, $linmax);
1408
                }
1409 5
                $tres = $this->GetTextsYMinMax(true);
1410 5
                if (is_array($tres)) {
1411
                    list($tmin, $tmax) = $tres;
1412
                    $min               = min($min, $tmin);
1413
                    $max               = max($max, $tmax);
1414
                }
1415 5
                $this->y2scale->AutoScale($this->img, $min, $max, $this->img->plotheight / $this->ytick_factor);
1416 1
            } elseif ($this->y2scale->IsSpecified() && ($this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified())) {
1417
                // The tick calculation will use the user suplied min/max values to determine
1418
                // the ticks. If auto_ticks is false the exact user specifed min and max
1419
                // values will be used for the scale.
1420
                // If auto_ticks is true then the scale might be slightly adjusted
1421
                // so that the min and max values falls on an even major step.
1422 1
                $min = $this->y2scale->scale[0];
1423 1
                $max = $this->y2scale->scale[1];
1424 1
                $this->y2scale->AutoScale(
1425 1
                    $this->img,
1426 1
                    $min,
1427 1
                    $max,
1428 1
                    $this->img->plotheight / $this->ytick_factor,
1429 1
                    $this->y2scale->auto_ticks
1430
                );
1431
1432
                // Now make sure we show enough precision to accurate display the
1433
                // labels. If this is not done then the user might end up with
1434
                // a scale that might actually start with, say 13.5, butdue to rounding
1435
                // the scale label will ony show 14.
1436 1
                if (abs(floor($min) - $min) > 0) {
1437
                    // If the user has set a format then we bail out
1438
                    if ($this->y2scale->ticks->label_formatstr == '' && $this->y2scale->ticks->label_dateformatstr == '') {
1439
                        $this->y2scale->ticks->precision = abs(floor(log10(abs(floor($min) - $min)))) + 1;
1440
                    }
1441
                }
1442
            }
1443
        }
1444
1445
        //
1446
        // Autoscale the extra Y-axises
1447
        //
1448 14
        $n = count($this->ynaxis);
1449 14
        for ($i = 0; $i < $n; ++$i) {
1450 1
            if ($this->ynscale[$i] != null) {
1451 1
                if (!$this->ynscale[$i]->IsSpecified() && count($this->ynplots[$i]) > 0) {
1452 1
                    list($min, $max) = $this->GetPlotsYMinMax($this->ynplots[$i]);
1453 1
                    $this->ynscale[$i]->AutoScale($this->img, $min, $max, $this->img->plotheight / $this->ytick_factor);
1454
                } elseif ($this->ynscale[$i]->IsSpecified() && ($this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified())) {
1455
                    // The tick calculation will use the user suplied min/max values to determine
1456
                    // the ticks. If auto_ticks is false the exact user specifed min and max
1457
                    // values will be used for the scale.
1458
                    // If auto_ticks is true then the scale might be slightly adjusted
1459
                    // so that the min and max values falls on an even major step.
1460
                    $min = $this->ynscale[$i]->scale[0];
1461
                    $max = $this->ynscale[$i]->scale[1];
1462
                    $this->ynscale[$i]->AutoScale(
1463
                        $this->img,
1464
                        $min,
1465
                        $max,
1466
                        $this->img->plotheight / $this->ytick_factor,
1467
                        $this->ynscale[$i]->auto_ticks
1468
                    );
1469
1470
                    // Now make sure we show enough precision to accurate display the
1471
                    // labels. If this is not done then the user might end up with
1472
                    // a scale that might actually start with, say 13.5, butdue to rounding
1473
                    // the scale label will ony show 14.
1474
                    if (abs(floor($min) - $min) > 0) {
1475
                        // If the user has set a format then we bail out
1476
                        if ($this->ynscale[$i]->ticks->label_formatstr == '' && $this->ynscale[$i]->ticks->label_dateformatstr == '') {
1477
                            $this->ynscale[$i]->ticks->precision = abs(floor(log10(abs(floor($min) - $min)))) + 1;
1478
                        }
1479
                    }
1480
                }
1481
            }
1482
        }
1483 14
    }
1484
1485
    public function doAutoScaleYAxis()
1486
    {
1487
        //Check if we should autoscale y-axis
1488 14
        if (!$this->yscale->IsSpecified() && count($this->plots) > 0) {
1489 13
            list($min, $max) = $this->GetPlotsYMinMax($this->plots);
1490 13
            $lres            = $this->GetLinesYMinMax($this->lines);
1491 13
            if (is_array($lres)) {
0 ignored issues
show
introduced by
The condition is_array($lres) is always false.
Loading history...
1492
                list($linmin, $linmax) = $lres;
1493
                $min                   = min($min, $linmin);
1494
                $max                   = max($max, $linmax);
1495
            }
1496 13
            $tres = $this->GetTextsYMinMax();
1497 13
            if (is_array($tres)) {
1498
                list($tmin, $tmax) = $tres;
1499
                $min               = min($min, $tmin);
1500
                $max               = max($max, $tmax);
1501
            }
1502 13
            $this->yscale->AutoScale(
1503 13
                $this->img,
1504 13
                $min,
1505 13
                $max,
1506 13
                $this->img->plotheight / $this->ytick_factor
1507
            );
1508 4
        } elseif ($this->yscale->IsSpecified() && ($this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified())) {
1509
            // The tick calculation will use the user suplied min/max values to determine
1510
            // the ticks. If auto_ticks is false the exact user specifed min and max
1511
            // values will be used for the scale.
1512
            // If auto_ticks is true then the scale might be slightly adjusted
1513
            // so that the min and max values falls on an even major step.
1514 4
            $min = $this->yscale->scale[0];
1515 4
            $max = $this->yscale->scale[1];
1516 4
            $this->yscale->AutoScale(
1517 4
                $this->img,
1518 4
                $min,
1519 4
                $max,
1520 4
                $this->img->plotheight / $this->ytick_factor,
1521 4
                $this->yscale->auto_ticks
1522
            );
1523
1524
            // Now make sure we show enough precision to accurate display the
1525
            // labels. If this is not done then the user might end up with
1526
            // a scale that might actually start with, say 13.5, butdue to rounding
1527
            // the scale label will ony show 14.
1528 4
            if (abs(floor($min) - $min) > 0) {
1529
                // If the user has set a format then we bail out
1530
                if ($this->yscale->ticks->label_formatstr == '' && $this->yscale->ticks->label_dateformatstr == '') {
1531
                    $this->yscale->ticks->precision = abs(floor(log10(abs(floor($min) - $min)))) + 1;
1532
                }
1533
            }
1534
        }
1535 14
    }
1536
1537
    public function InitScaleConstants()
1538
    {
1539
        // Setup scale constants
1540 14
        if ($this->yscale) {
1541 14
            $this->yscale->InitConstants($this->img);
1542
        }
1543
1544 14
        if ($this->xscale) {
1545 14
            $this->xscale->InitConstants($this->img);
1546
        }
1547
1548 14
        if ($this->y2scale) {
1549 5
            $this->y2scale->InitConstants($this->img);
1550
        }
1551
1552 14
        $n = count($this->ynscale);
1553 14
        for ($i = 0; $i < $n; ++$i) {
1554 1
            if ($this->ynscale[$i]) {
1555 1
                $this->ynscale[$i]->InitConstants($this->img);
1556
            }
1557
        }
1558 14
    }
1559
1560
    public function doPrestrokeAdjustments()
1561
    {
1562
        // Do any pre-stroke adjustment that is needed by the different plot types
1563
        // (i.e bar plots want's to add an offset to the x-labels etc)
1564 14
        for ($i = 0; $i < count($this->plots); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1565 14
            if ($this->plots[$i] instanceof Plot\Plot) {
1566 14
                $this->plots[$i]->PreStrokeAdjust($this);
1567 14
                $this->plots[$i]->DoLegend($this);
1568
            }
1569
        }
1570
1571
        // Any plots on the second Y scale?
1572 14
        if ($this->y2scale != null) {
1573 5
            for ($i = 0; $i < count($this->y2plots); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1574 5
                if ($this->plots[$i] instanceof Plot\Plot) {
1575 5
                    $this->y2plots[$i]->PreStrokeAdjust($this);
1576 5
                    $this->y2plots[$i]->DoLegend($this);
1577
                }
1578
            }
1579
        }
1580
1581
        // Any plots on the extra Y axises?
1582 14
        $n = count($this->ynaxis);
1583 14
        for ($i = 0; $i < $n; ++$i) {
1584 1
            if ($this->ynplots == null || $this->ynplots[$i] == null) {
1585
                Util\JpGraphError::RaiseL(25032, $i); //("No plots for Y-axis nbr:$i");
1586
            }
1587 1
            $m = count($this->ynplots[$i]);
1588 1
            for ($j = 0; $j < $m; ++$j) {
1589 1
                $this->ynplots[$i][$j]->PreStrokeAdjust($this);
1590 1
                $this->ynplots[$i][$j]->DoLegend($this);
1591
            }
1592
        }
1593 14
    }
1594
1595
    public function StrokeBands($aDepth, $aCSIM)
1596
    {
1597
        // Stroke bands
1598 14
        if ($this->bands != null && !$aCSIM) {
1599 2
            for ($i = 0; $i < count($this->bands); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1600
                // Stroke all bands that asks to be in the background
1601 2
                if ($this->bands[$i]->depth == $aDepth) {
1602 2
                    $this->bands[$i]->Stroke($this->img, $this->xscale, $this->yscale);
1603
                }
1604
            }
1605
        }
1606
1607 14
        if ($this->y2bands != null && $this->y2scale != null && !$aCSIM) {
1608
            for ($i = 0; $i < count($this->y2bands); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1609
                // Stroke all bands that asks to be in the foreground
1610
                if ($this->y2bands[$i]->depth == $aDepth) {
1611
                    $this->y2bands[$i]->Stroke($this->img, $this->xscale, $this->y2scale);
1612
                }
1613
            }
1614
        }
1615 14
    }
1616
1617
    // Stroke the graph
1618
    // $aStrokeFileName If != "" the image will be written to this file and NOT
1619
    // streamed back to the browser
1620
    public function Stroke($aStrokeFileName = '')
1621
    {
1622
        // Fist make a sanity check that user has specified a scale
1623 14
        if (empty($this->yscale)) {
1624
            Util\JpGraphError::RaiseL(25031); //('You must specify what scale to use with a call to Graph::SetScale().');
1625
        }
1626
1627
        // Start by adjusting the margin so that potential titles will fit.
1628 14
        $this->AdjustMarginsForTitles();
1629
1630
        // Give the plot a chance to do any scale adjuments the individual plots
1631
        // wants to do. Right now this is only used by the contour plot to set scale
1632
        // limits
1633 14
        for ($i = 0; $i < count($this->plots); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1634 14
            if ($this->plots[$i] instanceof Plot\Plot) {
1635 14
                $this->plots[$i]->PreScaleSetup($this);
1636
            }
1637
            //\Kint::dump($this->plots[$i]);
1638
        }
1639
1640
        // Init scale constants that are used to calculate the transformation from
1641
        // world to pixel coordinates
1642 14
        $this->InitScaleConstants();
1643
1644
        // If the filename is the predefined value = '_csim_special_'
1645
        // we assume that the call to stroke only needs to do enough
1646
        // to correctly generate the CSIM maps.
1647
        // We use this variable to skip things we don't strictly need
1648
        // to do to generate the image map to improve performance
1649
        // a best we can. Therefor you will see a lot of tests !$_csim in the
1650
        // code below.
1651 14
        $_csim = ($aStrokeFileName === _CSIM_SPECIALFILE);
1652
1653
        // If we are called the second time (perhaps the user has called GetHTMLImageMap()
1654
        // himself then the legends have alsready been populated once in order to get the
1655
        // CSIM coordinats. Since we do not want the legends to be populated a second time
1656
        // we clear the legends
1657 14
        $this->legend->Clear();
1658
1659
        // We need to know if we have stroked the plot in the
1660
        // GetCSIMareas. Otherwise the CSIM hasn't been generated
1661
        // and in the case of GetCSIM called before stroke to generate
1662
        // CSIM without storing an image to disk GetCSIM must call Stroke.
1663 14
        $this->iHasStroked = true;
1664
1665
        // Setup pre-stroked adjustments and Legends
1666 14
        $this->doPrestrokeAdjustments();
1667
1668 14
        if ($this->graph_theme) {
1669 14
            $this->graph_theme->PreStrokeApply($this);
1670
        }
1671
1672
        // Bail out if any of the Y-axis not been specified and
1673
        // has no plots. (This means it is impossible to do autoscaling and
1674
        // no other scale was given so we can't possible draw anything). If you use manual
1675
        // scaling you also have to supply the tick steps as well.
1676 14
        if ((!$this->yscale->IsSpecified() && count($this->plots) == 0) ||
1677 14
            ($this->y2scale != null && !$this->y2scale->IsSpecified() && count($this->y2plots) == 0)) {
1678
            //$e = "n=".count($this->y2plots)."\n";
1679
            // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n";
1680
            // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n";
1681
            // $e .= "2. Specified a scale manually but have forgot to specify the tick steps";
1682
            Util\JpGraphError::RaiseL(25026);
1683
        }
1684
1685
        // Bail out if no plots and no specified X-scale
1686 14
        if ((!$this->xscale->IsSpecified() && count($this->plots) == 0 && count($this->y2plots) == 0)) {
1687
            Util\JpGraphError::RaiseL(25034); //("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>");
1688
        }
1689
1690
        // Autoscale the normal Y-axis
1691 14
        $this->doAutoScaleYAxis();
1692
1693
        // Autoscale all additiopnal y-axis
1694 14
        $this->doAutoScaleYnAxis();
1695
1696
        // Autoscale the regular x-axis and position the y-axis properly
1697 14
        $this->doAutoScaleXAxis();
1698
1699
        // If we have a negative values and x-axis position is at 0
1700
        // we need to supress the first and possible the last tick since
1701
        // they will be drawn on top of the y-axis (and possible y2 axis)
1702
        // The test below might seem strange the reasone being that if
1703
        // the user hasn't specified a value for position this will not
1704
        // be set until we do the stroke for the axis so as of now it
1705
        // is undefined.
1706
        // For X-text scale we ignore all this since the tick are usually
1707
        // much further in and not close to the Y-axis. Hence the test
1708
        // for 'text'
1709 14
        if (($this->yaxis->pos == $this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos == 'min')) &&
1710 14
            !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 &&
1711 14
            substr($this->axtype, 0, 4) != 'text' && $this->xaxis->pos != 'min') {
1712
            //$this->yscale->ticks->SupressZeroLabel(false);
1713 3
            $this->xscale->ticks->SupressFirst();
1714 3
            if ($this->y2axis != null) {
1715 3
                $this->xscale->ticks->SupressLast();
1716
            }
1717 14
        } elseif (!is_numeric($this->yaxis->pos) && $this->yaxis->pos == 'max') {
1718
            $this->xscale->ticks->SupressLast();
1719
        }
1720
1721 14
        if (!$_csim) {
1722 14
            $this->StrokePlotArea();
1723 14
            if ($this->iIconDepth == DEPTH_BACK) {
1724 14
                $this->StrokeIcons();
1725
            }
1726
        }
1727 14
        $this->StrokeAxis(false);
1728
1729
        // Stroke colored bands
1730 14
        $this->StrokeBands(DEPTH_BACK, $_csim);
1731
1732 14
        if ($this->grid_depth == DEPTH_BACK && !$_csim) {
1733 14
            $this->ygrid->Stroke();
1734 14
            $this->xgrid->Stroke();
1735
        }
1736
1737
        // Stroke Y2-axis
1738 14
        if ($this->y2axis != null && !$_csim) {
1739 5
            $this->y2axis->Stroke($this->xscale);
1740 5
            $this->y2grid->Stroke();
1741
        }
1742
1743
        // Stroke yn-axis
1744 14
        $n = count($this->ynaxis);
1745 14
        for ($i = 0; $i < $n; ++$i) {
1746 1
            $this->ynaxis[$i]->Stroke($this->xscale);
1747
        }
1748
1749 14
        $oldoff = $this->xscale->off;
1750 14
        if (substr($this->axtype, 0, 4) == 'text') {
1751 11
            if ($this->text_scale_abscenteroff > -1) {
1752
                // For a text scale the scale factor is the number of pixel per step.
1753
                // Hence we can use the scale factor as a substitute for number of pixels
1754
                // per major scale step and use that in order to adjust the offset so that
1755
                // an object of width "abscenteroff" becomes centered.
1756 2
                $this->xscale->off += round($this->xscale->scale_factor / 2) - round($this->text_scale_abscenteroff / 2);
1757
            } else {
1758 11
                $this->xscale->off += ceil($this->xscale->scale_factor * $this->text_scale_off * $this->xscale->ticks->minor_step);
1759
            }
1760
        }
1761
1762 14
        if ($this->iDoClipping) {
1763 2
            $oldimage = $this->img->CloneCanvasH();
1764
        }
1765
1766 14
        if (!$this->y2orderback) {
1767
            // Stroke all plots for Y1 axis
1768
            for ($i = 0; $i < count($this->plots); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1769
                $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale);
1770
                if ($this->plots[$i] instanceof Plot\Plot) {
1771
                    $this->plots[$i]->StrokeMargin($this->img);
1772
                }
1773
            }
1774
        }
1775
1776
        // Stroke all plots for Y2 axis
1777 14
        if ($this->y2scale != null) {
1778 5
            for ($i = 0; $i < count($this->y2plots); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1779 5
                $this->y2plots[$i]->Stroke($this->img, $this->xscale, $this->y2scale);
1780
            }
1781
        }
1782
1783 14
        if ($this->y2orderback) {
1784
            // Stroke all plots for Y1 axis
1785 14
            for ($i = 0; $i < count($this->plots); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
1786 14
                $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale);
1787 14
                if ($this->plots[$i] instanceof Plot\Plot) {
1788 14
                    $this->plots[$i]->StrokeMargin($this->img);
1789
                }
1790
            }
1791
        }
1792
1793 14
        $n = count($this->ynaxis);
1794 14
        for ($i = 0; $i < $n; $i++) {
1795 1
            $m = count($this->ynplots[$i]);
1796 1
            for ($j = 0; $j < $m; $j++) {
1797 1
                $this->ynplots[$i][$j]->Stroke($this->img, $this->xscale, $this->ynscale[$i]);
1798 1
                if ($this->ynplots[$i][$j] instanceof Plot\Plot) {
1799 1
                    $this->ynplots[$i][$j]->StrokeMargin($this->img);
1800
                }
1801
            }
1802
        }
1803
1804 14
        if ($this->iIconDepth == DEPTH_FRONT) {
1805
            $this->StrokeIcons();
1806
        }
1807
1808 14
        if ($this->iDoClipping) {
1809
            // Clipping only supports graphs at 0 and 90 degrees
1810 2
            if ($this->img->a == 0) {
1811 2
                $this->img->CopyCanvasH(
1812 2
                    $oldimage,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $oldimage does not seem to be defined for all execution paths leading up to this point.
Loading history...
1813 2
                    $this->img->img,
1814 2
                    $this->img->left_margin,
1815 2
                    $this->img->top_margin,
1816 2
                    $this->img->left_margin,
1817 2
                    $this->img->top_margin,
1818 2
                    $this->img->plotwidth + 1,
1819 2
                    $this->img->plotheight
1820
                );
1821
            } elseif ($this->img->a == 90) {
1822
                $adj = ($this->img->height - $this->img->width) / 2;
1823
                $this->img->CopyCanvasH(
1824
                    $oldimage,
1825
                    $this->img->img,
1826
                    $this->img->bottom_margin - $adj,
1827
                    $this->img->left_margin + $adj,
1828
                    $this->img->bottom_margin - $adj,
1829
                    $this->img->left_margin + $adj,
1830
                    $this->img->plotheight + 1,
1831
                    $this->img->plotwidth
1832
                );
1833
            } else {
1834
                Util\JpGraphError::RaiseL(25035, $this->img->a); //('You have enabled clipping. Cliping is only supported for graphs at 0 or 90 degrees rotation. Please adjust you current angle (='.$this->img->a.' degrees) or disable clipping.');
1835
            }
1836 2
            $this->img->Destroy();
1837 2
            $this->img->SetCanvasH($oldimage);
1838
        }
1839
1840 14
        $this->xscale->off = $oldoff;
1841
1842 14
        if ($this->grid_depth == DEPTH_FRONT && !$_csim) {
1843 2
            $this->ygrid->Stroke();
1844 2
            $this->xgrid->Stroke();
1845
        }
1846
1847
        // Stroke colored bands
1848 14
        $this->StrokeBands(DEPTH_FRONT, $_csim);
1849
1850
        // Finally draw the axis again since some plots may have nagged
1851
        // the axis in the edges.
1852 14
        if (!$_csim) {
1853 14
            $this->StrokeAxis();
1854
        }
1855
1856 14
        if ($this->y2scale != null && !$_csim) {
1857 5
            $this->y2axis->Stroke($this->xscale, false);
1858
        }
1859
1860 14
        if (!$_csim) {
1861 14
            $this->StrokePlotBox();
1862
        }
1863
1864
        // The titles and legends never gets rotated so make sure
1865
        // that the angle is 0 before stroking them
1866 14
        $aa = $this->img->SetAngle(0);
1867 14
        $this->StrokeTitles();
1868 14
        $this->footer->Stroke($this->img);
1869 14
        $this->legend->Stroke($this->img);
1870 14
        $this->img->SetAngle($aa);
1871 14
        $this->StrokeTexts();
1872 14
        $this->StrokeTables();
1873
1874 14
        if (!$_csim) {
1875 14
            $this->img->SetAngle($aa);
1876
1877
            // Draw an outline around the image map
1878 14
            if (_JPG_DEBUG) {
1879
                $this->DisplayClientSideaImageMapAreas();
1880
            }
1881
1882
            // Should we do any final image transformation
1883 14
            if ($this->iImgTrans) {
1884
                $tform          = new Image\ImgTrans($this->img->img);
1885
                $this->img->img = $tform->Skew3D(
1886
                    $this->iImgTransHorizon,
1887
                    $this->iImgTransSkewDist,
1888
                    $this->iImgTransDirection,
1889
                    $this->iImgTransHighQ,
1890
                    $this->iImgTransMinSize,
1891
                    $this->iImgTransFillColor,
1892
                    $this->iImgTransBorder
1893
                );
1894
            }
1895
1896
            // If the filename is given as the special "__handle"
1897
            // then the image handler is returned and the image is NOT
1898
            // streamed back
1899 14
            if ($aStrokeFileName == _IMG_HANDLER) {
1900
                return $this->img->img;
1901
            }
1902
            // Finally stream the generated picture
1903 14
            $this->cache->PutAndStream($this->img, $this->cache_name, $this->inline, $aStrokeFileName);
1904
        }
1905 14
    }
1906
1907
    public function SetAxisLabelBackground($aType, $aXFColor = 'lightgray', $aXColor = 'black', $aYFColor = 'lightgray', $aYColor = 'black')
1908
    {
1909 1
        $this->iAxisLblBgType       = $aType;
1910 1
        $this->iXAxisLblBgFillColor = $aXFColor;
1911 1
        $this->iXAxisLblBgColor     = $aXColor;
1912 1
        $this->iYAxisLblBgFillColor = $aYFColor;
1913 1
        $this->iYAxisLblBgColor     = $aYColor;
1914 1
    }
1915
1916
    public function StrokeAxisLabelBackground()
1917
    {
1918
        // Types
1919
        // 0 = No background
1920
        // 1 = Only X-labels, length of axis
1921
        // 2 = Only Y-labels, length of axis
1922
        // 3 = As 1 but extends to width of graph
1923
        // 4 = As 2 but extends to height of graph
1924
        // 5 = Combination of 3 & 4
1925
        // 6 = Combination of 1 & 2
1926
1927 14
        $t = $this->iAxisLblBgType;
1928 14
        if ($t < 1) {
1929 14
            return;
1930
        }
1931
1932
        // Stroke optional X-axis label background color
1933 1
        if ($t == 1 || $t == 3 || $t == 5 || $t == 6) {
1934 1
            $this->img->PushColor($this->iXAxisLblBgFillColor);
1935 1
            if ($t == 1 || $t == 6) {
1936 1
                $xl = $this->img->left_margin;
1937 1
                $yu = $this->img->height - $this->img->bottom_margin + 1;
1938 1
                $xr = $this->img->width - $this->img->right_margin;
1939 1
                $yl = $this->img->height - 1 - $this->frame_weight;
1940
            } else {
1941
                // t==3 || t==5
1942 1
                $xl = $this->frame_weight;
1943 1
                $yu = $this->img->height - $this->img->bottom_margin + 1;
1944 1
                $xr = $this->img->width - 1 - $this->frame_weight;
1945 1
                $yl = $this->img->height - 1 - $this->frame_weight;
1946
            }
1947
1948 1
            $this->img->FilledRectangle($xl, $yu, $xr, $yl);
1949 1
            $this->img->PopColor();
1950
1951
            // Check if we should add the vertical lines at left and right edge
1952 1
            if ($this->iXAxisLblBgColor !== '') {
1953
                // Hardcode to one pixel wide
1954 1
                $this->img->SetLineWeight(1);
1955 1
                $this->img->PushColor($this->iXAxisLblBgColor);
1956 1
                if ($t == 1 || $t == 6) {
1957 1
                    $this->img->Line($xl, $yu, $xl, $yl);
1958 1
                    $this->img->Line($xr, $yu, $xr, $yl);
1959
                } else {
1960 1
                    $xl = $this->img->width - $this->img->right_margin;
1961 1
                    $this->img->Line($xl, $yu - 1, $xr, $yu - 1);
1962
                }
1963 1
                $this->img->PopColor();
1964
            }
1965
        }
1966
1967 1
        if ($t == 2 || $t == 4 || $t == 5 || $t == 6) {
1968 1
            $this->img->PushColor($this->iYAxisLblBgFillColor);
1969 1
            if ($t == 2 || $t == 6) {
1970 1
                $xl = $this->frame_weight;
1971 1
                $yu = $this->frame_weight + $this->img->top_margin;
1972 1
                $xr = $this->img->left_margin - 1;
1973 1
                $yl = $this->img->height - $this->img->bottom_margin + 1;
1974
            } else {
1975 1
                $xl = $this->frame_weight;
1976 1
                $yu = $this->frame_weight;
1977 1
                $xr = $this->img->left_margin - 1;
1978 1
                $yl = $this->img->height - 1 - $this->frame_weight;
1979
            }
1980
1981 1
            $this->img->FilledRectangle($xl, $yu, $xr, $yl);
1982 1
            $this->img->PopColor();
1983
1984
            // Check if we should add the vertical lines at left and right edge
1985 1
            if ($this->iXAxisLblBgColor !== '') {
1986 1
                $this->img->PushColor($this->iXAxisLblBgColor);
1987 1
                if ($t == 2 || $t == 6) {
1988 1
                    $this->img->Line($xl, $yu - 1, $xr, $yu - 1);
1989 1
                    $this->img->Line($xl, $yl - 1, $xr, $yl - 1);
1990
                } else {
1991 1
                    $this->img->Line($xr + 1, $yu, $xr + 1, $this->img->top_margin);
1992
                }
1993 1
                $this->img->PopColor();
1994
            }
1995
        }
1996 1
    }
1997
1998
    public function StrokeAxis($aStrokeLabels = true)
1999
    {
2000 14
        if ($aStrokeLabels) {
2001 14
            $this->StrokeAxisLabelBackground();
2002
        }
2003
2004
        // Stroke axis
2005 14
        if ($this->iAxisStyle != AXSTYLE_SIMPLE) {
2006 4
            switch ($this->iAxisStyle) {
2007 4
                case AXSTYLE_BOXIN:
2008 2
                    $toppos    = SIDE_DOWN;
2009 2
                    $bottompos = SIDE_UP;
2010 2
                    $leftpos   = SIDE_RIGHT;
2011 2
                    $rightpos  = SIDE_LEFT;
2012
2013 2
                    break;
2014 3
                case AXSTYLE_BOXOUT:
2015 3
                    $toppos    = SIDE_UP;
2016 3
                    $bottompos = SIDE_DOWN;
2017 3
                    $leftpos   = SIDE_LEFT;
2018 3
                    $rightpos  = SIDE_RIGHT;
2019
2020 3
                    break;
2021 1
                case AXSTYLE_YBOXIN:
2022 1
                    $toppos    = false;
2023 1
                    $bottompos = SIDE_UP;
2024 1
                    $leftpos   = SIDE_RIGHT;
2025 1
                    $rightpos  = SIDE_LEFT;
2026
2027 1
                    break;
2028
                case AXSTYLE_YBOXOUT:
2029
                    $toppos    = false;
2030
                    $bottompos = SIDE_DOWN;
2031
                    $leftpos   = SIDE_LEFT;
2032
                    $rightpos  = SIDE_RIGHT;
2033
2034
                    break;
2035
                default:
2036
                    Util\JpGraphError::RaiseL(25036, $this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle);
2037
                    break;
2038
            }
2039
2040
            // By default we hide the first label so it doesn't cross the
2041
            // Y-axis in case the positon hasn't been set by the user.
2042
            // However, if we use a box we always want the first value
2043
            // displayed so we make sure it will be displayed.
2044 4
            $this->xscale->ticks->SupressFirst(false);
2045
2046
            // Now draw the bottom X-axis
2047 4
            $this->xaxis->SetPos('min');
2048 4
            $this->xaxis->SetLabelSide(SIDE_DOWN);
2049 4
            $this->xaxis->scale->ticks->SetSide($bottompos);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $bottompos does not seem to be defined for all execution paths leading up to this point.
Loading history...
2050 4
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2051
2052 4
            if ($toppos !== false) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $toppos does not seem to be defined for all execution paths leading up to this point.
Loading history...
2053
                // We also want a top X-axis
2054 4
                $this->xaxis = $this->xaxis;
2055 4
                $this->xaxis->SetPos('max');
2056 4
                $this->xaxis->SetLabelSide(SIDE_UP);
2057
                // No title for the top X-axis
2058 4
                if ($aStrokeLabels) {
2059 4
                    $this->xaxis->title->Set('');
2060
                }
2061 4
                $this->xaxis->scale->ticks->SetSide($toppos);
2062 4
                $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2063
            }
2064
2065
            // Stroke the left Y-axis
2066 4
            $this->yaxis->SetPos('min');
2067 4
            $this->yaxis->SetLabelSide(SIDE_LEFT);
2068 4
            $this->yaxis->scale->ticks->SetSide($leftpos);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $leftpos does not seem to be defined for all execution paths leading up to this point.
Loading history...
2069 4
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2070
2071
            // Stroke the  right Y-axis
2072 4
            $this->yaxis->SetPos('max');
2073
            // No title for the right side
2074 4
            if ($aStrokeLabels) {
2075 4
                $this->yaxis->title->Set('');
2076
            }
2077 4
            $this->yaxis->SetLabelSide(SIDE_RIGHT);
2078 4
            $this->yaxis->scale->ticks->SetSide($rightpos);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rightpos does not seem to be defined for all execution paths leading up to this point.
Loading history...
2079 4
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2080
        } else {
2081 14
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2082 14
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2083
        }
2084 14
    }
2085
2086
    // Private helper function for backgound image
2087
    public static function LoadBkgImage($aImgFormat = '', $aFile = '', $aImgStr = '')
2088
    {
2089 7
        if ($aImgStr != '') {
2090
            return Image::CreateFromString($aImgStr);
2091
        }
2092
2093
        // Remove case sensitivity and setup appropriate function to create image
2094
        // Get file extension. This should be the LAST '.' separated part of the filename
2095 7
        $e   = explode('.', $aFile);
2096 7
        $ext = strtolower($e[count($e) - 1]);
2097 7
        if ($ext == 'jpeg') {
2098
            $ext = 'jpg';
2099
        }
2100
2101 7
        if (trim($ext) == '') {
2102
            $ext = 'png'; // Assume PNG if no extension specified
2103
        }
2104
2105 7
        if ($aImgFormat == '') {
2106 3
            $imgtag = $ext;
2107
        } else {
2108 5
            $imgtag = $aImgFormat;
2109
        }
2110
2111 7
        $supported = imagetypes();
2112 7
        if (($ext == 'jpg' && !($supported & IMG_JPG)) ||
2113 7
            ($ext == 'gif' && !($supported & IMG_GIF)) ||
2114 7
            ($ext == 'png' && !($supported & IMG_PNG)) ||
2115 7
            ($ext == 'bmp' && !($supported & IMG_WBMP)) ||
2116 7
            ($ext == 'xpm' && !($supported & IMG_XPM))) {
2117
            Util\JpGraphError::RaiseL(25037, $aFile); //('The image format of your background image ('.$aFile.') is not supported in your system configuration. ');
2118
        }
2119
2120 7
        if ($imgtag == 'jpg' || $imgtag == 'jpeg') {
2121 4
            $f      = 'imagecreatefromjpeg';
2122 4
            $imgtag = 'jpg';
2123
        } else {
2124 5
            $f = 'imagecreatefrom' . $imgtag;
2125
        }
2126
2127
        // Compare specified image type and file extension
2128 7
        if ($imgtag != $ext) {
2129
            //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'";
2130
            Util\JpGraphError::RaiseL(25038, $aImgFormat, $aFile);
2131
        }
2132
2133 7
        $img = @$f($aFile);
2134 7
        if (!$img) {
2135
            Util\JpGraphError::RaiseL(25039, $aFile); //(" Can't read background image: '".$aFile."'");
2136
        }
2137
2138 7
        return $img;
2139
    }
2140
2141
    public function StrokePlotGrad()
2142
    {
2143 14
        if ($this->plot_gradtype < 0) {
2144 14
            return;
2145
        }
2146
2147 1
        $grad = new Plot\Gradient($this->img);
2148 1
        $xl   = $this->img->left_margin;
2149 1
        $yt   = $this->img->top_margin;
2150 1
        $xr   = $xl + $this->img->plotwidth + 1;
2151 1
        $yb   = $yt + $this->img->plotheight;
2152 1
        $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->plot_gradfrom, $this->plot_gradto, $this->plot_gradtype);
2153 1
    }
2154
2155
    public function StrokeBackgroundGrad()
2156
    {
2157 15
        if ($this->bkg_gradtype < 0) {
2158 14
            return;
2159
        }
2160
2161 4
        $grad = new Plot\Gradient($this->img);
2162 4
        if ($this->bkg_gradstyle == BGRAD_PLOT) {
2163 2
            $xl = $this->img->left_margin;
2164 2
            $yt = $this->img->top_margin;
2165 2
            $xr = $xl + $this->img->plotwidth + 1;
2166 2
            $yb = $yt + $this->img->plotheight;
2167 2
            $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype);
2168
        } else {
2169 2
            $xl = 0;
2170 2
            $yt = 0;
2171 2
            $xr = $xl + $this->img->width - 1;
2172 2
            $yb = $yt + $this->img->height - 1;
2173 2
            if ($this->doshadow) {
2174
                $xr -= $this->shadow_width;
2175
                $yb -= $this->shadow_width;
2176
            }
2177 2
            if ($this->doframe) {
2178 1
                $yt += $this->frame_weight;
2179 1
                $yb -= $this->frame_weight;
2180 1
                $xl += $this->frame_weight;
2181 1
                $xr -= $this->frame_weight;
2182
            }
2183 2
            $aa = $this->img->SetAngle(0);
2184 2
            $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype);
2185 2
            $aa = $this->img->SetAngle($aa);
0 ignored issues
show
Unused Code introduced by
The assignment to $aa is dead and can be removed.
Loading history...
2186
        }
2187 4
    }
2188
2189
    public function StrokeFrameBackground()
2190
    {
2191 7
        if ($this->background_image != '' && $this->background_cflag != '') {
2192
            Util\JpGraphError::RaiseL(25040); //('It is not possible to specify both a background image and a background country flag.');
2193
        }
2194 7
        if ($this->background_image != '') {
2195 5
            $bkgimg = $this->LoadBkgImage($this->background_image_format, $this->background_image);
2196 2
        } elseif ($this->background_cflag != '') {
2197 2
            $fobj                        = new Image\FlagImages(FLAGSIZE4);
2198 2
            $dummy                       = '';
2199 2
            $bkgimg                      = $fobj->GetImgByName($this->background_cflag, $dummy);
2200 2
            $this->background_image_mix  = $this->background_cflag_mix;
2201 2
            $this->background_image_type = $this->background_cflag_type;
2202
        } else {
2203
            return;
2204
        }
2205
2206 7
        $bw = imagesx($bkgimg);
2207 7
        $bh = imagesy($bkgimg);
2208
2209
        // No matter what the angle is we always stroke the image and frame
2210
        // assuming it is 0 degree
2211 7
        $aa = $this->img->SetAngle(0);
2212
2213 7
        switch ($this->background_image_type) {
2214 7
            case BGIMG_FILLPLOT: // Resize to just fill the plotarea
2215 4
                $this->FillMarginArea();
2216 4
                $this->StrokeFrame();
2217
                // Special case to hande 90 degree rotated graph corectly
2218 4
                if ($aa == 90) {
2219
                    $this->img->SetAngle(90);
2220
                    $this->FillPlotArea();
2221
                    $aa  = $this->img->SetAngle(0);
2222
                    $adj = ($this->img->height - $this->img->width) / 2;
2223
                    $this->img->CopyMerge(
2224
                        $bkgimg,
2225
                        $this->img->bottom_margin - $adj,
2226
                        $this->img->left_margin + $adj,
2227
                        0,
2228
                        0,
2229
                        $this->img->plotheight + 1,
2230
                        $this->img->plotwidth,
2231
                        $bw,
2232
                        $bh,
2233
                        $this->background_image_mix
2234
                    );
2235
                } else {
2236 4
                    $this->FillPlotArea();
2237 4
                    $this->img->CopyMerge(
2238 4
                        $bkgimg,
2239 4
                        $this->img->left_margin,
2240 4
                        $this->img->top_margin + 1,
2241 4
                        0,
2242 4
                        0,
2243 4
                        $this->img->plotwidth + 1,
2244 4
                        $this->img->plotheight,
2245 4
                        $bw,
2246 4
                        $bh,
2247 4
                        $this->background_image_mix
2248
                    );
2249
                }
2250
2251 4
                break;
2252 5
            case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit
2253 4
                $hadj = 0;
2254 4
                $vadj = 0;
2255 4
                if ($this->doshadow) {
2256 3
                    $hadj = $this->shadow_width;
2257 3
                    $vadj = $this->shadow_width;
2258
                }
2259 4
                $this->FillMarginArea();
2260 4
                $this->FillPlotArea();
2261 4
                $this->img->CopyMerge(
2262 4
                    $bkgimg,
2263 4
                    0,
2264 4
                    0,
2265 4
                    0,
2266 4
                    0,
2267 4
                    $this->img->width - $hadj,
2268 4
                    $this->img->height - $vadj,
2269 4
                    $bw,
2270 4
                    $bh,
2271 4
                    $this->background_image_mix
2272
                );
2273 4
                $this->StrokeFrame();
2274
2275 4
                break;
2276 2
            case BGIMG_COPY: // Just copy the image from left corner, no resizing
2277 2
                $this->FillMarginArea();
2278 2
                $this->FillPlotArea();
2279 2
                $this->img->CopyMerge(
2280 2
                    $bkgimg,
2281 2
                    0,
2282 2
                    0,
2283 2
                    0,
2284 2
                    0,
2285 2
                    $bw,
2286 2
                    $bh,
2287 2
                    $bw,
2288 2
                    $bh,
2289 2
                    $this->background_image_mix
2290
                );
2291 2
                $this->StrokeFrame();
2292
2293 2
                break;
2294 1
            case BGIMG_CENTER: // Center original image in the plot area
2295 1
                $this->FillMarginArea();
2296 1
                $this->FillPlotArea();
2297 1
                $centerx = round($this->img->plotwidth / 2 + $this->img->left_margin - $bw / 2);
2298 1
                $centery = round($this->img->plotheight / 2 + $this->img->top_margin - $bh / 2);
2299 1
                $this->img->CopyMerge(
2300 1
                    $bkgimg,
2301 1
                    $centerx,
2302 1
                    $centery,
2303 1
                    0,
2304 1
                    0,
2305 1
                    $bw,
2306 1
                    $bh,
2307 1
                    $bw,
2308 1
                    $bh,
2309 1
                    $this->background_image_mix
2310
                );
2311 1
                $this->StrokeFrame();
2312
2313 1
                break;
2314 1
            case BGIMG_FREE: // Just copy the image to the specified location
2315 1
                $this->img->CopyMerge(
2316 1
                    $bkgimg,
2317 1
                    $this->background_image_xpos,
2318 1
                    $this->background_image_ypos,
2319 1
                    0,
2320 1
                    0,
2321 1
                    $bw,
2322 1
                    $bh,
2323 1
                    $bw,
2324 1
                    $bh,
2325 1
                    $this->background_image_mix
2326
                );
2327 1
                $this->StrokeFrame(); // New
2328 1
                break;
2329
            default:
2330
                Util\JpGraphError::RaiseL(25042); //(" Unknown background image layout");
2331
        }
2332 7
        $this->img->SetAngle($aa);
2333 7
    }
2334
2335
    // Private
2336
    // Draw a frame around the image
2337
    public function StrokeFrame()
2338
    {
2339 18
        if (!$this->doframe) {
2340 15
            return;
2341
        }
2342
2343 6
        if ($this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle == BGRAD_PLOT))) {
2344 6
            $c = $this->margin_color;
2345
        } else {
2346 2
            $c = false;
2347
        }
2348
2349 6
        if ($this->doshadow) {
2350 3
            $this->img->SetColor($this->frame_color);
2351 3
            $this->img->ShadowRectangle(
2352 3
                0,
2353 3
                0,
2354 3
                $this->img->width,
2355 3
                $this->img->height,
2356 3
                $c,
2357 3
                $this->shadow_width,
2358 3
                $this->shadow_color
2359
            );
2360 5
        } elseif ($this->framebevel) {
2361
            if ($c) {
2362
                $this->img->SetColor($this->margin_color);
2363
                $this->img->FilledRectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2364
            }
2365
            $this->img->Bevel(
2366
                1,
2367
                1,
2368
                $this->img->width - 2,
2369
                $this->img->height - 2,
2370
                $this->framebeveldepth,
2371
                $this->framebevelcolor1,
2372
                $this->framebevelcolor2
2373
            );
2374
            if ($this->framebevelborder) {
2375
                $this->img->SetColor($this->framebevelbordercolor);
2376
                $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2377
            }
2378
        } else {
2379 5
            $this->img->SetLineWeight($this->frame_weight);
2380 5
            if ($c) {
2381 5
                $this->img->SetColor($this->margin_color);
2382 5
                $this->img->FilledRectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2383
            }
2384 5
            $this->img->SetColor($this->frame_color);
2385 5
            $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2386
        }
2387 6
    }
2388
2389
    public function FillMarginArea()
2390
    {
2391 7
        $hadj = 0;
2392 7
        $vadj = 0;
2393 7
        if ($this->doshadow) {
2394 4
            $hadj = $this->shadow_width;
2395 4
            $vadj = $this->shadow_width;
2396
        }
2397
2398 7
        $this->img->SetColor($this->margin_color);
2399 7
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->height - 1 - $vadj);
2400
2401 7
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->top_margin);
2402 7
        $this->img->FilledRectangle(0, $this->img->top_margin, $this->img->left_margin, $this->img->height - 1 - $hadj);
2403 7
        $this->img->FilledRectangle(
2404 7
            $this->img->left_margin + 1,
2405 7
            $this->img->height - $this->img->bottom_margin,
2406 7
            $this->img->width - 1 - $hadj,
2407 7
            $this->img->height - 1 - $hadj
2408
        );
2409 7
        $this->img->FilledRectangle(
2410 7
            $this->img->width - $this->img->right_margin,
2411 7
            $this->img->top_margin + 1,
2412 7
            $this->img->width - 1 - $hadj,
2413 7
            $this->img->height - $this->img->bottom_margin - 1
2414
        );
2415 7
    }
2416
2417
    public function FillPlotArea()
2418
    {
2419 16
        $this->img->PushColor($this->plotarea_color);
2420 16
        $this->img->FilledRectangle(
2421 16
            $this->img->left_margin,
2422 16
            $this->img->top_margin,
2423 16
            $this->img->width - $this->img->right_margin,
2424 16
            $this->img->height - $this->img->bottom_margin
2425
        );
2426 16
        $this->img->PopColor();
2427 16
    }
2428
2429
    // Stroke the plot area with either a solid color or a background image
2430
    public function StrokePlotArea()
2431
    {
2432
        // Note: To be consistent we really should take a possible shadow
2433
        // into account. However, that causes some problem for the LinearScale class
2434
        // since in the current design it does not have any links to class Graph which
2435
        // means it has no way of compensating for the adjusted plotarea in case of a
2436
        // shadow. So, until I redesign LinearScale we can't compensate for this.
2437
        // So just set the two adjustment parameters to zero for now.
2438 16
        $boxadj = 0; //$this->doframe ? $this->frame_weight : 0 ;
0 ignored issues
show
Unused Code introduced by
The assignment to $boxadj is dead and can be removed.
Loading history...
2439 16
        $adj    = 0; //$this->doshadow ? $this->shadow_width : 0 ;
0 ignored issues
show
Unused Code introduced by
The assignment to $adj is dead and can be removed.
Loading history...
2440
2441 16
        if ($this->background_image != '' || $this->background_cflag != '') {
2442 6
            $this->StrokeFrameBackground();
2443
        } else {
2444 14
            $aa = $this->img->SetAngle(0);
2445 14
            $this->StrokeFrame();
2446 14
            $aa = $this->img->SetAngle($aa);
0 ignored issues
show
Unused Code introduced by
The assignment to $aa is dead and can be removed.
Loading history...
2447 14
            $this->StrokeBackgroundGrad();
2448 14
            if ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle == BGRAD_MARGIN)) {
2449 13
                $this->FillPlotArea();
2450
            }
2451 14
            $this->StrokePlotGrad();
2452
        }
2453 16
    }
2454
2455
    public function StrokeIcons()
2456
    {
2457 16
        $n = count($this->iIcons);
2458 16
        for ($i = 0; $i < $n; ++$i) {
2459 1
            $this->iIcons[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2460
        }
2461 16
    }
2462
2463
    public function StrokePlotBox()
2464
    {
2465
        // Should we draw a box around the plot area?
2466 15
        if ($this->boxed) {
2467 15
            $this->img->SetLineWeight(1);
2468 15
            $this->img->SetLineStyle('solid');
2469 15
            $this->img->SetColor($this->box_color);
2470 15
            for ($i = 0; $i < $this->box_weight; ++$i) {
2471 15
                $this->img->Rectangle(
2472 15
                    $this->img->left_margin - $i,
2473 15
                    $this->img->top_margin - $i,
2474 15
                    $this->img->width - $this->img->right_margin + $i,
2475 15
                    $this->img->height - $this->img->bottom_margin + $i
2476
                );
2477
            }
2478
        }
2479 15
    }
2480
2481
    public function SetTitleBackgroundFillStyle($aStyle, $aColor1 = 'black', $aColor2 = 'white')
2482
    {
2483 2
        $this->titlebkg_fillstyle = $aStyle;
2484 2
        $this->titlebkg_scolor1   = $aColor1;
2485 2
        $this->titlebkg_scolor2   = $aColor2;
2486 2
    }
2487
2488
    public function SetTitleBackground($aBackColor = 'gray', $aStyle = TITLEBKG_STYLE1, $aFrameStyle = TITLEBKG_FRAME_NONE, $aFrameColor = 'black', $aFrameWeight = 1, $aBevelHeight = 3, $aEnable = true)
2489
    {
2490 2
        $this->titlebackground             = $aEnable;
2491 2
        $this->titlebackground_color       = $aBackColor;
2492 2
        $this->titlebackground_style       = $aStyle;
2493 2
        $this->titlebackground_framecolor  = $aFrameColor;
2494 2
        $this->titlebackground_framestyle  = $aFrameStyle;
2495 2
        $this->titlebackground_frameweight = $aFrameWeight;
2496 2
        $this->titlebackground_bevelheight = $aBevelHeight;
2497 2
    }
2498
2499
    public function StrokeTitles()
2500
    {
2501 18
        $margin = 3;
2502
2503 18
        if ($this->titlebackground) {
2504
            // Find out height
2505 2
            $this->title->margin += 2;
2506 2
            $h = $this->title->GetTextHeight($this->img) + $this->title->margin + $margin;
2507 2
            if ($this->subtitle->t != '' && !$this->subtitle->hide) {
2508
                $h += $this->subtitle->GetTextHeight($this->img) + $margin +
2509
                $this->subtitle->margin;
2510
                $h += 2;
2511
            }
2512 2
            if ($this->subsubtitle->t != '' && !$this->subsubtitle->hide) {
2513
                $h += $this->subsubtitle->GetTextHeight($this->img) + $margin +
2514
                $this->subsubtitle->margin;
2515
                $h += 2;
2516
            }
2517 2
            $this->img->PushColor($this->titlebackground_color);
2518 2
            if ($this->titlebackground_style === TITLEBKG_STYLE1) {
2519
                // Inside the frame
2520 1
                if ($this->framebevel) {
2521
                    $x1 = $y1 = $this->framebeveldepth + 1;
2522
                    $x2 = $this->img->width - $this->framebeveldepth - 2;
2523
                    $this->title->margin += $this->framebeveldepth + 1;
2524
                    $h += $y1;
2525
                    $h += 2;
2526
                } else {
2527 1
                    $x1 = $y1 = $this->frame_weight;
2528 1
                    $x2 = $this->img->width - $this->frame_weight - 1;
2529
                }
2530 1
            } elseif ($this->titlebackground_style === TITLEBKG_STYLE2) {
2531
                // Cover the frame as well
2532 1
                $x1 = $y1 = 0;
2533 1
                $x2 = $this->img->width - 1;
2534
            } elseif ($this->titlebackground_style === TITLEBKG_STYLE3) {
2535
                // Cover the frame as well (the difference is that
2536
                // for style==3 a bevel frame border is on top
2537
                // of the title background)
2538
                $x1 = $y1 = 0;
2539
                $x2 = $this->img->width - 1;
2540
                $h += $this->framebeveldepth;
2541
                $this->title->margin += $this->framebeveldepth;
2542
            } else {
2543
                Util\JpGraphError::RaiseL(25043); //('Unknown title background style.');
2544
            }
2545
2546 2
            if ($this->titlebackground_framestyle === 3) {
2547 2
                $h += $this->titlebackground_bevelheight * 2 + 1;
2548 2
                $this->title->margin += $this->titlebackground_bevelheight;
2549
            }
2550
2551 2
            if ($this->doshadow) {
2552
                $x2 -= $this->shadow_width;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $x2 does not seem to be defined for all execution paths leading up to this point.
Loading history...
2553
            }
2554
2555 2
            $indent = 0;
2556 2
            if ($this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL) {
2557 2
                $indent = $this->titlebackground_bevelheight;
2558
            }
2559
2560 2
            if ($this->titlebkg_fillstyle == TITLEBKG_FILLSTYLE_HSTRIPED) {
2561 2
                $this->img->FilledRectangle2(
2562 2
                    $x1 + $indent,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $x1 does not seem to be defined for all execution paths leading up to this point.
Loading history...
2563 2
                    $y1 + $indent,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $y1 does not seem to be defined for all execution paths leading up to this point.
Loading history...
2564 2
                    $x2 - $indent,
2565 2
                    $h - $indent,
2566 2
                    $this->titlebkg_scolor1,
2567 2
                    $this->titlebkg_scolor2
2568
                );
2569
            } elseif ($this->titlebkg_fillstyle == TITLEBKG_FILLSTYLE_VSTRIPED) {
2570
                $this->img->FilledRectangle2(
2571
                    $x1 + $indent,
2572
                    $y1 + $indent,
2573
                    $x2 - $indent,
2574
                    $h - $indent,
2575
                    $this->titlebkg_scolor1,
2576
                    $this->titlebkg_scolor2,
2577
                    2
2578
                );
2579
            } else {
2580
                // Solid fill
2581
                $this->img->FilledRectangle($x1, $y1, $x2, $h);
2582
            }
2583 2
            $this->img->PopColor();
2584
2585 2
            $this->img->PushColor($this->titlebackground_framecolor);
2586 2
            $this->img->SetLineWeight($this->titlebackground_frameweight);
2587 2
            if ($this->titlebackground_framestyle == TITLEBKG_FRAME_FULL) {
2588
                // Frame background
2589
                $this->img->Rectangle($x1, $y1, $x2, $h);
2590 2
            } elseif ($this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM) {
2591
                // Bottom line only
2592
                $this->img->Line($x1, $h, $x2, $h);
2593 2
            } elseif ($this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL) {
2594 2
                $this->img->Bevel($x1, $y1, $x2, $h, $this->titlebackground_bevelheight);
2595
            }
2596 2
            $this->img->PopColor();
2597
2598
            // This is clumsy. But we neeed to stroke the whole graph frame if it is
2599
            // set to bevel to get the bevel shading on top of the text background
2600 2
            if ($this->framebevel && $this->doframe && $this->titlebackground_style === 3) {
2601
                $this->img->Bevel(
2602
                    1,
2603
                    1,
2604
                    $this->img->width - 2,
2605
                    $this->img->height - 2,
2606
                    $this->framebeveldepth,
2607
                    $this->framebevelcolor1,
2608
                    $this->framebevelcolor2
2609
                );
2610
                if ($this->framebevelborder) {
2611
                    $this->img->SetColor($this->framebevelbordercolor);
2612
                    $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2613
                }
2614
            }
2615
        }
2616
2617
        // Stroke title
2618 18
        $y = $this->title->margin;
2619 18
        if ($this->title->halign == 'center') {
2620 18
            $this->title->Center(0, $this->img->width, $y);
2621
        } elseif ($this->title->halign == 'left') {
2622
            $this->title->SetPos($this->title->margin + 2, $y);
2623
        } elseif ($this->title->halign == 'right') {
2624
            $indent = 0;
2625
            if ($this->doshadow) {
2626
                $indent = $this->shadow_width + 2;
2627
            }
2628
            $this->title->SetPos($this->img->width - $this->title->margin - $indent, $y, 'right');
2629
        }
2630 18
        $this->title->Stroke($this->img);
2631
2632
        // ... and subtitle
2633 18
        $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
2634 18
        if ($this->subtitle->halign == 'center') {
2635 18
            $this->subtitle->Center(0, $this->img->width, $y);
2636
        } elseif ($this->subtitle->halign == 'left') {
2637
            $this->subtitle->SetPos($this->subtitle->margin + 2, $y);
2638
        } elseif ($this->subtitle->halign == 'right') {
2639
            $indent = 0;
2640
            if ($this->doshadow) {
2641
                $indent = $this->shadow_width + 2;
2642
            }
2643
2644
            $this->subtitle->SetPos($this->img->width - $this->subtitle->margin - $indent, $y, 'right');
2645
        }
2646 18
        $this->subtitle->Stroke($this->img);
2647
2648
        // ... and subsubtitle
2649 18
        $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
2650 18
        if ($this->subsubtitle->halign == 'center') {
2651 18
            $this->subsubtitle->Center(0, $this->img->width, $y);
2652
        } elseif ($this->subsubtitle->halign == 'left') {
2653
            $this->subsubtitle->SetPos($this->subsubtitle->margin + 2, $y);
2654
        } elseif ($this->subsubtitle->halign == 'right') {
2655
            $indent = 0;
2656
            if ($this->doshadow) {
2657
                $indent = $this->shadow_width + 2;
2658
            }
2659
2660
            $this->subsubtitle->SetPos($this->img->width - $this->subsubtitle->margin - $indent, $y, 'right');
2661
        }
2662 18
        $this->subsubtitle->Stroke($this->img);
2663
2664
        // ... and fancy title
2665 18
        $this->tabtitle->Stroke($this->img);
2666 18
    }
2667
2668
    public function StrokeTexts()
2669
    {
2670
        // Stroke any user added text objects
2671 14
        if ($this->texts != null) {
2672 1
            for ($i = 0; $i < count($this->texts); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2673 1
                $this->texts[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2674
            }
2675
        }
2676
2677 14
        if ($this->y2texts != null && $this->y2scale != null) {
2678
            for ($i = 0; $i < count($this->y2texts); ++$i) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
2679
                $this->y2texts[$i]->StrokeWithScale($this->img, $this->xscale, $this->y2scale);
2680
            }
2681
        }
2682 14
    }
2683
2684
    public function StrokeTables()
2685
    {
2686 14
        if ($this->iTables != null) {
2687
            $n = count($this->iTables);
2688
            for ($i = 0; $i < $n; ++$i) {
2689
                $this->iTables[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2690
            }
2691
        }
2692 14
    }
2693
2694
    public function DisplayClientSideaImageMapAreas()
2695
    {
2696
        // Debug stuff - display the outline of the image map areas
2697
        $csim = '';
2698
        foreach ($this->plots as $p) {
2699
            $csim .= $p->GetCSIMareas();
2700
        }
2701
        $csim .= $this->legend->GetCSIMareas();
2702
        if (preg_match_all('/area shape="(\\w+)" coords="([0-9\\, ]+)"/', $csim, $coords)) {
2703
            $this->img->SetColor($this->csimcolor);
2704
            $n = count($coords[0]);
2705
            for ($i = 0; $i < $n; ++$i) {
2706
                if ($coords[1][$i] == 'poly') {
2707
                    preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/', $coords[2][$i], $pts);
2708
                    $this->img->SetStartPoint($pts[1][count($pts[0]) - 1], $pts[2][count($pts[0]) - 1]);
2709
                    $m = count($pts[0]);
2710
                    for ($j = 0; $j < $m; ++$j) {
2711
                        $this->img->LineTo($pts[1][$j], $pts[2][$j]);
2712
                    }
2713
                } elseif ($coords[1][$i] == 'rect') {
2714
                    $pts = preg_split('/,/', $coords[2][$i]);
2715
                    $this->img->SetStartPoint($pts[0], $pts[1]);
2716
                    $this->img->LineTo($pts[2], $pts[1]);
2717
                    $this->img->LineTo($pts[2], $pts[3]);
2718
                    $this->img->LineTo($pts[0], $pts[3]);
2719
                    $this->img->LineTo($pts[0], $pts[1]);
2720
                }
2721
            }
2722
        }
2723
    }
2724
2725
    // Text scale offset in world coordinates
2726
    public function SetTextScaleOff($aOff)
2727
    {
2728 13
        $this->text_scale_off         = $aOff;
2729 13
        $this->xscale->text_scale_off = $aOff;
2730 13
    }
2731
2732
    // Text width of bar to be centered in absolute pixels
2733
    public function SetTextScaleAbsCenterOff($aOff)
2734
    {
2735 2
        $this->text_scale_abscenteroff = $aOff;
2736 2
    }
2737
2738
    // Get Y min and max values for added lines
2739
    public function GetLinesYMinMax($aLines)
2740
    {
2741 13
        if (is_null($aLines)) {
2742 13
            return false;
2743
        }
2744
2745
        $n = count($aLines);
2746
        if ($n == 0) {
2747
            return false;
2748
        }
2749
2750
        $min = $aLines[0]->scaleposition;
2751
        $max = $min;
2752
        $flg = false;
2753
        for ($i = 0; $i < $n; ++$i) {
2754
            if ($aLines[$i]->direction == HORIZONTAL) {
2755
                $flg = true;
2756
                $v   = $aLines[$i]->scaleposition;
2757
                if ($min > $v) {
2758
                    $min = $v;
2759
                }
2760
2761
                if ($max < $v) {
2762
                    $max = $v;
2763
                }
2764
            }
2765
        }
2766
2767
        return $flg ? [$min, $max] : false;
0 ignored issues
show
introduced by
The condition $flg is always false.
Loading history...
2768
    }
2769
2770
    // Get X min and max values for added lines
2771
    public function GetLinesXMinMax($aLines)
2772
    {
2773 6
        $n = count($aLines);
2774 6
        if ($n == 0) {
2775 6
            return false;
2776
        }
2777
2778
        $min = $aLines[0]->scaleposition;
2779
        $max = $min;
2780
        $flg = false;
2781
        for ($i = 0; $i < $n; ++$i) {
2782
            if ($aLines[$i]->direction == VERTICAL) {
2783
                $flg = true;
2784
                $v   = $aLines[$i]->scaleposition;
2785
                if ($min > $v) {
2786
                    $min = $v;
2787
                }
2788
2789
                if ($max < $v) {
2790
                    $max = $v;
2791
                }
2792
            }
2793
        }
2794
2795
        return $flg ? [$min, $max] : false;
0 ignored issues
show
introduced by
The condition $flg is always false.
Loading history...
2796
    }
2797
2798
    // Get min and max values for all included plots
2799
    public function GetPlotsYMinMax($bPlots)
2800
    {
2801
        $aPlots = array_filter($bPlots, function ($plot) {
2802
            //\Kint::dump($plot, $plot instanceof Plot\Plot);
2803 13
            return $plot instanceof Plot\Plot;
2804 13
        });
2805 13
        reset($aPlots);
2806 13
        $n = count($aPlots);
2807 13
        $i = 0;
2808
        //\Kint::dump($n, $aPlots);
2809
        do {
2810
            //\Kint::dump($i, $aPlots[$i]);
2811 13
            list($xmax, $max) = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
2812 13
        } while (++$i < $n && !is_numeric($max));
2813
2814 13
        $i = 0;
2815
        do {
2816 13
            list($xmin, $min) = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
2817 13
        } while (++$i < $n && !is_numeric($min));
2818
2819 13
        if (!is_numeric($min) || !is_numeric($max)) {
2820
            Util\JpGraphError::RaiseL(25044); //('Cannot use autoscaling since it is impossible to determine a valid min/max value  of the Y-axis (only null values).');
2821
        }
2822
2823 13
        for ($i = 0; $i < $n; ++$i) {
2824 13
            list($xmax, $ymax) = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
2825 13
            list($xmin, $ymin) = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
2826 13
            if (is_numeric($ymax)) {
2827 13
                $max = max($max, $ymax);
2828
            }
2829
2830 13
            if (is_numeric($ymin)) {
2831 13
                $min = min($min, $ymin);
2832
            }
2833
        }
2834 13
        if ($min == '') {
2835 5
            $min = 0;
2836
        }
2837
2838 13
        if ($max == '') {
2839 1
            $max = 0;
2840
        }
2841
2842 13
        if ($min == 0 && $max == 0) {
2843
            // Special case if all values are 0
2844
            $min = 0;
2845
            $max = 1;
2846
        }
2847
2848 13
        return [$min, $max];
2849
    }
2850
2851
    public function hasLinePlotAndBarPlot()
2852
    {
2853
        $has_line = false;
2854
        $has_bar  = false;
2855
2856
        foreach ($this->plots as $plot) {
2857
            if ($plot instanceof Plot\LinePlot) {
2858
                $has_line = true;
2859
            }
2860
            if ($plot instanceof Plot\BarPlot) {
2861
                $has_bar = true;
2862
            }
2863
        }
2864
2865
        if ($has_line && $has_bar) {
2866
            return true;
2867
        }
2868
2869
        return false;
2870
    }
2871
2872
    public function SetTheme($graph_theme)
2873
    {
2874 1
        if (!($this instanceof PieGraph)) {
2875 1
            if (!$this->isAfterSetScale) {
2876
                Util\JpGraphError::RaiseL(25133); //('Use Graph::SetTheme() after Graph::SetScale().');
2877
            }
2878
        }
2879
2880 1
        if ($this->graph_theme) {
2881 1
            $this->ClearTheme();
2882
        }
2883 1
        $this->graph_theme = $graph_theme;
2884 1
        $this->graph_theme->ApplyGraph($this);
2885 1
    }
2886
2887
    public function ClearTheme()
2888
    {
2889 2
        $this->graph_theme = null;
2890
2891 2
        $this->isRunningClear = true;
2892
2893 2
        $this->__construct(
2894 2
            $this->inputValues['aWidth'],
2895 2
            $this->inputValues['aHeight'],
2896 2
            $this->inputValues['aCachedName'],
2897 2
            $this->inputValues['aTimeout'],
2898 2
            $this->inputValues['aInline']
2899
        );
2900
2901 2
        if (!($this instanceof PieGraph)) {
2902 2
            if ($this->isAfterSetScale) {
2903 1
                $this->SetScale(
2904 1
                    $this->inputValues['aAxisType'],
2905 1
                    $this->inputValues['aYMin'],
2906 1
                    $this->inputValues['aYMax'],
2907 1
                    $this->inputValues['aXMin'],
2908 1
                    $this->inputValues['aXMax']
2909
                );
2910
            }
2911
        }
2912
2913 2
        $this->isRunningClear = false;
2914 2
    }
2915
2916
    public function SetSupersampling($do = false, $scale = 2)
2917
    {
2918
        if ($do) {
2919
            define('SUPERSAMPLING_SCALE', $scale);
2920
            // $this->img->scale = $scale;
2921
        } else {
2922
            define('SUPERSAMPLING_SCALE', 1);
2923
            //$this->img->scale = 0;
2924
        }
2925
    }
2926
} // @class
2927