Test Failed
Push — feature/move_tests_to_pest_and... ( ffa61b...387f0b )
by Felipe
04:33
created

Graph::Set3DPerspective()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 11
Code Lines 9

Duplication

Lines 0
Ratio 0 %

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
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 - Community Edition
5
 */
6
7
namespace Amenadiel\JpGraph\Graph;
8
9
use Amenadiel\JpGraph\Image;
10
use Amenadiel\JpGraph\Plot;
11
use Amenadiel\JpGraph\Text;
12
use Amenadiel\JpGraph\Util;
13
use function count;
14
15
/**
16
 * @class Graph
17
  *  Description: Main class to handle graphs
18
 */
19
class Graph
20
{
21
    /**
22
     * @var Util\DateLocale
23
     */
24
    public $gDateLocale;
25
26
    /**
27
     * @var Util\DateLocale
28
     */
29
    public $gJpgDateLocale;
30
31
    /**
32
     * @var Image\ImgStreamCache
33
     */
34
    public $cache; // Cache object (singleton)
35
36
    public $img; // Img object (singleton)
37
38
    public $plots = []; // Array of all plot object in the graph (for Y 1 axis)
39
40
    public $y2plots = []; // Array of all plot object in the graph (for Y 2 axis)
41
42
    public $ynplots = [];
43
44
    /**
45
     * @var Scale\DateScale|Scale\LinearScale|Scale\LogScale|null
46
     */
47
    public $xscale; // X Scale object (could be instance of LinearScale or LogScale
48
    public $scale;
49
50
    /**
51
     * @var Scale\LinearScale|Scale\LogScale|null
52
     */
53
    public $yscale;
54
55
    /**
56
     * @var Scale\LinearScale|Scale\LogScale|null
57
     */
58
    public $y2scale;
59
60
    public $ynscale = [];
61
62
    public $iIcons = []; // Array of Icons to add to
63
64
    public $cache_name; // File name to be used for the current graph in the cache directory
65
66
    /**
67
     * @var Grid|null
68
     */
69
    public $xgrid; // X Grid object (linear or logarithmic)
70
71
    /**
72
     * @var Grid|null
73
     */
74
    public $ygrid;
75
76
    /**
77
     * @var Grid|null
78
     */
79
    public $y2grid; //dito for Y
80
81
    public $doframe;
82
83
    public $frame_color;
84
85
    public $frame_weight; // Frame around graph
86
87
    public $boxed = false;
88
89
    public $box_color = 'black';
90
91
    public $box_weight = 1; // Box around plot area
92
93
    public $doshadow = false;
94
95
    public $shadow_width = 4;
96
97
    public $shadow_color = '[email protected]'; // Shadow for graph
98
99
    public $xaxis; // X-axis (instane of Axis class)
100
101
    /**
102
     * @var Axis\Axis|null
103
     */
104
    public $yaxis;
105
106
    /**
107
     * @var Axis\Axis|null
108
     */
109
    public $y2axis;
110
111
    public $ynaxis = []; // Y axis (instance of Axis class)
112
113
    public $margin_color; // Margin color of graph
114
115
    public $plotarea_color = [255, 255, 255]; // Plot area color
116
117
    /**
118
     * @var Text\Text
119
     */
120
    public $title;
121
122
    /**
123
     * @var Text\Text
124
     */
125
    public $subtitle;
126
127
    /**
128
     * @var Text\Text
129
     */
130
    public $subsubtitle; // Title and subtitle(s) text object
131
132
    public $axtype = 'linlin'; // Type of axis
133
134
    /**
135
     * @var int
136
     *
137
     * @psalm-var 15|30|45|60
138
     */
139
    public $xtick_factor;
140
141
    /**
142
     * @var int
143
     *
144
     * @psalm-var 12|25|40|100
145
     */
146
    public $ytick_factor; // Factor to determine the maximum number of ticks depending on the plot width
147
148
    public $texts;
149
150
    public $y2texts; // Text object to ge shown in the graph
151
152
    public $lines;
153
154
    public $y2lines;
155
156
    public $bands;
157
158
    public $y2bands;
159
160
    public $text_scale_off = 0;
161
162
    public $text_scale_abscenteroff = -1; // Text scale in fractions and for centering bars
163
164
    public $background_image = '';
165
166
    public $background_image_type = -1;
167
168
    public $background_image_format = 'png';
169
170
    /**
171
     * @var int
172
     */
173
    public $background_image_bright = 0;
174
175
    /**
176
     * @var int
177
     */
178
    public $background_image_contr = 0;
179
180
    /**
181
     * @var int
182
     */
183
    public $background_image_sat = 0;
184
185
    public $background_image_xpos = 0;
186
187
    public $background_image_ypos = 0;
188
189
    /**
190
     * @var int
191
     */
192
    public $image_bright = 0;
193
194
    /**
195
     * @var int
196
     */
197
    public $image_contr = 0;
198
199
    /**
200
     * @var int
201
     */
202
    public $image_sat = 0;
203
204
    public $inline;
205
206
    /**
207
     * @var int
208
     */
209
    public $showcsim = 0;
210
211
    /**
212
     * @var string
213
     */
214
    public $csimcolor = 'red'; //debug stuff, draw the csim boundaris on the image if <>0
215
216
    public $grid_depth = Configs::DEPTH_BACK; // Draw grid under all plots as default
217
218
    public $iAxisStyle = Configs::AXSTYLE_SIMPLE;
219
220
    /**
221
     * @var false
222
     */
223
    public $iCSIMdisplay = false;
224
225
    /**
226
     * @var bool
227
     */
228
    public $iHasStroked = false;
229
230
    /**
231
     * @var Image\Footer
232
     */
233
    public $footer;
234
235
    /**
236
     * @var string
237
     */
238
    public $csimcachename = '';
239
240
    public $csimcachetimeout = 0;
241
242
    public $iCSIMImgAlt = '';
243
244
    public $iDoClipping = false;
245
246
    public $y2orderback = true;
247
248
    /**
249
     * @var Text\GraphTabTitle
250
     */
251
    public $tabtitle;
252
253
    public $bkg_gradtype = -1;
254
255
    public $bkg_gradstyle = Configs::BGRAD_MARGIN;
256
257
    public $bkg_gradfrom = 'navy';
258
259
    public $bkg_gradto = 'silver';
260
261
    public $plot_gradtype = -1;
262
263
    public $plot_gradstyle = Configs::BGRAD_MARGIN;
264
265
    public $plot_gradfrom = 'silver';
266
267
    public $plot_gradto = 'navy';
268
269
    public $titlebackground = false;
270
271
    public $titlebackground_color = 'lightblue';
272
273
    public $titlebackground_style = 1;
274
275
    public $titlebackground_framecolor;
276
277
    public $titlebackground_framestyle;
278
279
    public $titlebackground_frameweight;
280
281
    public $titlebackground_bevelheight;
282
283
    public $titlebkg_fillstyle = Configs::TITLEBKG_FILLSTYLE_SOLID;
284
285
    public $titlebkg_scolor1 = 'black';
286
287
    public $titlebkg_scolor2 = 'white';
288
289
    public $framebevel;
290
291
    public $framebeveldepth;
292
293
    public $framebevelborder;
294
295
    public $framebevelbordercolor;
296
297
    public $framebevelcolor1;
298
299
    public $framebevelcolor2;
300
301
    public $background_image_mix = 100;
302
303
    public $background_cflag = '';
304
305
    public $background_cflag_type = Configs::BGIMG_FILLPLOT;
306
307
    public $background_cflag_mix = 100;
308
309
    /**
310
     * @var bool
311
     */
312
    public $iImgTrans = false;
313
314
    public $iImgTransHorizon = 100;
315
316
    public $iImgTransSkewDist = 150;
317
318
    public $iImgTransDirection = 1;
319
320
    public $iImgTransMinSize = true;
321
322
    public $iImgTransFillColor = 'white';
323
324
    public $iImgTransHighQ = false;
325
326
    public $iImgTransBorder = false;
327
328
    public $iImgTransHorizonPos = 0.5;
329
330
    /**
331
     * @var Legend
332
     */
333
    public $legend;
334
335
    public $graph_theme;
336
337
    protected $iYAxisDeltaPos = 50;
338
339
    protected $iIconDepth = Configs::DEPTH_BACK;
340
341
    protected $iAxisLblBgType = 0;
342
343
    protected $iXAxisLblBgFillColor = 'lightgray';
344
345
    protected $iXAxisLblBgColor = 'black';
346
347
    protected $iYAxisLblBgFillColor = 'lightgray';
348
349
    protected $iYAxisLblBgColor = 'black';
350
351
    protected $iTables;
352
353
    /**
354
     * @var bool
355
     */
356
    protected $isRunningClear = false;
357
358
    protected $inputValues;
359
360
    /**
361
     * @var bool
362
     */
363
    protected $isAfterSetScale = false;
364
365
    // aWIdth   Width in pixels of image
366
    // aHeight   Height in pixels of image
367
    // aCachedName Name for image file in cache directory
368
    // aTimeOut  Timeout in minutes for image in cache
369
    // aInline  If true the image is streamed back in the call to Stroke()
370
    //   If false the image is just created in the cache
371
    public function __construct($aWidth = 300, $aHeight = 200, $aCachedName = '', $aTimeout = 0, $aInline = true)
372
    {
373
        // Bootstrap configs repository if it hasn't bootstrapped already
374
        Util\Helper::bootstrapLibrary();
375
376
        $this->gDateLocale = new Util\DateLocale();
377
        $this->gJpgDateLocale = new Util\DateLocale();
378
379
        if (!\is_numeric($aWidth) || !\is_numeric($aHeight)) {
380
            Util\JpGraphError::RaiseL(25008); //('Image width/height argument in Graph::Graph() must be numeric');
381
        }
382
383
        // Initialize frame and margin
384
        $this->InitializeFrameAndMargin();
385
386
        // Automatically generate the image file name based on the name of the script that
387
        // generates the graph
388
        if ('auto' === $aCachedName) {
389
            $aCachedName = Util\Helper::GenImgName();
390
        }
391
392
        // Should the image be streamed back to the browser or only to the cache?
393
        $this->inline = $aInline;
394
395
        $this->img = new Image\RotImage($aWidth, $aHeight);
396
        $this->cache = new Image\ImgStreamCache();
397
398
        // Window doesn't like '?' in the file name so replace it with an '_'
399
        $aCachedName = \str_replace('?', '_', $aCachedName);
400
        $this->SetupCache($aCachedName, $aTimeout);
401
402
        $this->title = new Text\Text();
403
        $this->title->ParagraphAlign('center');
404
        $this->title->SetFont(Configs::getConfig('FF_DEFAULT'), Configs::getConfig('FS_NORMAL')); //Configs::getConfig('FF_FONT2'), Configs::getConfig('FS_BOLD')
405
        $this->title->SetMargin(5);
406
        $this->title->SetAlign('center');
407
408
        $this->subtitle = new Text\Text();
409
        $this->subtitle->ParagraphAlign('center');
410
        $this->subtitle->SetMargin(3);
411
        $this->subtitle->SetAlign('center');
412
413
        $this->subsubtitle = new Text\Text();
414
        $this->subsubtitle->ParagraphAlign('center');
415
        $this->subsubtitle->SetMargin(3);
416
        $this->subsubtitle->SetAlign('center');
417
418
        $this->legend = new Legend();
419
        $this->footer = new Image\Footer();
420
421
        // If the cached version exist just read it directly from the
422
        // cache, stream it back to browser and exit
423
        if ('' !== $aCachedName && Configs::getConfig('READ_CACHE') && $aInline) {
424
            if ($this->cache->GetAndStream($this->img, $aCachedName)) {
425
                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...
426
            }
427
        }
428
429
        $this->SetTickDensity(); // Normal density
430
431
        $this->tabtitle = new Text\GraphTabTitle();
432
433
        if ($this->isRunningClear) {
434
            return;
435
        }
436
437
        $this->inputValues = [];
438
        $this->inputValues['aWidth'] = $aWidth;
439
        $this->inputValues['aHeight'] = $aHeight;
440
        $this->inputValues['aCachedName'] = $aCachedName;
441
        $this->inputValues['aTimeout'] = $aTimeout;
442
        $this->inputValues['aInline'] = $aInline;
443
444
        $theme_class = '\Amenadiel\JpGraph\Themes\\' . Configs::getConfig('DEFAULT_THEME_CLASS');
445
446
        if (!\class_exists($theme_class)) {
447
            return;
448
        }
449
450
        $this->graph_theme = new $theme_class();
451
    }
452
453
    public function InitializeFrameAndMargin()
454
    {
455
        $this->doframe = true;
456
        $this->frame_color = 'black';
457
        $this->frame_weight = 1;
458
459
        $this->titlebackground_framecolor = 'blue';
460
        $this->titlebackground_framestyle = 2;
461
        $this->titlebackground_frameweight = 1;
462
        $this->titlebackground_bevelheight = 3;
463
        $this->titlebkg_fillstyle = Configs::getConfig('TITLEBKG_FILLSTYLE_SOLID');
464
        $this->titlebkg_scolor1 = 'black';
465
        $this->titlebkg_scolor2 = 'white';
466
        $this->framebevel = false;
467
        $this->framebeveldepth = 2;
468
        $this->framebevelborder = false;
469
        $this->framebevelbordercolor = 'black';
470
        $this->framebevelcolor1 = '[email protected]';
471
        $this->framebevelcolor2 = '[email protected]';
472
473
        $this->margin_color = [250, 250, 250];
474
    }
475
476
    /**
477
     * @param string $aFilename
478
     */
479
    public function SetupCache($aFilename, $aTimeout = 60)
480
    {
481
        $this->cache_name = $aFilename;
482
        $this->cache->SetTimeOut($aTimeout);
483
    }
484
485
    // Enable final image perspective transformation
486
    public function Set3DPerspective($aDir = 1, $aHorizon = 100, $aSkewDist = 120, $aQuality = false, $aFillColor = '#FFFFFF', $aBorder = false, $aMinSize = true, $aHorizonPos = 0.5)
487
    {
488
        $this->iImgTrans = true;
489
        $this->iImgTransHorizon = $aHorizon;
490
        $this->iImgTransSkewDist = $aSkewDist;
491
        $this->iImgTransDirection = $aDir;
492
        $this->iImgTransMinSize = $aMinSize;
493
        $this->iImgTransFillColor = $aFillColor;
494
        $this->iImgTransHighQ = $aQuality;
495
        $this->iImgTransBorder = $aBorder;
496
        $this->iImgTransHorizonPos = $aHorizonPos;
497
    }
498
499
    public function SetUserFont($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
500
    {
501
        $this->img->ttf->SetUserFont($aNormal, $aBold, $aItalic, $aBoldIt);
502
    }
503
504
    public function SetUserFont1($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
505
    {
506
        $this->img->ttf->SetUserFont1($aNormal, $aBold, $aItalic, $aBoldIt);
507
    }
508
509
    public function SetUserFont2($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
510
    {
511
        $this->img->ttf->SetUserFont2($aNormal, $aBold, $aItalic, $aBoldIt);
512
    }
513
514
    public function SetUserFont3($aNormal, $aBold = '', $aItalic = '', $aBoldIt = '')
515
    {
516
        $this->img->ttf->SetUserFont3($aNormal, $aBold, $aItalic, $aBoldIt);
517
    }
518
519
    // Set Image format and optional quality
520
    public function SetImgFormat($aFormat, $aQuality = 75)
521
    {
522
        $this->img->SetImgFormat($aFormat, $aQuality);
523
    }
524
525
    // Should the grid be in front or back of the plot?
526
    /**
527
     * @param int $aDepth
528
     */
529
    public function SetGridDepth($aDepth)
530
    {
531
        $this->grid_depth = $aDepth;
532
    }
533
534
    public function SetIconDepth($aDepth)
535
    {
536
        $this->iIconDepth = $aDepth;
537
    }
538
539
    // Specify graph angle 0-360 degrees.
540
    /**
541
     * @param int $aAngle
542
     */
543
    public function SetAngle($aAngle)
544
    {
545
        $this->img->SetAngle($aAngle);
546
    }
547
548
    public function SetAlphaBlending($aFlg = true)
549
    {
550
        $this->img->SetAlphaBlending($aFlg);
551
    }
552
553
    // Shortcut to image margin
554
    /**
555
     * @param int $lm
556
     * @param int $rm
557
     * @param int $tm
558
     * @param int $bm
559
     */
560
    public function SetMargin($lm, $rm, $tm, $bm)
561
    {
562
        $this->img->SetMargin($lm, $rm, $tm, $bm);
563
    }
564
565
    public function SetY2OrderBack($aBack = true)
566
    {
567
        $this->y2orderback = $aBack;
568
    }
569
570
    // Rotate the graph 90 degrees and set the margin
571
    // when we have done a 90 degree rotation
572
    public function Set90AndMargin($lm = 0, $rm = 0, $tm = 0, $bm = 0)
573
    {
574
        $lm = 0 === $lm ? \floor(0.2 * $this->img->width) : $lm;
575
        $rm = 0 === $rm ? \floor(0.1 * $this->img->width) : $rm;
576
        $tm = 0 === $tm ? \floor(0.2 * $this->img->height) : $tm;
577
        $bm = 0 === $bm ? \floor(0.1 * $this->img->height) : $bm;
578
579
        $adj = ($this->img->height - $this->img->width) / 2;
580
        $this->img->SetMargin($tm - $adj, $bm - $adj, $rm + $adj, $lm + $adj);
581
        $this->img->SetCenter(\floor($this->img->width / 2), \floor($this->img->height / 2));
582
        $this->SetAngle(90);
583
584
        if (empty($this->yaxis) || empty($this->xaxis)) {
585
            Util\JpGraphError::RaiseL(25009); //('You must specify what scale to use with a call to Graph::SetScale()');
586
        }
587
        $this->xaxis->SetLabelAlign('right', 'center');
588
        $this->yaxis->SetLabelAlign('center', 'bottom');
589
    }
590
591
    public function SetClipping($aFlg = true)
592
    {
593
        $this->iDoClipping = $aFlg;
594
    }
595
596
    // Add a plot object to the graph
597
    /**
598
     * @param (Plot\LinePlot|mixed)[]|Text\Text $aPlot
599
     */
600
    public function Add($aPlot)
601
    {
602
        if (null === $aPlot) {
0 ignored issues
show
introduced by
The condition null === $aPlot is always false.
Loading history...
603
            Util\JpGraphError::RaiseL(25010); //("Graph::Add() You tried to add a null plot to the graph.");
604
        }
605
606
        if (\is_array($aPlot) && Configs::safe_count($aPlot) > 0) {
607
            $cl = $aPlot[0];
608
        } else {
609
            $cl = $aPlot;
610
        }
611
612
        if ($cl instanceof Text\Text) {
613
            $this->AddText($aPlot);
614
        } elseif (($cl instanceof Plot\PlotLine)) {
615
            $this->AddLine($aPlot);
616
        } elseif (($cl instanceof Plot\PlotBand)) {
617
            $this->AddBand($aPlot);
618
        } elseif (($cl instanceof Plot\IconPlot)) {
619
            $this->AddIcon($aPlot);
0 ignored issues
show
Bug introduced by
It seems like $aPlot can also be of type Amenadiel\JpGraph\Text\Text; however, parameter $aIcon of Amenadiel\JpGraph\Graph\Graph::AddIcon() does only seem to accept Amenadiel\JpGraph\Plot\IconPlot|array, maybe add an additional type check? ( Ignorable by Annotation )

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

619
            $this->AddIcon(/** @scrutinizer ignore-type */ $aPlot);
Loading history...
620
        } elseif (($cl instanceof Text\GTextTable)) {
621
            $this->AddTable($aPlot);
622
        } else {
623
            if (\is_array($aPlot)) {
624
                $this->plots = \array_merge($this->plots, $aPlot);
625
            } else {
626
                $this->plots[] = $aPlot;
627
            }
628
        }
629
630
        if (!$this->graph_theme) {
631
            return;
632
        }
633
634
        $this->graph_theme->SetupPlot($aPlot);
635
    }
636
637
    public function AddTable($aTable)
638
    {
639
        if (\is_array($aTable)) {
640
            for ($i = 0; Configs::safe_count($aTable) > $i; ++$i) {
641
                $this->iTables[] = $aTable[$i];
642
            }
643
        } else {
644
            $this->iTables[] = $aTable;
645
        }
646
    }
647
648
    /**
649
     * @param Plot\IconPlot|array $aIcon
650
     */
651
    public function AddIcon($aIcon)
652
    {
653
        if (\is_array($aIcon)) {
654
            for ($i = 0; Configs::safe_count($aIcon) > $i; ++$i) {
655
                $this->iIcons[] = $aIcon[$i];
656
            }
657
        } else {
658
            $this->iIcons[] = $aIcon;
659
        }
660
    }
661
662
    // Add plot to second Y-scale
663
    public function AddY2($aPlot)
664
    {
665
        if (null === $aPlot) {
666
            Util\JpGraphError::RaiseL(25011); //("Graph::AddY2() You tried to add a null plot to the graph.");
667
        }
668
669
        if (\is_array($aPlot) && Configs::safe_count($aPlot) > 0) {
670
            $cl = $aPlot[0];
671
        } else {
672
            $cl = $aPlot;
673
        }
674
675
        if ($cl instanceof Text\Text) {
676
            $this->AddText($aPlot, true);
677
        } elseif (($cl instanceof Plot\PlotLine)) {
678
            $this->AddLine($aPlot, true);
679
        } elseif (($cl instanceof Plot\PlotBand)) {
680
            $this->AddBand($aPlot, true);
681
        } else {
682
            $this->y2plots[] = $aPlot;
683
        }
684
685
        if (!$this->graph_theme) {
686
            return;
687
        }
688
689
        $this->graph_theme->SetupPlot($aPlot);
690
    }
691
692
    // Add plot to the extra Y-axises
693
    public function AddY($aN, $aPlot)
694
    {
695
        if (null === $aPlot) {
696
            Util\JpGraphError::RaiseL(25012); //("Graph::AddYN() You tried to add a null plot to the graph.");
697
        }
698
699
        if (\is_array($aPlot) && Configs::safe_count($aPlot) > 0) {
700
            $cl = $aPlot[0];
701
        } else {
702
            $cl = $aPlot;
703
        }
704
705
        if (($cl instanceof Text\Text)
706
            || ($cl instanceof Plot\PlotLine)
707
            || ($cl instanceof Plot\PlotBand)
708
        ) {
709
            Util\JpGraphError::RaiseL(25013); //('You can only add standard plots to multiple Y-axis');
710
        } else {
711
            $this->ynplots[$aN][] = $aPlot;
712
        }
713
714
        if (!$this->graph_theme) {
715
            return;
716
        }
717
718
        $this->graph_theme->SetupPlot($aPlot);
719
    }
720
721
    // Add text object to the graph
722
    /**
723
     * @param Text\Text|array $aTxt
724
     * @param bool $aToY2
725
     */
726
    public function AddText($aTxt, $aToY2 = false)
727
    {
728
        if (null === $aTxt) {
0 ignored issues
show
introduced by
The condition null === $aTxt is always false.
Loading history...
729
            Util\JpGraphError::RaiseL(25014); //("Graph::AddText() You tried to add a null text to the graph.");
730
        }
731
732
        if ($aToY2) {
733
            if (\is_array($aTxt)) {
734
                for ($i = 0; Configs::safe_count($aTxt) > $i; ++$i) {
735
                    $this->y2texts[] = $aTxt[$i];
736
                }
737
            } else {
738
                $this->y2texts[] = $aTxt;
739
            }
740
        } else {
741
            if (\is_array($aTxt)) {
742
                for ($i = 0; Configs::safe_count($aTxt) > $i; ++$i) {
743
                    $this->texts[] = $aTxt[$i];
744
                }
745
            } else {
746
                $this->texts[] = $aTxt;
747
            }
748
        }
749
    }
750
751
    // Add a line object (class PlotLine) to the graph
752
    /**
753
     * @param bool $aToY2
754
     */
755
    public function AddLine($aLine, $aToY2 = false)
756
    {
757
        if (null === $aLine) {
758
            Util\JpGraphError::RaiseL(25015); //("Graph::AddLine() You tried to add a null line to the graph.");
759
        }
760
761
        if ($aToY2) {
762
            if (\is_array($aLine)) {
763
                for ($i = 0; Configs::safe_count($aLine) > $i; ++$i) {
764
                    //$this->y2lines[]=$aLine[$i];
765
                    $this->y2plots[] = $aLine[$i];
766
                }
767
            } else {
768
                //$this->y2lines[] = $aLine;
769
                $this->y2plots[] = $aLine;
770
            }
771
        } else {
772
            if (\is_array($aLine)) {
773
                for ($i = 0; Configs::safe_count($aLine) > $i; ++$i) {
774
                    //$this->lines[]=$aLine[$i];
775
                    $this->plots[] = $aLine[$i];
776
                }
777
            } else {
778
                //$this->lines[] = $aLine;
779
                $this->plots[] = $aLine;
780
            }
781
        }
782
    }
783
784
    // Add vertical or horizontal band
785
    /**
786
     * @param bool $aToY2
787
     */
788
    public function AddBand($aBand, $aToY2 = false)
789
    {
790
        if (null === $aBand) {
791
            Util\JpGraphError::RaiseL(25016); //(" Graph::AddBand() You tried to add a null band to the graph.");
792
        }
793
794
        if ($aToY2) {
795
            if (\is_array($aBand)) {
796
                for ($i = 0; Configs::safe_count($aBand) > $i; ++$i) {
797
                    $this->y2bands[] = $aBand[$i];
798
                }
799
            } else {
800
                $this->y2bands[] = $aBand;
801
            }
802
        } else {
803
            if (\is_array($aBand)) {
804
                for ($i = 0; Configs::safe_count($aBand) > $i; ++$i) {
805
                    $this->bands[] = $aBand[$i];
806
                }
807
            } else {
808
                $this->bands[] = $aBand;
809
            }
810
        }
811
    }
812
813
    public function SetPlotGradient($aFrom = 'navy', $aTo = 'silver', $aGradType = 2)
814
    {
815
        $this->plot_gradtype = $aGradType;
816
        $this->plot_gradfrom = $aFrom;
817
        $this->plot_gradto = $aTo;
818
    }
819
820
    public function SetBackgroundGradient($aFrom = 'navy', $aTo = 'silver', $aGradType = 2, $aStyle = Configs::BGRAD_FRAME)
821
    {
822
        $this->bkg_gradtype = $aGradType;
823
        $this->bkg_gradstyle = $aStyle;
824
        $this->bkg_gradfrom = $aFrom;
825
        $this->bkg_gradto = $aTo;
826
    }
827
828
    // Set a country flag in the background
829
    public function SetBackgroundCFlag($aName, $aBgType = Configs::BGIMG_FILLPLOT, $aMix = 100)
830
    {
831
        $this->background_cflag = $aName;
832
        $this->background_cflag_type = $aBgType;
833
        $this->background_cflag_mix = $aMix;
834
    }
835
836
    // Alias for the above method
837
    public function SetBackgroundCountryFlag($aName, $aBgType = Configs::BGIMG_FILLPLOT, $aMix = 100)
838
    {
839
        $this->background_cflag = $aName;
840
        $this->background_cflag_type = $aBgType;
841
        $this->background_cflag_mix = $aMix;
842
    }
843
844
    // Specify a background image
845
    public function SetBackgroundImage($aFileName, $aBgType = Configs::BGIMG_FILLPLOT, $aImgFormat = 'auto')
846
    {
847
        // Get extension to determine image type
848
        if ('auto' === $aImgFormat) {
849
            $e = \explode('.', $aFileName);
850
851
            if (empty($e)) {
852
                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');
853
            }
854
855
            $valid_formats = ['png', 'jpg', 'gif'];
856
            $aImgFormat = \mb_strtolower($e[\count($e) - 1]);
857
858
            if ('jpeg' === $aImgFormat) {
859
                $aImgFormat = 'jpg';
860
            } elseif (!\in_array($aImgFormat, $valid_formats, true)) {
861
                Util\JpGraphError::RaiseL(25019, $aImgFormat); //('Unknown file extension ($aImgFormat) in Graph::SetBackgroundImage() for filename: '.$aFileName);
862
            }
863
        }
864
865
        $this->background_image = $aFileName;
866
        $this->background_image_type = $aBgType;
867
        $this->background_image_format = $aImgFormat;
868
    }
869
870
    public function SetBackgroundImageMix($aMix)
871
    {
872
        $this->background_image_mix = $aMix;
873
    }
874
875
    // Adjust background image position
876
    public function SetBackgroundImagePos($aXpos, $aYpos)
877
    {
878
        $this->background_image_xpos = $aXpos;
879
        $this->background_image_ypos = $aYpos;
880
    }
881
882
    // Specify axis style (boxed or single)
883
    public function SetAxisStyle($aStyle)
884
    {
885
        $this->iAxisStyle = $aStyle;
886
    }
887
888
    // Set a frame around the plot area
889
    /**
890
     * @param true $aDrawPlotFrame
891
     * @param int[]|string $aPlotFrameColor
892
     */
893
    public function SetBox($aDrawPlotFrame = true, $aPlotFrameColor = [0, 0, 0], $aPlotFrameWeight = 1)
894
    {
895
        $this->boxed = $aDrawPlotFrame;
896
        $this->box_weight = $aPlotFrameWeight;
897
        $this->box_color = $aPlotFrameColor;
898
    }
899
900
    // Specify color for the plotarea (not the margins)
901
    public function SetColor($aColor)
902
    {
903
        $this->plotarea_color = $aColor;
904
    }
905
906
    // Specify color for the margins (all areas outside the plotarea)
907
    /**
908
     * @param string $aColor
909
     */
910
    public function SetMarginColor($aColor)
911
    {
912
        $this->margin_color = $aColor;
913
    }
914
915
    // Set a frame around the entire image
916
    public function SetFrame($aDrawImgFrame = true, $aImgFrameColor = [0, 0, 0], $aImgFrameWeight = 1)
917
    {
918
        $this->doframe = $aDrawImgFrame;
919
        $this->frame_color = $aImgFrameColor;
920
        $this->frame_weight = $aImgFrameWeight;
921
    }
922
923
    public function SetFrameBevel($aDepth = 3, $aBorder = false, $aBorderColor = 'black', $aColor1 = '[email protected]', $aColor2 = '[email protected]', $aFlg = true)
924
    {
925
        $this->framebevel = $aFlg;
926
        $this->framebeveldepth = $aDepth;
927
        $this->framebevelborder = $aBorder;
928
        $this->framebevelbordercolor = $aBorderColor;
929
        $this->framebevelcolor1 = $aColor1;
930
        $this->framebevelcolor2 = $aColor2;
931
932
        $this->doshadow = false;
933
    }
934
935
    // Set the shadow around the whole image
936
    public function SetShadow($aShowShadow = true, $aShadowWidth = 5, $aShadowColor = 'darkgray')
937
    {
938
        $this->doshadow = $aShowShadow;
939
        $this->shadow_color = $aShadowColor;
940
        $this->shadow_width = $aShadowWidth;
941
        $this->footer->iBottomMargin += $aShadowWidth;
942
        $this->footer->iRightMargin += $aShadowWidth;
943
    }
944
945
    // Specify x,y scale. Note that if you manually specify the scale
946
    // you must also specify the tick distance with a call to Ticks::Set()
947
    /**
948
     * @param string $aAxisType
949
     * @param float|int $aYMin
950
     * @param float|int $aYMax
951
     * @param float|int $aXMin
952
     * @param float|int $aXMax
953
     */
954
    public function SetScale($aAxisType, $aYMin = 1, $aYMax = 1, $aXMin = 1, $aXMax = 1)
955
    {
956
        $this->axtype = $aAxisType;
957
958
        if ($aYMax < $aYMin || $aXMax < $aXMin) {
959
            Util\JpGraphError::RaiseL(25020); //('Graph::SetScale(): Specified Max value must be larger than the specified Min value.');
960
        }
961
962
        $yt = \mb_substr($aAxisType, -3, 3);
963
964
        if ('lin' === $yt) {
965
            $this->yscale = new Scale\LinearScale($aYMin, $aYMax);
966
        } elseif ('int' === $yt) {
967
            $this->yscale = new Scale\LinearScale($aYMin, $aYMax);
968
            $this->yscale->SetIntScale();
969
        } elseif ('log' === $yt) {
970
            $this->yscale = new Scale\LogScale($aYMin, $aYMax);
971
        } else {
972
            Util\JpGraphError::RaiseL(25021, $aAxisType); //("Unknown scale specification for Y-scale. ($aAxisType)");
973
        }
974
975
        $xt = \mb_substr($aAxisType, 0, 3);
976
977
        if ('lin' === $xt || 'tex' === $xt) {
978
            $this->xscale = new Scale\LinearScale($aXMin, $aXMax, 'x');
979
            $this->xscale->textscale = ('tex' === $xt);
0 ignored issues
show
Documentation Bug introduced by
The property $textscale was declared of type false, but 'tex' === $xt is of type boolean. Maybe add a type cast?

This check looks for assignments to scalar types that may be of the wrong type.

To ensure the code behaves as expected, it may be a good idea to add an explicit type cast.

$answer = 42;

$correct = false;

$correct = (bool) $answer;
Loading history...
980
        } elseif ('int' === $xt) {
981
            $this->xscale = new Scale\LinearScale($aXMin, $aXMax, 'x');
982
            $this->xscale->SetIntScale();
983
        } elseif ('dat' === $xt) {
984
            $this->xscale = new Scale\DateScale($aXMin, $aXMax, 'x');
985
        } elseif ('log' === $xt) {
986
            $this->xscale = new Scale\LogScale($aXMin, $aXMax, 'x');
987
        } else {
988
            Util\JpGraphError::RaiseL(25022, $aAxisType); //(" Unknown scale specification for X-scale. ($aAxisType)");
989
        }
990
991
        $this->xaxis = new Axis\Axis($this->img, $this->xscale);
992
        $this->yaxis = new Axis\Axis($this->img, $this->yscale);
993
        $this->xgrid = new Grid($this->xaxis);
994
        $this->ygrid = new Grid($this->yaxis);
995
        $this->ygrid->Show();
996
997
        if (!$this->isRunningClear) {
998
            $this->inputValues['aAxisType'] = $aAxisType;
999
            $this->inputValues['aYMin'] = $aYMin;
1000
            $this->inputValues['aYMax'] = $aYMax;
1001
            $this->inputValues['aXMin'] = $aXMin;
1002
            $this->inputValues['aXMax'] = $aXMax;
1003
1004
            if ($this->graph_theme) {
1005
                $this->graph_theme->ApplyGraph($this);
1006
            }
1007
        }
1008
1009
        $this->isAfterSetScale = true;
1010
    }
1011
1012
    // Specify secondary Y scale
1013
    public function SetY2Scale($aAxisType = 'lin', $aY2Min = 1, $aY2Max = 1)
1014
    {
1015
        if ('lin' === $aAxisType) {
1016
            $this->y2scale = new Scale\LinearScale($aY2Min, $aY2Max);
1017
        } elseif ('int' === $aAxisType) {
1018
            $this->y2scale = new Scale\LinearScale($aY2Min, $aY2Max);
1019
            $this->y2scale->SetIntScale();
1020
        } elseif ('log' === $aAxisType) {
1021
            $this->y2scale = new Scale\LogScale($aY2Min, $aY2Max);
1022
        } else {
1023
            Util\JpGraphError::RaiseL(25023, $aAxisType); //("JpGraph: Unsupported Y2 axis type: $aAxisType\nMust be one of (lin,log,int)");
1024
        }
1025
1026
        $this->y2axis = new Axis\Axis($this->img, $this->y2scale);
1027
        $this->y2axis->scale->ticks->SetDirection(Configs::getConfig('SIDE_LEFT'));
1028
        $this->y2axis->SetLabelSide(Configs::getConfig('SIDE_RIGHT'));
1029
        $this->y2axis->SetPos('max');
1030
        $this->y2axis->SetTitleSide(Configs::getConfig('SIDE_RIGHT'));
1031
1032
        // Deafult position is the max x-value
1033
        $this->y2grid = new Grid($this->y2axis);
1034
1035
        if (!$this->graph_theme) {
1036
            return;
1037
        }
1038
1039
        $this->graph_theme->ApplyGraph($this);
1040
    }
1041
1042
    // Set the delta position (in pixels) between the multiple Y-axis
1043
    public function SetYDeltaDist($aDist)
1044
    {
1045
        $this->iYAxisDeltaPos = $aDist;
1046
    }
1047
1048
    // Specify secondary Y scale
1049
    public function SetYScale($aN, $aAxisType = 'lin', $aYMin = 1, $aYMax = 1)
1050
    {
1051
        if ('lin' === $aAxisType) {
1052
            $this->ynscale[$aN] = new Scale\LinearScale($aYMin, $aYMax);
1053
        } elseif ('int' === $aAxisType) {
1054
            $this->ynscale[$aN] = new Scale\LinearScale($aYMin, $aYMax);
1055
            $this->ynscale[$aN]->SetIntScale();
1056
        } elseif ('log' === $aAxisType) {
1057
            $this->ynscale[$aN] = new Scale\LogScale($aYMin, $aYMax);
1058
        } else {
1059
            Util\JpGraphError::RaiseL(25024, $aAxisType); //("JpGraph: Unsupported Y axis type: $aAxisType\nMust be one of (lin,log,int)");
1060
        }
1061
1062
        $this->ynaxis[$aN] = new Axis\Axis($this->img, $this->ynscale[$aN]);
1063
        $this->ynaxis[$aN]->scale->ticks->SetDirection(Configs::getConfig('SIDE_LEFT'));
1064
        $this->ynaxis[$aN]->SetLabelSide(Configs::getConfig('SIDE_RIGHT'));
1065
1066
        if (!$this->graph_theme) {
1067
            return;
1068
        }
1069
1070
        $this->graph_theme->ApplyGraph($this);
1071
    }
1072
1073
    // Specify density of ticks when autoscaling 'normal', 'dense', 'sparse', 'verysparse'
1074
    // The dividing factor have been determined heuristically according to my aesthetic
1075
    // sense (or lack off) y.m.m.v !
1076
    /**
1077
     * @param int $aYDensity
1078
     */
1079
    public function SetTickDensity($aYDensity = Configs::TICKD_NORMAL, $aXDensity = Configs::TICKD_NORMAL)
1080
    {
1081
        $this->xtick_factor = 30;
1082
        $this->ytick_factor = 25;
1083
1084
        switch ($aYDensity) {
1085
            case Configs::getConfig('TICKD_DENSE'):
1086
                $this->ytick_factor = 12;
1087
1088
                break;
1089
            case Configs::getConfig('TICKD_NORMAL'):
1090
                $this->ytick_factor = 25;
1091
1092
                break;
1093
            case Configs::getConfig('TICKD_SPARSE'):
1094
                $this->ytick_factor = 40;
1095
1096
                break;
1097
            case Configs::getConfig('TICKD_VERYSPARSE'):
1098
                $this->ytick_factor = 100;
1099
1100
                break;
1101
1102
            default:
1103
                Util\JpGraphError::RaiseL(25025, $aYDensity); //("JpGraph: Unsupported Tick density: $densy");
1104
        }
1105
1106
        switch ($aXDensity) {
1107
            case Configs::getConfig('TICKD_DENSE'):
1108
                $this->xtick_factor = 15;
1109
1110
                break;
1111
            case Configs::getConfig('TICKD_NORMAL'):
1112
                $this->xtick_factor = 30;
1113
1114
                break;
1115
            case Configs::getConfig('TICKD_SPARSE'):
1116
                $this->xtick_factor = 45;
1117
1118
                break;
1119
            case Configs::getConfig('TICKD_VERYSPARSE'):
1120
                $this->xtick_factor = 60;
1121
1122
                break;
1123
1124
            default:
1125
                Util\JpGraphError::RaiseL(25025, $aXDensity); //("JpGraph: Unsupported Tick density: $densx");
1126
        }
1127
    }
1128
1129
    // Get a string of all image map areas
1130
    public function GetCSIMareas()
1131
    {
1132
        if (!$this->iHasStroked) {
1133
            $this->Stroke(Configs::getConfig('_CSIM_SPECIALFILE'));
1134
        }
1135
1136
        $csim = $this->title->GetCSIMAreas();
1137
        $csim .= $this->subtitle->GetCSIMAreas();
1138
        $csim .= $this->subsubtitle->GetCSIMAreas();
1139
        $csim .= $this->legend->GetCSIMAreas();
1140
1141
        if (null !== $this->y2axis) {
1142
            $csim .= $this->y2axis->title->GetCSIMAreas();
1143
        }
1144
1145
        if (null !== $this->texts) {
1146
            $n = Configs::safe_count($this->texts);
1147
1148
            for ($i = 0; $i < $n; ++$i) {
1149
                $csim .= $this->texts[$i]->GetCSIMAreas();
1150
            }
1151
        }
1152
1153
        if (null !== $this->y2texts && null !== $this->y2scale) {
1154
            $n = Configs::safe_count($this->y2texts);
1155
1156
            for ($i = 0; $i < $n; ++$i) {
1157
                $csim .= $this->y2texts[$i]->GetCSIMAreas();
1158
            }
1159
        }
1160
1161
        if (null !== $this->yaxis && null !== $this->xaxis) {
1162
            $csim .= $this->yaxis->title->GetCSIMAreas();
1163
            $csim .= $this->xaxis->title->GetCSIMAreas();
1164
        }
1165
1166
        $n = Configs::safe_count($this->plots);
1167
1168
        for ($i = 0; $i < $n; ++$i) {
1169
            $csim .= $this->plots[$i]->GetCSIMareas();
1170
        }
1171
1172
        $n = Configs::safe_count($this->y2plots);
1173
1174
        for ($i = 0; $i < $n; ++$i) {
1175
            $csim .= $this->y2plots[$i]->GetCSIMareas();
1176
        }
1177
1178
        $n = Configs::safe_count($this->ynaxis);
1179
1180
        for ($i = 0; $i < $n; ++$i) {
1181
            $m = Configs::safe_count($this->ynplots[$i]);
1182
1183
            for ($j = 0; $j < $m; ++$j) {
1184
                $csim .= $this->ynplots[$i][$j]->GetCSIMareas();
1185
            }
1186
        }
1187
1188
        $n = Configs::safe_count($this->iTables);
1189
1190
        for ($i = 0; $i < $n; ++$i) {
1191
            $csim .= $this->iTables[$i]->GetCSIMareas();
1192
        }
1193
1194
        return $csim;
1195
    }
1196
1197
    // Get a complete <MAP>..</MAP> tag for the final image map
1198
    public function GetHTMLImageMap($aMapName)
1199
    {
1200
        $im = "<map name=\"{$aMapName}\" id=\"{$aMapName}\" >\n";
1201
        $im .= $this->GetCSIMareas();
1202
        $im .= '</map>';
1203
1204
        return $im;
1205
    }
1206
1207
    public function CheckCSIMCache($aCacheName, $aTimeOut = 60)
1208
    {
1209
        global $_SERVER;
1210
1211
        if ('auto' === $aCacheName) {
1212
            $aCacheName = \basename($_SERVER['PHP_SELF']);
1213
        }
1214
1215
        $urlarg = $this->GetURLArguments();
1216
        $this->csimcachename = Configs::getConfig('CSIMCACHE_DIR') . $aCacheName . $urlarg;
0 ignored issues
show
Bug introduced by
Are you sure Amenadiel\JpGraph\Graph\...Config('CSIMCACHE_DIR') of type array can be used in concatenation? ( Ignorable by Annotation )

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

1216
        $this->csimcachename = /** @scrutinizer ignore-type */ Configs::getConfig('CSIMCACHE_DIR') . $aCacheName . $urlarg;
Loading history...
1217
        $this->csimcachetimeout = $aTimeOut;
1218
1219
        // First determine if we need to check for a cached version
1220
        // This differs from the standard cache in the sense that the
1221
        // image and Configs::getConfig('CSIM') map Configs::getConfig('HTML') file is written relative to the directory
1222
        // the script executes in and not the specified cache directory.
1223
        // The reason for this is that the cache directory is not necessarily
1224
        // accessible from the Configs::getConfig('HTTP') server.
1225
        if ('' !== $this->csimcachename) {
1226
            $dir = \dirname($this->csimcachename);
1227
            $base = \basename($this->csimcachename);
1228
            $base = \strtok($base, '.');
1229
            $suffix = \strtok('.');
0 ignored issues
show
Unused Code introduced by
The assignment to $suffix is dead and can be removed.
Loading history...
1230
            $basecsim = $dir . '/' . $base . '?' . $urlarg . '_csim_.html';
1231
            $baseimg = $dir . '/' . $base . '?' . $urlarg . '.' . $this->img->img_format;
1232
1233
            $timedout = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $timedout is dead and can be removed.
Loading history...
1234
            // Does it exist at all ?
1235
1236
            if (\file_exists($basecsim) && \file_exists($baseimg)) {
1237
                // Check that it hasn't timed out
1238
                $diff = \time() - \filemtime($basecsim);
1239
1240
                if (0 < $this->csimcachetimeout && ($this->csimcachetimeout * 60 < $diff)) {
1241
                    $timedout = true;
1242
                    \unlink($basecsim);
1243
                    \unlink($baseimg);
1244
                } else {
1245
                    if ($fh = \fopen($basecsim, 'rb')) {
1246
                        \fpassthru($fh);
1247
1248
                        return true;
1249
                    }
1250
                    Util\JpGraphError::RaiseL(25027, $basecsim); //(" Can't open cached Configs::getConfig('CSIM') \"$basecsim\" for reading.");
1251
                }
1252
            }
1253
        }
1254
1255
        return false;
1256
    }
1257
1258
    // Build the argument string to be used with the csim images
1259
    /**
1260
     * @param bool $aAddRecursiveBlocker
1261
     */
1262
    public static function GetURLArguments($aAddRecursiveBlocker = false)
1263
    {
1264
        if ($aAddRecursiveBlocker) {
1265
            // This is a Configs::getConfig('JPGRAPH') internal defined that prevents
1266
            // us from recursively coming here again
1267
            $urlarg = Configs::getConfig('_CSIM_DISPLAY') . '=1';
0 ignored issues
show
Bug introduced by
Are you sure Amenadiel\JpGraph\Graph\...Config('_CSIM_DISPLAY') of type array can be used in concatenation? ( Ignorable by Annotation )

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

1267
            $urlarg = /** @scrutinizer ignore-type */ Configs::getConfig('_CSIM_DISPLAY') . '=1';
Loading history...
1268
        }
1269
1270
        // Now reconstruct any user URL argument
1271
        \reset($_GET);
1272
1273
        foreach ($_GET as $key => $value) {
1274
            if (\is_array($value)) {
1275
                foreach ($value as $k => $v) {
1276
                    $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...
1277
                }
1278
            } else {
1279
                $urlarg .= '&amp;' . $key . '=' . \urlencode($value);
1280
            }
1281
        }
1282
1283
        // It's not ideal to convert Configs::getConfig('POST') argument to GET arguments
1284
        // but there is little else we can do. One idea for the
1285
        // future might be recreate the Configs::getConfig('POST') header in case.
1286
        \reset($_POST);
1287
1288
        foreach ($_POST as $key => $value) {
1289
            if (\is_array($value)) {
1290
                foreach ($value as $k => $v) {
1291
                    $urlarg .= '&amp;' . $key . '%5B' . $k . '%5D=' . \urlencode($v);
1292
                }
1293
            } else {
1294
                $urlarg .= '&amp;' . $key . '=' . \urlencode($value);
1295
            }
1296
        }
1297
1298
        return $urlarg;
1299
    }
1300
1301
    public function SetCSIMImgAlt($aAlt)
1302
    {
1303
        $this->iCSIMImgAlt = $aAlt;
1304
    }
1305
1306
    public function StrokeCSIM($aScriptName = 'auto', $aCSIMName = '', $aBorder = 0)
1307
    {
1308
        $microtime = \microtime(true);
1309
        $random = $microtime * 1000000;
1310
1311
        if ('' === $aCSIMName) {
1312
            // create a random map name
1313
            \mt_srand((int) $random);
1314
            $r = \mt_rand(0, 100000);
1315
            $aCSIMName = '__mapname' . $r . '__';
1316
        }
1317
1318
        if ('auto' === $aScriptName) {
1319
            $aScriptName = \basename($_SERVER['PHP_SELF']);
1320
        }
1321
1322
        $urlarg = $this->GetURLArguments(true);
1323
1324
        if (empty($_GET[Configs::getConfig('_CSIM_DISPLAY')])) {
1325
            // First determine if we need to check for a cached version
1326
            // This differs from the standard cache in the sense that the
1327
            // image and Configs::getConfig('CSIM') map Configs::getConfig('HTML') file is written relative to the directory
1328
            // the script executes in and not the specified cache directory.
1329
            // The reason for this is that the cache directory is not necessarily
1330
            // accessible from the Configs::getConfig('HTTP') server.
1331
            if ('' !== $this->csimcachename) {
1332
                $dir = \dirname($this->csimcachename);
1333
                $base = \basename($this->csimcachename);
1334
                $base = \strtok($base, '.');
1335
                $suffix = \strtok('.');
0 ignored issues
show
Unused Code introduced by
The assignment to $suffix is dead and can be removed.
Loading history...
1336
                $basecsim = $dir . '/' . $base . '?' . $urlarg . '_csim_.html';
1337
                $baseimg = $base . '?' . $urlarg . '.' . $this->img->img_format;
1338
1339
                // Check that apache can write to directory specified
1340
1341
                if (\file_exists($dir) && !\is_writable($dir)) {
1342
                    Util\JpGraphError::RaiseL(25028, $dir); //('Apache/PHP does not have permission to write to the Configs::getConfig('CSIM') cache directory ('.$dir.'). Check permissions.');
1343
                }
1344
1345
                // Make sure directory exists
1346
                $this->cache->MakeDirs($dir);
1347
1348
                // Write the image file
1349
                $this->Stroke(Configs::getConfig('CSIMCACHE_DIR') . $baseimg);
0 ignored issues
show
Bug introduced by
Are you sure Amenadiel\JpGraph\Graph\...Config('CSIMCACHE_DIR') of type array can be used in concatenation? ( Ignorable by Annotation )

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

1349
                $this->Stroke(/** @scrutinizer ignore-type */ Configs::getConfig('CSIMCACHE_DIR') . $baseimg);
Loading history...
1350
1351
                // Construct wrapper Configs::getConfig('HTML') and write to file and send it back to browser
1352
1353
                // In the src URL we must replace the '?' with its encoding to prevent the arguments
1354
                // to be converted to real arguments.
1355
                $tmp = \str_replace('?', '%3f', $baseimg);
1356
                $htmlwrap = $this->GetHTMLImageMap($aCSIMName) . "\n" .
1357
                    '<img src="' . Configs::getConfig('CSIMCACHE_HTTP_DIR') . $tmp . '" ismap="ismap" usemap="#' . $aCSIMName . ' width="' . $this->img->width . '" height="' . $this->img->height . '" alt="' . $this->iCSIMImgAlt . "\" />\n";
0 ignored issues
show
Bug introduced by
Are you sure Amenadiel\JpGraph\Graph\...g('CSIMCACHE_HTTP_DIR') of type array can be used in concatenation? ( Ignorable by Annotation )

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

1357
                    '<img src="' . /** @scrutinizer ignore-type */ Configs::getConfig('CSIMCACHE_HTTP_DIR') . $tmp . '" ismap="ismap" usemap="#' . $aCSIMName . ' width="' . $this->img->width . '" height="' . $this->img->height . '" alt="' . $this->iCSIMImgAlt . "\" />\n";
Loading history...
1358
1359
                if ($fh = \fopen($basecsim, 'wb')) {
1360
                    \fwrite($fh, $htmlwrap);
1361
                    \fclose($fh);
1362
                    echo $htmlwrap;
1363
                } else {
1364
                    Util\JpGraphError::RaiseL(25029, $basecsim); //(" Can't write Configs::getConfig('CSIM') \"$basecsim\" for writing. Check free space and permissions.");
1365
                }
1366
            } else {
1367
                if ('' === $aScriptName) {
1368
                    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().');
1369
                }
1370
                echo $this->GetHTMLImageMap($aCSIMName) . $this->GetCSIMImgHTML($aCSIMName, $aScriptName, $aBorder);
1371
            }
1372
        } else {
1373
            $this->Stroke();
1374
        }
1375
    }
1376
1377
    public function StrokeCSIMImage()
1378
    {
1379
        if (1 !== $_GET[Configs::getConfig('_CSIM_DISPLAY')]) {
1380
            return;
1381
        }
1382
1383
        $this->Stroke();
1384
    }
1385
1386
    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

1386
    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...
1387
    {
1388
        if ('auto' === $aScriptName) {
1389
            $aScriptName = \basename($_SERVER['PHP_SELF']);
1390
        }
1391
        $urlarg = $this->GetURLArguments(true);
1392
1393
        return '<img src="' . $aScriptName . '?' . $urlarg . '" ismap="ismap" usemap="#' . $aCSIMName . '" height="' . $this->img->height . '" alt="' . $this->iCSIMImgAlt . "\" />\n";
1394
    }
1395
1396
    /**
1397
     * @param bool $aY2
1398
     */
1399
    public function GetTextsYMinMax($aY2 = false)
1400
    {
1401
        if ($aY2) {
1402
            $txts = $this->y2texts;
1403
        } else {
1404
            $txts = $this->texts;
1405
        }
1406
        $n = Configs::safe_count($txts);
1407
        $min = null;
1408
        $max = null;
1409
1410
        for ($i = 0; $i < $n; ++$i) {
1411
            if (null === $txts[$i]->iScalePosY || null === $txts[$i]->iScalePosX) {
1412
                continue;
1413
            }
1414
1415
            if (null === $min) {
1416
                $min = $max = $txts[$i]->iScalePosY;
1417
            } else {
1418
                $min = \min($min, $txts[$i]->iScalePosY);
1419
                $max = \max($max, $txts[$i]->iScalePosY);
1420
            }
1421
        }
1422
1423
        if (null !== $min) {
0 ignored issues
show
introduced by
The condition null !== $min is always false.
Loading history...
1424
            return [$min, $max];
1425
        }
1426
1427
        return null;
1428
    }
1429
1430
    /**
1431
     * @param bool $aY2
1432
     */
1433
    public function GetTextsXMinMax($aY2 = false)
1434
    {
1435
        if ($aY2) {
1436
            $txts = $this->y2texts;
1437
        } else {
1438
            $txts = $this->texts;
1439
        }
1440
        $n = Configs::safe_count($txts);
1441
        $min = null;
1442
        $max = null;
1443
1444
        for ($i = 0; $i < $n; ++$i) {
1445
            if (null === $txts[$i]->iScalePosY || null === $txts[$i]->iScalePosX) {
1446
                continue;
1447
            }
1448
1449
            if (null === $min) {
1450
                $min = $max = $txts[$i]->iScalePosX;
1451
            } else {
1452
                $min = \min($min, $txts[$i]->iScalePosX);
1453
                $max = \max($max, $txts[$i]->iScalePosX);
1454
            }
1455
        }
1456
1457
        if (null !== $min) {
0 ignored issues
show
introduced by
The condition null !== $min is always false.
Loading history...
1458
            return [$min, $max];
1459
        }
1460
1461
        return null;
1462
    }
1463
1464
    public function GetXMinMax()
1465
    {
1466
        [$min, $ymin] = $this->plots[0]->Min();
1467
        [$max, $ymax] = $this->plots[0]->Max();
1468
1469
        $i = 0;
1470
        // Some plots, e.g. PlotLine should not affect the scale
1471
        // and will return (null,null). We should ignore those
1472
        // values.
1473
        while ((null === $min || null === $max) && (Configs::safe_count($this->plots) - 1 > $i)) {
1474
            ++$i;
1475
            [$min, $ymin] = $this->plots[$i]->Min();
1476
            [$max, $ymax] = $this->plots[$i]->Max();
1477
        }
1478
1479
        foreach ($this->plots as $p) {
1480
            [$xmin, $ymin] = $p->Min();
1481
            [$xmax, $ymax] = $p->Max();
1482
1483
            if (null === $xmin || null === $xmax) {
1484
                continue;
1485
            }
1486
1487
            $min = \min($xmin, $min);
1488
            $max = \max($xmax, $max);
1489
        }
1490
1491
        if (null !== $this->y2axis) {
1492
            foreach ($this->y2plots as $p) {
1493
                [$xmin, $ymin] = $p->Min();
1494
                [$xmax, $ymax] = $p->Max();
1495
                $min = \min($xmin, $min);
1496
                $max = \max($xmax, $max);
1497
            }
1498
        }
1499
1500
        $n = Configs::safe_count($this->ynaxis);
1501
1502
        for ($i = 0; $i < $n; ++$i) {
1503
            if (null === $this->ynaxis[$i]) {
1504
                continue;
1505
            }
1506
1507
            foreach ($this->ynplots[$i] as $p) {
1508
                [$xmin, $ymin] = $p->Min();
1509
                [$xmax, $ymax] = $p->Max();
1510
                $min = \min($xmin, $min);
1511
                $max = \max($xmax, $max);
1512
            }
1513
        }
1514
1515
        return [$min, $max];
1516
    }
1517
1518
    public function AdjustMarginsForTitles()
1519
    {
1520
        $totrequired =
1521
            ('' !== $this->title->t
1522
                ? $this->title->GetTextHeight($this->img) + $this->title->margin + 5 * Configs::getConfig('SUPERSAMPLING_SCALE')
1523
                : 0) +
1524
            ('' !== $this->subtitle->t
1525
                ? $this->subtitle->GetTextHeight($this->img) + $this->subtitle->margin + 5 * Configs::getConfig('SUPERSAMPLING_SCALE')
1526
                : 0) +
1527
            ('' !== $this->subsubtitle->t
1528
                ? $this->subsubtitle->GetTextHeight($this->img) + $this->subsubtitle->margin + 5 * Configs::getConfig('SUPERSAMPLING_SCALE')
1529
                : 0);
1530
1531
        $btotrequired = 0;
1532
1533
        if (null !== $this->xaxis && !$this->xaxis->hide && !$this->xaxis->hide_labels) {
1534
            // Minimum bottom margin
1535
            if ('' !== $this->xaxis->title->t) {
1536
                if (90 === $this->img->a) {
1537
                    $btotrequired = $this->yaxis->title->GetTextHeight($this->img) + 7;
1538
                } else {
1539
                    $btotrequired = $this->xaxis->title->GetTextHeight($this->img) + 7;
1540
                }
1541
            } else {
1542
                $btotrequired = 0;
1543
            }
1544
1545
            if (90 === $this->img->a) {
1546
                $this->img->SetFont(
1547
                    $this->yaxis->font_family,
1548
                    $this->yaxis->font_style,
1549
                    $this->yaxis->font_size
1550
                );
1551
                $lh = $this->img->GetTextHeight('Mg', $this->yaxis->label_angle);
1552
            } else {
1553
                $this->img->SetFont(
1554
                    $this->xaxis->font_family,
1555
                    $this->xaxis->font_style,
1556
                    $this->xaxis->font_size
1557
                );
1558
                $lh = $this->img->GetTextHeight('Mg', $this->xaxis->label_angle);
1559
            }
1560
1561
            $btotrequired += $lh + 6;
1562
        }
1563
1564
        if (90 === $this->img->a) {
1565
            // DO Nothing. It gets too messy to do this properly for 90 deg...
1566
        } else {
1567
            // need more top margin
1568
            if ($this->img->top_margin < $totrequired) {
1569
                $this->SetMargin(
1570
                    $this->img->raw_left_margin,
1571
                    $this->img->raw_right_margin,
1572
                    $totrequired / Configs::getConfig('SUPERSAMPLING_SCALE'),
1573
                    $this->img->raw_bottom_margin
1574
                );
1575
            }
1576
1577
            // need more bottom margin
1578
            if ($this->img->bottom_margin < $btotrequired) {
1579
                $this->SetMargin(
1580
                    $this->img->raw_left_margin,
1581
                    $this->img->raw_right_margin,
1582
                    $this->img->raw_top_margin,
1583
                    $btotrequired / Configs::getConfig('SUPERSAMPLING_SCALE')
1584
                );
1585
            }
1586
        }
1587
    }
1588
public function getScale()  {
1589
    return $this->scale;
1590
}
1591
    public function StrokeStore($aStrokeFileName)
1592
    {
1593
        // Get the handler to prevent the library from sending the
1594
        // image to the browser
1595
        $ih = $this->Stroke(Configs::getConfig('_IMG_HANDLER'));
0 ignored issues
show
Unused Code introduced by
The assignment to $ih is dead and can be removed.
Loading history...
1596
1597
        // Stroke it to a file
1598
        $this->img->Stream($aStrokeFileName);
1599
1600
        // Send it back to browser
1601
        $this->img->Headers();
1602
        $this->img->Stream();
1603
    }
1604
1605
    public function doAutoScaleXAxis()
1606
    {
1607
        $aPlots = \array_filter($this->plots, function ($plot) {
1608
            return $plot instanceof Plot\Plot;
1609
        });
1610
1611
        //Check if we should autoscale x-axis
1612
        if (!$this->xscale->IsSpecified()) {
0 ignored issues
show
Bug introduced by
The method IsSpecified() does not exist on null. ( Ignorable by Annotation )

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

1612
        if (!$this->xscale->/** @scrutinizer ignore-call */ IsSpecified()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1613
            if (\mb_substr($this->axtype, 0, 4) === 'text') {
1614
                $max = 0;
1615
                $n = Configs::safe_count($aPlots);
1616
1617
                for ($i = 0; $i < $n; ++$i) {
1618
                    $p = $aPlots[$i];
1619
1620
                    // We need some unfortunate sub class knowledge here in order
1621
                    // to increase number of data points in case it is a line plot
1622
                    // which has the barcenter set. If not it could mean that the
1623
                    // last point of the data is outside the scale since the barcenter
1624
                    // settings means that we will shift the entire plot half a tick step
1625
                    // to the right in oder to align with the center of the bars.
1626
1627
                    $cl = \mb_strtolower(\get_class($p));
0 ignored issues
show
Unused Code introduced by
The assignment to $cl is dead and can be removed.
Loading history...
1628
1629
                    if (empty($p->barcenter)) {
1630
                        $max = \max($max, $p->numpoints - 1);
1631
                    } else {
1632
                        $max = \max($max, $p->numpoints);
1633
                    }
1634
                }
1635
                $min = 0;
1636
1637
                if (null !== $this->y2axis) {
1638
                    foreach ($this->y2plots as $p) {
1639
                        $max = \max($max, $p->numpoints - 1);
1640
                    }
1641
                }
1642
                $n = Configs::safe_count($this->ynaxis);
1643
1644
                for ($i = 0; $i < $n; ++$i) {
1645
                    if (null === $this->ynaxis[$i]) {
1646
                        continue;
1647
                    }
1648
1649
                    foreach ($this->ynplots[$i] as $p) {
1650
                        $max = \max($max, $p->numpoints - 1);
1651
                    }
1652
                }
1653
1654
                $this->xscale->Update($this->img, $min, $max);
1655
                $this->xscale->ticks->Set($this->xaxis->tick_step, 1);
1656
                $this->xscale->ticks->SupressMinorTickMarks();
1657
            } else {
1658
                [$min, $max] = $this->GetXMinMax();
1659
1660
                $lres = $this->GetLinesXMinMax($this->lines);
1661
1662
                if ($lres) {
0 ignored issues
show
introduced by
The condition $lres is always false.
Loading history...
1663
                    [$linmin, $linmax] = $lres;
1664
                    $min = \min($min, $linmin);
1665
                    $max = \max($max, $linmax);
1666
                }
1667
1668
                $lres = $this->GetLinesXMinMax($this->y2lines);
1669
1670
                if ($lres) {
0 ignored issues
show
introduced by
The condition $lres is always false.
Loading history...
1671
                    [$linmin, $linmax] = $lres;
1672
                    $min = \min($min, $linmin);
1673
                    $max = \max($max, $linmax);
1674
                }
1675
1676
                $tres = $this->GetTextsXMinMax();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $tres is correct as $this->GetTextsXMinMax() targeting Amenadiel\JpGraph\Graph\Graph::GetTextsXMinMax() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1677
1678
                if ($tres) {
0 ignored issues
show
introduced by
$tres is of type null, thus it always evaluated to false.
Loading history...
1679
                    [$tmin, $tmax] = $tres;
1680
                    $min = \min($min, $tmin);
1681
                    $max = \max($max, $tmax);
1682
                }
1683
1684
                $tres = $this->GetTextsXMinMax(true);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $tres is correct as $this->GetTextsXMinMax(true) targeting Amenadiel\JpGraph\Graph\Graph::GetTextsXMinMax() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1685
1686
                if ($tres) {
0 ignored issues
show
introduced by
$tres is of type null, thus it always evaluated to false.
Loading history...
1687
                    [$tmin, $tmax] = $tres;
1688
                    $min = \min($min, $tmin);
1689
                    $max = \max($max, $tmax);
1690
                }
1691
1692
                $this->xscale->AutoScale($this->img, $min, $max, \round($this->img->plotwidth / $this->xtick_factor));
1693
            }
1694
1695
            //Adjust position of y-axis and y2-axis to minimum/maximum of x-scale
1696
            if (!\is_numeric($this->yaxis->pos) && !\is_string($this->yaxis->pos)) {
1697
                $this->yaxis->SetPos($this->xscale->GetMinVal());
0 ignored issues
show
Bug introduced by
The method SetPos() does not exist on null. ( Ignorable by Annotation )

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

1697
                $this->yaxis->/** @scrutinizer ignore-call */ 
1698
                              SetPos($this->xscale->GetMinVal());

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1698
            }
1699
        } elseif ($this->xscale->IsSpecified()
1700
            && ($this->xscale->auto_ticks || !$this->xscale->ticks->IsSpecified())
1701
        ) {
1702
            // The tick calculation will use the user suplied min/max values to determine
1703
            // the ticks. If auto_ticks is false the exact user specifed min and max
1704
            // values will be used for the scale.
1705
            // If auto_ticks is true then the scale might be slightly adjusted
1706
            // so that the min and max values falls on an even major step.
1707
            $min = $this->xscale->scale[0];
1708
            $max = $this->xscale->scale[1];
1709
            $this->xscale->AutoScale($this->img, $min, $max, \round($this->img->plotwidth / $this->xtick_factor), false);
1710
1711
            // Now make sure we show enough precision to accurate display the
1712
            // labels. If this is not done then the user might end up with
1713
            // a scale that might actually start with, say 13.5, butdue to rounding
1714
            // the scale label will ony show 14.
1715
            if (\abs(\floor($min) - $min) > 0) {
1716
                // If the user has set a format then we bail out
1717
                if ('' === $this->xscale->ticks->label_formatstr && '' === $this->xscale->ticks->label_dateformatstr) {
1718
                    $this->xscale->ticks->precision = \abs(\floor(\log10(\abs(\floor($min) - $min)))) + 1;
1719
                }
1720
            }
1721
        }
1722
1723
        // Position the optional Y2 and Yn axis to the rightmost position of the x-axis
1724
        if (null !== $this->y2axis) {
1725
            if (!\is_numeric($this->y2axis->pos) && !\is_string($this->y2axis->pos)) {
1726
                $this->y2axis->SetPos($this->xscale->GetMaxVal());
1727
            }
1728
            $this->y2axis->SetTitleSide(Configs::getConfig('SIDE_RIGHT'));
1729
        }
1730
1731
        $n = Configs::safe_count($this->ynaxis);
1732
        $nY2adj = null !== $this->y2axis ? $this->iYAxisDeltaPos : 0;
1733
1734
        for ($i = 0; $i < $n; ++$i) {
1735
            if (null === $this->ynaxis[$i]) {
1736
                continue;
1737
            }
1738
1739
            if (!\is_numeric($this->ynaxis[$i]->pos) && !\is_string($this->ynaxis[$i]->pos)) {
1740
                $this->ynaxis[$i]->SetPos($this->xscale->GetMaxVal());
1741
                $this->ynaxis[$i]->SetPosAbsDelta($i * $this->iYAxisDeltaPos + $nY2adj);
1742
            }
1743
            $this->ynaxis[$i]->SetTitleSide(Configs::getConfig('SIDE_RIGHT'));
1744
        }
1745
    }
1746
1747
    public function doAutoScaleYnAxis()
1748
    {
1749
        if (null !== $this->y2scale) {
1750
            if (!$this->y2scale->IsSpecified() && Configs::safe_count($this->y2plots) > 0) {
1751
                [$min, $max] = $this->GetPlotsYMinMax($this->y2plots);
1752
1753
                $lres = $this->GetLinesYMinMax($this->y2lines);
1754
1755
                if (\is_array($lres)) {
0 ignored issues
show
introduced by
The condition is_array($lres) is always false.
Loading history...
1756
                    [$linmin, $linmax] = $lres;
1757
                    $min = \min($min, $linmin);
1758
                    $max = \max($max, $linmax);
1759
                }
1760
                $tres = $this->GetTextsYMinMax(true);
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $tres is correct as $this->GetTextsYMinMax(true) targeting Amenadiel\JpGraph\Graph\Graph::GetTextsYMinMax() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1761
1762
                if (\is_array($tres)) {
0 ignored issues
show
introduced by
The condition is_array($tres) is always false.
Loading history...
1763
                    [$tmin, $tmax] = $tres;
1764
                    $min = \min($min, $tmin);
1765
                    $max = \max($max, $tmax);
1766
                }
1767
                $this->y2scale->AutoScale($this->img, $min, $max, $this->img->plotheight / $this->ytick_factor);
1768
            } elseif ($this->y2scale->IsSpecified() && ($this->y2scale->auto_ticks || !$this->y2scale->ticks->IsSpecified())) {
1769
                // The tick calculation will use the user suplied min/max values to determine
1770
                // the ticks. If auto_ticks is false the exact user specifed min and max
1771
                // values will be used for the scale.
1772
                // If auto_ticks is true then the scale might be slightly adjusted
1773
                // so that the min and max values falls on an even major step.
1774
                $min = $this->y2scale->scale[0];
1775
                $max = $this->y2scale->scale[1];
1776
                $this->y2scale->AutoScale(
1777
                    $this->img,
1778
                    $min,
1779
                    $max,
1780
                    $this->img->plotheight / $this->ytick_factor,
1781
                    $this->y2scale->auto_ticks
1782
                );
1783
1784
                // Now make sure we show enough precision to accurate display the
1785
                // labels. If this is not done then the user might end up with
1786
                // a scale that might actually start with, say 13.5, butdue to rounding
1787
                // the scale label will ony show 14.
1788
                if (\abs(\floor($min) - $min) > 0) {
1789
                    // If the user has set a format then we bail out
1790
                    if ('' === $this->y2scale->ticks->label_formatstr && '' === $this->y2scale->ticks->label_dateformatstr) {
1791
                        $this->y2scale->ticks->precision = \abs(\floor(\log10(\abs(\floor($min) - $min)))) + 1;
1792
                    }
1793
                }
1794
            }
1795
        }
1796
1797
        // Autoscale the extra Y-axises
1798
        $n = Configs::safe_count($this->ynaxis);
1799
1800
        for ($i = 0; $i < $n; ++$i) {
1801
            if (null === $this->ynscale[$i]) {
1802
                continue;
1803
            }
1804
1805
            if (!$this->ynscale[$i]->IsSpecified() && Configs::safe_count($this->ynplots[$i]) > 0) {
1806
                [$min, $max] = $this->GetPlotsYMinMax($this->ynplots[$i]);
1807
                $this->ynscale[$i]->AutoScale($this->img, $min, $max, $this->img->plotheight / $this->ytick_factor);
1808
            } elseif ($this->ynscale[$i]->IsSpecified() && ($this->ynscale[$i]->auto_ticks || !$this->ynscale[$i]->ticks->IsSpecified())) {
1809
                // The tick calculation will use the user suplied min/max values to determine
1810
                // the ticks. If auto_ticks is false the exact user specifed min and max
1811
                // values will be used for the scale.
1812
                // If auto_ticks is true then the scale might be slightly adjusted
1813
                // so that the min and max values falls on an even major step.
1814
                $min = $this->ynscale[$i]->scale[0];
1815
                $max = $this->ynscale[$i]->scale[1];
1816
                $this->ynscale[$i]->AutoScale(
1817
                    $this->img,
1818
                    $min,
1819
                    $max,
1820
                    $this->img->plotheight / $this->ytick_factor,
1821
                    $this->ynscale[$i]->auto_ticks
1822
                );
1823
1824
                // Now make sure we show enough precision to accurate display the
1825
                // labels. If this is not done then the user might end up with
1826
                // a scale that might actually start with, say 13.5, butdue to rounding
1827
                // the scale label will ony show 14.
1828
                if (\abs(\floor($min) - $min) > 0) {
1829
                    // If the user has set a format then we bail out
1830
                    if ('' === $this->ynscale[$i]->ticks->label_formatstr && '' === $this->ynscale[$i]->ticks->label_dateformatstr) {
1831
                        $this->ynscale[$i]->ticks->precision = \abs(\floor(\log10(\abs(\floor($min) - $min)))) + 1;
1832
                    }
1833
                }
1834
            }
1835
        }
1836
    }
1837
1838
    public function doAutoScaleYAxis()
1839
    {
1840
        //Check if we should autoscale y-axis
1841
        if (!$this->yscale->IsSpecified() && Configs::safe_count($this->plots) > 0) {
0 ignored issues
show
Bug introduced by
The method IsSpecified() does not exist on null. ( Ignorable by Annotation )

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

1841
        if (!$this->yscale->/** @scrutinizer ignore-call */ IsSpecified() && Configs::safe_count($this->plots) > 0) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
1842
            [$min, $max] = $this->GetPlotsYMinMax($this->plots);
1843
            $lres = $this->GetLinesYMinMax($this->lines);
1844
1845
            if (\is_array($lres)) {
0 ignored issues
show
introduced by
The condition is_array($lres) is always false.
Loading history...
1846
                [$linmin, $linmax] = $lres;
1847
                $min = \min($min, $linmin);
1848
                $max = \max($max, $linmax);
1849
            }
1850
            $tres = $this->GetTextsYMinMax();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $tres is correct as $this->GetTextsYMinMax() targeting Amenadiel\JpGraph\Graph\Graph::GetTextsYMinMax() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
1851
1852
            if (\is_array($tres)) {
0 ignored issues
show
introduced by
The condition is_array($tres) is always false.
Loading history...
1853
                [$tmin, $tmax] = $tres;
1854
                $min = \min($min, $tmin);
1855
                $max = \max($max, $tmax);
1856
            }
1857
            $this->yscale->AutoScale(
1858
                $this->img,
1859
                $min,
1860
                $max,
1861
                $this->img->plotheight / $this->ytick_factor
1862
            );
1863
        } elseif ($this->yscale->IsSpecified() && ($this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified())) {
1864
            // The tick calculation will use the user suplied min/max values to determine
1865
            // the ticks. If auto_ticks is false the exact user specifed min and max
1866
            // values will be used for the scale.
1867
            // If auto_ticks is true then the scale might be slightly adjusted
1868
            // so that the min and max values falls on an even major step.
1869
            $min = $this->yscale->scale[0];
1870
            $max = $this->yscale->scale[1];
1871
            $this->yscale->AutoScale(
1872
                $this->img,
1873
                $min,
1874
                $max,
1875
                $this->img->plotheight / $this->ytick_factor,
1876
                $this->yscale->auto_ticks
1877
            );
1878
1879
            // Now make sure we show enough precision to accurate display the
1880
            // labels. If this is not done then the user might end up with
1881
            // a scale that might actually start with, say 13.5, butdue to rounding
1882
            // the scale label will ony show 14.
1883
            if (\abs(\floor($min) - $min) > 0) {
1884
                // If the user has set a format then we bail out
1885
                if ('' === $this->yscale->ticks->label_formatstr && '' === $this->yscale->ticks->label_dateformatstr) {
1886
                    $this->yscale->ticks->precision = \abs(\floor(\log10(\abs(\floor($min) - $min)))) + 1;
1887
                }
1888
            }
1889
        }
1890
    }
1891
1892
    public function InitScaleConfigs()
1893
    {
1894
        // Setup scale constants
1895
        if ($this->yscale) {
1896
            $this->yscale->InitConfigs($this->img);
1897
        }
1898
1899
        if ($this->xscale) {
1900
            $this->xscale->InitConfigs($this->img);
1901
        }
1902
1903
        if ($this->y2scale) {
1904
            $this->y2scale->InitConfigs($this->img);
1905
        }
1906
1907
        $n = Configs::safe_count($this->ynscale);
1908
1909
        for ($i = 0; $i < $n; ++$i) {
1910
            if (!$this->ynscale[$i]) {
1911
                continue;
1912
            }
1913
1914
            $this->ynscale[$i]->InitConfigs($this->img);
1915
        }
1916
    }
1917
1918
    public function doPrestrokeAdjustments()
1919
    {
1920
        // Do any pre-stroke adjustment that is needed by the different plot types
1921
        // (i.e bar plots want's to add an offset to the x-labels etc)
1922
        for ($i = 0; Configs::safe_count($this->plots) > $i; ++$i) {
1923
            if (!($this->plots[$i] instanceof Plot\Plot)) {
1924
                continue;
1925
            }
1926
1927
            $this->plots[$i]->PreStrokeAdjust($this);
1928
            $this->plots[$i]->DoLegend($this);
1929
        }
1930
1931
        // Any plots on the second Y scale?
1932
        if (null !== $this->y2scale) {
1933
            for ($i = 0; Configs::safe_count($this->y2plots) > $i; ++$i) {
1934
                if (!($this->plots[$i] instanceof Plot\Plot)) {
1935
                    continue;
1936
                }
1937
1938
                $this->y2plots[$i]->PreStrokeAdjust($this);
1939
                $this->y2plots[$i]->DoLegend($this);
1940
            }
1941
        }
1942
1943
        // Any plots on the extra Y axises?
1944
        $n = Configs::safe_count($this->ynaxis);
1945
1946
        for ($i = 0; $i < $n; ++$i) {
1947
            if (null === $this->ynplots || null === $this->ynplots[$i]) {
1948
                Util\JpGraphError::RaiseL(25032, $i); //("No plots for Y-axis nbr:$i");
1949
            }
1950
            $m = Configs::safe_count($this->ynplots[$i]);
1951
1952
            for ($j = 0; $j < $m; ++$j) {
1953
                $this->ynplots[$i][$j]->PreStrokeAdjust($this);
1954
                $this->ynplots[$i][$j]->DoLegend($this);
1955
            }
1956
        }
1957
    }
1958
1959
    /**
1960
     * @param array $aDepth
1961
     * @param bool $aCSIM
1962
     */
1963
    public function StrokeBands($aDepth, $aCSIM)
1964
    {
1965
        // Stroke bands
1966
        if (null !== $this->bands && !$aCSIM) {
1967
            for ($i = 0; Configs::safe_count($this->bands) > $i; ++$i) {
1968
                // Stroke all bands that asks to be in the background
1969
                if ($this->bands[$i]->depth !== $aDepth) {
1970
                    // Stroke all bands that asks to be in the background
1971
                    continue;
1972
                    // Stroke all bands that asks to be in the background
1973
                }
1974
1975
                $this->bands[$i]->Stroke($this->img, $this->xscale, $this->yscale);
1976
            }
1977
        }
1978
1979
        if (null === $this->y2bands || null === $this->y2scale || $aCSIM) {
1980
            return;
1981
        }
1982
1983
        for ($i = 0; Configs::safe_count($this->y2bands) > $i; ++$i) {
1984
            // Stroke all bands that asks to be in the foreground
1985
            if ($this->y2bands[$i]->depth !== $aDepth) {
1986
                // Stroke all bands that asks to be in the foreground
1987
                continue;
1988
                // Stroke all bands that asks to be in the foreground
1989
            }
1990
1991
            $this->y2bands[$i]->Stroke($this->img, $this->xscale, $this->y2scale);
1992
        }
1993
    }
1994
1995
    // Stroke the graph
1996
    // $aStrokeFileName If != "" the image will be written to this file and NOT
1997
    // streamed back to the browser
1998
    /**
1999
     * @param array|string $aStrokeFileName
2000
     */
2001
    public function Stroke($aStrokeFileName = '')
2002
    {
2003
        // Fist make a sanity check that user has specified a scale
2004
        if (empty($this->yscale)) {
2005
            Util\JpGraphError::RaiseL(25031); //('You must specify what scale to use with a call to Graph::SetScale().');
2006
        }
2007
2008
        // Start by adjusting the margin so that potential titles will fit.
2009
        $this->AdjustMarginsForTitles();
2010
2011
        // Give the plot a chance to do any scale adjuments the individual plots
2012
        // wants to do. Right now this is only used by the contour plot to set scale
2013
        // limits
2014
        for ($i = 0; Configs::safe_count($this->plots) > $i; ++$i) {
2015
            if (!($this->plots[$i] instanceof Plot\Plot)) {
2016
                continue;
2017
            }
2018
2019
            $this->plots[$i]->PreScaleSetup($this);
2020
        }
2021
2022
        // Init scale constants that are used to calculate the transformation from
2023
        // world to pixel coordinates
2024
        $this->InitScaleConfigs();
2025
2026
        // If the filename is the predefined value = '_csim_special_'
2027
        // we assume that the call to stroke only needs to do enough
2028
        // to correctly generate the Configs::getConfig('CSIM') maps.
2029
        // We use this variable to skip things we don't strictly need
2030
        // to do to generate the image map to improve performance
2031
        // a best we can. Therefor you will see a lot of tests !$_csim in the
2032
        // code below.
2033
        $_csim = (Configs::getConfig('_CSIM_SPECIALFILE') === $aStrokeFileName);
2034
2035
        // If we are called the second time (perhaps the user has called GetHTMLImageMap()
2036
        // himself then the legends have alsready been populated once in order to get the
2037
        // Configs::getConfig('CSIM') coordinats. Since we do not want the legends to be populated a second time
2038
        // we clear the legends
2039
        $this->legend->Clear();
2040
2041
        // We need to know if we have stroked the plot in the
2042
        // GetCSIMareas. Otherwise the Configs::getConfig('CSIM') hasn't been generated
2043
        // and in the case of GetCSIM called before stroke to generate
2044
        // Configs::getConfig('CSIM') without storing an image to disk GetCSIM must call Stroke.
2045
        $this->iHasStroked = true;
2046
2047
        // Setup pre-stroked adjustments and Legends
2048
        $this->doPrestrokeAdjustments();
2049
2050
        if ($this->graph_theme) {
2051
            $this->graph_theme->PreStrokeApply($this);
2052
        }
2053
2054
        // Bail out if any of the Y-axis not been specified and
2055
        // has no plots. (This means it is impossible to do autoscaling and
2056
        // no other scale was given so we can't possible draw anything). If you use manual
2057
        // scaling you also have to supply the tick steps as well.
2058
        if ((!$this->yscale->IsSpecified() && Configs::safe_count($this->plots) === 0)
2059
            || (null !== $this->y2scale && !$this->y2scale->IsSpecified() && Configs::safe_count($this->y2plots) === 0)
2060
        ) {
2061
            //$e = "n=". Configs::safe_count($this->y2plots)."\n";
2062
            // $e = "Can't draw unspecified Y-scale.<br>\nYou have either:<br>\n";
2063
            // $e .= "1. Specified an Y axis for autoscaling but have not supplied any plots<br>\n";
2064
            // $e .= "2. Specified a scale manually but have forgot to specify the tick steps";
2065
            Util\JpGraphError::RaiseL(25026);
2066
        }
2067
2068
        // Bail out if no plots and no specified X-scale
2069
        if ((!$this->xscale->IsSpecified() && Configs::safe_count($this->plots) === 0 && Configs::safe_count($this->y2plots) === 0)) {
2070
            Util\JpGraphError::RaiseL(25034); //("<strong>JpGraph: Can't draw unspecified X-scale.</strong><br>No plots.<br>");
2071
        }
2072
2073
        // Autoscale the normal Y-axis
2074
        $this->doAutoScaleYAxis();
2075
2076
        // Autoscale all additiopnal y-axis
2077
        $this->doAutoScaleYnAxis();
2078
2079
        // Autoscale the regular x-axis and position the y-axis properly
2080
        $this->doAutoScaleXAxis();
2081
2082
        // If we have a negative values and x-axis position is at 0
2083
        // we need to supress the first and possible the last tick since
2084
        // they will be drawn on top of the y-axis (and possible y2 axis)
2085
        // The test below might seem strange the reasone being that if
2086
        // the user hasn't specified a value for position this will not
2087
        // be set until we do the stroke for the axis so as of now it
2088
        // is undefined.
2089
        // For X-text scale we ignore all this since the tick are usually
2090
        // much further in and not close to the Y-axis. Hence the test
2091
        // for 'text'
2092
        if (($this->xscale->GetMinVal() === $this->yaxis->pos || (\is_string($this->yaxis->pos) && 'min' === $this->yaxis->pos))
2093
            && !\is_numeric($this->xaxis->pos) && $this->yscale->GetMinVal() < 0
2094
            && \mb_substr($this->axtype, 0, 4) !== 'text' && 'min' !== $this->xaxis->pos
2095
        ) {
2096
            //$this->yscale->ticks->SupressZeroLabel(false);
2097
            $this->xscale->ticks->SupressFirst();
2098
2099
            if (null !== $this->y2axis) {
2100
                $this->xscale->ticks->SupressLast();
2101
            }
2102
        } elseif (!\is_numeric($this->yaxis->pos) && 'max' === $this->yaxis->pos) {
2103
            $this->xscale->ticks->SupressLast();
2104
        }
2105
2106
        if (!$_csim) {
2107
            $this->StrokePlotArea();
2108
2109
            if (Configs::getConfig('DEPTH_BACK') === $this->iIconDepth) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...) === $this->iIconDepth is always false.
Loading history...
2110
                $this->StrokeIcons();
2111
            }
2112
        }
2113
        $this->StrokeAxis(false);
2114
2115
        // Stroke colored bands
2116
        $this->StrokeBands(Configs::getConfig('DEPTH_BACK'), $_csim);
2117
2118
        if (Configs::getConfig('DEPTH_BACK') === $this->grid_depth && !$_csim) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...) === $this->grid_depth is always false.
Loading history...
2119
            $this->ygrid->Stroke();
2120
            $this->xgrid->Stroke();
2121
        }
2122
2123
        // Stroke Y2-axis
2124
        if (null !== $this->y2axis && !$_csim) {
2125
            $this->y2axis->Stroke($this->xscale);
2126
            $this->y2grid->Stroke();
0 ignored issues
show
Bug introduced by
The method Stroke() does not exist on null. ( Ignorable by Annotation )

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

2126
            $this->y2grid->/** @scrutinizer ignore-call */ 
2127
                           Stroke();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2127
        }
2128
2129
        // Stroke yn-axis
2130
        $n = Configs::safe_count($this->ynaxis);
2131
2132
        for ($i = 0; $i < $n; ++$i) {
2133
            $this->ynaxis[$i]->Stroke($this->xscale);
2134
        }
2135
2136
        $oldoff = $this->xscale->off;
2137
2138
        if (\mb_substr($this->axtype, 0, 4) === 'text') {
2139
            if (-1 < $this->text_scale_abscenteroff) {
2140
                // For a text scale the scale factor is the number of pixel per step.
2141
                // Hence we can use the scale factor as a substitute for number of pixels
2142
                // per major scale step and use that in order to adjust the offset so that
2143
                // an object of width "abscenteroff" becomes centered.
2144
                $this->xscale->off += \round($this->xscale->scale_factor / 2) - \round($this->text_scale_abscenteroff / 2);
2145
            } else {
2146
                $this->xscale->off += \ceil($this->xscale->scale_factor * $this->text_scale_off * $this->xscale->ticks->minor_step);
0 ignored issues
show
Bug introduced by
The property minor_step is declared private in Amenadiel\JpGraph\Graph\Tick\RadarLinearTicks and cannot be accessed from this context.
Loading history...
2147
            }
2148
        }
2149
2150
        if ($this->iDoClipping) {
2151
            $oldimage = $this->img->CloneCanvasH();
2152
        }
2153
2154
        if (!$this->y2orderback) {
2155
            // Stroke all plots for Y1 axis
2156
            for ($i = 0; Configs::safe_count($this->plots) > $i; ++$i) {
2157
                $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale);
2158
2159
                if (!($this->plots[$i] instanceof Plot\Plot)) {
2160
                    continue;
2161
                }
2162
2163
                $this->plots[$i]->StrokeMargin($this->img);
2164
            }
2165
        }
2166
2167
        // Stroke all plots for Y2 axis
2168
        if (null !== $this->y2scale) {
2169
            for ($i = 0; Configs::safe_count($this->y2plots) > $i; ++$i) {
2170
                $this->y2plots[$i]->Stroke($this->img, $this->xscale, $this->y2scale);
2171
            }
2172
        }
2173
2174
        if ($this->y2orderback) {
2175
            // Stroke all plots for Y1 axis
2176
            for ($i = 0; Configs::safe_count($this->plots) > $i; ++$i) {
2177
                $this->plots[$i]->Stroke($this->img, $this->xscale, $this->yscale);
2178
2179
                if (!($this->plots[$i] instanceof Plot\Plot)) {
2180
                    continue;
2181
                }
2182
2183
                $this->plots[$i]->StrokeMargin($this->img);
2184
            }
2185
        }
2186
2187
        $n = Configs::safe_count($this->ynaxis);
2188
2189
        for ($i = 0; $i < $n; ++$i) {
2190
            $m = Configs::safe_count($this->ynplots[$i]);
2191
2192
            for ($j = 0; $j < $m; ++$j) {
2193
                $this->ynplots[$i][$j]->Stroke($this->img, $this->xscale, $this->ynscale[$i]);
2194
2195
                if (!($this->ynplots[$i][$j] instanceof Plot\Plot)) {
2196
                    continue;
2197
                }
2198
2199
                $this->ynplots[$i][$j]->StrokeMargin($this->img);
2200
            }
2201
        }
2202
2203
        if (Configs::getConfig('DEPTH_FRONT') === $this->iIconDepth) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...) === $this->iIconDepth is always false.
