Issues (459)

src/graph/RadarGraph.php (1 issue)

1
<?php
2
3
/**
4
 * JPGraph v4.0.3
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
14
/**
15
 * @class RadarGraph
16
 * // Description: Main container for a radar graph
17
 */
18
class RadarGraph extends Graph
19
{
20
    public $grid;
21
    public $axis;
22
    private $posx;
23
    private $posy;
24
    private $len;
25
    private $axis_title;
26
27
    public function __construct($width = 300, $height = 200, $cachedName = '', $timeout = 0, $inline = 1)
28
    {
29
        parent::__construct($width, $height, $cachedName, $timeout, $inline);
30
        $this->posx = $width / 2;
31
        $this->posy = $height / 2;
32
        $this->len  = min($width, $height) * 0.35;
33
        $this->SetColor([255, 255, 255]);
34
        $this->SetTickDensity(TICKD_NORMAL);
35
        $this->SetScale('lin');
36
        $this->SetGridDepth(DEPTH_FRONT);
37
    }
38
39
    public function HideTickMarks($aFlag = true)
40
    {
41
        $this->axis->scale->ticks->SupressTickMarks($aFlag);
42
    }
43
44
    public function ShowMinorTickmarks($aFlag = true)
45
    {
46
        $this->yscale->ticks->SupressMinorTickMarks(!$aFlag);
47
    }
48
49
    public function SetScale($axtype, $ymin = 1, $ymax = 1, $dummy1 = null, $dumy2 = null)
50
    {
51
        if ($axtype != 'lin' && $axtype != 'log') {
52
            Util\JpGraphError::RaiseL(18003, $axtype);
53
            //("Illegal scale for radarplot ($axtype). Must be \"lin\" or \"log\"");
54
        }
55
        if ($axtype == 'lin') {
56
            $this->yscale        = new LinearScale($ymin, $ymax);
57
            $this->yscale->ticks = new RadarLinearTicks();
58
            $this->yscale->ticks->SupressMinorTickMarks();
59
        } elseif ($axtype == 'log') {
60
            $this->yscale        = new LogScale($ymin, $ymax);
61
            $this->yscale->ticks = new RadarLogTicks();
62
        }
63
64
        $this->axis = new RadarAxis($this->img, $this->yscale);
65
        $this->grid = new RadarGrid();
66
    }
67
68
    public function SetSize($aSize)
69
    {
70
        if ($aSize < 0.1 || $aSize > 1) {
71
            Util\JpGraphError::RaiseL(18004, $aSize);
72
            //("Radar Plot size must be between 0.1 and 1. (Your value=$s)");
73
        }
74
        $this->len = min($this->img->width, $this->img->height) * $aSize / 2;
75
    }
76
77
    public function SetPlotSize($aSize)
78
    {
79
        $this->SetSize($aSize);
80
    }
81
82
    public function SetTickDensity($densy = TICKD_NORMAL, $dummy1 = null)
83
    {
84
        $this->ytick_factor = 25;
85
        switch ($densy) {
86
            case TICKD_DENSE:
87
                $this->ytick_factor = 12;
88
89
                break;
90
            case TICKD_NORMAL:
91
                $this->ytick_factor = 25;
92
93
                break;
94
            case TICKD_SPARSE:
95
                $this->ytick_factor = 40;
96
97
                break;
98
            case TICKD_VERYSPARSE:
99
                $this->ytick_factor = 70;
100
101
                break;
102
            default:
103
                Util\JpGraphError::RaiseL(18005, $densy);
104
                //("RadarPlot Unsupported Tick density: $densy");
105
        }
106
    }
107
108
    public function SetPos($px, $py = 0.5)
109
    {
110
        $this->SetCenter($px, $py);
111
    }
112
113
    public function SetCenter($px, $py = 0.5)
114
    {
115
        if ($px >= 0 && $px <= 1) {
116
            $this->posx = $this->img->width * $px;
117
        } else {
118
            $this->posx = $px;
119
        }
120
        if ($py >= 0 && $py <= 1) {
121
            $this->posy = $this->img->height * $py;
122
        } else {
123
            $this->posy = $py;
124
        }
125
    }
126
127
    public function SetColor($aColor)
128
    {
129
        $this->SetMarginColor($aColor);
130
    }
131
132
    public function SetTitles($aTitleArray)
133
    {
134
        $this->axis_title = $aTitleArray;
135
    }
136
137
    public function Add($aPlot)
138
    {
139
        if ($aPlot == null) {
140
            Util\JpGraphError::RaiseL(25010); //("Graph::Add() You tried to add a null plot to the graph.");
141
        }
142
        if (is_array($aPlot) && safe_count($aPlot) > 0) {
143
            $cl = $aPlot[0];
144
        } else {
145
            $cl = $aPlot;
146
        }
147
148
        if ($cl instanceof Text\Text) {
149
            $this->AddText($aPlot);
150
        } elseif (($cl instanceof Plot\IconPlot)) {
151
            $this->AddIcon($aPlot);
152
        } else {
153
            $this->plots[] = $aPlot;
154
        }
155
    }
156
157
    public function GetPlotsYMinMax($aPlots)
158
    {
159
        $min = $aPlots[0]->Min();
160
        $max = $aPlots[0]->Max();
161
        foreach ($this->plots as $p) {
162
            $max = max($max, $p->Max());
163
            $min = min($min, $p->Min());
164
        }
165
        if ($min < 0) {
166
            Util\JpGraphError::RaiseL(18006, $min);
167
            //("Minimum data $min (Radar plots should only be used when all data points > 0)");
168
        }
169
170
        return [$min, $max];
171
    }
172
173
    public function StrokeIcons()
174
    {
175
        if ($this->iIcons != null) {
176
            $n = safe_count($this->iIcons);
177
            for ($i = 0; $i < $n; ++$i) {
178
                $this->iIcons[$i]->Stroke($this->img);
179
            }
180
        }
181
    }
182
183
    public function StrokeTexts()
184
    {
185
        if ($this->texts != null) {
186
            $n = safe_count($this->texts);
187
            for ($i = 0; $i < $n; ++$i) {
188
                $this->texts[$i]->Stroke($this->img);
189
            }
190
        }
191
    }
192
193
    // Stroke the Radar graph
194
    public function Stroke($aStrokeFileName = '')
195
    {
196
        // If the filename is the predefined value = '_csim_special_'
197
        // we assume that the call to stroke only needs to do enough
198
        // to correctly generate the CSIM maps.
199
        // We use this variable to skip things we don't strictly need
200
        // to do to generate the image map to improve performance
201
        // a best we can. Therefor you will see a lot of tests !$_csim in the
202
        // code below.
203
        $_csim = ($aStrokeFileName === _CSIM_SPECIALFILE);
204
205
        // We need to know if we have stroked the plot in the
206
        // GetCSIMareas. Otherwise the CSIM hasn't been generated
207
        // and in the case of GetCSIM called before stroke to generate
208
        // CSIM without storing an image to disk GetCSIM must call Stroke.
209
        $this->iHasStroked = true;
210
211
        $n = safe_count($this->plots);
212
        // Set Y-scale
213
214
        if (!$this->yscale->IsSpecified() && safe_count($this->plots) > 0) {
215
            list($min, $max) = $this->GetPlotsYMinMax($this->plots);
216
            $this->yscale->AutoScale($this->img, 0, $max, $this->len / $this->ytick_factor);
217
        } elseif ($this->yscale->IsSpecified() &&
218
            ($this->yscale->auto_ticks || !$this->yscale->ticks->IsSpecified())) {
219
            // The tick calculation will use the user suplied min/max values to determine
220
            // the ticks. If auto_ticks is false the exact user specifed min and max
221
            // values will be used for the scale.
222
            // If auto_ticks is true then the scale might be slightly adjusted
223
            // so that the min and max values falls on an even major step.
224
            $min = $this->yscale->scale[0];
225
            $max = $this->yscale->scale[1];
226
            $this->yscale->AutoScale(
227
                $this->img,
228
                $min,
229
                $max,
230
                $this->len / $this->ytick_factor,
231
                $this->yscale->auto_ticks
232
            );
233
        }
234
235
        // Set start position end length of scale (in absolute pixels)
236
        $this->yscale->SetConstants($this->posx, $this->len);
237
238
        // We need as many axis as there are data points
239
        $nbrpnts = $this->plots[0]->GetCount();
240
241
        // If we have no titles just number the axis 1,2,3,...
242
        if ($this->axis_title == null) {
243
            for ($i = 0; $i < $nbrpnts; ++$i) {
244
                $this->axis_title[$i] = $i + 1;
245
            }
246
        } elseif (safe_count($this->axis_title) < $nbrpnts) {
247
            Util\JpGraphError::RaiseL(18007);
248
            // ("Number of titles does not match number of points in plot.");
249
        }
250
        for ($i = 0; $i < $n; ++$i) {
251
            if ($nbrpnts != $this->plots[$i]->GetCount()) {
252
                Util\JpGraphError::RaiseL(18008);
253
                //("Each radar plot must have the same number of data points.");
254
            }
255
        }
256
257
        if (!$_csim) {
258
            if ($this->background_image != '') {
259
                $this->StrokeFrameBackground();
260
            } else {
261
                $this->StrokeFrame();
262
                $this->StrokeBackgroundGrad();
263
            }
264
        }
265
        $astep = 2 * M_PI / $nbrpnts;
266
267
        if (!$_csim) {
268
            if ($this->iIconDepth == DEPTH_BACK) {
269
                $this->StrokeIcons();
270
            }
271
272
            // Prepare legends
273
            for ($i = 0; $i < $n; ++$i) {
274
                $this->plots[$i]->Legend($this);
275
            }
276
            $this->legend->Stroke($this->img);
277
            $this->footer->Stroke($this->img);
278
        }
279
280
        if (!$_csim) {
281
            if ($this->grid_depth == DEPTH_BACK) {
282
                // Draw axis and grid
283
                for ($i = 0, $a = M_PI / 2; $i < $nbrpnts; ++$i, $a += $astep) {
284
                    $this->axis->Stroke($this->posy, $a, $grid[$i], $this->axis_title[$i], $i == 0);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $grid seems to be never defined.
Loading history...
285
                }
286
                $this->grid->Stroke($this->img, $grid);
287
            }
288
            if ($this->iIconDepth == DEPTH_BACK) {
289
                $this->StrokeIcons();
290
            }
291
        }
292
293
        // Plot points
294
        $a = M_PI / 2;
295
        for ($i = 0; $i < $n; ++$i) {
296
            $this->plots[$i]->Stroke($this->img, $this->posy, $this->yscale, $a);
297
        }
298
299
        if (!$_csim) {
300
            if ($this->grid_depth != DEPTH_BACK) {
301
                // Draw axis and grid
302
                for ($i = 0, $a = M_PI / 2; $i < $nbrpnts; ++$i, $a += $astep) {
303
                    $this->axis->Stroke($this->posy, $a, $grid[$i], $this->axis_title[$i], $i == 0);
304
                }
305
                $this->grid->Stroke($this->img, $grid);
306
            }
307
308
            $this->StrokeTitles();
309
            $this->StrokeTexts();
310
            if ($this->iIconDepth == DEPTH_FRONT) {
311
                $this->StrokeIcons();
312
            }
313
        }
314
315
        // Should we do any final image transformation
316
        if ($this->iImgTrans && !$_csim) {
317
            $tform          = new Image\ImgTrans($this->img->img);
318
            $this->img->img = $tform->Skew3D(
319
                $this->iImgTransHorizon,
320
                $this->iImgTransSkewDist,
321
                $this->iImgTransDirection,
322
                $this->iImgTransHighQ,
323
                $this->iImgTransMinSize,
324
                $this->iImgTransFillColor,
325
                $this->iImgTransBorder
326
            );
327
        }
328
329
        if (!$_csim) {
330
            // If the filename is given as the special "__handle"
331
            // then the image handler is returned and the image is NOT
332
            // streamed back
333
            if ($aStrokeFileName == _IMG_HANDLER) {
334
                return $this->img->img;
335
            }
336
            // Finally stream the generated picture
337
            $this->cache->PutAndStream($this->img, $this->cache_name, $this->inline, $aStrokeFileName);
338
        }
339
    }
340
} // @class
341