Graph   F
last analyzed

Complexity

Total Complexity 566

Size/Duplication

Total Lines 2903
Duplicated Lines 0 %

Test Coverage

Coverage 58.04%

Importance

Changes 3
Bugs 1 Features 0
Metric Value
eloc 1638
c 3
b 1
f 0
dl 0
loc 2903
ccs 956
cts 1647
cp 0.5804
rs 0.8
wmc 566

92 Methods

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

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 v4.0.3
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 21
    public function __construct($aWidth = 300, $aHeight = 200, $aCachedName = '', $aTimeout = 0, $aInline = true)
152
    {
153 21
        $this->gDateLocale    = new Util\DateLocale();
154 21
        $this->gJpgDateLocale = new Util\DateLocale();
155 21
        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 21
        $this->InitializeFrameAndMargin();
161
162
        // Automatically generate the image file name based on the name of the script that
163
        // generates the graph
164 21
        if ($aCachedName == 'auto') {
165
            $aCachedName = Util\Helper::GenImgName();
166
        }
167
168
        // Should the image be streamed back to the browser or only to the cache?
169 21
        $this->inline = $aInline;
170
171 21
        $this->img   = new Image\RotImage($aWidth, $aHeight);
172 21
        $this->cache = new Image\ImgStreamCache();
173
174
        // Window doesn't like '?' in the file name so replace it with an '_'
175 21
        $aCachedName = str_replace('?', '_', $aCachedName);
176 21
        $this->SetupCache($aCachedName, $aTimeout);
177
178 21
        $this->title = new Text\Text();
179 21
        $this->title->ParagraphAlign('center');
180 21
        $this->title->SetFont(FF_DEFAULT, FS_NORMAL); //FF_FONT2, FS_BOLD
181 21
        $this->title->SetMargin(5);
182 21
        $this->title->SetAlign('center');
183
184 21
        $this->subtitle = new Text\Text();
185 21
        $this->subtitle->ParagraphAlign('center');
186 21
        $this->subtitle->SetMargin(3);
187 21
        $this->subtitle->SetAlign('center');
188
189 21
        $this->subsubtitle = new Text\Text();
190 21
        $this->subsubtitle->ParagraphAlign('center');
191 21
        $this->subsubtitle->SetMargin(3);
192 21
        $this->subsubtitle->SetAlign('center');
193
194 21
        $this->legend = new Legend();
195 21
        $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 21
        if ($aCachedName != '' && READ_CACHE && $aInline) {
200
            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 21
        $this->SetTickDensity(); // Normal density
206
207 21
        $this->tabtitle = new Text\GraphTabTitle();
208
209 21
        if (!$this->isRunningClear) {
210 21
            $this->inputValues                = [];
211 21
            $this->inputValues['aWidth']      = $aWidth;
212 21
            $this->inputValues['aHeight']     = $aHeight;
213 21
            $this->inputValues['aCachedName'] = $aCachedName;
214 21
            $this->inputValues['aTimeout']    = $aTimeout;
215 21
            $this->inputValues['aInline']     = $aInline;
216
217 21
            $theme_class = '\Amenadiel\JpGraph\Themes\\' . DEFAULT_THEME_CLASS;
218
219 21
            if (class_exists($theme_class)) {
220 21
                $this->graph_theme = new $theme_class();
221
            }
222
        }
223 21
    }
224
225 21
    public function InitializeFrameAndMargin()
226
    {
227 21
        $this->doframe      = true;
228 21
        $this->frame_color  = 'black';
229 21
        $this->frame_weight = 1;
230
231 21
        $this->titlebackground_framecolor  = 'blue';
232 21
        $this->titlebackground_framestyle  = 2;
233 21
        $this->titlebackground_frameweight = 1;
234 21
        $this->titlebackground_bevelheight = 3;
235 21
        $this->titlebkg_fillstyle          = TITLEBKG_FILLSTYLE_SOLID;
236 21
        $this->titlebkg_scolor1            = 'black';
237 21
        $this->titlebkg_scolor2            = 'white';
238 21
        $this->framebevel                  = false;
239 21
        $this->framebeveldepth             = 2;
240 21
        $this->framebevelborder            = false;
241 21
        $this->framebevelbordercolor       = 'black';
242 21
        $this->framebevelcolor1            = '[email protected]';
243 21
        $this->framebevelcolor2            = '[email protected]';
244
245 21
        $this->margin_color = [250, 250, 250];
246 21
    }
247
248 21
    public function SetupCache($aFilename, $aTimeout = 60)
249
    {
250 21
        $this->cache_name = $aFilename;
251 21
        $this->cache->SetTimeOut($aTimeout);
252 21
    }
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 1
    public function SetGridDepth($aDepth)
296
    {
297 1
        $this->grid_depth = $aDepth;
298 1
    }
299
300
    public function SetIconDepth($aDepth)
301
    {
302
        $this->iIconDepth = $aDepth;
303
    }
304
305
    // Specify graph angle 0-360 degrees.
306 2
    public function SetAngle($aAngle)
307
    {
308 2
        $this->img->SetAngle($aAngle);
309 2
    }
310
311 1
    public function SetAlphaBlending($aFlg = true)
312
    {
313 1
        $this->img->SetAlphaBlending($aFlg);
314 1
    }
315
316
    // Shortcut to image margin
317 17
    public function SetMargin($lm, $rm, $tm, $bm)
318
    {
319 17
        $this->img->SetMargin($lm, $rm, $tm, $bm);
320 17
    }
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 1
    public function Set90AndMargin($lm = 0, $rm = 0, $tm = 0, $bm = 0)
330
    {
331 1
        $lm = $lm == 0 ? floor(0.2 * $this->img->width) : $lm;
332 1
        $rm = $rm == 0 ? floor(0.1 * $this->img->width) : $rm;
333 1
        $tm = $tm == 0 ? floor(0.2 * $this->img->height) : $tm;
334 1
        $bm = $bm == 0 ? floor(0.1 * $this->img->height) : $bm;
335
336 1
        $adj = ($this->img->height - $this->img->width) / 2;
337 1
        $this->img->SetMargin($tm - $adj, $bm - $adj, $rm + $adj, $lm + $adj);
338 1
        $this->img->SetCenter(floor($this->img->width / 2), floor($this->img->height / 2));
339 1
        $this->SetAngle(90);
340 1
        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 1
        $this->xaxis->SetLabelAlign('right', 'center');
344 1
        $this->yaxis->SetLabelAlign('center', 'bottom');
345 1
    }
346
347 1
    public function SetClipping($aFlg = true)
348
    {
349 1
        $this->iDoClipping = $aFlg;
350 1
    }
351
352
    // Add a plot object to the graph
353 19
    public function Add($aPlot)
354
    {
355 19
        if ($aPlot == null) {
356
            Util\JpGraphError::RaiseL(25010); //("Graph::Add() You tried to add a null plot to the graph.");
357
        }
358 19
        if (is_array($aPlot) && safe_count($aPlot) > 0) {
359 1
            $cl = $aPlot[0];
360
        } else {
361 19
            $cl = $aPlot;
362
        }
363
364 19
        if ($cl instanceof Text\Text) {
365 1
            $this->AddText($aPlot);
366 19
        } elseif (($cl instanceof Plot\PlotLine)) {
367 1
            $this->AddLine($aPlot);
368 19
        } elseif (($cl instanceof Plot\PlotBand)) {
369
            $this->AddBand($aPlot);
370 19
        } elseif (($cl instanceof Plot\IconPlot)) {
371
            $this->AddIcon($aPlot);
372 19
        } elseif (($cl instanceof Text\GTextTable)) {
373
            $this->AddTable($aPlot);
374
        } else {
375 19
            if (is_array($aPlot)) {
376 1
                $this->plots = array_merge($this->plots, $aPlot);
377
            } else {
378 19
                $this->plots[] = $aPlot;
379
            }
380
        }
381
382 19
        if ($this->graph_theme) {
383 19
            $this->graph_theme->SetupPlot($aPlot);
384
        }
385 19
    }
386
387
    public function AddTable($aTable)
388
    {
389
        if (is_array($aTable)) {
390
            for ($i = 0; $i < safe_count($aTable); ++$i) {
391
                $this->iTables[] = $aTable[$i];
392
            }
393
        } else {
394
            $this->iTables[] = $aTable;
395
        }
396
    }
397
398
    public function AddIcon($aIcon)
399
    {
400
        if (is_array($aIcon)) {
401
            for ($i = 0; $i < safe_count($aIcon); ++$i) {
402
                $this->iIcons[] = $aIcon[$i];
403
            }
404
        } else {
405
            $this->iIcons[] = $aIcon;
406
        }
407
    }
408
409
    // Add plot to second Y-scale
410 3
    public function AddY2($aPlot)
411
    {
412 3
        if ($aPlot == null) {
413
            Util\JpGraphError::RaiseL(25011); //("Graph::AddY2() You tried to add a null plot to the graph.");
414
        }
415
416 3
        if (is_array($aPlot) && safe_count($aPlot) > 0) {
417
            $cl = $aPlot[0];
418
        } else {
419 3
            $cl = $aPlot;
420
        }
421
422 3
        if ($cl instanceof Text\Text) {
423
            $this->AddText($aPlot, true);
424 3
        } elseif (($cl instanceof Plot\PlotLine)) {
425
            $this->AddLine($aPlot, true);
426 3
        } elseif (($cl instanceof Plot\PlotBand)) {
427
            $this->AddBand($aPlot, true);
428
        } else {
429 3
            $this->y2plots[] = $aPlot;
430
        }
431
432 3
        if ($this->graph_theme) {
433 3
            $this->graph_theme->SetupPlot($aPlot);
434
        }
435 3
    }
436
437
    // Add plot to the extra Y-axises
438
    public function AddY($aN, $aPlot)
439
    {
440
        if ($aPlot == null) {
441
            Util\JpGraphError::RaiseL(25012); //("Graph::AddYN() You tried to add a null plot to the graph.");
442
        }
443
444
        if (is_array($aPlot) && safe_count($aPlot) > 0) {
445
            $cl = $aPlot[0];
446
        } else {
447
            $cl = $aPlot;
448
        }
449
450
        if (($cl instanceof Text\Text) ||
451
            ($cl instanceof Plot\PlotLine) ||
452
            ($cl instanceof Plot\PlotBand)) {
453
            Util\JpGraphError::RaiseL(25013); //('You can only add standard plots to multiple Y-axis');
454
        } else {
455
            $this->ynplots[$aN][] = $aPlot;
456
        }
457
458
        if ($this->graph_theme) {
459
            $this->graph_theme->SetupPlot($aPlot);
460
        }
461
    }
462
463
    // Add text object to the graph
464 1
    public function AddText($aTxt, $aToY2 = false)
465
    {
466 1
        if ($aTxt == null) {
467
            Util\JpGraphError::RaiseL(25014); //("Graph::AddText() You tried to add a null text to the graph.");
468
        }
469 1
        if ($aToY2) {
470
            if (is_array($aTxt)) {
471
                for ($i = 0; $i < safe_count($aTxt); ++$i) {
472
                    $this->y2texts[] = $aTxt[$i];
473
                }
474
            } else {
475
                $this->y2texts[] = $aTxt;
476
            }
477
        } else {
478 1
            if (is_array($aTxt)) {
479
                for ($i = 0; $i < safe_count($aTxt); ++$i) {
480
                    $this->texts[] = $aTxt[$i];
481
                }
482
            } else {
483 1
                $this->texts[] = $aTxt;
484
            }
485
        }
486 1
    }
487
488
    // Add a line object (class PlotLine) to the graph
489 2
    public function AddLine($aLine, $aToY2 = false)
490
    {
491 2
        if ($aLine == null) {
492
            Util\JpGraphError::RaiseL(25015); //("Graph::AddLine() You tried to add a null line to the graph.");
493
        }
494
495 2
        if ($aToY2) {
496
            if (is_array($aLine)) {
497
                for ($i = 0; $i < safe_count($aLine); ++$i) {
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 2
            if (is_array($aLine)) {
507
                for ($i = 0; $i < safe_count($aLine); ++$i) {
508
                    //$this->lines[]=$aLine[$i];
509
                    $this->plots[] = $aLine[$i];
510
                }
511
            } else {
512
                //$this->lines[] = $aLine;
513 2
                $this->plots[] = $aLine;
514
            }
515
        }
516 2
    }
517
518
    // Add vertical or horizontal band
519
    public function AddBand($aBand, $aToY2 = false)
520
    {
521
        if ($aBand == null) {
522
            Util\JpGraphError::RaiseL(25016); //(" Graph::AddBand() You tried to add a null band to the graph.");
523
        }
524
525
        if ($aToY2) {
526
            if (is_array($aBand)) {
527
                for ($i = 0; $i < safe_count($aBand); ++$i) {
528
                    $this->y2bands[] = $aBand[$i];
529
                }
530
            } else {
531
                $this->y2bands[] = $aBand;
532
            }
533
        } else {
534
            if (is_array($aBand)) {
535
                for ($i = 0; $i < safe_count($aBand); ++$i) {
536
                    $this->bands[] = $aBand[$i];
537
                }
538
            } else {
539
                $this->bands[] = $aBand;
540
            }
541
        }
542
    }
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 3
    public function SetBackgroundGradient($aFrom = 'navy', $aTo = 'silver', $aGradType = 2, $aStyle = BGRAD_FRAME)
552
    {
553 3
        $this->bkg_gradtype  = $aGradType;
554 3
        $this->bkg_gradstyle = $aStyle;
555 3
        $this->bkg_gradfrom  = $aFrom;
556 3
        $this->bkg_gradto    = $aTo;
557 3
    }
558
559
    // Set a country flag in the background
560
    public function SetBackgroundCFlag($aName, $aBgType = BGIMG_FILLPLOT, $aMix = 100)
561
    {
562
        $this->background_cflag      = $aName;
563
        $this->background_cflag_type = $aBgType;
564
        $this->background_cflag_mix  = $aMix;
565
    }
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 4
    public function SetBackgroundImage($aFileName, $aBgType = BGIMG_FILLPLOT, $aImgFormat = 'auto')
577
    {
578
        // Get extension to determine image type
579 4
        if ($aImgFormat == 'auto') {
580 4
            $e = explode('.', $aFileName);
581 4
            if (empty($e)) {
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 4
            $valid_formats = ['png', 'jpg', 'gif'];
586 4
            $aImgFormat    = strtolower($e[count($e) - 1]);
587 4
            if ($aImgFormat == 'jpeg') {
588
                $aImgFormat = 'jpg';
589 4
            } 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 4
        $this->background_image        = $aFileName;
595 4
        $this->background_image_type   = $aBgType;
596 4
        $this->background_image_format = $aImgFormat;
597 4
    }
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 3
    public function SetAxisStyle($aStyle)
613
    {
614 3
        $this->iAxisStyle = $aStyle;
615 3
    }
616
617
    // Set a frame around the plot area
618 19
    public function SetBox($aDrawPlotFrame = true, $aPlotFrameColor = [0, 0, 0], $aPlotFrameWeight = 1)
619
    {
620 19
        $this->boxed      = $aDrawPlotFrame;
621 19
        $this->box_weight = $aPlotFrameWeight;
622 19
        $this->box_color  = $aPlotFrameColor;
623 19
    }
624
625
    // Specify color for the plotarea (not the margins)
626 3
    public function SetColor($aColor)
627
    {
628 3
        $this->plotarea_color = $aColor;
629 3
    }
630
631
    // Specify color for the margins (all areas outside the plotarea)
632 21
    public function SetMarginColor($aColor)
633
    {
634 21
        $this->margin_color = $aColor;
635 21
    }
636
637
    // Set a frame around the entire image
638 21
    public function SetFrame($aDrawImgFrame = true, $aImgFrameColor = [0, 0, 0], $aImgFrameWeight = 1)
639
    {
640 21
        $this->doframe      = $aDrawImgFrame;
641 21
        $this->frame_color  = $aImgFrameColor;
642 21
        $this->frame_weight = $aImgFrameWeight;
643 21
    }
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 11
    public function SetShadow($aShowShadow = true, $aShadowWidth = 5, $aShadowColor = 'darkgray')
659
    {
660 11
        $this->doshadow     = $aShowShadow;
661 11
        $this->shadow_color = $aShadowColor;
662 11
        $this->shadow_width = $aShadowWidth;
663 11
        $this->footer->iBottomMargin += $aShadowWidth;
664 11
        $this->footer->iRightMargin += $aShadowWidth;
665 11
    }
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 19
    public function SetScale($aAxisType, $aYMin = 1, $aYMax = 1, $aXMin = 1, $aXMax = 1)
670
    {
671 19
        $this->axtype = $aAxisType;
672
673 19
        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 19
        $yt = substr($aAxisType, -3, 3);
678 19
        if ($yt == 'lin') {
679 17
            $this->yscale = new LinearScale($aYMin, $aYMax);
680 4
        } elseif ($yt == 'int') {
681 2
            $this->yscale = new LinearScale($aYMin, $aYMax);
682 2
            $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 19
        $xt = substr($aAxisType, 0, 3);
690 19
        if ($xt == 'lin' || $xt == 'tex') {
691 17
            $this->xscale            = new LinearScale($aXMin, $aXMax, 'x');
692 17
            $this->xscale->textscale = ($xt == 'tex');
693 5
        } elseif ($xt == 'int') {
694 5
            $this->xscale = new LinearScale($aXMin, $aXMax, 'x');
695 5
            $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 19
        $this->xaxis = new Axis($this->img, $this->xscale);
705 19
        $this->yaxis = new Axis($this->img, $this->yscale);
706 19
        $this->xgrid = new Grid($this->xaxis);
707 19
        $this->ygrid = new Grid($this->yaxis);
708 19
        $this->ygrid->Show();
709
710 19
        if (!$this->isRunningClear) {
711 19
            $this->inputValues['aAxisType'] = $aAxisType;
712 19
            $this->inputValues['aYMin']     = $aYMin;
713 19
            $this->inputValues['aYMax']     = $aYMax;
714 19
            $this->inputValues['aXMin']     = $aXMin;
715 19
            $this->inputValues['aXMax']     = $aXMax;
716
717 19
            if ($this->graph_theme) {
718 19
                $this->graph_theme->ApplyGraph($this);
719
            }
720
        }
721
722 19
        $this->isAfterSetScale = true;
723 19
    }
724
725
    // Specify secondary Y scale
726 3
    public function SetY2Scale($aAxisType = 'lin', $aY2Min = 1, $aY2Max = 1)
727
    {
728 3
        if ($aAxisType == 'lin') {
729 3
            $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 3
        $this->y2axis = new Axis($this->img, $this->y2scale);
740 3
        $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
741 3
        $this->y2axis->SetLabelSide(SIDE_RIGHT);
742 3
        $this->y2axis->SetPos('max');
743 3
        $this->y2axis->SetTitleSide(SIDE_RIGHT);
744
745
        // Deafult position is the max x-value
746 3
        $this->y2grid = new Grid($this->y2axis);
747
748 3
        if ($this->graph_theme) {
749 3
            $this->graph_theme->ApplyGraph($this);
750
        }
751 3
    }
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
    public function SetYScale($aN, $aAxisType = 'lin', $aYMin = 1, $aYMax = 1)
761
    {
762
        if ($aAxisType == 'lin') {
763
            $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
        $this->ynaxis[$aN] = new Axis($this->img, $this->ynscale[$aN]);
774
        $this->ynaxis[$aN]->scale->ticks->SetDirection(SIDE_LEFT);
775
        $this->ynaxis[$aN]->SetLabelSide(SIDE_RIGHT);
776
777
        if ($this->graph_theme) {
778
            $this->graph_theme->ApplyGraph($this);
779
        }
780
    }
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 21
    public function SetTickDensity($aYDensity = TICKD_NORMAL, $aXDensity = TICKD_NORMAL)
786
    {
787 21
        $this->xtick_factor = 30;
788 21
        $this->ytick_factor = 25;
789
        switch ($aYDensity) {
790 21
            case TICKD_DENSE:
791
                $this->ytick_factor = 12;
792
793
                break;
794 21
            case TICKD_NORMAL:
795 21
                $this->ytick_factor = 25;
796
797 21
                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 21
            case TICKD_DENSE:
811
                $this->xtick_factor = 15;
812
813
                break;
814 21
            case TICKD_NORMAL:
815 21
                $this->xtick_factor = 30;
816
817 21
                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 21
    }
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 = safe_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 = safe_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 = safe_count($this->plots);
867
        for ($i = 0; $i < $n; ++$i) {
868
            $csim .= $this->plots[$i]->GetCSIMareas();
869
        }
870
871
        $n = safe_count($this->y2plots);
872
        for ($i = 0; $i < $n; ++$i) {
873
            $csim .= $this->y2plots[$i]->GetCSIMareas();
874
        }
875
876
        $n = safe_count($this->ynaxis);
877
        for ($i = 0; $i < $n; ++$i) {
878
            $m = safe_count($this->ynplots[$i]);
879
            for ($j = 0; $j < $m; ++$j) {
880
                $csim .= $this->ynplots[$i][$j]->GetCSIMareas();
881
            }
882
        }
883
884
        $n = safe_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
        foreach ($_GET as $key => $value) {
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
        foreach ($_POST as $key => $value) {
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((int) (microtime() * 1000000));
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 17
    public function GetTextsYMinMax($aY2 = false)
1081
    {
1082 17
        if ($aY2) {
1083 3
            $txts = $this->y2texts;
1084
        } else {
1085 17
            $txts = $this->texts;
1086
        }
1087 17
        $n   = safe_count($txts);
1088 17
        $min = null;
1089 17
        $max = null;
1090 17
        for ($i = 0; $i < $n; ++$i) {
1091
            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 17
        if ($min !== null) {
1101
            return [$min, $max];
1102
        }
1103
1104 17
        return null;
1105
    }
1106
1107 7
    public function GetTextsXMinMax($aY2 = false)
1108
    {
1109 7
        if ($aY2) {
1110 7
            $txts = $this->y2texts;
1111
        } else {
1112 7
            $txts = $this->texts;
1113
        }
1114 7
        $n   = safe_count($txts);
1115 7
        $min = null;
1116 7
        $max = null;
1117 7
        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 7
        if ($min !== null) {
1128
            return [$min, $max];
1129
        }
1130
1131 7
        return null;
1132
    }
1133
1134 7
    public function GetXMinMax()
1135
    {
1136 7
        list($min, $ymin) = $this->plots[0]->Min();
1137 7
        list($max, $ymax) = $this->plots[0]->Max();
1138
1139 7
        $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 7
        while (($min === null || $max === null) && ($i < safe_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 7
        foreach ($this->plots as $p) {
1150 7
            list($xmin, $ymin) = $p->Min();
1151 7
            list($xmax, $ymax) = $p->Max();
1152
1153 7
            if ($xmin !== null && $xmax !== null) {
1154 7
                $min = min($xmin, $min);
1155 7
                $max = max($xmax, $max);
1156
            }
1157
        }
1158
1159 7
        if ($this->y2axis != null) {
1160 1
            foreach ($this->y2plots as $p) {
1161 1
                list($xmin, $ymin) = $p->Min();
1162 1
                list($xmax, $ymax) = $p->Max();
1163 1
                $min               = min($xmin, $min);
1164 1
                $max               = max($xmax, $max);
1165
            }
1166
        }
1167
1168 7
        $n = safe_count($this->ynaxis);
1169 7
        for ($i = 0; $i < $n; ++$i) {
1170
            if ($this->ynaxis[$i] != null) {
1171
                foreach ($this->ynplots[$i] as $p) {
1172
                    list($xmin, $ymin) = $p->Min();
1173
                    list($xmax, $ymax) = $p->Max();
1174
                    $min               = min($xmin, $min);
1175
                    $max               = max($xmax, $max);
1176
                }
1177
            }
1178
        }
1179
1180 7
        return [$min, $max];
1181
    }
1182
1183 19
    public function AdjustMarginsForTitles()
1184
    {
1185
        $totrequired =
1186 19
            ($this->title->t != ''
1187 15
            ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * SUPERSAMPLING_SCALE
1188 7
            : 0) +
1189 19
            ($this->subtitle->t != ''
1190 6
            ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * SUPERSAMPLING_SCALE
1191 19
            : 0) +
1192 19
            ($this->subsubtitle->t != ''
1193
            ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * SUPERSAMPLING_SCALE
1194 19
            : 0);
1195
1196 19
        $btotrequired = 0;
1197 19
        if ($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels) {
1198
            // Minimum bottom margin
1199 19
            if ($this->xaxis->title->t != '') {
1200 5
                if ($this->img->a == 90) {
1201 1
                    $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7;
1202
                } else {
1203 5
                    $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7;
1204
                }
1205
            } else {
1206 16
                $btotrequired = 0;
1207
            }
1208
1209 19
            if ($this->img->a == 90) {
1210 2
                $this->img->SetFont(
1211 2
                    $this->yaxis->font_family,
1212 2
                    $this->yaxis->font_style,
1213 2
                    $this->yaxis->font_size
1214
                );
1215 2
                $lh = $this->img->GetTextHeight('Mg', $this->yaxis->label_angle);
1216
            } else {
1217 19
                $this->img->SetFont(
1218 19
                    $this->xaxis->font_family,
1219 19
                    $this->xaxis->font_style,
1220 19
                    $this->xaxis->font_size
1221
                );
1222 19
                $lh = $this->img->GetTextHeight('Mg', $this->xaxis->label_angle);
1223
            }
1224
1225 19
            $btotrequired += $lh + 6;
1226
        }
1227
1228 19
        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 19
            if ($this->img->top_margin < $totrequired) {
1233 5
                $this->SetMargin(
1234 5
                    $this->img->raw_left_margin,
1235 5
                    $this->img->raw_right_margin,
1236 5
                    $totrequired / SUPERSAMPLING_SCALE,
1237 5
                    $this->img->raw_bottom_margin
1238
                );
1239
            }
1240
1241
            // need more bottom margin
1242 19
            if ($this->img->bottom_margin < $btotrequired) {
1243 1
                $this->SetMargin(
1244 1
                    $this->img->raw_left_margin,
1245 1
                    $this->img->raw_right_margin,
1246 1
                    $this->img->raw_top_margin,
1247 1
                    $btotrequired / SUPERSAMPLING_SCALE
1248
                );
1249
            }
1250
        }
1251 19
    }
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 19
    public function doAutoscaleXAxis()
1268
    {
1269
        $aPlots = array_filter($this->plots, function ($plot) {
1270
            //\Kint::dump($plot, $plot instanceof Plot\Plot);
1271 19
            return $plot instanceof Plot\Plot;
1272 19
        });
1273
1274
        //Check if we should autoscale x-axis
1275 19
        if (!$this->xscale->IsSpecified()) {
1276 17
            if (substr($this->axtype, 0, 4) == 'text') {
1277 13
                $max = 0;
1278 13
                $n   = safe_count($aPlots);
1279
1280 13
                for ($i = 0; $i < $n; ++$i) {
1281 13
                    $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 13
                    $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 13
                    if (empty($p->barcenter)) {
1292 13
                        $max = max($max, $p->numpoints - 1);
1293
                    } else {
1294
                        $max = max($max, $p->numpoints);
1295
                    }
1296
                }
1297 13
                $min = 0;
1298 13
                if ($this->y2axis != null) {
1299 2
                    foreach ($this->y2plots as $p) {
1300 2
                        $max = max($max, $p->numpoints - 1);
1301
                    }
1302
                }
1303 13
                $n = safe_count($this->ynaxis);
1304 13
                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 13
                $this->xscale->Update($this->img, $min, $max);
1313 13
                $this->xscale->ticks->Set($this->xaxis->tick_step, 1);
1314 13
                $this->xscale->ticks->SupressMinorTickMarks();
1315
            } else {
1316 7
                list($min, $max) = $this->GetXMinMax();
1317
1318 7
                $lres = $this->GetLinesXMinMax($this->lines);
1319 7
                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 7
                $lres = $this->GetLinesXMinMax($this->y2lines);
1326 7
                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 7
                $tres = $this->GetTextsXMinMax();
1333 7
                if ($tres) {
1334
                    list($tmin, $tmax) = $tres;
1335
                    $min               = min($min, $tmin);
1336
                    $max               = max($max, $tmax);
1337
                }
1338
1339 7
                $tres = $this->GetTextsXMinMax(true);
1340 7
                if ($tres) {
1341
                    list($tmin, $tmax) = $tres;
1342
                    $min               = min($min, $tmin);
1343
                    $max               = max($max, $tmax);
1344
                }
1345
1346 7
                $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 17
            if (!is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos)) {
1351 17
                $this->yaxis->SetPos($this->xscale->GetMinVal());
1352
            }
1353 4
        } elseif ($this->xscale->IsSpecified() &&
1354 4
            ($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 19
        if ($this->y2axis != null) {
1378 3
            if (!is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos)) {
1379
                $this->y2axis->SetPos($this->xscale->GetMaxVal());
1380
            }
1381 3
            $this->y2axis->SetTitleSide(SIDE_RIGHT);
1382
        }
1383
1384 19
        $n      = safe_count($this->ynaxis);
1385 19
        $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0;
1386 19
        for ($i = 0; $i < $n; ++$i) {
1387
            if ($this->ynaxis[$i] != null) {
1388
                if (!is_numeric($this->ynaxis[$i]->pos) && !is_string($this->ynaxis[$i]->pos)) {
1389
                    $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal());
1390
                    $this->ynaxis[$i]->SetPosAbsDelta($i * $this->iYAxisDeltaPos + $nY2adj);
1391
                }
1392
                $this->ynaxis[$i]->SetTitleSide(SIDE_RIGHT);
1393
            }
1394
        }
1395 19
    }
1396
1397 19
    public function doAutoScaleYnAxis()
1398
    {
1399 19
        if ($this->y2scale != null) {
1400 3
            if (!$this->y2scale->IsSpecified() && safe_count($this->y2plots) > 0) {
1401 3
                list($min, $max) = $this->GetPlotsYMinMax($this->y2plots);
1402
1403 3
                $lres = $this->GetLinesYMinMax($this->y2lines);
1404 3
                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 3
                $tres = $this->GetTextsYMinMax(true);
1410 3
                if (is_array($tres)) {
1411
                    list($tmin, $tmax) = $tres;
1412
                    $min               = min($min, $tmin);
1413
                    $max               = max($max, $tmax);
1414
                }
1415 3
                $this->y2scale->AutoScale($this->img, $min, $max, $this->img->plotheight / $this->ytick_factor);
1416
            } 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
                $min = $this->y2scale->scale[0];
1423
                $max = $this->y2scale->scale[1];
1424
                $this->y2scale->AutoScale(
1425
                    $this->img,
1426
                    $min,
1427
                    $max,
1428
                    $this->img->plotheight / $this->ytick_factor,
1429
                    $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
                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 19
        $n = safe_count($this->ynaxis);
1449 19
        for ($i = 0; $i < $n; ++$i) {
1450
            if ($this->ynscale[$i] != null) {
1451
                if (!$this->ynscale[$i]->IsSpecified() && safe_count($this->ynplots[$i]) > 0) {
1452
                    list($min, $max) = $this->GetPlotsYMinMax($this->ynplots[$i]);
1453
                    $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 19
    }
1484
1485 19
    public function doAutoScaleYAxis()
1486
    {
1487
        //Check if we should autoscale y-axis
1488 19
        if (!$this->yscale->IsSpecified() && safe_count($this->plots) > 0) {
1489 17
            list($min, $max) = $this->GetPlotsYMinMax($this->plots);
1490 17
            $lres            = $this->GetLinesYMinMax($this->lines);
1491 17
            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 17
            $tres = $this->GetTextsYMinMax();
1497 17
            if (is_array($tres)) {
1498
                list($tmin, $tmax) = $tres;
1499
                $min               = min($min, $tmin);
1500
                $max               = max($max, $tmax);
1501
            }
1502 17
            $this->yscale->AutoScale(
1503 17
                $this->img,
1504 17
                $min,
1505 17
                $max,
1506 17
                $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 19
    }
1536
1537 19
    public function InitScaleConstants()
1538
    {
1539
        // Setup scale constants
1540 19
        if ($this->yscale) {
1541 19
            $this->yscale->InitConstants($this->img);
1542
        }
1543
1544 19
        if ($this->xscale) {
1545 19
            $this->xscale->InitConstants($this->img);
1546
        }
1547
1548 19
        if ($this->y2scale) {
1549 3
            $this->y2scale->InitConstants($this->img);
1550
        }
1551
1552 19
        $n = safe_count($this->ynscale);
1553 19
        for ($i = 0; $i < $n; ++$i) {
1554
            if ($this->ynscale[$i]) {
1555
                $this->ynscale[$i]->InitConstants($this->img);
1556
            }
1557
        }
1558 19
    }
1559
1560 19
    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 19
        for ($i = 0; $i < safe_count($this->plots); ++$i) {
1565 19
            if ($this->plots[$i] instanceof Plot\Plot) {
1566 19
                $this->plots[$i]->PreStrokeAdjust($this);
1567 19
                $this->plots[$i]->DoLegend($this);
1568
            }
1569
        }
1570
1571
        // Any plots on the second Y scale?
1572 19
        if ($this->y2scale != null) {
1573 3
            for ($i = 0; $i < safe_count($this->y2plots); ++$i) {
1574 3
                if ($this->plots[$i] instanceof Plot\Plot) {
1575 3
                    $this->y2plots[$i]->PreStrokeAdjust($this);
1576 3
                    $this->y2plots[$i]->DoLegend($this);
1577
                }
1578
            }
1579
        }
1580
1581
        // Any plots on the extra Y axises?
1582 19
        $n = safe_count($this->ynaxis);
1583 19
        for ($i = 0; $i < $n; ++$i) {
1584
            if ($this->ynplots == null || $this->ynplots[$i] == null) {
1585
                Util\JpGraphError::RaiseL(25032, $i); //("No plots for Y-axis nbr:$i");
1586
            }
1587
            $m = safe_count($this->ynplots[$i]);
1588
            for ($j = 0; $j < $m; ++$j) {
1589
                $this->ynplots[$i][$j]->PreStrokeAdjust($this);
1590
                $this->ynplots[$i][$j]->DoLegend($this);
1591
            }
1592
        }
1593 19
    }
1594
1595 19
    public function StrokeBands($aDepth, $aCSIM)
1596
    {
1597
        // Stroke bands
1598 19
        if ($this->bands != null && !$aCSIM) {
1599
            for ($i = 0; $i < safe_count($this->bands); ++$i) {
1600
                // Stroke all bands that asks to be in the background
1601
                if ($this->bands[$i]->depth == $aDepth) {
1602
                    $this->bands[$i]->Stroke($this->img, $this->xscale, $this->yscale);
1603
                }
1604
            }
1605
        }
1606
1607 19
        if ($this->y2bands != null && $this->y2scale != null && !$aCSIM) {
1608
            for ($i = 0; $i < safe_count($this->y2bands); ++$i) {
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 19
    }
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 19
    public function Stroke($aStrokeFileName = '')
1621
    {
1622
        // Fist make a sanity check that user has specified a scale
1623 19
        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 19
        $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 19
        for ($i = 0; $i < safe_count($this->plots); ++$i) {
1634 19
            if ($this->plots[$i] instanceof Plot\Plot) {
1635 19
                $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 19
        $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 19
        $_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 19
        $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 19
        $this->iHasStroked = true;
1664
1665
        // Setup pre-stroked adjustments and Legends
1666 19
        $this->doPrestrokeAdjustments();
1667
1668 19
        if ($this->graph_theme) {
1669 19
            $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 19
        if ((!$this->yscale->IsSpecified() && safe_count($this->plots) == 0) ||
1677 19
            ($this->y2scale != null && !$this->y2scale->IsSpecified() && safe_count($this->y2plots) == 0)) {
1678
            //$e = "n=". safe_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 19
        if ((!$this->xscale->IsSpecified() && safe_count($this->plots) == 0 && safe_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 19
        $this->doAutoScaleYAxis();
1692
1693
        // Autoscale all additiopnal y-axis
1694 19
        $this->doAutoScaleYnAxis();
1695
1696
        // Autoscale the regular x-axis and position the y-axis properly
1697 19
        $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 19
        if (($this->yaxis->pos == $this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos == 'min')) &&
1710 19
            !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 &&
1711 19
            substr($this->axtype, 0, 4) != 'text' && $this->xaxis->pos != 'min') {
1712
            //$this->yscale->ticks->SupressZeroLabel(false);
1713 2
            $this->xscale->ticks->SupressFirst();
1714 2
            if ($this->y2axis != null) {
1715 2
                $this->xscale->ticks->SupressLast();
1716
            }
1717 19
        } elseif (!is_numeric($this->yaxis->pos) && $this->yaxis->pos == 'max') {
1718
            $this->xscale->ticks->SupressLast();
1719
        }
1720
1721 19
        if (!$_csim) {
1722 19
            $this->StrokePlotArea();
1723 19
            if ($this->iIconDepth == DEPTH_BACK) {
1724 19
                $this->StrokeIcons();
1725
            }
1726
        }
1727 19
        $this->StrokeAxis(false);
1728
1729
        // Stroke colored bands
1730 19
        $this->StrokeBands(DEPTH_BACK, $_csim);
1731
1732 19
        if ($this->grid_depth == DEPTH_BACK && !$_csim) {
1733 19
            $this->ygrid->Stroke();
1734 19
            $this->xgrid->Stroke();
1735
        }
1736
1737
        // Stroke Y2-axis
1738 19
        if ($this->y2axis != null && !$_csim) {
1739 3
            $this->y2axis->Stroke($this->xscale);
1740 3
            $this->y2grid->Stroke();
1741
        }
1742
1743
        // Stroke yn-axis
1744 19
        $n = safe_count($this->ynaxis);
1745 19
        for ($i = 0; $i < $n; ++$i) {
1746
            $this->ynaxis[$i]->Stroke($this->xscale);
1747
        }
1748
1749 19
        $oldoff = $this->xscale->off;
1750 19
        if (substr($this->axtype, 0, 4) == 'text') {
1751 13
            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 1
                $this->xscale->off += round($this->xscale->scale_factor / 2) - round($this->text_scale_abscenteroff / 2);
1757
            } else {
1758 12
                $this->xscale->off += ceil($this->xscale->scale_factor * $this->text_scale_off * $this->xscale->ticks->minor_step);
1759
            }
1760
        }
1761
1762 19
        if ($this->iDoClipping) {
1763 1
            $oldimage = $this->img->CloneCanvasH();
1764
        }
1765
1766 19
        if (!$this->y2orderback) {
1767
            // Stroke all plots for Y1 axis
1768
            for ($i = 0; $i < safe_count($this->plots); ++$i) {
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 19
        if ($this->y2scale != null) {
1778 3
            for ($i = 0; $i < safe_count($this->y2plots); ++$i) {
1779 3
                $this->y2plots[$i]->Stroke($this->img, $this->xscale, $this->y2scale);
1780
            }
1781
        }
1782
1783 19
        if ($this->y2orderback) {
1784
            // Stroke all plots for Y1 axis
1785 19
            for ($i = 0; $i < safe_count($this->plots); ++$i) {
1786 19
                $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale);
1787 19
                if ($this->plots[$i] instanceof Plot\Plot) {
1788 19
                    $this->plots[$i]->StrokeMargin($this->img);
1789
                }
1790
            }
1791
        }
1792
1793 19
        $n = safe_count($this->ynaxis);
1794 19
        for ($i = 0; $i < $n; ++$i) {
1795
            $m = safe_count($this->ynplots[$i]);
1796
            for ($j = 0; $j < $m; ++$j) {
1797
                $this->ynplots[$i][$j]->Stroke($this->img, $this->xscale, $this->ynscale[$i]);
1798
                if ($this->ynplots[$i][$j] instanceof Plot\Plot) {
1799
                    $this->ynplots[$i][$j]->StrokeMargin($this->img);
1800
                }
1801
            }
1802
        }
1803
1804 19
        if ($this->iIconDepth == DEPTH_FRONT) {
1805
            $this->StrokeIcons();
1806
        }
1807
1808 19
        if ($this->iDoClipping) {
1809
            // Clipping only supports graphs at 0 and 90 degrees
1810 1
            if ($this->img->a == 0) {
1811 1
                $this->img->CopyCanvasH(
1812 1
                    $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 1
                    $this->img->img,
1814 1
                    $this->img->left_margin,
1815 1
                    $this->img->top_margin,
1816 1
                    $this->img->left_margin,
1817 1
                    $this->img->top_margin,
1818 1
                    $this->img->plotwidth + 1,
1819 1
                    $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 1
            $this->img->Destroy();
1837 1
            $this->img->SetCanvasH($oldimage);
1838
        }
1839
1840 19
        $this->xscale->off = $oldoff;
1841
1842 19
        if ($this->grid_depth == DEPTH_FRONT && !$_csim) {
1843 1
            $this->ygrid->Stroke();
1844 1
            $this->xgrid->Stroke();
1845
        }
1846
1847
        // Stroke colored bands
1848 19
        $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 19
        if (!$_csim) {
1853 19
            $this->StrokeAxis();
1854
        }
1855
1856 19
        if ($this->y2scale != null && !$_csim) {
1857 3
            $this->y2axis->Stroke($this->xscale, false);
1858
        }
1859
1860 19
        if (!$_csim) {
1861 19
            $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 19
        $aa = $this->img->SetAngle(0);
1867 19
        $this->StrokeTitles();
1868 19
        $this->footer->Stroke($this->img);
1869 19
        $this->legend->Stroke($this->img);
1870 19
        $this->img->SetAngle($aa);
1871 19
        $this->StrokeTexts();
1872 19
        $this->StrokeTables();
1873
1874 19
        if (!$_csim) {
1875 19
            $this->img->SetAngle($aa);
1876
1877
            // Draw an outline around the image map
1878 19
            if (_JPG_DEBUG) {
1879
                $this->DisplayClientSideaImageMapAreas();
1880
            }
1881
1882
            // Should we do any final image transformation
1883 19
            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 19
            if ($aStrokeFileName == _IMG_HANDLER) {
1900
                return $this->img->img;
1901
            }
1902
            // Finally stream the generated picture
1903 19
            $this->cache->PutAndStream($this->img, $this->cache_name, $this->inline, $aStrokeFileName);
1904
        }
1905 19
    }
1906
1907
    public function SetAxisLabelBackground($aType, $aXFColor = 'lightgray', $aXColor = 'black', $aYFColor = 'lightgray', $aYColor = 'black')
1908
    {
1909
        $this->iAxisLblBgType       = $aType;
1910
        $this->iXAxisLblBgFillColor = $aXFColor;
1911
        $this->iXAxisLblBgColor     = $aXColor;
1912
        $this->iYAxisLblBgFillColor = $aYFColor;
1913
        $this->iYAxisLblBgColor     = $aYColor;
1914
    }
1915
1916 19
    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 19
        $t = $this->iAxisLblBgType;
1928 19
        if ($t < 1) {
1929 19
            return;
1930
        }
1931
1932
        // Stroke optional X-axis label background color
1933
        if ($t == 1 || $t == 3 || $t == 5 || $t == 6) {
1934
            $this->img->PushColor($this->iXAxisLblBgFillColor);
1935
            if ($t == 1 || $t == 6) {
1936
                $xl = $this->img->left_margin;
1937
                $yu = $this->img->height - $this->img->bottom_margin + 1;
1938
                $xr = $this->img->width - $this->img->right_margin;
1939
                $yl = $this->img->height - 1 - $this->frame_weight;
1940
            } else {
1941
                // t==3 || t==5
1942
                $xl = $this->frame_weight;
1943
                $yu = $this->img->height - $this->img->bottom_margin + 1;
1944
                $xr = $this->img->width - 1 - $this->frame_weight;
1945
                $yl = $this->img->height - 1 - $this->frame_weight;
1946
            }
1947
1948
            $this->img->FilledRectangle($xl, $yu, $xr, $yl);
1949
            $this->img->PopColor();
1950
1951
            // Check if we should add the vertical lines at left and right edge
1952
            if ($this->iXAxisLblBgColor !== '') {
1953
                // Hardcode to one pixel wide
1954
                $this->img->SetLineWeight(1);
1955
                $this->img->PushColor($this->iXAxisLblBgColor);
1956
                if ($t == 1 || $t == 6) {
1957
                    $this->img->Line($xl, $yu, $xl, $yl);
1958
                    $this->img->Line($xr, $yu, $xr, $yl);
1959
                } else {
1960
                    $xl = $this->img->width - $this->img->right_margin;
1961
                    $this->img->Line($xl, $yu - 1, $xr, $yu - 1);
1962
                }
1963
                $this->img->PopColor();
1964
            }
1965
        }
1966
1967
        if ($t == 2 || $t == 4 || $t == 5 || $t == 6) {
1968
            $this->img->PushColor($this->iYAxisLblBgFillColor);
1969
            if ($t == 2 || $t == 6) {
1970
                $xl = $this->frame_weight;
1971
                $yu = $this->frame_weight + $this->img->top_margin;
1972
                $xr = $this->img->left_margin - 1;
1973
                $yl = $this->img->height - $this->img->bottom_margin + 1;
1974
            } else {
1975
                $xl = $this->frame_weight;
1976
                $yu = $this->frame_weight;
1977
                $xr = $this->img->left_margin - 1;
1978
                $yl = $this->img->height - 1 - $this->frame_weight;
1979
            }
1980
1981
            $this->img->FilledRectangle($xl, $yu, $xr, $yl);
1982
            $this->img->PopColor();
1983
1984
            // Check if we should add the vertical lines at left and right edge
1985
            if ($this->iXAxisLblBgColor !== '') {
1986
                $this->img->PushColor($this->iXAxisLblBgColor);
1987
                if ($t == 2 || $t == 6) {
1988
                    $this->img->Line($xl, $yu - 1, $xr, $yu - 1);
1989
                    $this->img->Line($xl, $yl - 1, $xr, $yl - 1);
1990
                } else {
1991
                    $this->img->Line($xr + 1, $yu, $xr + 1, $this->img->top_margin);
1992
                }
1993
                $this->img->PopColor();
1994
            }
1995
        }
1996
    }
1997
1998 19
    public function StrokeAxis($aStrokeLabels = true)
1999
    {
2000 19
        if ($aStrokeLabels) {
2001 19
            $this->StrokeAxisLabelBackground();
2002
        }
2003
2004
        // Stroke axis
2005 19
        if ($this->iAxisStyle != AXSTYLE_SIMPLE) {
2006 3
            switch ($this->iAxisStyle) {
2007 3
                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 2
                case AXSTYLE_BOXOUT:
2015 2
                    $toppos    = SIDE_UP;
2016 2
                    $bottompos = SIDE_DOWN;
2017 2
                    $leftpos   = SIDE_LEFT;
2018 2
                    $rightpos  = SIDE_RIGHT;
2019
2020 2
                    break;
2021
                case AXSTYLE_YBOXIN:
2022
                    $toppos    = false;
2023
                    $bottompos = SIDE_UP;
2024
                    $leftpos   = SIDE_RIGHT;
2025
                    $rightpos  = SIDE_LEFT;
2026
2027
                    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 3
            $this->xscale->ticks->SupressFirst(false);
2045
2046
            // Now draw the bottom X-axis
2047 3
            $this->xaxis->SetPos('min');
2048 3
            $this->xaxis->SetLabelSide(SIDE_DOWN);
2049 3
            $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 3
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2051
2052 3
            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 3
                $this->xaxis = $this->xaxis;
2055 3
                $this->xaxis->SetPos('max');
2056 3
                $this->xaxis->SetLabelSide(SIDE_UP);
2057
                // No title for the top X-axis
2058 3
                if ($aStrokeLabels) {
2059 3
                    $this->xaxis->title->Set('');
2060
                }
2061 3
                $this->xaxis->scale->ticks->SetSide($toppos);
2062 3
                $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2063
            }
2064
2065
            // Stroke the left Y-axis
2066 3
            $this->yaxis->SetPos('min');
2067 3
            $this->yaxis->SetLabelSide(SIDE_LEFT);
2068 3
            $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 3
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2070
2071
            // Stroke the  right Y-axis
2072 3
            $this->yaxis->SetPos('max');
2073
            // No title for the right side
2074 3
            if ($aStrokeLabels) {
2075 3
                $this->yaxis->title->Set('');
2076
            }
2077 3
            $this->yaxis->SetLabelSide(SIDE_RIGHT);
2078 3
            $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 3
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2080
        } else {
2081 19
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2082 19
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2083
        }
2084 19
    }
2085
2086
    // Private helper function for backgound image
2087 5
    public static function LoadBkgImage($aImgFormat = '', $aFile = '', $aImgStr = '')
2088
    {
2089 5
        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 5
        $e   = explode('.', $aFile);
2096 5
        $ext = strtolower($e[count($e) - 1]);
2097 5
        if ($ext == 'jpeg') {
2098
            $ext = 'jpg';
2099
        }
2100
2101 5
        if (trim($ext) == '') {
2102
            $ext = 'png'; // Assume PNG if no extension specified
2103
        }
2104
2105 5
        if ($aImgFormat == '') {
2106 2
            $imgtag = $ext;
2107
        } else {
2108 4
            $imgtag = $aImgFormat;
2109
        }
2110
2111 5
        $supported = imagetypes();
2112 5
        if (($ext == 'jpg' && !($supported & IMG_JPG)) ||
2113 5
            ($ext == 'gif' && !($supported & IMG_GIF)) ||
2114 5
            ($ext == 'png' && !($supported & IMG_PNG)) ||
2115 5
            ($ext == 'bmp' && !($supported & IMG_WBMP)) ||
2116 5
            ($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 5
        if ($imgtag == 'jpg' || $imgtag == 'jpeg') {
2121 3
            $f      = 'imagecreatefromjpeg';
2122 3
            $imgtag = 'jpg';
2123
        } else {
2124 2
            $f = 'imagecreatefrom' . $imgtag;
2125
        }
2126
2127
        // Compare specified image type and file extension
2128 5
        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 5
        $img = @$f($aFile);
2134 5
        if (!$img) {
2135
            Util\JpGraphError::RaiseL(25039, $aFile); //(" Can't read background image: '".$aFile."'");
2136
        }
2137
2138 5
        return $img;
2139
    }
2140
2141 15
    public function StrokePlotGrad()
2142
    {
2143 15
        if ($this->plot_gradtype < 0) {
2144 15
            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 17
    public function StrokeBackgroundGrad()
2156
    {
2157 17
        if ($this->bkg_gradtype < 0) {
2158 15
            return;
2159
        }
2160
2161 3
        $grad = new Plot\Gradient($this->img);
2162 3
        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 1
            $xl = 0;
2170 1
            $yt = 0;
2171 1
            $xr = $xl + $this->img->width - 1;
2172 1
            $yb = $yt + $this->img->height - 1;
2173 1
            if ($this->doshadow) {
2174
                $xr -= $this->shadow_width;
2175
                $yb -= $this->shadow_width;
2176
            }
2177 1
            if ($this->doframe) {
2178
                $yt += $this->frame_weight;
2179
                $yb -= $this->frame_weight;
2180
                $xl += $this->frame_weight;
2181
                $xr -= $this->frame_weight;
2182
            }
2183 1
            $aa = $this->img->SetAngle(0);
2184 1
            $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype);
2185 1
            $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 3
    }
2188
2189 5
    public function StrokeFrameBackground()
2190
    {
2191 5
        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 5
        if ($this->background_image != '') {
2195 4
            $bkgimg = $this->LoadBkgImage($this->background_image_format, $this->background_image);
2196 1
        } elseif ($this->background_cflag != '') {
2197 1
            $fobj                        = new Image\FlagImages(FLAGSIZE4);
2198 1
            $dummy                       = '';
2199 1
            $bkgimg                      = $fobj->GetImgByName($this->background_cflag, $dummy);
2200 1
            $this->background_image_mix  = $this->background_cflag_mix;
2201 1
            $this->background_image_type = $this->background_cflag_type;
2202
        } else {
2203
            return;
2204
        }
2205
2206 5
        $bw = imagesx($bkgimg);
2207 5
        $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 5
        $aa = $this->img->SetAngle(0);
2212
2213 5
        switch ($this->background_image_type) {
2214 5
            case BGIMG_FILLPLOT: // Resize to just fill the plotarea
2215 3
                $this->FillMarginArea();
2216 3
                $this->StrokeFrame();
2217
                // Special case to hande 90 degree rotated graph corectly
2218 3
                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 3
                    $this->FillPlotArea();
2237 3
                    $this->img->CopyMerge(
2238 3
                        $bkgimg,
2239 3
                        $this->img->left_margin,
2240 3
                        $this->img->top_margin + 1,
2241 3
                        0,
2242 3
                        0,
2243 3
                        $this->img->plotwidth + 1,
2244 3
                        $this->img->plotheight,
2245 3
                        $bw,
2246 3
                        $bh,
2247 3
                        $this->background_image_mix
2248
                    );
2249
                }
2250
2251 3
                break;
2252 4
            case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit
2253 3
                $hadj = 0;
2254 3
                $vadj = 0;
2255 3
                if ($this->doshadow) {
2256 2
                    $hadj = $this->shadow_width;
2257 2
                    $vadj = $this->shadow_width;
2258
                }
2259 3
                $this->FillMarginArea();
2260 3
                $this->FillPlotArea();
2261 3
                $this->img->CopyMerge(
2262 3
                    $bkgimg,
2263 3
                    0,
2264 3
                    0,
2265 3
                    0,
2266 3
                    0,
2267 3
                    $this->img->width - $hadj,
2268 3
                    $this->img->height - $vadj,
2269 3
                    $bw,
2270 3
                    $bh,
2271 3
                    $this->background_image_mix
2272
                );
2273 3
                $this->StrokeFrame();
2274
2275 3
                break;
2276 3
            case BGIMG_COPY: // Just copy the image from left corner, no resizing
2277 3
                $this->FillMarginArea();
2278 3
                $this->FillPlotArea();
2279 3
                $this->img->CopyMerge(
2280 3
                    $bkgimg,
2281 3
                    0,
2282 3
                    0,
2283 3
                    0,
2284 3
                    0,
2285 3
                    $bw,
2286 3
                    $bh,
2287 3
                    $bw,
2288 3
                    $bh,
2289 3
                    $this->background_image_mix
2290
                );
2291 3
                $this->StrokeFrame();
2292
2293 3
                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 5
        $this->img->SetAngle($aa);
2333 5
    }
2334
2335
    // Private
2336
    // Draw a frame around the image
2337 21
    public function StrokeFrame()
2338
    {
2339 21
        if (!$this->doframe) {
2340 20
            return;
2341
        }
2342
2343 2
        if ($this->background_image_type <= 1 && ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle == BGRAD_PLOT))) {
2344 2
            $c = $this->margin_color;
2345
        } else {
2346
            $c = false;
2347
        }
2348
2349 2
        if ($this->doshadow) {
2350
            $this->img->SetColor($this->frame_color);
2351
            $this->img->ShadowRectangle(
2352
                0,
2353
                0,
2354
                $this->img->width,
2355
                $this->img->height,
2356
                $c,
2357
                $this->shadow_width,
2358
                $this->shadow_color
2359
            );
2360 2
        } 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 2
            $this->img->SetLineWeight($this->frame_weight);
2380 2
            if ($c) {
2381 2
                $this->img->SetColor($this->margin_color);
2382 2
                $this->img->FilledRectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2383
            }
2384 2
            $this->img->SetColor($this->frame_color);
2385 2
            $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2386
        }
2387 2
    }
2388
2389 5
    public function FillMarginArea()
2390
    {
2391 5
        $hadj = 0;
2392 5
        $vadj = 0;
2393 5
        if ($this->doshadow) {
2394 3
            $hadj = $this->shadow_width;
2395 3
            $vadj = $this->shadow_width;
2396
        }
2397
2398 5
        $this->img->SetColor($this->margin_color);
2399 5
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->height - 1 - $vadj);
2400
2401 5
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->top_margin);
2402 5
        $this->img->FilledRectangle(0, $this->img->top_margin, $this->img->left_margin, $this->img->height - 1 - $hadj);
2403 5
        $this->img->FilledRectangle(
2404 5
            $this->img->left_margin + 1,
2405 5
            $this->img->height - $this->img->bottom_margin,
2406 5
            $this->img->width - 1 - $hadj,
2407 5
            $this->img->height - 1 - $hadj
2408
        );
2409 5
        $this->img->FilledRectangle(
2410 5
            $this->img->width - $this->img->right_margin,
2411 5
            $this->img->top_margin + 1,
2412 5
            $this->img->width - 1 - $hadj,
2413 5
            $this->img->height - $this->img->bottom_margin - 1
2414
        );
2415 5
    }
2416
2417 17
    public function FillPlotArea()
2418
    {
2419 17
        $this->img->PushColor($this->plotarea_color);
2420 17
        $this->img->FilledRectangle(
2421 17
            $this->img->left_margin,
2422 17
            $this->img->top_margin,
2423 17
            $this->img->width - $this->img->right_margin,
2424 17
            $this->img->height - $this->img->bottom_margin
2425
        );
2426 17
        $this->img->PopColor();
2427 17
    }
2428
2429
    // Stroke the plot area with either a solid color or a background image
2430 19
    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 19
        $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 19
        $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 19
        if ($this->background_image != '' || $this->background_cflag != '') {
2442 5
            $this->StrokeFrameBackground();
2443
        } else {
2444 15
            $aa = $this->img->SetAngle(0);
2445 15
            $this->StrokeFrame();
2446 15
            $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 15
            $this->StrokeBackgroundGrad();
2448 15
            if ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle == BGRAD_MARGIN)) {
2449 13
                $this->FillPlotArea();
2450
            }
2451 15
            $this->StrokePlotGrad();
2452
        }
2453 19
    }
2454
2455 21
    public function StrokeIcons()
2456
    {
2457 21
        $n = safe_count($this->iIcons);
2458 21
        for ($i = 0; $i < $n; ++$i) {
2459
            $this->iIcons[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2460
        }
2461 21
    }
2462
2463 19
    public function StrokePlotBox()
2464
    {
2465
        // Should we draw a box around the plot area?
2466 19
        if ($this->boxed) {
2467 19
            $this->img->SetLineWeight(1);
2468 19
            $this->img->SetLineStyle('solid');
2469 19
            $this->img->SetColor($this->box_color);
2470 19
            for ($i = 0; $i < $this->box_weight; ++$i) {
2471 19
                $this->img->Rectangle(
2472 19
                    $this->img->left_margin - $i,
2473 19
                    $this->img->top_margin - $i,
2474 19
                    $this->img->width - $this->img->right_margin + $i,
2475 19
                    $this->img->height - $this->img->bottom_margin + $i
2476
                );
2477
            }
2478
        }
2479 19
    }
2480
2481 1
    public function SetTitleBackgroundFillStyle($aStyle, $aColor1 = 'black', $aColor2 = 'white')
2482
    {
2483 1
        $this->titlebkg_fillstyle = $aStyle;
2484 1
        $this->titlebkg_scolor1   = $aColor1;
2485 1
        $this->titlebkg_scolor2   = $aColor2;
2486 1
    }
2487
2488 1
    public function SetTitleBackground($aBackColor = 'gray', $aStyle = TITLEBKG_STYLE1, $aFrameStyle = TITLEBKG_FRAME_NONE, $aFrameColor = 'black', $aFrameWeight = 1, $aBevelHeight = 3, $aEnable = true)
2489
    {
2490 1
        $this->titlebackground             = $aEnable;
2491 1
        $this->titlebackground_color       = $aBackColor;
2492 1
        $this->titlebackground_style       = $aStyle;
2493 1
        $this->titlebackground_framecolor  = $aFrameColor;
2494 1
        $this->titlebackground_framestyle  = $aFrameStyle;
2495 1
        $this->titlebackground_frameweight = $aFrameWeight;
2496 1
        $this->titlebackground_bevelheight = $aBevelHeight;
2497 1
    }
2498
2499 21
    public function StrokeTitles()
2500
    {
2501 21
        $margin = 3;
2502
2503 21
        if ($this->titlebackground) {
2504
            // Find out height
2505 1
            $this->title->margin += 2;
2506 1
            $h = $this->title->GetTextHeight($this->img) + $this->title->margin + $margin;
2507 1
            if ($this->subtitle->t != '' && !$this->subtitle->hide) {
2508
                $h += $this->subtitle->GetTextHeight($this->img) + $margin +
2509
                $this->subtitle->margin;
2510
                $h += 2;
2511
            }
2512 1
            if ($this->subsubtitle->t != '' && !$this->subsubtitle->hide) {
2513
                $h += $this->subsubtitle->GetTextHeight($this->img) + $margin +
2514
                $this->subsubtitle->margin;
2515
                $h += 2;
2516
            }
2517 1
            $this->img->PushColor($this->titlebackground_color);
2518 1
            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
            } elseif ($this->titlebackground_style === TITLEBKG_STYLE2) {
2531
                // Cover the frame as well
2532
                $x1 = $y1 = 0;
2533
                $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 1
            if ($this->titlebackground_framestyle === 3) {
2547 1
                $h += $this->titlebackground_bevelheight * 2 + 1;
2548 1
                $this->title->margin += $this->titlebackground_bevelheight;
2549
            }
2550
2551 1
            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 1
            $indent = 0;
2556 1
            if ($this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL) {
2557 1
                $indent = $this->titlebackground_bevelheight;
2558
            }
2559
2560 1
            if ($this->titlebkg_fillstyle == TITLEBKG_FILLSTYLE_HSTRIPED) {
2561 1
                $this->img->FilledRectangle2(
2562 1
                    $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 1
                    $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 1
                    $x2 - $indent,
2565 1
                    $h - $indent,
2566 1
                    $this->titlebkg_scolor1,
2567 1
                    $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 1
            $this->img->PopColor();
2584
2585 1
            $this->img->PushColor($this->titlebackground_framecolor);
2586 1
            $this->img->SetLineWeight($this->titlebackground_frameweight);
2587 1
            if ($this->titlebackground_framestyle == TITLEBKG_FRAME_FULL) {
2588
                // Frame background
2589
                $this->img->Rectangle($x1, $y1, $x2, $h);
2590 1
            } elseif ($this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM) {
2591
                // Bottom line only
2592
                $this->img->Line($x1, $h, $x2, $h);
2593 1
            } elseif ($this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL) {
2594 1
                $this->img->Bevel($x1, $y1, $x2, $h, $this->titlebackground_bevelheight);
2595
            }
2596 1
            $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 1
            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 21
        $y = $this->title->margin;
2619 21
        if ($this->title->halign == 'center') {
2620 21
            $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 21
        $this->title->Stroke($this->img);
2631
2632
        // ... and subtitle
2633 21
        $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
2634 21
        if ($this->subtitle->halign == 'center') {
2635 21
            $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 21
        $this->subtitle->Stroke($this->img);
2647
2648
        // ... and subsubtitle
2649 21
        $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
2650 21
        if ($this->subsubtitle->halign == 'center') {
2651 21
            $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 21
        $this->subsubtitle->Stroke($this->img);
2663
2664
        // ... and fancy title
2665 21
        $this->tabtitle->Stroke($this->img);
2666 21
    }
2667
2668 19
    public function StrokeTexts()
2669
    {
2670
        // Stroke any user added text objects
2671 19
        if ($this->texts != null) {
2672 1
            for ($i = 0; $i < safe_count($this->texts); ++$i) {
2673 1
                $this->texts[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2674
            }
2675
        }
2676
2677 19
        if ($this->y2texts != null && $this->y2scale != null) {
2678
            for ($i = 0; $i < safe_count($this->y2texts); ++$i) {
2679
                $this->y2texts[$i]->StrokeWithScale($this->img, $this->xscale, $this->y2scale);
2680
            }
2681
        }
2682 19
    }
2683
2684 19
    public function StrokeTables()
2685
    {
2686 19
        if ($this->iTables != null) {
2687
            $n = safe_count($this->iTables);
2688
            for ($i = 0; $i < $n; ++$i) {
2689
                $this->iTables[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2690
            }
2691
        }
2692 19
    }
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 = safe_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 = safe_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 18
    public function SetTextScaleOff($aOff)
2727
    {
2728 18
        $this->text_scale_off         = $aOff;
2729 18
        $this->xscale->text_scale_off = $aOff;
2730 18
    }
2731
2732
    // Text width of bar to be centered in absolute pixels
2733 1
    public function SetTextScaleAbsCenterOff($aOff)
2734
    {
2735 1
        $this->text_scale_abscenteroff = $aOff;
2736 1
    }
2737
2738
    // Get Y min and max values for added lines
2739 17
    public function GetLinesYMinMax($aLines)
2740
    {
2741 17
        if (is_null($aLines)) {
2742 17
            return false;
2743
        }
2744
2745
        $n = safe_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 7
    public function GetLinesXMinMax($aLines)
2772
    {
2773 7
        $n = safe_count($aLines);
2774 7
        if ($n == 0) {
2775 7
            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 17
    public function GetPlotsYMinMax($bPlots)
2800
    {
2801
        $aPlots = array_filter($bPlots, function ($plot) {
2802
            //\Kint::dump($plot, $plot instanceof Plot\Plot);
2803 17
            return $plot instanceof Plot\Plot;
2804 17
        });
2805 17
        reset($aPlots);
2806 17
        $n = safe_count($aPlots);
2807 17
        $i = 0;
2808
        //\Kint::dump($n, $aPlots);
2809
        do {
2810
            //\Kint::dump($i, $aPlots[$i]);
2811 17
            list($xmax, $max) = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
2812 17
        } while (++$i < $n && !is_numeric($max));
2813
2814 17
        $i = 0;
2815
        do {
2816 17
            list($xmin, $min) = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
2817 17
        } while (++$i < $n && !is_numeric($min));
2818
2819 17
        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 17
        for ($i = 0; $i < $n; ++$i) {
2824 17
            list($xmax, $ymax) = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
2825 17
            list($xmin, $ymin) = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
2826 17
            if (is_numeric($ymax)) {
2827 17
                $max = max($max, $ymax);
2828
            }
2829
2830 17
            if (is_numeric($ymin)) {
2831 17
                $min = min($min, $ymin);
2832
            }
2833
        }
2834 17
        if ($min == '') {
2835 3
            $min = 0;
2836
        }
2837
2838 17
        if ($max == '') {
2839
            $max = 0;
2840
        }
2841
2842 17
        if ($min == 0 && $max == 0) {
2843
            // Special case if all values are 0
2844
            $min = 0;
2845
            $max = 1;
2846
        }
2847
2848 17
        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 1
    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 2
    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