Loading history...
2204
            $this->StrokeIcons();
2205
        }
2206
2207
        if ($this->iDoClipping) {
2208
            // Clipping only supports graphs at 0 and 90 degrees
2209
            if (0 === $this->img->a) {
2210
                $this->img->CopyCanvasH(
2211
                    $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...
2212
                    $this->img->img,
2213
                    $this->img->left_margin,
2214
                    $this->img->top_margin,
2215
                    $this->img->left_margin,
2216
                    $this->img->top_margin,
2217
                    $this->img->plotwidth + 1,
2218
                    $this->img->plotheight
2219
                );
2220
            } elseif (90 === $this->img->a) {
2221
                $adj = ($this->img->height - $this->img->width) / 2;
2222
                $this->img->CopyCanvasH(
2223
                    $oldimage,
2224
                    $this->img->img,
2225
                    $this->img->bottom_margin - $adj,
2226
                    $this->img->left_margin + $adj,
2227
                    $this->img->bottom_margin - $adj,
2228
                    $this->img->left_margin + $adj,
2229
                    $this->img->plotheight + 1,
2230
                    $this->img->plotwidth
2231
                );
2232
            } else {
2233
                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.');
2234
            }
2235
            $this->img->Destroy();
2236
            $this->img->SetCanvasH($oldimage);
2237
        }
