Test Failed
Pull Request — master (#122)
by Felipe
08:16 queued 04:08
created

Graph::Set3DPerspective()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 9
c 1
b 0
f 0
nc 1
nop 8
dl 0
loc 11
ccs 0
cts 10
cp 0
crap 2
rs 9.9666

How to fix   Many Parameters   

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 20
    public function __construct($aWidth = 300, $aHeight = 200, $aCachedName = '', $aTimeout = 0, $aInline = true)
152
    {
153 20
        $this->gDateLocale    = new Util\DateLocale();
154 20
        $this->gJpgDateLocale = new Util\DateLocale();
155 20
        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 20
        $this->InitializeFrameAndMargin();
161
162
        // Automatically generate the image file name based on the name of the script that
163
        // generates the graph
164 20
        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 20
        $this->inline = $aInline;
170
171 20
        $this->img   = new Image\RotImage($aWidth, $aHeight);
172 20
        $this->cache = new Image\ImgStreamCache();
173
174
        // Window doesn't like '?' in the file name so replace it with an '_'
175 20
        $aCachedName = str_replace('?', '_', $aCachedName);
176 20
        $this->SetupCache($aCachedName, $aTimeout);
177
178 20
        $this->title = new Text\Text();
179 20
        $this->title->ParagraphAlign('center');
180 20
        $this->title->SetFont(FF_DEFAULT, FS_NORMAL); //FF_FONT2, FS_BOLD
181 20
        $this->title->SetMargin(5);
182 20
        $this->title->SetAlign('center');
183
184 20
        $this->subtitle = new Text\Text();
185 20
        $this->subtitle->ParagraphAlign('center');
186 20
        $this->subtitle->SetMargin(3);
187 20
        $this->subtitle->SetAlign('center');
188
189 20
        $this->subsubtitle = new Text\Text();
190 20
        $this->subsubtitle->ParagraphAlign('center');
191 20
        $this->subsubtitle->SetMargin(3);
192 20
        $this->subsubtitle->SetAlign('center');
193
194 20
        $this->legend = new Legend();
195 20
        $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 20
        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 20
        $this->SetTickDensity(); // Normal density
206
207 20
        $this->tabtitle = new Text\GraphTabTitle();
208
209 20
        if (!$this->isRunningClear) {
210 20
            $this->inputValues                = [];
211 20
            $this->inputValues['aWidth']      = $aWidth;
212 20
            $this->inputValues['aHeight']     = $aHeight;
213 20
            $this->inputValues['aCachedName'] = $aCachedName;
214 20
            $this->inputValues['aTimeout']    = $aTimeout;
215 20
            $this->inputValues['aInline']     = $aInline;
216
217 20
            $theme_class = '\Amenadiel\JpGraph\Themes\\' . DEFAULT_THEME_CLASS;
218
219 20
            if (class_exists($theme_class)) {
220 20
                $this->graph_theme = new $theme_class();
221
            }
222
        }
223 20
    }
224
225 20
    public function InitializeFrameAndMargin()
226
    {
227 20
        $this->doframe      = true;
228 20
        $this->frame_color  = 'black';
229 20
        $this->frame_weight = 1;
230
231 20
        $this->titlebackground_framecolor  = 'blue';
232 20
        $this->titlebackground_framestyle  = 2;
233 20
        $this->titlebackground_frameweight = 1;
234 20
        $this->titlebackground_bevelheight = 3;
235 20
        $this->titlebkg_fillstyle          = TITLEBKG_FILLSTYLE_SOLID;
236 20
        $this->titlebkg_scolor1            = 'black';
237 20
        $this->titlebkg_scolor2            = 'white';
238 20
        $this->framebevel                  = false;
239 20
        $this->framebeveldepth             = 2;
240 20
        $this->framebevelborder            = false;
241 20
        $this->framebevelbordercolor       = 'black';
242 20
        $this->framebevelcolor1            = '[email protected]';
243 20
        $this->framebevelcolor2            = '[email protected]';
244
245 20
        $this->margin_color = [250, 250, 250];
246 20
    }
247
248 20
    public function SetupCache($aFilename, $aTimeout = 60)
249
    {
250 20
        $this->cache_name = $aFilename;
251 20
        $this->cache->SetTimeOut($aTimeout);
252 20
    }
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 1
    public function SetAngle($aAngle)
307
    {
308 1
        $this->img->SetAngle($aAngle);
309 1
    }
310
311 1
    public function SetAlphaBlending($aFlg = true)
312
    {
313 1
        $this->img->SetAlphaBlending($aFlg);
314 1
    }
315
316
    // Shortcut to image margin
317 16
    public function SetMargin($lm, $rm, $tm, $bm)
318
    {
319 16
        $this->img->SetMargin($lm, $rm, $tm, $bm);
320 16
    }
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
    public function Set90AndMargin($lm = 0, $rm = 0, $tm = 0, $bm = 0)
330
    {
331
        $lm = $lm == 0 ? floor(0.2 * $this->img->width) : $lm;
332
        $rm = $rm == 0 ? floor(0.1 * $this->img->width) : $rm;
333
        $tm = $tm == 0 ? floor(0.2 * $this->img->height) : $tm;
334
        $bm = $bm == 0 ? floor(0.1 * $this->img->height) : $bm;
335
336
        $adj = ($this->img->height - $this->img->width) / 2;
337
        $this->img->SetMargin($tm - $adj, $bm - $adj, $rm + $adj, $lm + $adj);
338
        $this->img->SetCenter(floor($this->img->width / 2), floor($this->img->height / 2));
339
        $this->SetAngle(90);
340
        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
        $this->xaxis->SetLabelAlign('right', 'center');
344
        $this->yaxis->SetLabelAlign('center', 'bottom');
345
    }
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 18
    public function Add($aPlot)
354
    {
355 18
        if ($aPlot == null) {
356
            Util\JpGraphError::RaiseL(25010); //("Graph::Add() You tried to add a null plot to the graph.");
357
        }
358 18
        if (is_array($aPlot) && safe_count($aPlot) > 0) {
359 1
            $cl = $aPlot[0];
360
        } else {
361 18
            $cl = $aPlot;
362
        }
363
364 18
        if ($cl instanceof Text\Text) {
365 1
            $this->AddText($aPlot);
366 18
        } elseif (($cl instanceof Plot\PlotLine)) {
367 1
            $this->AddLine($aPlot);
368 18
        } elseif (($cl instanceof Plot\PlotBand)) {
369
            $this->AddBand($aPlot);
370 18
        } elseif (($cl instanceof Plot\IconPlot)) {
371
            $this->AddIcon($aPlot);
372 18
        } elseif (($cl instanceof Text\GTextTable)) {
373
            $this->AddTable($aPlot);
374
        } else {
375 18
            if (is_array($aPlot)) {
376 1
                $this->plots = array_merge($this->plots, $aPlot);
377
            } else {
378 18
                $this->plots[] = $aPlot;
379
            }
380
        }
381
382 18
        if ($this->graph_theme) {
383 18
            $this->graph_theme->SetupPlot($aPlot);
384
        }
385 18
    }
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 2
    public function AddY2($aPlot)
411
    {
412 2
        if ($aPlot == null) {
413
            Util\JpGraphError::RaiseL(25011); //("Graph::AddY2() You tried to add a null plot to the graph.");
414
        }
415
416 2
        if (is_array($aPlot) && safe_count($aPlot) > 0) {
417
            $cl = $aPlot[0];
418
        } else {
419 2
            $cl = $aPlot;
420
        }
421
422 2
        if ($cl instanceof Text\Text) {
423
            $this->AddText($aPlot, true);
424 2
        } elseif (($cl instanceof Plot\PlotLine)) {
425
            $this->AddLine($aPlot, true);
426 2
        } elseif (($cl instanceof Plot\PlotBand)) {
427
            $this->AddBand($aPlot, true);
428
        } else {
429 2
            $this->y2plots[] = $aPlot;
430
        }
431
432 2
        if ($this->graph_theme) {
433 2
            $this->graph_theme->SetupPlot($aPlot);
434
        }
435 2
    }
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 1
    public function AddLine($aLine, $aToY2 = false)
490
    {
491 1
        if ($aLine == null) {
492
            Util\JpGraphError::RaiseL(25015); //("Graph::AddLine() You tried to add a null line to the graph.");
493
        }
494
495 1
        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 1
            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 1
                $this->plots[] = $aLine;
514
            }
515
        }
