1 | <?php |
||
2 | |||
3 | /** |
||
4 | * JPGraph v4.0.3 |
||
5 | */ |
||
6 | |||
7 | namespace Amenadiel\JpGraph\Graph; |
||
8 | |||
9 | use Amenadiel\JpGraph\Text; |
||
10 | use Amenadiel\JpGraph\Util; |
||
11 | |||
12 | /** |
||
13 | * @class PolarAxis |
||
14 | */ |
||
15 | class PolarAxis extends Axis |
||
16 | { |
||
17 | private $angle_step = 15; |
||
18 | private $angle_color = 'lightgray'; |
||
19 | private $angle_label_color = 'black'; |
||
0 ignored issues
–
show
introduced
by
![]() |
|||
20 | private $angle_fontfam = FF_FONT1; |
||
21 | private $angle_fontstyle = FS_NORMAL; |
||
22 | private $angle_fontsize = 10; |
||
23 | private $angle_fontcolor = 'navy'; |
||
24 | private $gridminor_color = 'lightgray'; |
||
25 | private $gridmajor_color = 'lightgray'; |
||
26 | private $show_minor_grid = false; |
||
27 | private $show_major_grid = true; |
||
28 | private $show_angle_mark = true; |
||
29 | private $show_angle_grid = true; |
||
30 | private $show_angle_label = true; |
||
31 | private $angle_tick_len = 3; |
||
32 | private $angle_tick_len2 = 3; |
||
33 | private $angle_tick_color = 'black'; |
||
34 | private $show_angle_tick = true; |
||
35 | private $radius_tick_color = 'black'; |
||
36 | |||
37 | public function __construct($img, $aScale) |
||
38 | { |
||
39 | parent::__construct($img, $aScale); |
||
40 | } |
||
41 | |||
42 | public function ShowAngleDegreeMark($aFlg = true) |
||
43 | { |
||
44 | $this->show_angle_mark = $aFlg; |
||
45 | } |
||
46 | |||
47 | public function SetAngleStep($aStep) |
||
48 | { |
||
49 | $this->angle_step = $aStep; |
||
50 | } |
||
51 | |||
52 | public function HideTicks($aFlg = true, $aAngleFlg = true) |
||
53 | { |
||
54 | parent::HideTicks($aFlg, $aFlg); |
||
55 | $this->show_angle_tick = !$aAngleFlg; |
||
56 | } |
||
57 | |||
58 | public function ShowAngleLabel($aFlg = true) |
||
59 | { |
||
60 | $this->show_angle_label = $aFlg; |
||
61 | } |
||
62 | |||
63 | public function ShowGrid($aMajor = true, $aMinor = false, $aAngle = true) |
||
64 | { |
||
65 | $this->show_minor_grid = $aMinor; |
||
66 | $this->show_major_grid = $aMajor; |
||
67 | $this->show_angle_grid = $aAngle; |
||
68 | } |
||
69 | |||
70 | public function SetAngleFont($aFontFam, $aFontStyle = FS_NORMAL, $aFontSize = 10) |
||
71 | { |
||
72 | $this->angle_fontfam = $aFontFam; |
||
73 | $this->angle_fontstyle = $aFontStyle; |
||
74 | $this->angle_fontsize = $aFontSize; |
||
75 | } |
||
76 | |||
77 | public function SetColor($aColor, $aRadColor = '', $aAngleColor = '') |
||
78 | { |
||
79 | if ($aAngleColor == '') { |
||
80 | $aAngleColor = $aColor; |
||
81 | } |
||
82 | |||
83 | parent::SetColor($aColor, $aRadColor); |
||
84 | $this->angle_fontcolor = $aAngleColor; |
||
85 | } |
||
86 | |||
87 | public function SetGridColor($aMajorColor, $aMinorColor = '', $aAngleColor = '') |
||
88 | { |
||
89 | if ($aMinorColor == '') { |
||
90 | $aMinorColor = $aMajorColor; |
||
91 | } |
||
92 | |||
93 | if ($aAngleColor == '') { |
||
94 | $aAngleColor = $aMajorColor; |
||
95 | } |
||
96 | |||
97 | $this->gridminor_color = $aMinorColor; |
||
98 | $this->gridmajor_color = $aMajorColor; |
||
99 | $this->angle_color = $aAngleColor; |
||
100 | } |
||
101 | |||
102 | public function SetTickColors($aRadColor, $aAngleColor = '') |
||
103 | { |
||
104 | $this->radius_tick_color = $aRadColor; |
||
105 | $this->angle_tick_color = $aAngleColor; |
||
106 | } |
||
107 | |||
108 | // Private methods |
||
109 | public function StrokeGrid($pos) |
||
110 | { |
||
111 | $x = round($this->img->left_margin + $this->img->plotwidth / 2); |
||
112 | $this->scale->ticks->Stroke($this->img, $this->scale, $pos); |
||
113 | |||
114 | // Stroke the minor arcs |
||
115 | $pmin = []; |
||
116 | $p = $this->scale->ticks->ticks_pos; |
||
117 | $n = safe_count($p); |
||
118 | $i = 0; |
||
119 | $this->img->SetColor($this->gridminor_color); |
||
120 | while ($i < $n) { |
||
121 | $r = $p[$i] - $x + 1; |
||
122 | $pmin[] = $r; |
||
123 | if ($this->show_minor_grid) { |
||
124 | $this->img->Circle($x, $pos, $r); |
||
125 | } |
||
126 | ++$i; |
||
127 | } |
||
128 | |||
129 | $limit = max($this->img->plotwidth, $this->img->plotheight) * 1.4; |
||
130 | while ($r < $limit) { |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
|
|||
131 | $off = $r; |
||
132 | $i = 1; |
||
133 | $r = $off + round($p[$i] - $x + 1); |
||
134 | while ($r < $limit && $i < $n) { |
||
135 | $r = $off + $p[$i] - $x; |
||
136 | $pmin[] = $r; |
||
137 | if ($this->show_minor_grid) { |
||
138 | $this->img->Circle($x, $pos, $r); |
||
139 | } |
||
140 | ++$i; |
||
141 | } |
||
142 | } |
||
143 | |||
144 | // Stroke the major arcs |
||
145 | if ($this->show_major_grid) { |
||
146 | // First determine how many minor step on |
||
147 | // every major step. We have recorded the minor radius |
||
148 | // in pmin and use these values. This is done in order |
||
149 | // to avoid rounding errors if we were to recalculate the |
||
150 | // different major radius. |
||
151 | $pmaj = $this->scale->ticks->maj_ticks_pos; |
||
152 | $p = $this->scale->ticks->ticks_pos; |
||
153 | if ($this->scale->name == 'lin') { |
||
154 | $step = round(($pmaj[1] - $pmaj[0]) / ($p[1] - $p[0])); |
||
155 | } else { |
||
156 | $step = 9; |
||
157 | } |
||
158 | $n = round(safe_count($pmin) / $step); |
||
159 | $i = 0; |
||
0 ignored issues
–
show
|
|||
160 | $this->img->SetColor($this->gridmajor_color); |
||
161 | $limit = max($this->img->plotwidth, $this->img->plotheight) * 1.4; |
||
162 | $off = $r; |
||
0 ignored issues
–
show
|
|||
163 | $i = 0; |
||
164 | $r = $pmin[$i * $step]; |
||
165 | while ($r < $limit && $i < $n) { |
||
166 | $r = $pmin[$i * $step]; |
||
167 | $this->img->Circle($x, $pos, $r); |
||
168 | ++$i; |
||
169 | } |
||
170 | } |
||
171 | |||
172 | // Draw angles |
||
173 | if ($this->show_angle_grid) { |
||
174 | $this->img->SetColor($this->angle_color); |
||
175 | $d = max($this->img->plotheight, $this->img->plotwidth) * 1.4; |
||
176 | $a = 0; |
||
177 | $p = $this->scale->ticks->ticks_pos; |
||
178 | $start_radius = $p[1] - $x; |
||
179 | while ($a < 360) { |
||
180 | if ($a == 90 || $a == 270) { |
||
181 | // Make sure there are no rounding problem with |
||
182 | // exactly vertical lines |
||
183 | $this->img->Line( |
||
184 | $x + $start_radius * cos($a / 180 * M_PI) + 1, |
||
185 | $pos - $start_radius * sin($a / 180 * M_PI), |
||
186 | $x + $start_radius * cos($a / 180 * M_PI) + 1, |
||
187 | $pos - $d * sin($a / 180 * M_PI) |
||
188 | ); |
||
189 | } else { |
||
190 | $this->img->Line( |
||
191 | $x + $start_radius * cos($a / 180 * M_PI) + 1, |
||
192 | $pos - $start_radius * sin($a / 180 * M_PI), |
||
193 | $x + $d * cos($a / 180 * M_PI), |
||
194 | $pos - $d * sin($a / 180 * M_PI) |
||
195 | ); |
||
196 | } |
||
197 | $a += $this->angle_step; |
||
198 | } |
||
199 | } |
||
200 | } |
||
201 | |||
202 | public function StrokeAngleLabels($pos, $type) |
||
203 | { |
||
204 | if (!$this->show_angle_label) { |
||
205 | return; |
||
206 | } |
||
207 | |||
208 | $x0 = round($this->img->left_margin + $this->img->plotwidth / 2) + 1; |
||
209 | |||
210 | $d = max($this->img->plotwidth, $this->img->plotheight) * 1.42; |
||
211 | $a = $this->angle_step; |
||
212 | $t = new Text\Text(); |
||
213 | $t->SetColor($this->angle_fontcolor); |
||
214 | $t->SetFont($this->angle_fontfam, $this->angle_fontstyle, $this->angle_fontsize); |
||
215 | $xright = $this->img->width - $this->img->right_margin; |
||
216 | $ytop = $this->img->top_margin; |
||
217 | $xleft = $this->img->left_margin; |
||
218 | $ybottom = $this->img->height - $this->img->bottom_margin; |
||
219 | $ha = 'left'; |
||
220 | $va = 'center'; |
||
221 | $w = $this->img->plotwidth / 2; |
||
222 | $h = $this->img->plotheight / 2; |
||
223 | $xt = $x0; |
||
224 | $yt = $pos; |
||
225 | $margin = 5; |
||
226 | |||
227 | $tl = $this->angle_tick_len; // Outer len |
||
228 | $tl2 = $this->angle_tick_len2; // Interior len |
||
229 | |||
230 | $this->img->SetColor($this->angle_tick_color); |
||
231 | $rot90 = $this->img->a == 90; |
||
232 | |||
233 | if ($type == POLAR_360) { |
||
234 | // Corner angles of the four corners |
||
235 | $ca1 = atan($h / $w) / M_PI * 180; |
||
236 | $ca2 = 180 - $ca1; |
||
237 | $ca3 = $ca1 + 180; |
||
238 | $ca4 = 360 - $ca1; |
||
239 | $end = 360; |
||
240 | |||
241 | while ($a < $end) { |
||
242 | $ca = cos($a / 180 * M_PI); |
||
243 | $sa = sin($a / 180 * M_PI); |
||
244 | $x = $d * $ca; |
||
245 | $y = $d * $sa; |
||
246 | $xt = 1000; |
||
247 | $yt = 1000; |
||
248 | if ($a <= $ca1 || $a >= $ca4) { |
||
249 | $yt = $pos - $w * $y / $x; |
||
250 | $xt = $xright + $margin; |
||
251 | if ($rot90) { |
||
252 | $ha = 'center'; |
||
253 | $va = 'top'; |
||
254 | } else { |
||
255 | $ha = 'left'; |
||
256 | $va = 'center'; |
||
257 | } |
||
258 | $x1 = $xright - $tl2; |
||
259 | $x2 = $xright + $tl; |
||
260 | $y1 = $y2 = $yt; |
||
261 | } elseif ($a > $ca1 && $a < $ca2) { |
||
262 | $xt = $x0 + $h * $x / $y; |
||
263 | $yt = $ytop - $margin; |
||
264 | if ($rot90) { |
||
265 | $ha = 'left'; |
||
266 | $va = 'center'; |
||
267 | } else { |
||
268 | $ha = 'center'; |
||
269 | $va = 'bottom'; |
||
270 | } |
||
271 | $y1 = $ytop + $tl2; |
||
272 | $y2 = $ytop - $tl; |
||
273 | $x1 = $x2 = $xt; |
||
274 | } elseif ($a >= $ca2 && $a <= $ca3) { |
||
275 | $yt = $pos + $w * $y / $x; |
||
276 | $xt = $xleft - $margin; |
||
277 | if ($rot90) { |
||
278 | $ha = 'center'; |
||
279 | $va = 'bottom'; |
||
280 | } else { |
||
281 | $ha = 'right'; |
||
282 | $va = 'center'; |
||
283 | } |
||
284 | $x1 = $xleft + $tl2; |
||
285 | $x2 = $xleft - $tl; |
||
286 | $y1 = $y2 = $yt; |
||
287 | } else { |
||
288 | $xt = $x0 - $h * $x / $y; |
||
289 | $yt = $ybottom + $margin; |
||
290 | if ($rot90) { |
||
291 | $ha = 'right'; |
||
292 | $va = 'center'; |
||
293 | } else { |
||
294 | $ha = 'center'; |
||
295 | $va = 'top'; |
||
296 | } |
||
297 | $y1 = $ybottom - $tl2; |
||
298 | $y2 = $ybottom + $tl; |
||
299 | $x1 = $x2 = $xt; |
||
300 | } |
||
301 | if ($a != 0 && $a != 180) { |
||
302 | $t->Align($ha, $va); |
||
303 | if ($this->scale->clockwise) { |
||
304 | $t->Set(360 - $a); |
||
305 | } else { |
||
306 | $t->Set($a); |
||
307 | } |
||
308 | if ($this->show_angle_mark && $t->font_family > 4) { |
||
309 | $a .= SymChar::Get('degree'); |
||
310 | } |
||
311 | $t->Stroke($this->img, $xt, $yt); |
||
312 | if ($this->show_angle_tick) { |
||
313 | $this->img->Line($x1, $y1, $x2, $y2); |
||
314 | } |
||
315 | } |
||
316 | $a += $this->angle_step; |
||
317 | } |
||
318 | } else { |
||
319 | // POLAR_HALF |
||
320 | $ca1 = atan($h / $w * 2) / M_PI * 180; |
||
321 | $ca2 = 180 - $ca1; |
||
322 | $end = 180; |
||
323 | while ($a < $end) { |
||
324 | $ca = cos($a / 180 * M_PI); |
||
325 | $sa = sin($a / 180 * M_PI); |
||
326 | $x = $d * $ca; |
||
327 | $y = $d * $sa; |
||
328 | if ($a <= $ca1) { |
||
329 | $yt = $pos - $w * $y / $x; |
||
330 | $xt = $xright + $margin; |
||
331 | if ($rot90) { |
||
332 | $ha = 'center'; |
||
333 | $va = 'top'; |
||
334 | } else { |
||
335 | $ha = 'left'; |
||
336 | $va = 'center'; |
||
337 | } |
||
338 | $x1 = $xright - $tl2; |
||
339 | $x2 = $xright + $tl; |
||
340 | $y1 = $y2 = $yt; |
||
341 | } elseif ($a > $ca1 && $a < $ca2) { |
||
342 | $xt = $x0 + 2 * $h * $x / $y; |
||
343 | $yt = $ytop - $margin; |
||
344 | if ($rot90) { |
||
345 | $ha = 'left'; |
||
346 | $va = 'center'; |
||
347 | } else { |
||
348 | $ha = 'center'; |
||
349 | $va = 'bottom'; |
||
350 | } |
||
351 | $y1 = $ytop + $tl2; |
||
352 | $y2 = $ytop - $tl; |
||
353 | $x1 = $x2 = $xt; |
||
354 | } elseif ($a >= $ca2) { |
||
355 | $yt = $pos + $w * $y / $x; |
||
356 | $xt = $xleft - $margin; |
||
357 | if ($rot90) { |
||
358 | $ha = 'center'; |
||
359 | $va = 'bottom'; |
||
360 | } else { |
||
361 | $ha = 'right'; |
||
362 | $va = 'center'; |
||
363 | } |
||
364 | $x1 = $xleft + $tl2; |
||
365 | $x2 = $xleft - $tl; |
||
366 | $y1 = $y2 = $yt; |
||
367 | } |
||
368 | $t->Align($ha, $va); |
||
369 | if ($this->show_angle_mark && $t->font_family > 4) { |
||
370 | $a .= SymChar::Get('degree'); |
||
371 | } |
||
372 | $t->Set($a); |
||
373 | $t->Stroke($this->img, $xt, $yt); |
||
374 | if ($this->show_angle_tick) { |
||
375 | $this->img->Line($x1, $y1, $x2, $y2); |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
Comprehensibility
Best Practice
introduced
by
|
|||
376 | } |
||
377 | $a += $this->angle_step; |
||
378 | } |
||
379 | } |
||
380 | } |
||
381 | |||
382 | public function Stroke($pos, $dummy = true) |
||
383 | { |
||
384 | $this->img->SetLineWeight($this->weight); |
||
385 | $this->img->SetColor($this->color); |
||
386 | $this->img->SetFont($this->font_family, $this->font_style, $this->font_size); |
||
387 | if (!$this->hide_line) { |
||
388 | $this->img->FilledRectangle( |
||
389 | $this->img->left_margin, |
||
390 | $pos, |
||
391 | $this->img->width - $this->img->right_margin, |
||
392 | $pos + $this->weight - 1 |
||
393 | ); |
||
394 | } |
||
395 | $y = $pos + $this->img->GetFontHeight() + $this->title_margin + $this->title->margin; |
||
396 | if ($this->title_adjust == 'high') { |
||
397 | $this->title->SetPos($this->img->width - $this->img->right_margin, $y, 'right', 'top'); |
||
398 | } elseif ($this->title_adjust == 'middle' || $this->title_adjust == 'center') { |
||
399 | $this->title->SetPos( |
||
400 | ($this->img->width - $this->img->left_margin - $this->img->right_margin) / 2 + $this->img->left_margin, |
||
401 | $y, |
||
402 | 'center', |
||
403 | 'top' |
||
404 | ); |
||
405 | } elseif ($this->title_adjust == 'low') { |
||
406 | $this->title->SetPos($this->img->left_margin, $y, 'left', 'top'); |
||
407 | } else { |
||
408 | Util\JpGraphError::RaiseL(17002, $this->title_adjust); |
||
409 | //('Unknown alignment specified for X-axis title. ('.$this->title_adjust.')'); |
||
410 | } |
||
411 | |||
412 | if (!$this->hide_labels) { |
||
413 | $this->StrokeLabels($pos, false); |
||
414 | } |
||
415 | $this->img->SetColor($this->radius_tick_color); |
||
416 | $this->scale->ticks->Stroke($this->img, $this->scale, $pos); |
||
417 | |||
418 | // |
||
419 | // Mirror the positions for the left side of the scale |
||
420 | // |
||
421 | $mid = 2 * ($this->img->left_margin + $this->img->plotwidth / 2); |
||
422 | $n = safe_count($this->scale->ticks->ticks_pos); |
||
423 | $i = 0; |
||
424 | while ($i < $n) { |
||
425 | $this->scale->ticks->ticks_pos[$i] = |
||
426 | $mid - $this->scale->ticks->ticks_pos[$i]; |
||
427 | ++$i; |
||
428 | } |
||
429 | |||
430 | $n = safe_count($this->scale->ticks->maj_ticks_pos); |
||
431 | $i = 0; |
||
432 | while ($i < $n) { |
||
433 | $this->scale->ticks->maj_ticks_pos[$i] = |
||
434 | $mid - $this->scale->ticks->maj_ticks_pos[$i]; |
||
435 | ++$i; |
||
436 | } |
||
437 | |||
438 | $n = safe_count($this->scale->ticks->maj_ticklabels_pos); |
||
439 | $i = 1; |
||
440 | while ($i < $n) { |
||
441 | $this->scale->ticks->maj_ticklabels_pos[$i] = |
||
442 | $mid - $this->scale->ticks->maj_ticklabels_pos[$i]; |
||
443 | ++$i; |
||
444 | } |
||
445 | |||
446 | // Draw the left side of the scale |
||
447 | $n = safe_count($this->scale->ticks->ticks_pos); |
||
448 | $yu = $pos - $this->scale->ticks->direction * $this->scale->ticks->GetMinTickAbsSize(); |
||
449 | |||
450 | // Minor ticks |
||
451 | if (!$this->scale->ticks->supress_minor_tickmarks) { |
||
452 | $i = 1; |
||
453 | while ($i < $n / 2) { |
||
454 | $x = round($this->scale->ticks->ticks_pos[$i]); |
||
455 | $this->img->Line($x, $pos, $x, $yu); |
||
456 | ++$i; |
||
457 | } |
||
458 | } |
||
459 | |||
460 | $n = safe_count($this->scale->ticks->maj_ticks_pos); |
||
461 | $yu = $pos - $this->scale->ticks->direction * $this->scale->ticks->GetMajTickAbsSize(); |
||
462 | |||
463 | // Major ticks |
||
464 | if (!$this->scale->ticks->supress_tickmarks) { |
||
465 | $i = 1; |
||
466 | while ($i < $n / 2) { |
||
467 | $x = round($this->scale->ticks->maj_ticks_pos[$i]); |
||
468 | $this->img->Line($x, $pos, $x, $yu); |
||
469 | ++$i; |
||
470 | } |
||
471 | } |
||
472 | if (!$this->hide_labels) { |
||
473 | $this->StrokeLabels($pos, false); |
||
474 | } |
||
475 | $this->title->Stroke($this->img); |
||
476 | } |
||
477 | } |
||
478 |