2238
2239
        $this->xscale->off = $oldoff;
2240
2241
        if (Configs::getConfig('DEPTH_FRONT') === $this->grid_depth && !$_csim) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...) === $this->grid_depth is always false.
Loading history...
2242
            $this->ygrid->Stroke();
2243
            $this->xgrid->Stroke();
2244
        }
2245
2246
        // Stroke colored bands
2247
        $this->StrokeBands(Configs::getConfig('DEPTH_FRONT'), $_csim);
2248
2249
        // Finally draw the axis again since some plots may have nagged
2250
        // the axis in the edges.
2251
        if (!$_csim) {
2252
            $this->StrokeAxis();
2253
        }
2254
2255
        if (null !== $this->y2scale && !$_csim) {
2256
            $this->y2axis->Stroke($this->xscale, false);
0 ignored issues
show
Bug introduced by
The method Stroke() does not exist on null. ( Ignorable by Annotation )

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

2256
            $this->y2axis->/** @scrutinizer ignore-call */ 
2257
                           Stroke($this->xscale, false);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2257
        }
2258
2259
        if (!$_csim) {
2260
            $this->StrokePlotBox();
2261
        }
2262
2263
        // The titles and legends never gets rotated so make sure
2264
        // that the angle is 0 before stroking them
2265
        $aa = $this->img->SetAngle(0);