516 1
    }
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 3
    public function SetBackgroundImage($aFileName, $aBgType = BGIMG_FILLPLOT, $aImgFormat = 'auto')
577
    {
578
        // Get extension to determine image type
579 3
        if ($aImgFormat == 'auto') {
580 3
            $e = explode('.', $aFileName);
581 3
            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 3
            $valid_formats = ['png', 'jpg', 'gif'];
586 3
            $aImgFormat    = strtolower($e[count($e) - 1]);
587 3
            if ($aImgFormat == 'jpeg') {
588
                $aImgFormat = 'jpg';
589 3
            } 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 3
        $this->background_image        = $aFileName;
595 3
        $this->background_image_type   = $aBgType;
596 3
        $this->background_image_format = $aImgFormat;
597 3
    }
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 2
    public function SetAxisStyle($aStyle)
613
    {
614 2
        $this->iAxisStyle = $aStyle;
615 2
    }
616
617
    // Set a frame around the plot area
618 18
    public function SetBox($aDrawPlotFrame = true, $aPlotFrameColor = [0, 0, 0], $aPlotFrameWeight = 1)
619
    {
620 18
        $this->boxed      = $aDrawPlotFrame;
621 18
        $this->box_weight = $aPlotFrameWeight;
622 18
        $this->box_color  = $aPlotFrameColor;
623 18
    }
624
625
    // Specify color for the plotarea (not the margins)
626 2
    public function SetColor($aColor)
627
    {
628 2
        $this->plotarea_color = $aColor;
629 2
    }
630
631
    // Specify color for the margins (all areas outside the plotarea)
632 20
    public function SetMarginColor($aColor)
633
    {
634 20
        $this->margin_color = $aColor;
635 20
    }
636
637
    // Set a frame around the entire image
638 20
    public function SetFrame($aDrawImgFrame = true, $aImgFrameColor = [0, 0, 0], $aImgFrameWeight = 1)
639
    {
640 20
        $this->doframe      = $aDrawImgFrame;
641 20
        $this->frame_color  = $aImgFrameColor;
642 20
        $this->frame_weight = $aImgFrameWeight;
643 20
    }
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 10
    public function SetShadow($aShowShadow = true, $aShadowWidth = 5, $aShadowColor = 'darkgray')
659
    {
660 10
        $this->doshadow     = $aShowShadow;
661 10
        $this->shadow_color = $aShadowColor;
662 10
        $this->shadow_width = $aShadowWidth;
663 10
        $this->footer->iBottomMargin += $aShadowWidth;
664 10
        $this->footer->iRightMargin += $aShadowWidth;
665 10
    }
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 18
    public function SetScale($aAxisType, $aYMin = 1, $aYMax = 1, $aXMin = 1, $aXMax = 1)
670
    {
671 18
        $this->axtype = $aAxisType;
672
673 18
        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 18
        $yt = substr($aAxisType, -3, 3);
678 18
        if ($yt == 'lin') {
679 16
            $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 2
        } elseif ($yt == 'log') {
684 2
            $this->yscale = new LogScale($aYMin, $aYMax);
685
        } else {
686
            Util\JpGraphError::RaiseL(25021, $aAxisType); //("Unknown scale specification for Y-scale. ($aAxisType)");
687
        }
688
689 18
        $xt = substr($aAxisType, 0, 3);
690 18
        if ($xt == 'lin' || $xt == 'tex') {
691 16
            $this->xscale            = new LinearScale($aXMin, $aXMax, 'x');
692 16
            $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
        } elseif ($xt == 'dat') {
697
            $this->xscale = new DateScale($aXMin, $aXMax, 'x');
698
        } elseif ($xt == 'log') {
699
            $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 18
        $this->xaxis = new Axis($this->img, $this->xscale);
705 18
        $this->yaxis = new Axis($this->img, $this->yscale);
706 18
        $this->xgrid = new Grid($this->xaxis);
707 18
        $this->ygrid = new Grid($this->yaxis);
708 18
        $this->ygrid->Show();
709
710 18
        if (!$this->isRunningClear) {
711 18
            $this->inputValues['aAxisType'] = $aAxisType;
712 18
            $this->inputValues['aYMin']     = $aYMin;
713 18
            $this->inputValues['aYMax']     = $aYMax;
714 18
            $this->inputValues['aXMin']     = $aXMin;
715 18
            $this->inputValues['aXMax']     = $aXMax;
716
717 18
            if ($this->graph_theme) {
718 18
                $this->graph_theme->ApplyGraph($this);
719
            }
720
        }
721
722 18
        $this->isAfterSetScale = true;
723 18
    }
724
725
    // Specify secondary Y scale
726 2
    public function SetY2Scale($aAxisType = 'lin', $aY2Min = 1, $aY2Max = 1)
727
    {
728 2
        if ($aAxisType == 'lin') {
729 2
            $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 2
        $this->y2axis = new Axis($this->img, $this->y2scale);
740 2
        $this->y2axis->scale->ticks->SetDirection(SIDE_LEFT);
741 2
        $this->y2axis->SetLabelSide(SIDE_RIGHT);
742 2
        $this->y2axis->SetPos('max');
743 2
        $this->y2axis->SetTitleSide(SIDE_RIGHT);
744
745
        // Deafult position is the max x-value
746 2
        $this->y2grid = new Grid($this->y2axis);
747
748 2
        if ($this->graph_theme) {
749 2
            $this->graph_theme->ApplyGraph($this);
750
        }
751 2
    }
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 20
    public function SetTickDensity($aYDensity = TICKD_NORMAL, $aXDensity = TICKD_NORMAL)
786
    {
787 20
        $this->xtick_factor = 30;
788 20
        $this->ytick_factor = 25;
789
        switch ($aYDensity) {
790 20
            case TICKD_DENSE:
791
                $this->ytick_factor = 12;
792
793
                break;
794 20
            case TICKD_NORMAL:
795 20
                $this->ytick_factor = 25;
796
797 20
                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 20
            case TICKD_DENSE:
811
                $this->xtick_factor = 15;
812
813
                break;
814 20
            case TICKD_NORMAL:
815 20
                $this->xtick_factor = 30;
816
817 20
                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 20
    }
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 16
    public function GetTextsYMinMax($aY2 = false)
1081
    {
1082 16
        if ($aY2) {
1083 2
            $txts = $this->y2texts;
1084
        } else {
1085 16
            $txts = $this->texts;
1086
        }
1087 16
        $n   = safe_count($txts);
1088 16
        $min = null;
1089 16
        $max = null;
1090 16
        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 16
        if ($min !== null) {
1101
            return [$min, $max];
1102
        }
1103
1104 16
        return null;
1105
    }
1106
1107 6
    public function GetTextsXMinMax($aY2 = false)
1108
    {
1109 6
        if ($aY2) {
1110 6
            $txts = $this->y2texts;
1111
        } else {
1112 6
            $txts = $this->texts;
1113
        }
1114 6
        $n   = safe_count($txts);
1115 6
        $min = null;
1116 6
        $max = null;
1117 6
        for ($i = 0; $i < $n; ++$i) {
1118
            if ($txts[$i]->iScalePosY !== null && $txts[$i]->iScalePosX !== null) {
1119
                if ($min === null) {
1120
                    $min = $max = $txts[$i]->iScalePosX;
1121
                } else {
1122
                    $min = min($min, $txts[$i]->iScalePosX);
1123
                    $max = max($max, $txts[$i]->iScalePosX);
1124
                }
1125
            }
1126
        }
1127 6
        if ($min !== null) {
1128
            return [$min, $max];
1129
        }
1130
1131 6
        return null;
1132
    }
1133
1134 6
    public function GetXMinMax()
1135
    {
1136 6
        list($min, $ymin) = $this->plots[0]->Min();
1137 6
        list($max, $ymax) = $this->plots[0]->Max();
1138
1139 6
        $i = 0;
1140
        // Some plots, e.g. PlotLine should not affect the scale
1141
        // and will return (null,null). We should ignore those
1142
        // values.
1143 6
        while (($min === null || $max === null) && ($i < safe_count($this->plots) - 1)) {
1144
            ++$i;
1145
            list($min, $ymin) = $this->plots[$i]->Min();
1146
            list($max, $ymax) = $this->plots[$i]->Max();
1147
        }
1148
1149 6
        foreach ($this->plots as $p) {
1150 6
            list($xmin, $ymin) = $p->Min();
1151 6
            list($xmax, $ymax) = $p->Max();
1152
1153 6
            if ($xmin !== null && $xmax !== null) {
1154 6
                $min = min($xmin, $min);
1155 6
                $max = max($xmax, $max);
1156
            }
1157
        }
1158
1159 6
        if ($this->y2axis != null) {
1160
            foreach ($this->y2plots as $p) {
1161
                list($xmin, $ymin) = $p->Min();
1162
                list($xmax, $ymax) = $p->Max();
1163
                $min               = min($xmin, $min);
1164
                $max               = max($xmax, $max);
1165
            }
1166
        }
1167
1168 6
        $n = safe_count($this->ynaxis);
1169 6
        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 6
        return [$min, $max];
1181
    }
1182
1183 18
    public function AdjustMarginsForTitles()
1184
    {
1185
        $totrequired =
1186 18
            ($this->title->t != ''
1187 15
            ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * SUPERSAMPLING_SCALE
1188 6
            : 0) +
1189 18
            ($this->subtitle->t != ''
1190 6
            ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * SUPERSAMPLING_SCALE
1191 18
            : 0) +
1192 18
            ($this->subsubtitle->t != ''
1193
            ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * SUPERSAMPLING_SCALE
1194 18
            : 0);
1195
1196 18
        $btotrequired = 0;
1197 18
        if ($this->xaxis != null && !$this->xaxis->hide && !$this->xaxis->hide_labels) {
1198
            // Minimum bottom margin
1199 18
            if ($this->xaxis->title->t != '') {
1200 4
                if ($this->img->a == 90) {
1201
                    $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7;
1202
                } else {
1203 4
                    $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7;
1204
                }
1205
            } else {
1206 15
                $btotrequired = 0;
1207
            }
1208
1209 18
            if ($this->img->a == 90) {
1210 1
                $this->img->SetFont(
1211 1
                    $this->yaxis->font_family,
1212 1
                    $this->yaxis->font_style,
1213 1
                    $this->yaxis->font_size
1214
                );
1215 1
                $lh = $this->img->GetTextHeight('Mg', $this->yaxis->label_angle);
1216
            } else {
1217 18
                $this->img->SetFont(
1218 18
                    $this->xaxis->font_family,
1219 18
                    $this->xaxis->font_style,
1220 18
                    $this->xaxis->font_size
1221
                );
1222 18
                $lh = $this->img->GetTextHeight('Mg', $this->xaxis->label_angle);
1223
            }
1224
1225 18
            $btotrequired += $lh + 6;
1226
        }
1227
1228 18
        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 18
            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 18
            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 18
    }
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 18
    public function doAutoscaleXAxis()
1268
    {
1269
        $aPlots = array_filter($this->plots, function ($plot) {
1270
            //\Kint::dump($plot, $plot instanceof Plot\Plot);
1271 18
            return $plot instanceof Plot\Plot;
1272 18
        });
1273
1274
        //Check if we should autoscale x-axis
1275 18
        if (!$this->xscale->IsSpecified()) {
1276 15
            if (substr($this->axtype, 0, 4) == 'text') {
1277 12
                $max = 0;
1278 12
                $n   = safe_count($aPlots);
1279
1280 12
                for ($i = 0; $i < $n; ++$i) {
1281 12
                    $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 12
                    $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 12
                    if (empty($p->barcenter)) {
1292 12
                        $max = max($max, $p->numpoints - 1);
1293
                    } else {
1294
                        $max = max($max, $p->numpoints);
1295
                    }
1296
                }
1297 12
                $min = 0;
1298 12
                if ($this->y2axis != null) {
1299 2
                    foreach ($this->y2plots as $p) {
1300 2
                        $max = max($max, $p->numpoints - 1);
1301
                    }
1302
                }
1303 12
                $n = safe_count($this->ynaxis);
1304 12
                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 12
                $this->xscale->Update($this->img, $min, $max);
1313 12
                $this->xscale->ticks->Set($this->xaxis->tick_step, 1);
1314 12
                $this->xscale->ticks->SupressMinorTickMarks();
1315
            } else {
1316 6
                list($min, $max) = $this->GetXMinMax();
1317
1318 6
                $lres = $this->GetLinesXMinMax($this->lines);
1319 6
                if ($lres) {
0 ignored issues
show
introduced by
The condition $lres is always false.
Loading history...
1320
                    list($linmin, $linmax) = $lres;
1321
                    $min                   = min($min, $linmin);
1322
                    $max                   = max($max, $linmax);
1323
                }
1324
1325 6
                $lres = $this->GetLinesXMinMax($this->y2lines);
1326 6
                if ($lres) {
0 ignored issues
show
introduced by
The condition $lres is always false.
Loading history...
1327
                    list($linmin, $linmax) = $lres;
1328
                    $min                   = min($min, $linmin);
1329
                    $max                   = max($max, $linmax);
1330
                }
1331
1332 6
                $tres = $this->GetTextsXMinMax();
1333 6
                if ($tres) {
1334
                    list($tmin, $tmax) = $tres;
1335
                    $min               = min($min, $tmin);
1336
                    $max               = max($max, $tmax);
1337
                }
1338
1339 6
                $tres = $this->GetTextsXMinMax(true);
1340 6
                if ($tres) {
1341
                    list($tmin, $tmax) = $tres;
1342
                    $min               = min($min, $tmin);
1343
                    $max               = max($max, $tmax);
1344
                }
1345
1346 6
                $this->xscale->AutoScale($this->img, $min, $max, round($this->img->plotwidth / $this->xtick_factor));
1347
            }
1348
1349
            //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale
1350 15
            if (!is_numeric($this->yaxis->pos) && !is_string($this->yaxis->pos)) {
1351 15
                $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 18
        if ($this->y2axis != null) {
1378 2
            if (!is_numeric($this->y2axis->pos) && !is_string($this->y2axis->pos)) {
1379
                $this->y2axis->SetPos($this->xscale->GetMaxVal());
1380
            }
1381 2
            $this->y2axis->SetTitleSide(SIDE_RIGHT);
1382
        }
1383
1384 18
        $n      = safe_count($this->ynaxis);
1385 18
        $nY2adj = $this->y2axis != null ? $this->iYAxisDeltaPos : 0;
1386 18
        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 18
    }
1396
1397 18
    public function doAutoScaleYnAxis()
1398
    {
1399 18
        if ($this->y2scale != null) {
1400 2
            if (!$this->y2scale->IsSpecified() && safe_count($this->y2plots) > 0) {
1401 2
                list($min, $max) = $this->GetPlotsYMinMax($this->y2plots);
1402
1403 2
                $lres = $this->GetLinesYMinMax($this->y2lines);
1404 2
                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 2
                $tres = $this->GetTextsYMinMax(true);
1410 2
                if (is_array($tres)) {
1411
                    list($tmin, $tmax) = $tres;
1412
                    $min               = min($min, $tmin);
1413
                    $max               = max($max, $tmax);
1414
                }
1415 2
                $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 18
        $n = safe_count($this->ynaxis);
1449 18
        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 18
    }
1484
1485 18
    public function doAutoScaleYAxis()
1486
    {
1487
        //Check if we should autoscale y-axis
1488 18
        if (!$this->yscale->IsSpecified() && safe_count($this->plots) > 0) {
1489 16
            list($min, $max) = $this->GetPlotsYMinMax($this->plots);
1490 16
            $lres            = $this->GetLinesYMinMax($this->lines);
1491 16
            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 16
            $tres = $this->GetTextsYMinMax();
1497 16
            if (is_array($tres)) {
1498
                list($tmin, $tmax) = $tres;
1499
                $min               = min($min, $tmin);
1500
                $max               = max($max, $tmax);
1501
            }
1502 16
            $this->yscale->AutoScale(
1503 16
                $this->img,
1504
                $min,
1505
                $max,
1506 16
                $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
                $min,
1519
                $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 18
    }
1536
1537 18
    public function InitScaleConstants()
1538
    {
1539
        // Setup scale constants
1540 18
        if ($this->yscale) {
1541 18
            $this->yscale->InitConstants($this->img);
1542
        }
1543
1544 18
        if ($this->xscale) {
1545 18
            $this->xscale->InitConstants($this->img);
1546
        }
1547
1548 18
        if ($this->y2scale) {
1549 2
            $this->y2scale->InitConstants($this->img);
1550
        }
1551
1552 18
        $n = safe_count($this->ynscale);
1553 18
        for ($i = 0; $i < $n; ++$i) {
1554
            if ($this->ynscale[$i]) {
1555
                $this->ynscale[$i]->InitConstants($this->img);
1556
            }
1557
        }
1558 18
    }
1559
1560 18
    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 18
        for ($i = 0; $i < safe_count($this->plots); ++$i) {
1565 18
            if ($this->plots[$i] instanceof Plot\Plot) {
1566 18
                $this->plots[$i]->PreStrokeAdjust($this);
1567 18
                $this->plots[$i]->DoLegend($this);
1568
            }
1569
        }
1570
1571
        // Any plots on the second Y scale?
1572 18
        if ($this->y2scale != null) {
1573 2
            for ($i = 0; $i < safe_count($this->y2plots); ++$i) {
1574 2
                if ($this->plots[$i] instanceof Plot\Plot) {
1575 2
                    $this->y2plots[$i]->PreStrokeAdjust($this);
1576 2
                    $this->y2plots[$i]->DoLegend($this);
1577
                }
1578
            }
1579
        }
1580
1581
        // Any plots on the extra Y axises?
1582 18
        $n = safe_count($this->ynaxis);
1583 18
        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 18
    }
1594
1595 17
    public function StrokeBands($aDepth, $aCSIM)
1596
    {
1597
        // Stroke bands
1598 17
        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 17
        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 17
    }
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 18
    public function Stroke($aStrokeFileName = '')
1621
    {
1622
        // Fist make a sanity check that user has specified a scale
1623 18
        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 18
        $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 18
        for ($i = 0; $i < safe_count($this->plots); ++$i) {
1634 18
            if ($this->plots[$i] instanceof Plot\Plot) {
1635 18
                $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 18
        $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 18
        $_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 18
        $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 18
        $this->iHasStroked = true;
1664
1665
        // Setup pre-stroked adjustments and Legends
1666 18
        $this->doPrestrokeAdjustments();
1667
1668 18
        if ($this->graph_theme) {
1669 18
            $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 18
        if ((!$this->yscale->IsSpecified() && safe_count($this->plots) == 0) ||
1677 18
            ($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 18
        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 18
        $this->doAutoScaleYAxis();
1692
1693
        // Autoscale all additiopnal y-axis
1694 18
        $this->doAutoScaleYnAxis();
1695
1696
        // Autoscale the regular x-axis and position the y-axis properly
1697 18
        $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 18
        if (($this->yaxis->pos == $this->xscale->GetMinVal() || (is_string($this->yaxis->pos) && $this->yaxis->pos == 'min')) &&
1710 18
            !is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0 &&
1711 18
            substr($this->axtype, 0, 4) != 'text' && $this->xaxis->pos != 'min') {
1712
            //$this->yscale->ticks->SupressZeroLabel(false);
1713 1
            $this->xscale->ticks->SupressFirst();
1714 1
            if ($this->y2axis != null) {
1715 1
                $this->xscale->ticks->SupressLast();
1716
            }
1717 18
        } elseif (!is_numeric($this->yaxis->pos) && $this->yaxis->pos == 'max') {
1718
            $this->xscale->ticks->SupressLast();
1719
        }
1720
1721 18
        if (!$_csim) {
1722 18
            $this->StrokePlotArea();
1723 17
            if ($this->iIconDepth == DEPTH_BACK) {
1724 17
                $this->StrokeIcons();
1725
            }
1726
        }
1727 17
        $this->StrokeAxis(false);
1728
1729
        // Stroke colored bands
1730 17
        $this->StrokeBands(DEPTH_BACK, $_csim);
1731
1732 17
        if ($this->grid_depth == DEPTH_BACK && !$_csim) {
1733 17
            $this->ygrid->Stroke();
1734 17
            $this->xgrid->Stroke();
1735
        }
1736
1737
        // Stroke Y2-axis
1738 17
        if ($this->y2axis != null && !$_csim) {
1739 2
            $this->y2axis->Stroke($this->xscale);
1740 2
            $this->y2grid->Stroke();
1741
        }
1742
1743
        // Stroke yn-axis
1744 17
        $n = safe_count($this->ynaxis);
1745 17
        for ($i = 0; $i < $n; ++$i) {
1746
            $this->ynaxis[$i]->Stroke($this->xscale);
1747
        }
1748
1749 17
        $oldoff = $this->xscale->off;
1750 17
        if (substr($this->axtype, 0, 4) == 'text') {
1751 11
            if ($this->text_scale_abscenteroff > -1) {
1752
                // For a text scale the scale factor is the number of pixel per step.
1753
                // Hence we can use the scale factor as a substitute for number of pixels
1754
                // per major scale step and use that in order to adjust the offset so that
1755
                // an object of width "abscenteroff" becomes centered.
1756 1
                $this->xscale->off += round($this->xscale->scale_factor / 2) - round($this->text_scale_abscenteroff / 2);
1757
            } else {
1758 10
                $this->xscale->off += ceil($this->xscale->scale_factor * $this->text_scale_off * $this->xscale->ticks->minor_step);
1759
            }
1760
        }
1761
1762 17
        if ($this->iDoClipping) {
1763 1
            $oldimage = $this->img->CloneCanvasH();
1764
        }
1765
1766 17
        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 17
        if ($this->y2scale != null) {
1778 2
            for ($i = 0; $i < safe_count($this->y2plots); ++$i) {
1779 2
                $this->y2plots[$i]->Stroke($this->img, $this->xscale, $this->y2scale);
1780
            }
1781
        }
1782
1783 17
        if ($this->y2orderback) {
1784
            // Stroke all plots for Y1 axis
1785 17
            for ($i = 0; $i < safe_count($this->plots); ++$i) {
1786 17
                $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale);
1787 17
                if ($this->plots[$i] instanceof Plot\Plot) {
1788 17
                    $this->plots[$i]->StrokeMargin($this->img);
1789
                }
1790
            }
1791
        }
1792
1793 17
        $n = safe_count($this->ynaxis);
1794 17
        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 17
        if ($this->iIconDepth == DEPTH_FRONT) {
1805
            $this->StrokeIcons();
1806
        }
1807
1808 17
        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 17
        $this->xscale->off = $oldoff;
1841
1842 17
        if ($this->grid_depth == DEPTH_FRONT && !$_csim) {
1843 1
            $this->ygrid->Stroke();
1844 1
            $this->xgrid->Stroke();
1845
        }
1846
1847
        // Stroke colored bands
1848 17
        $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 17
        if (!$_csim) {
1853 17
            $this->StrokeAxis();
1854
        }
1855
1856 16
        if ($this->y2scale != null && !$_csim) {
1857 2
            $this->y2axis->Stroke($this->xscale, false);
1858
        }
1859
1860 16
        if (!$_csim) {
1861 16
            $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 16
        $aa = $this->img->SetAngle(0);
1867 16
        $this->StrokeTitles();
1868 16
        $this->footer->Stroke($this->img);
1869 16
        $this->legend->Stroke($this->img);
1870 16
        $this->img->SetAngle($aa);
1871 16
        $this->StrokeTexts();
1872 16
        $this->StrokeTables();
1873
1874 16
        if (!$_csim) {
1875 16
            $this->img->SetAngle($aa);
1876
1877
            // Draw an outline around the image map
1878 16
            if (_JPG_DEBUG) {
1879
                $this->DisplayClientSideaImageMapAreas();
1880
            }
1881
1882
            // Should we do any final image transformation
1883 16
            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 16
            if ($aStrokeFileName == _IMG_HANDLER) {
1900
                return $this->img->img;
1901
            }
1902
            // Finally stream the generated picture
1903 16
            $this->cache->PutAndStream($this->img, $this->cache_name, $this->inline, $aStrokeFileName);
1904
        }
1905 16
    }
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 17
    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 17
        $t = $this->iAxisLblBgType;
1928 17
        if ($t < 1) {
1929 17
            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 17
    public function StrokeAxis($aStrokeLabels = true)
1999
    {
2000 17
        if ($aStrokeLabels) {
2001 17
            $this->StrokeAxisLabelBackground();
2002
        }
2003
2004
        // Stroke axis
2005 17
        if ($this->iAxisStyle != AXSTYLE_SIMPLE) {
2006 2
            switch ($this->iAxisStyle) {
2007 2
                case AXSTYLE_BOXIN:
2008 1
                    $toppos    = SIDE_DOWN;
2009 1
                    $bottompos = SIDE_UP;
2010 1
                    $leftpos   = SIDE_RIGHT;
2011 1
                    $rightpos  = SIDE_LEFT;
2012
2013 1
                    break;
2014 1
                case AXSTYLE_BOXOUT:
2015 1
                    $toppos    = SIDE_UP;
2016 1
                    $bottompos = SIDE_DOWN;
2017 1
                    $leftpos   = SIDE_LEFT;
2018 1
                    $rightpos  = SIDE_RIGHT;
2019
2020 1
                    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 2
            $this->xscale->ticks->SupressFirst(false);
2045
2046
            // Now draw the bottom X-axis
2047 2
            $this->xaxis->SetPos('min');
2048 2
            $this->xaxis->SetLabelSide(SIDE_DOWN);
2049 2
            $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 2
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2051
2052 2
            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 2
                $this->xaxis = $this->xaxis;
2055 2
                $this->xaxis->SetPos('max');
2056 2
                $this->xaxis->SetLabelSide(SIDE_UP);
2057
                // No title for the top X-axis
2058 2
                if ($aStrokeLabels) {
2059 2
                    $this->xaxis->title->Set('');
2060
                }
2061 2
                $this->xaxis->scale->ticks->SetSide($toppos);
2062 2
                $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2063
            }
2064
2065
            // Stroke the left Y-axis
2066 2
            $this->yaxis->SetPos('min');
2067 2
            $this->yaxis->SetLabelSide(SIDE_LEFT);
2068 2
            $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 2
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2070
2071
            // Stroke the  right Y-axis
2072 2
            $this->yaxis->SetPos('max');
2073
            // No title for the right side
2074 2
            if ($aStrokeLabels) {
2075 2
                $this->yaxis->title->Set('');
2076
            }
2077 2
            $this->yaxis->SetLabelSide(SIDE_RIGHT);
2078 2
            $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 2
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2080
        } else {
2081 17
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2082 17
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2083
        }
2084 17
    }
2085
2086
    // Private helper function for backgound image
2087 4
    public static function LoadBkgImage($aImgFormat = '', $aFile = '', $aImgStr = '')
2088
    {
2089 4
        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 4
        $e   = explode('.', $aFile);
2096 4
        $ext = strtolower($e[count($e) - 1]);
2097 4
        if ($ext == 'jpeg') {
2098
            $ext = 'jpg';
2099
        }
2100
2101 4
        if (trim($ext) == '') {
2102
            $ext = 'png'; // Assume PNG if no extension specified
2103
        }
2104
2105 4
        if ($aImgFormat == '') {
2106 1
            $imgtag = $ext;
2107
        } else {
2108 3
            $imgtag = $aImgFormat;
2109
        }
2110
2111 4
        $supported = imagetypes();
2112 4
        if (($ext == 'jpg' && !($supported & IMG_JPG)) ||
2113 2
            ($ext == 'gif' && !($supported & IMG_GIF)) ||
2114 2
            ($ext == 'png' && !($supported & IMG_PNG)) ||
2115 2
            ($ext == 'bmp' && !($supported & IMG_WBMP)) ||
2116 4
            ($ext == 'xpm' && !($supported & IMG_XPM))) {
2117 2
            Util\JpGraphError::RaiseL(25037, $aFile); //('The image format of your background image ('.$aFile.') is not supported in your system configuration. ');
2118
        }
2119
2120 2
        if ($imgtag == 'jpg' || $imgtag == 'jpeg') {
2121
            $f      = 'imagecreatefromjpeg';
2122
            $imgtag = 'jpg';
2123
        } else {
2124 2
            $f = 'imagecreatefrom' . $imgtag;
2125
        }
2126
2127
        // Compare specified image type and file extension
2128 2
        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 2
        $img = @$f($aFile);
2134 2
        if (!$img) {
2135
            Util\JpGraphError::RaiseL(25039, $aFile); //(" Can't read background image: '".$aFile."'");
2136
        }
2137
2138 2
        return $img;
2139
    }
2140
2141 14
    public function StrokePlotGrad()
2142
    {
2143 14
        if ($this->plot_gradtype < 0) {
2144 14
            return;
2145
        }
2146
2147 1
        $grad = new Plot\Gradient($this->img);
2148 1
        $xl   = $this->img->left_margin;
2149 1
        $yt   = $this->img->top_margin;
2150 1
        $xr   = $xl + $this->img->plotwidth + 1;
2151 1
        $yb   = $yt + $this->img->plotheight;
2152 1
        $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->plot_gradfrom, $this->plot_gradto, $this->plot_gradtype);
2153 1
    }
2154
2155 16
    public function StrokeBackgroundGrad()
2156
    {
2157 16
        if ($this->bkg_gradtype < 0) {
2158 14
            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 4
    public function StrokeFrameBackground()
2190
    {
2191 4
        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 4
        if ($this->background_image != '') {
2195 3
            $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 3
        $bw = imagesx($bkgimg);
2207 3
        $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 3
        $aa = $this->img->SetAngle(0);
2212
2213 3
        switch ($this->background_image_type) {
2214 3
            case BGIMG_FILLPLOT: // Resize to just fill the plotarea
2215 1
                $this->FillMarginArea();
2216 1
                $this->StrokeFrame();
2217
                // Special case to hande 90 degree rotated graph corectly
2218 1
                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 1
                    $this->FillPlotArea();
2237 1
                    $this->img->CopyMerge(
2238 1
                        $bkgimg,
2239 1
                        $this->img->left_margin,
2240 1
                        $this->img->top_margin + 1,
2241 1
                        0,
2242 1
                        0,
2243 1
                        $this->img->plotwidth + 1,
2244 1
                        $this->img->plotheight,
2245
                        $bw,
2246
                        $bh,
2247 1
                        $this->background_image_mix
2248
                    );
2249
                }
2250
2251 1
                break;
2252 3
            case BGIMG_FILLFRAME: // Fill the whole area from upper left corner, resize to just fit
2253 2
                $hadj = 0;
2254 2
                $vadj = 0;
2255 2
                if ($this->doshadow) {
2256 2
                    $hadj = $this->shadow_width;
2257 2
                    $vadj = $this->shadow_width;
2258
                }
2259 2
                $this->FillMarginArea();
2260 2
                $this->FillPlotArea();
2261 2
                $this->img->CopyMerge(
2262 2
                    $bkgimg,
2263 2
                    0,
2264 2
                    0,
2265 2
                    0,
2266 2
                    0,
2267 2
                    $this->img->width - $hadj,
2268 2
                    $this->img->height - $vadj,
2269
                    $bw,
2270
                    $bh,
2271 2
                    $this->background_image_mix
2272
                );
2273 2
                $this->StrokeFrame();
2274
2275 2
                break;
2276 2
            case BGIMG_COPY: // Just copy the image from left corner, no resizing
2277 2
                $this->FillMarginArea();
2278 2
                $this->FillPlotArea();
2279 2
                $this->img->CopyMerge(
2280 2
                    $bkgimg,
2281 2
                    0,
2282 2
                    0,
2283 2
                    0,
2284 2
                    0,
2285
                    $bw,
2286
                    $bh,
2287
                    $bw,
2288
                    $bh,
2289 2
                    $this->background_image_mix
2290
                );
2291 2
                $this->StrokeFrame();
2292
2293 2
                break;
2294
            case BGIMG_CENTER: // Center original image in the plot area
2295
                $this->FillMarginArea();
2296
                $this->FillPlotArea();
2297
                $centerx = round($this->img->plotwidth / 2 + $this->img->left_margin - $bw / 2);
2298
                $centery = round($this->img->plotheight / 2 + $this->img->top_margin - $bh / 2);
2299
                $this->img->CopyMerge(
2300
                    $bkgimg,
2301
                    $centerx,
2302
                    $centery,
2303
                    0,
2304
                    0,
2305
                    $bw,
2306
                    $bh,
2307
                    $bw,
2308
                    $bh,
2309
                    $this->background_image_mix
2310
                );
2311
                $this->StrokeFrame();
2312
2313
                break;
2314
            case BGIMG_FREE: // Just copy the image to the specified location
2315
                $this->img->CopyMerge(
2316
                    $bkgimg,
2317
                    $this->background_image_xpos,
2318
                    $this->background_image_ypos,
2319
                    0,
2320
                    0,
2321
                    $bw,
2322
                    $bh,
2323
                    $bw,
2324
                    $bh,
2325
                    $this->background_image_mix
2326
                );
2327
                $this->StrokeFrame(); // New
2328
                break;
2329
            default:
2330
                Util\JpGraphError::RaiseL(25042); //(" Unknown background image layout");
2331
        }
2332 3
        $this->img->SetAngle($aa);
2333 3
    }
2334
2335
    // Private
2336
    // Draw a frame around the image
2337 19
    public function StrokeFrame()
2338
    {
2339 19
        if (!$this->doframe) {
2340 18
            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 3
    public function FillMarginArea()
2390
    {
2391 3
        $hadj = 0;
2392 3
        $vadj = 0;
2393 3
        if ($this->doshadow) {
2394 3
            $hadj = $this->shadow_width;
2395 3
            $vadj = $this->shadow_width;
2396
        }
2397
2398 3
        $this->img->SetColor($this->margin_color);
2399 3
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->height - 1 - $vadj);
2400
2401 3
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->top_margin);
2402 3
        $this->img->FilledRectangle(0, $this->img->top_margin, $this->img->left_margin, $this->img->height - 1 - $hadj);
2403 3
        $this->img->FilledRectangle(
2404 3
            $this->img->left_margin + 1,
2405 3
            $this->img->height - $this->img->bottom_margin,
2406 3
            $this->img->width - 1 - $hadj,
2407 3
            $this->img->height - 1 - $hadj
2408
        );
2409 3
        $this->img->FilledRectangle(
2410 3
            $this->img->width - $this->img->right_margin,
2411 3
            $this->img->top_margin + 1,
2412 3
            $this->img->width - 1 - $hadj,
2413 3
            $this->img->height - $this->img->bottom_margin - 1
2414
        );
2415 3
    }
2416
2417 15
    public function FillPlotArea()
2418
    {
2419 15
        $this->img->PushColor($this->plotarea_color);
2420 15
        $this->img->FilledRectangle(
2421 15
            $this->img->left_margin,
2422 15
            $this->img->top_margin,
2423 15
            $this->img->width - $this->img->right_margin,
2424 15
            $this->img->height - $this->img->bottom_margin
2425
        );
2426 15
        $this->img->PopColor();
2427 15
    }
2428
2429
    // Stroke the plot area with either a solid color or a background image
2430 18
    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 18
        $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 18
        $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 18
        if ($this->background_image != '' || $this->background_cflag != '') {
2442 4
            $this->StrokeFrameBackground();
2443
        } else {
2444 14
            $aa = $this->img->SetAngle(0);
2445 14
            $this->StrokeFrame();
2446 14
            $aa = $this->img->SetAngle($aa);
0 ignored issues
show
Unused Code introduced by
The assignment to $aa is dead and can be removed.
Loading history...
2447 14
            $this->StrokeBackgroundGrad();
2448 14
            if ($this->bkg_gradtype < 0 || ($this->bkg_gradtype > 0 && $this->bkg_gradstyle == BGRAD_MARGIN)) {
2449 12
                $this->FillPlotArea();
2450
            }
2451 14
            $this->StrokePlotGrad();
2452
        }
2453 17
    }
2454
2455 19
    public function StrokeIcons()
2456
    {
2457 19
        $n = safe_count($this->iIcons);
2458 19
        for ($i = 0; $i < $n; ++$i) {
2459
            $this->iIcons[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2460
        }
2461 19
    }
2462
2463 16
    public function StrokePlotBox()
2464
    {
2465
        // Should we draw a box around the plot area?
2466 16
        if ($this->boxed) {
2467 16
            $this->img->SetLineWeight(1);
2468 16
            $this->img->SetLineStyle('solid');
2469 16
            $this->img->SetColor($this->box_color);
2470 16
            for ($i = 0; $i < $this->box_weight; ++$i) {
2471 16
                $this->img->Rectangle(
2472 16
                    $this->img->left_margin - $i,
2473 16
                    $this->img->top_margin - $i,
2474 16
                    $this->img->width - $this->img->right_margin + $i,
2475 16
                    $this->img->height - $this->img->bottom_margin + $i
2476
                );
2477
            }
2478
        }
2479 16
    }
2480
2481
    public function SetTitleBackgroundFillStyle($aStyle, $aColor1 = 'black', $aColor2 = 'white')
2482
    {
2483
        $this->titlebkg_fillstyle = $aStyle;
2484
        $this->titlebkg_scolor1   = $aColor1;
2485
        $this->titlebkg_scolor2   = $aColor2;
2486
    }
2487
2488
    public function SetTitleBackground($aBackColor = 'gray', $aStyle = TITLEBKG_STYLE1, $aFrameStyle = TITLEBKG_FRAME_NONE, $aFrameColor = 'black', $aFrameWeight = 1, $aBevelHeight = 3, $aEnable = true)
2489
    {
2490
        $this->titlebackground             = $aEnable;
2491
        $this->titlebackground_color       = $aBackColor;
2492
        $this->titlebackground_style       = $aStyle;
2493
        $this->titlebackground_framecolor  = $aFrameColor;
2494
        $this->titlebackground_framestyle  = $aFrameStyle;
2495
        $this->titlebackground_frameweight = $aFrameWeight;
2496
        $this->titlebackground_bevelheight = $aBevelHeight;
2497
    }
2498
2499 18
    public function StrokeTitles()
2500
    {
2501 18
        $margin = 3;
2502
2503 18
        if ($this->titlebackground) {
2504
            // Find out height
2505
            $this->title->margin += 2;
2506
            $h = $this->title->GetTextHeight($this->img) + $this->title->margin + $margin;
2507
            if ($this->subtitle->t != '' && !$this->subtitle->hide) {
2508
                $h += $this->subtitle->GetTextHeight($this->img) + $margin +
2509
                $this->subtitle->margin;
2510
                $h += 2;
2511
            }
2512
            if ($this->subsubtitle->t != '' && !$this->subsubtitle->hide) {
2513
                $h += $this->subsubtitle->GetTextHeight($this->img) + $margin +
2514
                $this->subsubtitle->margin;
2515
                $h += 2;
2516
            }
2517
            $this->img->PushColor($this->titlebackground_color);
2518
            if ($this->titlebackground_style === TITLEBKG_STYLE1) {
2519
                // Inside the frame
2520
                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
                    $x1 = $y1 = $this->frame_weight;
2528
                    $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
            if ($this->titlebackground_framestyle === 3) {
2547
                $h += $this->titlebackground_bevelheight * 2 + 1;
2548
                $this->title->margin += $this->titlebackground_bevelheight;
2549
            }
2550
2551
            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
            $indent = 0;
2556
            if ($this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL) {
2557
                $indent = $this->titlebackground_bevelheight;
2558
            }
2559
2560
            if ($this->titlebkg_fillstyle == TITLEBKG_FILLSTYLE_HSTRIPED) {
2561
                $this->img->FilledRectangle2(
2562
                    $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
                    $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
                    $x2 - $indent,
2565
                    $h - $indent,
2566
                    $this->titlebkg_scolor1,
2567
                    $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
            $this->img->PopColor();
2584
2585
            $this->img->PushColor($this->titlebackground_framecolor);
2586
            $this->img->SetLineWeight($this->titlebackground_frameweight);
2587
            if ($this->titlebackground_framestyle == TITLEBKG_FRAME_FULL) {
2588
                // Frame background
2589
                $this->img->Rectangle($x1, $y1, $x2, $h);
2590
            } elseif ($this->titlebackground_framestyle == TITLEBKG_FRAME_BOTTOM) {
2591
                // Bottom line only
2592
                $this->img->Line($x1, $h, $x2, $h);
2593
            } elseif ($this->titlebackground_framestyle == TITLEBKG_FRAME_BEVEL) {
2594
                $this->img->Bevel($x1, $y1, $x2, $h, $this->titlebackground_bevelheight);
2595
            }
2596
            $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
            if ($this->framebevel && $this->doframe && $this->titlebackground_style === 3) {
2601
                $this->img->Bevel(
2602
                    1,
2603
                    1,
2604
                    $this->img->width - 2,
2605
                    $this->img->height - 2,
2606
                    $this->framebeveldepth,
2607
                    $this->framebevelcolor1,
2608
                    $this->framebevelcolor2
2609
                );
2610
                if ($this->framebevelborder) {
2611
                    $this->img->SetColor($this->framebevelbordercolor);
2612
                    $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2613
                }
2614
            }
2615
        }
2616
2617
        // Stroke title
2618 18
        $y = $this->title->margin;
2619 18
        if ($this->title->halign == 'center') {
2620 18
            $this->title->Center(0, $this->img->width, $y);
2621
        } elseif ($this->title->halign == 'left') {
2622
            $this->title->SetPos($this->title->margin + 2, $y);
2623
        } elseif ($this->title->halign == 'right') {
2624
            $indent = 0;
2625
            if ($this->doshadow) {
2626
                $indent = $this->shadow_width + 2;
2627
            }
2628
            $this->title->SetPos($this->img->width - $this->title->margin - $indent, $y, 'right');
2629
        }
2630 18
        $this->title->Stroke($this->img);
2631
2632
        // ... and subtitle
2633 18
        $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
2634 18
        if ($this->subtitle->halign == 'center') {
2635 18
            $this->subtitle->Center(0, $this->img->width, $y);
2636
        } elseif ($this->subtitle->halign == 'left') {
2637
            $this->subtitle->SetPos($this->subtitle->margin + 2, $y);
2638
        } elseif ($this->subtitle->halign == 'right') {
2639
            $indent = 0;
2640
            if ($this->doshadow) {
2641
                $indent = $this->shadow_width + 2;
2642
            }
2643
2644
            $this->subtitle->SetPos($this->img->width - $this->subtitle->margin - $indent, $y, 'right');
2645
        }
2646 18
        $this->subtitle->Stroke($this->img);
2647
2648
        // ... and subsubtitle
2649 18
        $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
2650 18
        if ($this->subsubtitle->halign == 'center') {
2651 18
            $this->subsubtitle->Center(0, $this->img->width, $y);
2652
        } elseif ($this->subsubtitle->halign == 'left') {
2653
            $this->subsubtitle->SetPos($this->subsubtitle->margin + 2, $y);
2654
        } elseif ($this->subsubtitle->halign == 'right') {
2655
            $indent = 0;
2656
            if ($this->doshadow) {
2657
                $indent = $this->shadow_width + 2;
2658
            }
2659
2660
            $this->subsubtitle->SetPos($this->img->width - $this->subsubtitle->margin - $indent, $y, 'right');
2661
        }
2662 18
        $this->subsubtitle->Stroke($this->img);
2663
2664
        // ... and fancy title
2665 18
        $this->tabtitle->Stroke($this->img);
2666 18
    }
2667
2668 16
    public function StrokeTexts()
2669
    {
2670
        // Stroke any user added text objects
2671 16
        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 16
        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 16
    }
2683
2684 16
    public function StrokeTables()
2685
    {
2686 16
        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 16
    }
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 17
    public function SetTextScaleOff($aOff)
2727
    {
2728 17
        $this->text_scale_off         = $aOff;
2729 17
        $this->xscale->text_scale_off = $aOff;
2730 17
    }
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 16
    public function GetLinesYMinMax($aLines)
2740
    {
2741 16
        if (is_null($aLines)) {
2742 16
            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 6
    public function GetLinesXMinMax($aLines)
2772
    {
2773 6
        $n = safe_count($aLines);
2774 6
        if ($n == 0) {
2775 6
            return false;
2776
        }
2777
2778
        $min = $aLines[0]->scaleposition;
2779
        $max = $min;
2780
        $flg = false;
2781
        for ($i = 0; $i < $n; ++$i) {
2782
            if ($aLines[$i]->direction == VERTICAL) {
2783
                $flg = true;
2784
                $v   = $aLines[$i]->scaleposition;
2785
                if ($min > $v) {
2786
                    $min = $v;
2787
                }
2788
2789
                if ($max < $v) {
2790
                    $max = $v;
2791
                }
2792
            }
2793
        }
2794
2795
        return $flg ? [$min, $max] : false;
0 ignored issues
show
introduced by
The condition $flg is always false.
Loading history...
2796
    }
2797
2798
    // Get min and max values for all included plots
2799 16
    public function GetPlotsYMinMax($bPlots)
2800
    {
2801
        $aPlots = array_filter($bPlots, function ($plot) {
2802
            //\Kint::dump($plot, $plot instanceof Plot\Plot);
2803 16
            return $plot instanceof Plot\Plot;
2804 16
        });
2805 16
        reset($aPlots);
2806 16
        $n = safe_count($aPlots);
2807 16
        $i = 0;
2808
        //\Kint::dump($n, $aPlots);
2809
        do {
2810
            //\Kint::dump($i, $aPlots[$i]);
2811 16
            list($xmax, $max) = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
2812 16
        } while (++$i < $n && !is_numeric($max));
2813
2814 16
        $i = 0;
2815
        do {
2816 16
            list($xmin, $min) = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
2817 16
        } while (++$i < $n && !is_numeric($min));
2818
2819 16
        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 16
        for ($i = 0; $i < $n; ++$i) {
2824 16
            list($xmax, $ymax) = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
2825 16
            list($xmin, $ymin) = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
2826 16
            if (is_numeric($ymax)) {
2827 16
                $max = max($max, $ymax);
2828
            }
2829
2830 16
            if (is_numeric($ymin)) {
2831 16
                $min = min($min, $ymin);
2832
            }
2833
        }
2834 16
        if ($min == '') {
2835 3
            $min = 0;
2836
        }
2837
2838 16
        if ($max == '') {
2839
            $max = 0;
2840
        }
2841
2842 16
        if ($min == 0 && $max == 0) {
2843
            // Special case if all values are 0
2844
            $min = 0;
2845
            $max = 1;
2846
        }
2847
2848 16
        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