2266
        $this->StrokeTitles();
2267
        $this->footer->Stroke($this->img);
2268
        $this->legend->Stroke($this->img);
2269
        $this->img->SetAngle($aa);
2270
        $this->StrokeTexts();
2271
        $this->StrokeTables();
2272
2273
        if ($_csim) {
2274
            return;
2275
        }
2276
2277
        $this->img->SetAngle($aa);
2278
2279
        // Draw an outline around the image map
2280
        if (Configs::_JPG_DEBUG) {
2281
            $this->DisplayClientSideaImageMapAreas();
2282
        }
2283
2284
        // Should we do any final image transformation
2285
        if ($this->iImgTrans) {
2286
            $tform = new Image\ImgTrans($this->img->img);
2287
            $this->img->img = $tform->Skew3D(
2288
                $this->iImgTransHorizon,
2289
                $this->iImgTransSkewDist,
2290
                $this->iImgTransDirection,
2291
                $this->iImgTransHighQ,
2292
                $this->iImgTransMinSize,
2293
                $this->iImgTransFillColor,
2294
                $this->iImgTransBorder
2295
            );
2296
        }
2297
2298
        // If the filename is given as the special "__handle"
2299
        // then the image handler is returned and the image is NOT
2300
        // streamed back
2301
        if (Configs::getConfig('_IMG_HANDLER') === $aStrokeFileName) {
2302
            return $this->img->img;
2303
        }
2304
        // Finally stream the generated picture
2305
        $this->cache->PutAndStream($this->img, $this->cache_name, $this->inline, $aStrokeFileName);
2306
    }
2307
2308
    public function SetAxisLabelBackground($aType, $aXFColor = 'lightgray', $aXColor = 'black', $aYFColor = 'lightgray', $aYColor = 'black')
2309
    {
2310
        $this->iAxisLblBgType = $aType;
2311
        $this->iXAxisLblBgFillColor = $aXFColor;
2312
        $this->iXAxisLblBgColor = $aXColor;
2313
        $this->iYAxisLblBgFillColor = $aYFColor;
2314
        $this->iYAxisLblBgColor = $aYColor;
2315
    }
2316
2317
    public function StrokeAxisLabelBackground()
2318
    {
2319
        // Types
2320
        // 0 = No background
2321
        // 1 = Only X-labels, length of axis
2322
        // 2 = Only Y-labels, length of axis
2323
        // 3 = As 1 but extends to width of graph
2324
        // 4 = As 2 but extends to height of graph
2325
        // 5 = Combination of 3 & 4
2326
        // 6 = Combination of 1 & 2
2327
2328
        $t = $this->iAxisLblBgType;
2329
2330
        if (1 > $t) {
2331
            return;
2332
        }
2333
2334
        // Stroke optional X-axis label background color
2335
        if (1 === $t || 3 === $t || 5 === $t || 6 === $t) {
2336
            $this->img->PushColor($this->iXAxisLblBgFillColor);
2337
2338
            if (1 === $t || 6 === $t) {
2339
                $xl = $this->img->left_margin;
2340
                $yu = $this->img->height - $this->img->bottom_margin + 1;
2341
                $xr = $this->img->width - $this->img->right_margin;
2342
                $yl = $this->img->height - 1 - $this->frame_weight;
2343
            } else {
2344
                // t==3 || t==5
2345
                $xl = $this->frame_weight;
2346
                $yu = $this->img->height - $this->img->bottom_margin + 1;
2347
                $xr = $this->img->width - 1 - $this->frame_weight;
2348
                $yl = $this->img->height - 1 - $this->frame_weight;
2349
            }
2350
2351
            $this->img->FilledRectangle($xl, $yu, $xr, $yl);
2352
            $this->img->PopColor();
2353
2354
            // Check if we should add the vertical lines at left and right edge
2355
            if ('' !== $this->iXAxisLblBgColor) {
2356
                // Hardcode to one pixel wide
2357
                $this->img->SetLineWeight(1);
2358
                $this->img->PushColor($this->iXAxisLblBgColor);
2359
2360
                if (1 === $t || 6 === $t) {
2361
                    $this->img->Line($xl, $yu, $xl, $yl);
2362
                    $this->img->Line($xr, $yu, $xr, $yl);
2363
                } else {
2364
                    $xl = $this->img->width - $this->img->right_margin;
2365
                    $this->img->Line($xl, $yu - 1, $xr, $yu - 1);
2366
                }
2367
                $this->img->PopColor();
2368
            }
2369
        }
2370
2371
        if (2 !== $t && 4 !== $t && 5 !== $t && 6 !== $t) {
2372
            return;
2373
        }
2374
2375
        $this->img->PushColor($this->iYAxisLblBgFillColor);
2376
2377
        if (2 === $t || 6 === $t) {
2378
            $xl = $this->frame_weight;
2379
            $yu = $this->frame_weight + $this->img->top_margin;
2380
            $xr = $this->img->left_margin - 1;
2381
            $yl = $this->img->height - $this->img->bottom_margin + 1;
2382
        } else {
2383
            $xl = $this->frame_weight;
2384
            $yu = $this->frame_weight;
2385
            $xr = $this->img->left_margin - 1;
2386
            $yl = $this->img->height - 1 - $this->frame_weight;
2387
        }
2388
2389
        $this->img->FilledRectangle($xl, $yu, $xr, $yl);
2390
        $this->img->PopColor();
2391
2392
        // Check if we should add the vertical lines at left and right edge
2393
        if ('' === $this->iXAxisLblBgColor) {
2394
            // Check if we should add the vertical lines at left and right edge
2395
            return;
2396
            // Check if we should add the vertical lines at left and right edge
2397
        }
2398
2399
        $this->img->PushColor($this->iXAxisLblBgColor);
2400
2401
        if (2 === $t || 6 === $t) {
2402
            $this->img->Line($xl, $yu - 1, $xr, $yu - 1);
2403
            $this->img->Line($xl, $yl - 1, $xr, $yl - 1);
2404
        } else {
2405
            $this->img->Line($xr + 1, $yu, $xr + 1, $this->img->top_margin);
2406
        }
2407
        $this->img->PopColor();
2408
    }
2409
2410
    /**
2411
     * @param bool $aStrokeLabels
2412
     */
2413
    public function StrokeAxis($aStrokeLabels = true)
2414
    {
2415
        if ($aStrokeLabels) {
2416
            $this->StrokeAxisLabelBackground();
2417
        }
2418
2419
        // Stroke axis
2420
        if (Configs::getConfig('AXSTYLE_SIMPLE') !== $this->iAxisStyle) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...) !== $this->iAxisStyle is always true.
Loading history...
2421
            switch ($this->iAxisStyle) {
2422
                case Configs::getConfig('AXSTYLE_BOXIN'):
2423
                    $toppos = Configs::getConfig('SIDE_DOWN');
2424
                    $bottompos = Configs::getConfig('SIDE_UP');
2425
                    $leftpos = Configs::getConfig('SIDE_RIGHT');
2426
                    $rightpos = Configs::getConfig('SIDE_LEFT');
2427
2428
                    break;
2429
                case Configs::getConfig('AXSTYLE_BOXOUT'):
2430
                    $toppos = Configs::getConfig('SIDE_UP');
2431
                    $bottompos = Configs::getConfig('SIDE_DOWN');
2432
                    $leftpos = Configs::getConfig('SIDE_LEFT');
2433
                    $rightpos = Configs::getConfig('SIDE_RIGHT');
2434
2435
                    break;
2436
                case Configs::getConfig('AXSTYLE_YBOXIN'):
2437
                    $toppos = false;
2438
                    $bottompos = Configs::getConfig('SIDE_UP');
2439
                    $leftpos = Configs::getConfig('SIDE_RIGHT');
2440
                    $rightpos = Configs::getConfig('SIDE_LEFT');
2441
2442
                    break;
2443
                case Configs::getConfig('AXSTYLE_YBOXOUT'):
2444
                    $toppos = false;
2445
                    $bottompos = Configs::getConfig('SIDE_DOWN');
2446
                    $leftpos = Configs::getConfig('SIDE_LEFT');
2447
                    $rightpos = Configs::getConfig('SIDE_RIGHT');
2448
2449
                    break;
2450
2451
                default:
2452
                    Util\JpGraphError::RaiseL(25036, $this->iAxisStyle); //('Unknown AxisStyle() : '.$this->iAxisStyle);
2453
2454
                    break;
2455
            }
2456
2457
            // By default we hide the first label so it doesn't cross the
2458
            // Y-axis in case the positon hasn't been set by the user.
2459
            // However, if we use a box we always want the first value
2460
            // displayed so we make sure it will be displayed.
2461
            $this->xscale->ticks->SupressFirst(false);
2462
2463
            // Now draw the bottom X-axis
2464
            $this->xaxis->SetPos('min');
2465
            $this->xaxis->SetLabelSide(Configs::getConfig('SIDE_DOWN'));
2466
            $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...
2467
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2468
2469
            if (false !== $toppos) {
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...
2470
                // We also want a top X-axis
2471
                $this->xaxis = $this->xaxis;
2472
                $this->xaxis->SetPos('max');
2473
                $this->xaxis->SetLabelSide(Configs::getConfig('SIDE_UP'));
2474
                // No title for the top X-axis
2475
                if ($aStrokeLabels) {
2476
                    $this->xaxis->title->Set('');
2477
                }
2478
                $this->xaxis->scale->ticks->SetSide($toppos);
2479
                $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2480
            }
2481
2482
            // Stroke the left Y-axis
2483
            $this->yaxis->SetPos('min');
2484
            $this->yaxis->SetLabelSide(Configs::getConfig('SIDE_LEFT'));
2485
            $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...
2486
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2487
2488
            // Stroke the  right Y-axis
2489
            $this->yaxis->SetPos('max');
2490
            // No title for the right side
2491
            if ($aStrokeLabels) {
2492
                $this->yaxis->title->Set('');
2493
            }
2494
            $this->yaxis->SetLabelSide(Configs::getConfig('SIDE_RIGHT'));
2495
            $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...
2496
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2497
        } else {
2498
            $this->xaxis->Stroke($this->yscale, $aStrokeLabels);
2499
            $this->yaxis->Stroke($this->xscale, $aStrokeLabels);
2500
        }
2501
    }
2502
2503
    // Private helper function for backgound image
2504
    /**
2505
     * @param string $aImgFormat
2506
     * @param string $aFile
2507
     */
2508
    public static function LoadBkgImage($aImgFormat = '', $aFile = '', $aImgStr = '')
2509
    {
2510
        if ('' !== $aImgStr) {
2511
            return Image\Image::CreateFromString($aImgStr);
2512
        }
2513
2514
        // Remove case sensitivity and setup appropriate function to create image
2515
        // Get file extension. This should be the Configs::getConfig('LAST') '.' separated part of the filename
2516
        $e = \explode('.', $aFile);
2517
        $ext = \mb_strtolower($e[\count($e) - 1]);
2518
2519
        if ('jpeg' === $ext) {
2520
            $ext = 'jpg';
2521
        }
2522
2523
        if (\trim($ext) === '') {
2524
            $ext = 'png'; // Assume PNG if no extension specified
2525
        }
2526
2527
        if ('' === $aImgFormat) {
2528
            $imgtag = $ext;
2529
        } else {
2530
            $imgtag = $aImgFormat;
2531
        }
2532
2533
        $supported = \imagetypes();
2534
2535
        if (('jpg' === $ext && !($supported & \IMG_JPG))
2536
            || ('gif' === $ext && !($supported & \IMG_GIF))
2537
            || ('png' === $ext && !($supported & \IMG_PNG))
2538
            || ('bmp' === $ext && !($supported & \IMG_WBMP))
2539
            || ('xpm' === $ext && !($supported & \IMG_XPM))
2540
        ) {
2541
            Util\JpGraphError::RaiseL(25037, $aFile); //('The image format of your background image ('.$aFile.') is not supported in your system configuration. ');
2542
        }
2543
2544
        if ('jpg' === $imgtag || 'jpeg' === $imgtag) {
2545
            $f = 'imagecreatefromjpeg';
2546
            $imgtag = 'jpg';
2547
        } else {
2548
            $f = 'imagecreatefrom' . $imgtag;
2549
        }
2550
2551
        // Compare specified image type and file extension
2552
        if ($imgtag !== $ext) {
2553
            //$t = "Background image seems to be of different type (has different file extension) than specified imagetype. Specified: '".$aImgFormat."'File: '".$aFile."'";
2554
            Util\JpGraphError::RaiseL(25038, $aImgFormat, $aFile);
2555
        }
2556
2557
        $img = $f($aFile);
2558
2559
        if (!$img) {
2560
            Util\JpGraphError::RaiseL(25039, $aFile); //(" Can't read background image: '".$aFile."'");
2561
        }
2562
2563
        return $img;
2564
    }
2565
2566
    public function StrokePlotGrad()
2567
    {
2568
        if (0 > $this->plot_gradtype) {
2569
            return;
2570
        }
2571
2572
        $grad = new Plot\Gradient($this->img);
2573
        $xl = $this->img->left_margin;
2574
        $yt = $this->img->top_margin;
2575
        $xr = $xl + $this->img->plotwidth + 1;
2576
        $yb = $yt + $this->img->plotheight;
2577
        $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->plot_gradfrom, $this->plot_gradto, $this->plot_gradtype);
2578
    }
2579
2580
    public function StrokeBackgroundGrad()
2581
    {
2582
        if (0 > $this->bkg_gradtype) {
2583
            return;
2584
        }
2585
2586
        $grad = new Plot\Gradient($this->img);
2587
2588
        if (Configs::getConfig('BGRAD_PLOT') === $this->bkg_gradstyle) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...== $this->bkg_gradstyle is always false.
Loading history...
2589
            $xl = $this->img->left_margin;
2590
            $yt = $this->img->top_margin;
2591
            $xr = $xl + $this->img->plotwidth + 1;
2592
            $yb = $yt + $this->img->plotheight;
2593
            $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype);
2594
        } else {
2595
            $xl = 0;
2596
            $yt = 0;
2597
            $xr = $xl + $this->img->width - 1;
2598
            $yb = $yt + $this->img->height - 1;
2599
2600
            if ($this->doshadow) {
2601
                $xr -= $this->shadow_width;
2602
                $yb -= $this->shadow_width;
2603
            }
2604
2605
            if ($this->doframe) {
2606
                $yt += $this->frame_weight;
2607
                $yb -= $this->frame_weight;
2608
                $xl += $this->frame_weight;
2609
                $xr -= $this->frame_weight;
2610
            }
2611
            $aa = $this->img->SetAngle(0);
2612
            $grad->FilledRectangle($xl, $yt, $xr, $yb, $this->bkg_gradfrom, $this->bkg_gradto, $this->bkg_gradtype);
2613
            $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...
2614
        }
2615
    }
2616
2617
    public function StrokeFrameBackground()
2618
    {
2619
        if ('' !== $this->background_image && '' !== $this->background_cflag) {
2620
            Util\JpGraphError::RaiseL(25040); //('It is not possible to specify both a background image and a background country flag.');
2621
        }
2622
2623
        if ('' !== $this->background_image) {
2624
            $bkgimg = $this->LoadBkgImage($this->background_image_format, $this->background_image);
2625
        } elseif ('' !== $this->background_cflag) {
2626
            $fobj = new Image\FlagImages(Configs::getConfig('FLAGSIZE4'));
2627
            $dummy = '';
2628
            $bkgimg = $fobj->GetImgByName($this->background_cflag, $dummy);
2629
            $this->background_image_mix = $this->background_cflag_mix;
2630
            $this->background_image_type = $this->background_cflag_type;
2631
        } else {
2632
            return;
2633
        }
2634
2635
        $bw = \imagesx($bkgimg);
2636
        $bh = \imagesy($bkgimg);
2637
2638
        // No matter what the angle is we always stroke the image and frame
2639
        // assuming it is 0 degree
2640
        $aa = $this->img->SetAngle(0);
2641
2642
        switch ($this->background_image_type) {
2643
            case Configs::getConfig('BGIMG_FILLPLOT'): // Resize to just fill the plotarea
2644
                $this->FillMarginArea();
2645
                $this->StrokeFrame();
2646
                // Special case to hande 90 degree rotated graph corectly
2647
                if (90 === $aa) {
2648
                    $this->img->SetAngle(90);
2649
                    $this->FillPlotArea();
2650
                    $aa = $this->img->SetAngle(0);
2651
                    $adj = ($this->img->height - $this->img->width) / 2;
2652
                    $this->img->CopyMerge(
2653
                        $bkgimg,
2654
                        $this->img->bottom_margin - $adj,
2655
                        $this->img->left_margin + $adj,
2656
                        0,
2657
                        0,
2658
                        $this->img->plotheight + 1,
2659
                        $this->img->plotwidth,
2660
                        $bw,
2661
                        $bh,
2662
                        $this->background_image_mix
2663
                    );
2664
                } else {
2665
                    $this->FillPlotArea();
2666
                    $this->img->CopyMerge(
2667
                        $bkgimg,
2668
                        $this->img->left_margin,
2669
                        $this->img->top_margin + 1,
2670
                        0,
2671
                        0,
2672
                        $this->img->plotwidth + 1,
2673
                        $this->img->plotheight,
2674
                        $bw,
2675
                        $bh,
2676
                        $this->background_image_mix
2677
                    );
2678
                }
2679
2680
                break;
2681
            case Configs::getConfig('BGIMG_FILLFRAME'): // Fill the whole area from upper left corner, resize to just fit
2682
                $hadj = 0;
2683
                $vadj = 0;
2684
2685
                if ($this->doshadow) {
2686
                    $hadj = $this->shadow_width;
2687
                    $vadj = $this->shadow_width;
2688
                }
2689
                $this->FillMarginArea();
2690
                $this->FillPlotArea();
2691
                $this->img->CopyMerge(
2692
                    $bkgimg,
2693
                    0,
2694
                    0,
2695
                    0,
2696
                    0,
2697
                    $this->img->width - $hadj,
2698
                    $this->img->height - $vadj,
2699
                    $bw,
2700
                    $bh,
2701
                    $this->background_image_mix
2702
                );
2703
                $this->StrokeFrame();
2704
2705
                break;
2706
            case Configs::getConfig('BGIMG_COPY'): // Just copy the image from left corner, no resizing
2707
                $this->FillMarginArea();
2708
                $this->FillPlotArea();
2709
                $this->img->CopyMerge(
2710
                    $bkgimg,
2711
                    0,
2712
                    0,
2713
                    0,
2714
                    0,
2715
                    $bw,
2716
                    $bh,
2717
                    $bw,
2718
                    $bh,
2719
                    $this->background_image_mix
2720
                );
2721
                $this->StrokeFrame();
2722
2723
                break;
2724
            case Configs::getConfig('BGIMG_CENTER'): // Center original image in the plot area
2725
                $this->FillMarginArea();
2726
                $this->FillPlotArea();
2727
                $centerx = \round($this->img->plotwidth / 2 + $this->img->left_margin - $bw / 2);
2728
                $centery = \round($this->img->plotheight / 2 + $this->img->top_margin - $bh / 2);
2729
                $this->img->CopyMerge(
2730
                    $bkgimg,
2731
                    $centerx,
2732
                    $centery,
2733
                    0,
2734
                    0,
2735
                    $bw,
2736
                    $bh,
2737
                    $bw,
2738
                    $bh,
2739
                    $this->background_image_mix
2740
                );
2741
                $this->StrokeFrame();
2742
2743
                break;
2744
            case Configs::getConfig('BGIMG_FREE'): // Just copy the image to the specified location
2745
                $this->img->CopyMerge(
2746
                    $bkgimg,
2747
                    $this->background_image_xpos,
2748
                    $this->background_image_ypos,
2749
                    0,
2750
                    0,
2751
                    $bw,
2752
                    $bh,
2753
                    $bw,
2754
                    $bh,
2755
                    $this->background_image_mix
2756
                );
2757
                $this->StrokeFrame(); // New
2758
2759
                break;
2760
2761
            default:
2762
                Util\JpGraphError::RaiseL(25042); //(" Unknown background image layout");
2763
        }
2764
        $this->img->SetAngle($aa);
2765
    }
2766
2767
    // Private
2768
    // Draw a frame around the image
2769
    public function StrokeFrame()
2770
    {
2771
        if (!$this->doframe) {
2772
            return;
2773
        }
2774
2775
        if (1 >= $this->background_image_type && (0 > $this->bkg_gradtype || (0 < $this->bkg_gradtype && Configs::getConfig('BGRAD_PLOT') === $this->bkg_gradstyle))) {
2776
            $c = $this->margin_color;
2777
        } else {
2778
            $c = false;
2779
        }
2780
2781
        if ($this->doshadow) {
2782
            $this->img->SetColor($this->frame_color);
2783
            $this->img->ShadowRectangle(
2784
                0,
2785
                0,
2786
                $this->img->width,
2787
                $this->img->height,
2788
                $c,
2789
                $this->shadow_width,
2790
                $this->shadow_color
2791
            );
2792
        } elseif ($this->framebevel) {
2793
            if ($c) {
2794
                $this->img->SetColor($this->margin_color);
2795
                $this->img->FilledRectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2796
            }
2797
            $this->img->Bevel(
2798
                1,
2799
                1,
2800
                $this->img->width - 2,
2801
                $this->img->height - 2,
2802
                $this->framebeveldepth,
2803
                $this->framebevelcolor1,
2804
                $this->framebevelcolor2
2805
            );
2806
2807
            if ($this->framebevelborder) {
2808
                $this->img->SetColor($this->framebevelbordercolor);
2809
                $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2810
            }
2811
        } else {
2812
            $this->img->SetLineWeight($this->frame_weight);
2813
2814
            if ($c) {
2815
                $this->img->SetColor($this->margin_color);
2816
                $this->img->FilledRectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2817
            }
2818
            $this->img->SetColor($this->frame_color);
2819
            $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
2820
        }
2821
    }
2822
2823
    public function FillMarginArea()
2824
    {
2825
        $hadj = 0;
2826
        $vadj = 0;
2827
2828
        if ($this->doshadow) {
2829
            $hadj = $this->shadow_width;
2830
            $vadj = $this->shadow_width;
2831
        }
2832
2833
        $this->img->SetColor($this->margin_color);
2834
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->height - 1 - $vadj);
2835
2836
        $this->img->FilledRectangle(0, 0, $this->img->width - 1 - $hadj, $this->img->top_margin);
2837
        $this->img->FilledRectangle(0, $this->img->top_margin, $this->img->left_margin, $this->img->height - 1 - $hadj);
2838
        $this->img->FilledRectangle(
2839
            $this->img->left_margin + 1,
2840
            $this->img->height - $this->img->bottom_margin,
2841
            $this->img->width - 1 - $hadj,
2842
            $this->img->height - 1 - $hadj
2843
        );
2844
        $this->img->FilledRectangle(
2845
            $this->img->width - $this->img->right_margin,
2846
            $this->img->top_margin + 1,
2847
            $this->img->width - 1 - $hadj,
2848
            $this->img->height - $this->img->bottom_margin - 1
2849
        );
2850
    }
2851
2852
    public function FillPlotArea()
2853
    {
2854
        $this->img->PushColor($this->plotarea_color);
2855
        $this->img->FilledRectangle(
2856
            $this->img->left_margin,
2857
            $this->img->top_margin,
2858
            $this->img->width - $this->img->right_margin,
2859
            $this->img->height - $this->img->bottom_margin
2860
        );
2861
        $this->img->PopColor();
2862
    }
2863
2864
    // Stroke the plot area with either a solid color or a background image
2865
    public function StrokePlotArea()
2866
    {
2867
        // Note: To be consistent we really should take a possible shadow
2868
        // into account. However, that causes some problem for the LinearScale class
2869
        // since in the current design it does not have any links to class Graph which
2870
        // means it has no way of compensating for the adjusted plotarea in case of a
2871
        // shadow. So, until I redesign LinearScale we can't compensate for this.
2872
        // So just set the two adjustment parameters to zero for now.
2873
        $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...
2874
        $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...
2875
2876
        if ('' !== $this->background_image || '' !== $this->background_cflag) {
2877
            $this->StrokeFrameBackground();
2878
        } else {
2879
            $aa = $this->img->SetAngle(0);
2880
            $this->StrokeFrame();
2881
            $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...
2882
            $this->StrokeBackgroundGrad();
2883
2884
            if (0 > $this->bkg_gradtype || (0 < $this->bkg_gradtype && Configs::getConfig('BGRAD_MARGIN') === $this->bkg_gradstyle)) {
2885
                $this->FillPlotArea();
2886
            }
2887
            $this->StrokePlotGrad();
2888
        }
2889
    }
2890
2891
    public function StrokeIcons()
2892
    {
2893
        $n = Configs::safe_count($this->iIcons);
2894
2895
        for ($i = 0; $i < $n; ++$i) {
2896
            $this->iIcons[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
2897
        }
2898
    }
2899
2900
    public function StrokePlotBox()
2901
    {
2902
        // Should we draw a box around the plot area?
2903
        if (!$this->boxed) {
2904
            // Should we draw a box around the plot area?
2905
            return;
2906
            // Should we draw a box around the plot area?
2907
        }
2908
2909
        $this->img->SetLineWeight(1);
2910
        $this->img->SetLineStyle('solid');
2911
        $this->img->SetColor($this->box_color);
2912
2913
        for ($i = 0; $i < $this->box_weight; ++$i) {
2914
            $this->img->Rectangle(
2915
                $this->img->left_margin - $i,
2916
                $this->img->top_margin - $i,
2917
                $this->img->width - $this->img->right_margin + $i,
2918
                $this->img->height - $this->img->bottom_margin + $i
2919
            );
2920
        }
2921
    }
2922
2923
    public function SetTitleBackgroundFillStyle($aStyle, $aColor1 = 'black', $aColor2 = 'white')
2924
    {
2925
        $this->titlebkg_fillstyle = $aStyle;
2926
        $this->titlebkg_scolor1 = $aColor1;
2927
        $this->titlebkg_scolor2 = $aColor2;
2928
    }
2929
2930
    public function SetTitleBackground(
2931
        $aBackColor = 'gray',
2932
        $aStyle = Configs::TITLEBKG_STYLE1,
2933
        $aFrameStyle = Configs::TITLEBKG_FRAME_NONE,
2934
        $aFrameColor = 'black',
2935
        $aFrameWeight = 1,
2936
        $aBevelHeight = 3,
2937
        $aEnable = true
2938
    ) {
2939
        $this->titlebackground = $aEnable;
2940
        $this->titlebackground_color = $aBackColor;
2941
        $this->titlebackground_style = $aStyle;
2942
        $this->titlebackground_framecolor = $aFrameColor;
2943
        $this->titlebackground_framestyle = $aFrameStyle;
2944
        $this->titlebackground_frameweight = $aFrameWeight;
2945
        $this->titlebackground_bevelheight = $aBevelHeight;
2946
    }
2947
2948
    public function StrokeTitles()
2949
    {
2950
        $margin = 3;
2951
2952
        if ($this->titlebackground) {
2953
            // Find out height
2954
            $this->title->margin += 2;
2955
            $h = $this->title->GetTextHeight($this->img) + $this->title->margin + $margin;
2956
2957
            if ('' !== $this->subtitle->t && !$this->subtitle->hide) {
2958
                $h += $this->subtitle->GetTextHeight($this->img) + $margin +
2959
                    $this->subtitle->margin;
2960
                $h += 2;
2961
            }
2962
2963
            if ('' !== $this->subsubtitle->t && !$this->subsubtitle->hide) {
2964
                $h += $this->subsubtitle->GetTextHeight($this->img) + $margin +
2965
                    $this->subsubtitle->margin;
2966
                $h += 2;
2967
            }
2968
            $this->img->PushColor($this->titlebackground_color);
2969
2970
            if (Configs::getConfig('TITLEBKG_STYLE1') === $this->titlebackground_style) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...->titlebackground_style is always false.
Loading history...
2971
                // Inside the frame
2972
                if ($this->framebevel) {
2973
                    $x1 = $y1 = $this->framebeveldepth + 1;
2974
                    $x2 = $this->img->width - $this->framebeveldepth - 2;
2975
                    $this->title->margin += $this->framebeveldepth + 1;
2976
                    $h += $y1;
2977
                    $h += 2;
2978
                } else {
2979
                    $x1 = $y1 = $this->frame_weight;
2980
                    $x2 = $this->img->width - $this->frame_weight - 1;
2981
                }
2982
            } elseif (Configs::getConfig('TITLEBKG_STYLE2') === $this->titlebackground_style) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...->titlebackground_style is always false.
Loading history...
2983
                // Cover the frame as well
2984
                $x1 = $y1 = 0;
2985
                $x2 = $this->img->width - 1;
2986
            } elseif (Configs::getConfig('TITLEBKG_STYLE3') === $this->titlebackground_style) {
0 ignored issues
show
introduced by
The condition Amenadiel\JpGraph\Graph\...->titlebackground_style is always false.
Loading history...
2987
                // Cover the frame as well (the difference is that
2988
                // for style==3 a bevel frame border is on top
2989
                // of the title background)
2990
                $x1 = $y1 = 0;
2991
                $x2 = $this->img->width - 1;
2992
                $h += $this->framebeveldepth;
2993
                $this->title->margin += $this->framebeveldepth;
2994
            } else {
2995
                Util\JpGraphError::RaiseL(25043); //('Unknown title background style.');
2996
            }
2997
2998
            if (3 === $this->titlebackground_framestyle) {
2999
                $h += $this->titlebackground_bevelheight * 2 + 1;
3000
                $this->title->margin += $this->titlebackground_bevelheight;
3001
            }
3002
3003
            if ($this->doshadow) {
3004
                $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...
3005
            }
3006
3007
            $indent = 0;
3008
3009
            if (Configs::getConfig('TITLEBKG_FRAME_BEVEL') === $this->titlebackground_framestyle) {
3010
                $indent = $this->titlebackground_bevelheight;
3011
            }
3012
3013
            if (Configs::getConfig('TITLEBKG_FILLSTYLE_HSTRIPED') === $this->titlebkg_fillstyle) {
3014
                $this->img->FilledRectangle2(
3015
                    $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...
3016
                    $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...
3017
                    $x2 - $indent,
3018
                    $h - $indent,
3019
                    $this->titlebkg_scolor1,
3020
                    $this->titlebkg_scolor2
3021
                );
3022
            } elseif (Configs::getConfig('TITLEBKG_FILLSTYLE_VSTRIPED') === $this->titlebkg_fillstyle) {
3023
                $this->img->FilledRectangle2(
3024
                    $x1 + $indent,
3025
                    $y1 + $indent,
3026
                    $x2 - $indent,
3027
                    $h - $indent,
3028
                    $this->titlebkg_scolor1,
3029
                    $this->titlebkg_scolor2,
3030
                    2
3031
                );
3032
            } else {
3033
                // Solid fill
3034
                $this->img->FilledRectangle($x1, $y1, $x2, $h);
3035
            }
3036
            $this->img->PopColor();
3037
3038
            $this->img->PushColor($this->titlebackground_framecolor);
3039
            $this->img->SetLineWeight($this->titlebackground_frameweight);
3040
3041
            if (Configs::getConfig('TITLEBKG_FRAME_FULL') === $this->titlebackground_framestyle) {
3042
                // Frame background
3043
                $this->img->Rectangle($x1, $y1, $x2, $h);
3044
            } elseif (Configs::getConfig('TITLEBKG_FRAME_BOTTOM') === $this->titlebackground_framestyle) {
3045
                // Bottom line only
3046
                $this->img->Line($x1, $h, $x2, $h);
3047
            } elseif (Configs::getConfig('TITLEBKG_FRAME_BEVEL') === $this->titlebackground_framestyle) {
3048
                $this->img->Bevel($x1, $y1, $x2, $h, $this->titlebackground_bevelheight);
3049
            }
3050
            $this->img->PopColor();
3051
3052
            // This is clumsy. But we neeed to stroke the whole graph frame if it is
3053
            // set to bevel to get the bevel shading on top of the text background
3054
            if ($this->framebevel && $this->doframe && 3 === $this->titlebackground_style) {
3055
                $this->img->Bevel(
3056
                    1,
3057
                    1,
3058
                    $this->img->width - 2,
3059
                    $this->img->height - 2,
3060
                    $this->framebeveldepth,
3061
                    $this->framebevelcolor1,
3062
                    $this->framebevelcolor2
3063
                );
3064
3065
                if ($this->framebevelborder) {
3066
                    $this->img->SetColor($this->framebevelbordercolor);
3067
                    $this->img->Rectangle(0, 0, $this->img->width - 1, $this->img->height - 1);
3068
                }
3069
            }
3070
        }
3071
3072
        // Stroke title
3073
        $y = $this->title->margin;
3074
3075
        if ('center' === $this->title->halign) {
3076
            $this->title->Center(0, $this->img->width, $y);
3077
        } elseif ('left' === $this->title->halign) {
3078
            $this->title->SetPos($this->title->margin + 2, $y);
3079
        } elseif ('right' === $this->title->halign) {
3080
            $indent = 0;
3081
3082
            if ($this->doshadow) {
3083
                $indent = $this->shadow_width + 2;
3084
            }
3085
            $this->title->SetPos($this->img->width - $this->title->margin - $indent, $y, 'right');
3086
        }
3087
        $this->title->Stroke($this->img);
3088
3089
        // ... and subtitle
3090
        $y += $this->title->GetTextHeight($this->img) + $margin + $this->subtitle->margin;
3091
3092
        if ('center' === $this->subtitle->halign) {
3093
            $this->subtitle->Center(0, $this->img->width, $y);
3094
        } elseif ('left' === $this->subtitle->halign) {
3095
            $this->subtitle->SetPos($this->subtitle->margin + 2, $y);
3096
        } elseif ('right' === $this->subtitle->halign) {
3097
            $indent = 0;
3098
3099
            if ($this->doshadow) {
3100
                $indent = $this->shadow_width + 2;
3101
            }
3102
3103
            $this->subtitle->SetPos($this->img->width - $this->subtitle->margin - $indent, $y, 'right');
3104
        }
3105
        $this->subtitle->Stroke($this->img);
3106
3107
        // ... and subsubtitle
3108
        $y += $this->subtitle->GetTextHeight($this->img) + $margin + $this->subsubtitle->margin;
3109
3110
        if ('center' === $this->subsubtitle->halign) {
3111
            $this->subsubtitle->Center(0, $this->img->width, $y);
3112
        } elseif ('left' === $this->subsubtitle->halign) {
3113
            $this->subsubtitle->SetPos($this->subsubtitle->margin + 2, $y);
3114
        } elseif ('right' === $this->subsubtitle->halign) {
3115
            $indent = 0;
3116
3117
            if ($this->doshadow) {
3118
                $indent = $this->shadow_width + 2;
3119
            }
3120
3121
            $this->subsubtitle->SetPos($this->img->width - $this->subsubtitle->margin - $indent, $y, 'right');
3122
        }
3123
        $this->subsubtitle->Stroke($this->img);
3124
3125
        // ... and fancy title
3126
        $this->tabtitle->Stroke($this->img);
3127
    }
3128
3129
    public function StrokeTexts()
3130
    {
3131
        // Stroke any user added text objects
3132
        if (null !== $this->texts) {
3133
            for ($i = 0; Configs::safe_count($this->texts) > $i; ++$i) {
3134
                $this->texts[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
3135
            }
3136
        }
3137
3138
        if (null === $this->y2texts || null === $this->y2scale) {
3139
            return;
3140
        }
3141
3142
        for ($i = 0; Configs::safe_count($this->y2texts) > $i; ++$i) {
3143
            $this->y2texts[$i]->StrokeWithScale($this->img, $this->xscale, $this->y2scale);
3144
        }
3145
    }
3146
3147
    public function StrokeTables()
3148
    {
3149
        if (null === $this->iTables) {
3150
            return;
3151
        }
3152
3153
        $n = Configs::safe_count($this->iTables);
3154
3155
        for ($i = 0; $i < $n; ++$i) {
3156
            $this->iTables[$i]->StrokeWithScale($this->img, $this->xscale, $this->yscale);
3157
        }
3158
    }
3159
3160
    public function DisplayClientSideaImageMapAreas()
3161
    {
3162
        // Debug stuff - display the outline of the image map areas
3163
        $csim = '';
3164
3165
        foreach ($this->plots as $p) {
3166
            $csim .= $p->GetCSIMareas();
3167
        }
3168
        $csim .= $this->legend->GetCSIMareas();
3169
3170
        if (!\preg_match_all('/area shape="(\\w+)" coords="([0-9\\, ]+)"/', $csim, $coords)) {
3171
            return;
3172
        }
3173
3174
        $this->img->SetColor($this->csimcolor);
3175
        $n = Configs::safe_count($coords[0]);
3176
3177
        for ($i = 0; $i < $n; ++$i) {
3178
            if ('poly' === $coords[1][$i]) {
3179
                \preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/', $coords[2][$i], $pts);
3180
                $this->img->SetStartPoint($pts[1][\count($pts[0]) - 1], $pts[2][\count($pts[0]) - 1]);
3181
                $m = Configs::safe_count($pts[0]);
3182
3183
                for ($j = 0; $j < $m; ++$j) {
3184
                    $this->img->LineTo($pts[1][$j], $pts[2][$j]);
3185
                }
3186
            } elseif ('rect' === $coords[1][$i]) {
3187
                $pts = \preg_split('/,/', $coords[2][$i]);
3188
                $this->img->SetStartPoint($pts[0], $pts[1]);
3189
                $this->img->LineTo($pts[2], $pts[1]);
3190
                $this->img->LineTo($pts[2], $pts[3]);
3191
                $this->img->LineTo($pts[0], $pts[3]);
3192
                $this->img->LineTo($pts[0], $pts[1]);
3193
            }
3194
        }
3195
    }
3196
3197
    // Text scale offset in world coordinates
3198
    public function SetTextScaleOff($aOff)
3199
    {
3200
        $this->text_scale_off = $aOff;
3201
        $this->xscale->text_scale_off = $aOff;
3202
    }
3203
3204
    // Text width of bar to be centered in absolute pixels
3205
    public function SetTextScaleAbsCenterOff($aOff)
3206
    {
3207
        $this->text_scale_abscenteroff = $aOff;
3208
    }
3209
3210
    // Get Y min and max values for added lines
3211
    public function GetLinesYMinMax($aLines)
3212
    {
3213
        if (null === $aLines) {
3214
            return false;
3215
        }
3216
3217
        $n = Configs::safe_count($aLines);
3218
3219
        if (0 === $n) {
3220
            return false;
3221
        }
3222
3223
        $min = $aLines[0]->scaleposition;
3224
        $max = $min;
3225
        $flg = false;
3226
3227
        for ($i = 0; $i < $n; ++$i) {
3228
            if (Configs::getConfig('HORIZONTAL') !== $aLines[$i]->direction) {
3229
                continue;
3230
            }
3231
3232
            $flg = true;
3233
            $v = $aLines[$i]->scaleposition;
3234
3235
            if ($min > $v) {
3236
                $min = $v;
3237
            }
3238
3239
            if ($max >= $v) {
3240
                continue;
3241
            }
3242
3243
            $max = $v;
3244
        }
3245
3246
        return $flg ? [$min, $max] : false;
0 ignored issues
show
introduced by
The condition $flg is always false.
Loading history...
3247
    }
3248
3249
    // Get X min and max values for added lines
3250
    public function GetLinesXMinMax($aLines)
3251
    {
3252
        $n = Configs::safe_count($aLines);
3253
3254
        if (0 === $n) {
3255
            return false;
3256
        }
3257
3258
        $min = $aLines[0]->scaleposition;
3259
        $max = $min;
3260
        $flg = false;
3261
3262
        for ($i = 0; $i < $n; ++$i) {
3263
            if (Configs::getConfig('VERTICAL') !== $aLines[$i]->direction) {
3264
                continue;
3265
            }
3266
3267
            $flg = true;
3268
            $v = $aLines[$i]->scaleposition;
3269
3270
            if ($min > $v) {
3271
                $min = $v;
3272
            }
3273
3274
            if ($max >= $v) {
3275
                continue;
3276
            }
3277
3278
            $max = $v;
3279
        }
3280
3281
        return $flg ? [$min, $max] : false;
0 ignored issues
show
introduced by
The condition $flg is always false.
Loading history...
3282
    }
3283
3284
    // Get min and max values for all included plots
3285
    public function GetPlotsYMinMax($bPlots)
3286
    {
3287
        $aPlots = \array_filter($bPlots, function ($plot) {
3288
            return $plot instanceof Plot\Plot;
3289
        });
3290
        \reset($aPlots);
3291
        $n = Configs::safe_count($aPlots);
3292
        $i = 0;
3293
3294
        do {
3295
            [$xmax, $max] = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
3296
        } while (++$i < $n && !\is_numeric($max));
3297
3298
        $i = 0;
3299
3300
        do {
3301
            [$xmin, $min] = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
3302
        } while (++$i < $n && !\is_numeric($min));
3303
3304
        if (!\is_numeric($min) || !\is_numeric($max)) {
3305
            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).');
3306
        }
3307
3308
        for ($i = 0; $i < $n; ++$i) {
3309
            [$xmax, $ymax] = isset($aPlots[$i]) ? $aPlots[$i]->Max() : [null, null];
3310
            [$xmin, $ymin] = isset($aPlots[$i]) ? $aPlots[$i]->Min() : [null, null];
3311
3312
            if (\is_numeric($ymax)) {
3313
                $max = \max($max, $ymax);
3314
            }
3315
3316
            if (!\is_numeric($ymin)) {
3317
                continue;
3318
            }
3319
3320
            $min = \min($min, $ymin);
3321
        }
3322
3323
        if ('' === $min) {
3324
            $min = 0;
3325
        }
3326
3327
        if ('' === $max) {
3328
            $max = 0;
3329
        }
3330
3331
        if (0 === $min && 0 === $max) {
3332
            // Special case if all values are 0
3333
            $min = 0;
3334
            $max = 1;
3335
        }
3336
3337
        return [$min, $max];
3338
    }
3339
3340
    public function hasLinePlotAndBarPlot()
3341
    {
3342
        $has_line = false;
3343
        $has_bar = false;
3344
3345
        foreach ($this->plots as $plot) {
3346
            if ($plot instanceof Plot\LinePlot) {
3347
                $has_line = true;
3348
            }
3349
3350
            if (!($plot instanceof Plot\BarPlot)) {
3351
                continue;
3352
            }
3353
3354
            $has_bar = true;
3355
        }
3356
3357
        if ($has_line && $has_bar) {
3358
            return true;
3359
        }
3360
3361
        return false;
3362
    }
3363
3364
    public function SetTheme($graph_theme)
3365
    {
3366
        if (!($this instanceof PieGraph)) {
3367
            if (!$this->isAfterSetScale) {
3368
                Util\JpGraphError::RaiseL(25133); //('Use Graph::SetTheme() after Graph::SetScale().');
3369
            }
3370
        }
3371
3372
        if ($this->graph_theme) {
3373
            $this->ClearTheme();
3374
        }
3375
        $this->graph_theme = $graph_theme;
3376
        $this->graph_theme->ApplyGraph($this);
3377
    }
3378
3379
    public function ClearTheme()
3380
    {
3381
        $this->graph_theme = null;
3382
3383
        $this->isRunningClear = true;
3384
3385
        $this->__construct(
3386
            $this->inputValues['aWidth'],
3387
            $this->inputValues['aHeight'],
3388
            $this->inputValues['aCachedName'],
3389
            $this->inputValues['aTimeout'],
3390
            $this->inputValues['aInline']
3391
        );
3392
3393
        if ($this->isAfterSetScale) {
3394
            $this->SetScale(
3395
                $this->inputValues['aAxisType'],
3396
                $this->inputValues['aYMin'],
3397
                $this->inputValues['aYMax'],
3398
                $this->inputValues['aXMin'],
3399
                $this->inputValues['aXMax']
3400
            );
3401
        }
3402
3403
        $this->isRunningClear = false;
3404
    }
3405
3406
    public function SetSupersampling($do = false, $scale = 2)
3407
    {
3408
        if ($do) {
3409
            Configs::setConfig('SUPERSAMPLING_SCALE', $scale);
3410
        // $this->img->scale = $scale;
3411
        } else {
3412
            Configs::setConfig('SUPERSAMPLING_SCALE', 1);
3413
            //$this->img->scale = 0;
3414
        }
3415
    }
3416
}
3417
3418
// @class
3419