xref: /plugin/statdisplay/vendor/szymach/c-pchart/src/Chart/Radar.php (revision 03cdebb71906645bc452782ad23f052261c2cb18)
1<?php
2
3namespace CpChart\Chart;
4
5use CpChart\Data;
6use CpChart\Image;
7
8class Radar
9{
10    /**
11     * @var Image
12     */
13    public $pChartObject;
14
15    /**
16     * Draw a radar chart
17     * @param Image $Object
18     * @param Data $Values
19     * @param array $Format
20     */
21    public function drawRadar(Image $Object, Data $Values, array $Format = [])
22    {
23        $this->pChartObject = $Object;
24
25        $FixedMax = isset($Format["FixedMax"]) ? $Format["FixedMax"] : VOID;
26        $AxisR = isset($Format["AxisR"]) ? $Format["AxisR"] : 60;
27        $AxisG = isset($Format["AxisG"]) ? $Format["AxisG"] : 60;
28        $AxisB = isset($Format["AxisB"]) ? $Format["AxisB"] : 60;
29        $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 50;
30        $AxisRotation = isset($Format["AxisRotation"]) ? $Format["AxisRotation"] : 0;
31        $DrawTicks = isset($Format["DrawTicks"]) ? $Format["DrawTicks"] : true;
32        $TicksLength = isset($Format["TicksLength"]) ? $Format["TicksLength"] : 2;
33        $DrawAxisValues = isset($Format["DrawAxisValues"]) ? $Format["DrawAxisValues"] : true;
34        $AxisBoxRounded = isset($Format["AxisBoxRounded"]) ? $Format["AxisBoxRounded"] : true;
35        $AxisFontName = isset($Format["AxisFontName"]) ? $Format["AxisFontName"] : $this->pChartObject->FontName;
36        $AxisFontSize = isset($Format["AxisFontSize"]) ? $Format["AxisFontSize"] : $this->pChartObject->FontSize;
37        $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : false;
38        $WriteValuesInBubble = isset($Format["WriteValuesInBubble"]) ? $Format["WriteValuesInBubble"] : true;
39        $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName
40        ;
41        $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize
42        ;
43        $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 4;
44        $OuterBubbleRadius = isset($Format["OuterBubbleRadius"]) ? $Format["OuterBubbleRadius"] : 2;
45        $OuterBubbleR = isset($Format["OuterBubbleR"]) ? $Format["OuterBubbleR"] : VOID;
46        $OuterBubbleG = isset($Format["OuterBubbleG"]) ? $Format["OuterBubbleG"] : VOID;
47        $OuterBubbleB = isset($Format["OuterBubbleB"]) ? $Format["OuterBubbleB"] : VOID;
48        $OuterBubbleAlpha = isset($Format["OuterBubbleAlpha"]) ? $Format["OuterBubbleAlpha"] : 100;
49        $InnerBubbleR = isset($Format["InnerBubbleR"]) ? $Format["InnerBubbleR"] : 255;
50        $InnerBubbleG = isset($Format["InnerBubbleG"]) ? $Format["InnerBubbleG"] : 255;
51        $InnerBubbleB = isset($Format["InnerBubbleB"]) ? $Format["InnerBubbleB"] : 255;
52        $InnerBubbleAlpha = isset($Format["InnerBubbleAlpha"]) ? $Format["InnerBubbleAlpha"] : 100;
53        $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : true;
54        $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255;
55        $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255;
56        $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255;
57        $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 50;
58        $BackgroundGradient = isset($Format["BackgroundGradient"]) ? $Format["BackgroundGradient"] : null;
59        $Layout = isset($Format["Layout"]) ? $Format["Layout"] : RADAR_LAYOUT_STAR;
60        $SegmentHeight = isset($Format["SegmentHeight"]) ? $Format["SegmentHeight"] : SEGMENT_HEIGHT_AUTO;
61        $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 4;
62        $WriteLabels = isset($Format["WriteLabels"]) ? $Format["WriteLabels"] : true;
63        $SkipLabels = isset($Format["SkipLabels"]) ? $Format["SkipLabels"] : 1;
64        $LabelMiddle = isset($Format["LabelMiddle"]) ? $Format["LabelMiddle"] : false;
65        $LabelsBackground = isset($Format["LabelsBackground"]) ? $Format["LabelsBackground"] : true;
66        $LabelsBGR = isset($Format["LabelsBGR"]) ? $Format["LabelsBGR"] : 255;
67        $LabelsBGG = isset($Format["LabelsBGR"]) ? $Format["LabelsBGG"] : 255;
68        $LabelsBGB = isset($Format["LabelsBGR"]) ? $Format["LabelsBGB"] : 255;
69        $LabelsBGAlpha = isset($Format["LabelsBGAlpha"]) ? $Format["LabelsBGAlpha"] : 50;
70        $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : RADAR_LABELS_ROTATED;
71        $LabelPadding = isset($Format["LabelPadding"]) ? $Format["LabelPadding"] : 4;
72        $DrawPoints = isset($Format["DrawPoints"]) ? $Format["DrawPoints"] : true;
73        $PointRadius = isset($Format["PointRadius"]) ? $Format["PointRadius"] : 4;
74        $PointSurrounding = isset($Format["PointRadius"]) ? $Format["PointRadius"] : -30;
75        $DrawLines = isset($Format["DrawLines"]) ? $Format["DrawLines"] : true;
76        $LineLoopStart = isset($Format["LineLoopStart"]) ? $Format["LineLoopStart"] : true;
77        $DrawPoly = isset($Format["DrawPoly"]) ? $Format["DrawPoly"] : false;
78        $PolyAlpha = isset($Format["PolyAlpha"]) ? $Format["PolyAlpha"] : 40;
79        $FontSize = $Object->FontSize;
80        $X1 = $Object->GraphAreaX1;
81        $Y1 = $Object->GraphAreaY1;
82        $X2 = $Object->GraphAreaX2;
83        $Y2 = $Object->GraphAreaY2;
84        $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false;
85
86        /* Cancel default tick length if ticks not enabled */
87        if ($DrawTicks == false) {
88            $TicksLength = 0;
89        }
90
91        /* Data Processing */
92        $Data = $Values->getData();
93        $Palette = $Values->getPalette();
94
95        /* Catch the number of required axis */
96        $LabelSerie = $Data["Abscissa"];
97        if ($LabelSerie) {
98            $Points = count($Data["Series"][$LabelSerie]["Data"]);
99        } else {
100            $Points = 0;
101            foreach ($Data["Series"] as $SerieName => $DataArray) {
102                if (count($DataArray["Data"]) > $Points) {
103                    $Points = count($DataArray["Data"]);
104                }
105            }
106        }
107
108        /* Draw the axis */
109        $CenterX = ($X2 - $X1) / 2 + $X1;
110        $CenterY = ($Y2 - $Y1) / 2 + $Y1;
111
112        $EdgeHeight = min(($X2 - $X1) / 2, ($Y2 - $Y1) / 2);
113        if ($WriteLabels) {
114            $EdgeHeight = $EdgeHeight - $FontSize - $LabelPadding - $TicksLength;
115        }
116        /* Determine the scale if set to automatic */
117        if ($SegmentHeight == SEGMENT_HEIGHT_AUTO) {
118            if ($FixedMax != VOID) {
119                $Max = $FixedMax;
120            } else {
121                $Max = 0;
122                foreach ($Data["Series"] as $SerieName => $DataArray) {
123                    if ($SerieName != $LabelSerie) {
124                        if (max($DataArray["Data"]) > $Max) {
125                            $Max = max($DataArray["Data"]);
126                        }
127                    }
128                }
129            }
130            $MaxSegments = $EdgeHeight / 20;
131            $Scale = $Object->computeScale(0, $Max, $MaxSegments, [1, 2, 5]);
132
133            $Segments = $Scale["Rows"];
134            $SegmentHeight = $Scale["RowHeight"];
135        }
136
137        if ($LabelMiddle && $SkipLabels == 1) {
138            $Axisoffset = (360 / $Points) / 2;
139        } elseif ($LabelMiddle && $SkipLabels != 1) {
140            $Axisoffset = (360 / ($Points / $SkipLabels)) / 2;
141        } elseif (!$LabelMiddle) {
142            $Axisoffset = 0;
143        }
144
145        /* Background processing */
146        if ($DrawBackground) {
147            $RestoreShadow = $Object->Shadow;
148            $Object->Shadow = false;
149
150            if ($BackgroundGradient == null) {
151                if ($Layout == RADAR_LAYOUT_STAR) {
152                    $Color = [
153                        "R" => $BackgroundR,
154                        "G" => $BackgroundG,
155                        "B" => $BackgroundB,
156                        "Alpha" => $BackgroundAlpha
157                    ];
158                    $PointArray = [];
159                    for ($i = 0; $i <= 360; $i = $i + (360 / $Points)) {
160                        $PointArray[] = cos(deg2rad($i + $AxisRotation)) * $EdgeHeight + $CenterX;
161                        $PointArray[] = sin(deg2rad($i + $AxisRotation)) * $EdgeHeight + $CenterY;
162                    }
163                    $Object->drawPolygon($PointArray, $Color);
164                } elseif ($Layout == RADAR_LAYOUT_CIRCLE) {
165                    $Color = [
166                        "R" => $BackgroundR,
167                        "G" => $BackgroundG,
168                        "B" => $BackgroundB,
169                        "Alpha" => $BackgroundAlpha
170                    ];
171                    $Object->drawFilledCircle(
172                        $CenterX,
173                        $CenterY,
174                        $EdgeHeight,
175                        $Color
176                    );
177                }
178            } else {
179                $GradientROffset = ($BackgroundGradient["EndR"] - $BackgroundGradient["StartR"]) / $Segments;
180                $GradientGOffset = ($BackgroundGradient["EndG"] - $BackgroundGradient["StartG"]) / $Segments;
181                $GradientBOffset = ($BackgroundGradient["EndB"] - $BackgroundGradient["StartB"]) / $Segments;
182                $GradientAlphaOffset = ($BackgroundGradient["EndAlpha"] - $BackgroundGradient["StartAlpha"])
183                    / $Segments
184                ;
185
186                if ($Layout == RADAR_LAYOUT_STAR) {
187                    for ($j = $Segments; $j >= 1; $j--) {
188                        $Color = [
189                            "R" => $BackgroundGradient["StartR"] + $GradientROffset * $j,
190                            "G" => $BackgroundGradient["StartG"] + $GradientGOffset * $j,
191                            "B" => $BackgroundGradient["StartB"] + $GradientBOffset * $j,
192                            "Alpha" => $BackgroundGradient["StartAlpha"] + $GradientAlphaOffset * $j
193                        ];
194                        $PointArray = [];
195
196                        for ($i = 0; $i <= 360; $i = $i + (360 / $Points)) {
197                            $PointArray[] = cos(deg2rad($i + $AxisRotation))
198                                * ($EdgeHeight / $Segments) * $j + $CenterX
199                            ;
200                            $PointArray[] = sin(deg2rad($i + $AxisRotation))
201                                * ($EdgeHeight / $Segments) * $j + $CenterY
202                            ;
203                        }
204                        $Object->drawPolygon($PointArray, $Color);
205                    }
206                } elseif ($Layout == RADAR_LAYOUT_CIRCLE) {
207                    for ($j = $Segments; $j >= 1; $j--) {
208                        $Color = [
209                            "R" => $BackgroundGradient["StartR"] + $GradientROffset * $j,
210                            "G" => $BackgroundGradient["StartG"] + $GradientGOffset * $j,
211                            "B" => $BackgroundGradient["StartB"] + $GradientBOffset * $j,
212                            "Alpha" => $BackgroundGradient["StartAlpha"] + $GradientAlphaOffset * $j
213                        ];
214                        $Object->drawFilledCircle(
215                            $CenterX,
216                            $CenterY,
217                            ($EdgeHeight / $Segments) * $j,
218                            $Color
219                        );
220                    }
221                }
222            }
223            $Object->Shadow = $RestoreShadow;
224        }
225
226        /* Axis to axis lines */
227        $Color = ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha];
228        $ColorDotted = [
229            "R" => $AxisR,
230            "G" => $AxisG,
231            "B" => $AxisB,
232            "Alpha" => $AxisAlpha * .8,
233            "Ticks" => 2
234        ];
235        if ($Layout == RADAR_LAYOUT_STAR) {
236            for ($j = 1; $j <= $Segments; $j++) {
237                for ($i = 0; $i < 360; $i = $i + (360 / $Points)) {
238                    $EdgeX1 = cos(deg2rad($i + $AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterX;
239                    $EdgeY1 = sin(deg2rad($i + $AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterY;
240                    $EdgeX2 = cos(deg2rad($i + $AxisRotation + (360 / $Points)))
241                        * ($EdgeHeight / $Segments) * $j + $CenterX
242                    ;
243                    $EdgeY2 = sin(deg2rad($i + $AxisRotation + (360 / $Points)))
244                        * ($EdgeHeight / $Segments) * $j + $CenterY
245                    ;
246
247                    $Object->drawLine($EdgeX1, $EdgeY1, $EdgeX2, $EdgeY2, $Color);
248                }
249            }
250        } elseif ($Layout == RADAR_LAYOUT_CIRCLE) {
251            for ($j = 1; $j <= $Segments; $j++) {
252                $Radius = ($EdgeHeight / $Segments) * $j;
253                $Object->drawCircle($CenterX, $CenterY, $Radius, $Radius, $Color);
254            }
255        }
256
257        if ($DrawAxisValues) {
258            if ($LabelsBackground) {
259                $Options = [
260                    "DrawBox"  => true,
261                    "Align"  => TEXT_ALIGN_MIDDLEMIDDLE,
262                    "BoxR" => $LabelsBGR,
263                    "BoxG" => $LabelsBGG,
264                    "BoxB" => $LabelsBGB,
265                    "BoxAlpha" => $LabelsBGAlpha
266                ];
267            } else {
268                $Options = ["Align" => TEXT_ALIGN_MIDDLEMIDDLE];
269            }
270            if ($AxisBoxRounded) {
271                $Options["BoxRounded"] = true;
272            }
273
274            $Options["FontName"] = $AxisFontName;
275            $Options["FontSize"] = $AxisFontSize;
276
277            $Angle = 360 / ($Points * 2);
278            for ($j = 1; $j <= $Segments; $j++) {
279                $Label = $j * $SegmentHeight;
280
281                if ($Layout == RADAR_LAYOUT_CIRCLE) {
282                    $EdgeX1 = cos(deg2rad($Angle + $AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterX;
283                    $EdgeY1 = sin(deg2rad($Angle + $AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterY;
284                } elseif ($Layout == RADAR_LAYOUT_STAR) {
285                    $EdgeX1 = cos(deg2rad($AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterX;
286                    $EdgeY1 = sin(deg2rad($AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterY;
287                    $EdgeX2 = cos(deg2rad((360 / $Points) + $AxisRotation)) * ($EdgeHeight / $Segments)
288                        * $j + $CenterX
289                    ;
290                    $EdgeY2 = sin(deg2rad((360 / $Points) + $AxisRotation)) * ($EdgeHeight / $Segments)
291                        * $j + $CenterY
292                    ;
293
294                    $EdgeX1 = ($EdgeX2 - $EdgeX1) / 2 + $EdgeX1;
295                    $EdgeY1 = ($EdgeY2 - $EdgeY1) / 2 + $EdgeY1;
296                }
297
298                $Object->drawText($EdgeX1, $EdgeY1, $Label, $Options);
299            }
300        }
301
302        /* Axis lines */
303        $ID = 0;
304        for ($i = 0; $i < 360; $i = $i + (360 / $Points)) {
305            $EdgeX = cos(deg2rad($i + $AxisRotation)) * ($EdgeHeight + $TicksLength) + $CenterX;
306            $EdgeY = sin(deg2rad($i + $AxisRotation)) * ($EdgeHeight + $TicksLength) + $CenterY;
307
308            if ($ID % $SkipLabels == 0) {
309                $Object->drawLine($CenterX, $CenterY, $EdgeX, $EdgeY, $Color);
310            } else {
311                $Object->drawLine($CenterX, $CenterY, $EdgeX, $EdgeY, $ColorDotted);
312            }
313
314            if ($WriteLabels) {
315                $LabelX = cos(deg2rad($i + $AxisRotation + $Axisoffset))
316                    * ($EdgeHeight + $LabelPadding + $TicksLength) + $CenterX
317                ;
318                $LabelY = sin(deg2rad($i + $AxisRotation + $Axisoffset))
319                    * ($EdgeHeight + $LabelPadding + $TicksLength) + $CenterY
320                ;
321
322                if ($LabelSerie) {
323                    $Label = isset($Data["Series"][$LabelSerie]["Data"][$ID])
324                        ? $Data["Series"][$LabelSerie]["Data"][$ID] : ""
325                    ;
326                } else {
327                    $Label = $ID;
328                }
329
330                if ($ID % $SkipLabels == 0) {
331                    if ($LabelPos == RADAR_LABELS_ROTATED) {
332                        $Object->drawText(
333                            $LabelX,
334                            $LabelY,
335                            $Label,
336                            [
337                                "Angle" => (360 - ($i + $AxisRotation + $Axisoffset)) - 90,
338                                "Align" => TEXT_ALIGN_BOTTOMMIDDLE
339                            ]
340                        );
341                    } else {
342                        if ((floor($LabelX) == floor($CenterX)) && (floor($LabelY) < floor($CenterY))) {
343                            $Object->drawText(
344                                $LabelX,
345                                $LabelY,
346                                $Label,
347                                ["Align" => TEXT_ALIGN_BOTTOMMIDDLE]
348                            );
349                        }
350                        if ((floor($LabelX) > floor($CenterX)) && (floor($LabelY) < floor($CenterY))) {
351                            $Object->drawText(
352                                $LabelX,
353                                $LabelY,
354                                $Label,
355                                ["Align" => TEXT_ALIGN_BOTTOMLEFT]
356                            );
357                        }
358                        if ((floor($LabelX) > floor($CenterX)) && (floor($LabelY) == floor($CenterY))) {
359                            $Object->drawText(
360                                $LabelX,
361                                $LabelY,
362                                $Label,
363                                ["Align" => TEXT_ALIGN_MIDDLELEFT]
364                            );
365                        }
366                        if ((floor($LabelX) > floor($CenterX)) && (floor($LabelY) > floor($CenterY))) {
367                            $Object->drawText(
368                                $LabelX,
369                                $LabelY,
370                                $Label,
371                                ["Align" => TEXT_ALIGN_TOPLEFT]
372                            );
373                        }
374                        if ((floor($LabelX) < floor($CenterX)) && (floor($LabelY) < floor($CenterY))) {
375                            $Object->drawText(
376                                $LabelX,
377                                $LabelY,
378                                $Label,
379                                ["Align" => TEXT_ALIGN_BOTTOMRIGHT]
380                            );
381                        }
382                        if ((floor($LabelX) < floor($CenterX)) && (floor($LabelY) == floor($CenterY))) {
383                            $Object->drawText(
384                                $LabelX,
385                                $LabelY,
386                                $Label,
387                                ["Align" => TEXT_ALIGN_MIDDLERIGHT]
388                            );
389                        }
390                        if ((floor($LabelX) < floor($CenterX)) && (floor($LabelY) > floor($CenterY))) {
391                            $Object->drawText(
392                                $LabelX,
393                                $LabelY,
394                                $Label,
395                                ["Align" => TEXT_ALIGN_TOPRIGHT]
396                            );
397                        }
398                        if ((floor($LabelX) == floor($CenterX)) && (floor($LabelY) > floor($CenterY))) {
399                            $Object->drawText(
400                                $LabelX,
401                                $LabelY,
402                                $Label,
403                                ["Align" => TEXT_ALIGN_TOPMIDDLE]
404                            );
405                        }
406                    }
407                }
408            }
409            $ID++;
410        }
411
412        /* Compute the plots position */
413        $ID = 0;
414        $Plot = [];
415        foreach ($Data["Series"] as $SerieName => $DataS) {
416            if ($SerieName != $LabelSerie) {
417                $Series[$ID] = &$Data["Series"][$SerieName]; // Map $ID to series to allow customisation
418                $Color = [
419                    "R" => $Palette[$ID]["R"],
420                    "G" => $Palette[$ID]["G"],
421                    "B" => $Palette[$ID]["B"],
422                    "Alpha" => $Palette[$ID]["Alpha"],
423                    "Surrounding" => $PointSurrounding
424                ];
425                foreach ($DataS["Data"] as $Key => $Value) {
426                    $Angle = (360 / $Points) * $Key;
427                    $Length = ($EdgeHeight / ($Segments * $SegmentHeight)) * $Value;
428
429                    $X = cos(deg2rad($Angle + $AxisRotation)) * $Length + $CenterX;
430                    $Y = sin(deg2rad($Angle + $AxisRotation)) * $Length + $CenterY;
431
432                    $Plot[$ID][] = [$X, $Y, $Value];
433
434                    if ($RecordImageMap) {
435                        $this->pChartObject->addToImageMap(
436                            "CIRCLE",
437                            sprintf("%s,%s,%s", floor($X), floor($Y), floor($PointRadius)),
438                            $this->pChartObject->toHTMLColor(
439                                $Palette[$ID]["R"],
440                                $Palette[$ID]["G"],
441                                $Palette[$ID]["B"]
442                            ),
443                            $DataS["Description"],
444                            $Data["Series"][$LabelSerie]["Data"][$Key] . " = " . $Value
445                        );
446                    }
447                }
448                $ID++;
449            }
450        }
451
452        /* Draw all that stuff! */
453        foreach ($Plot as $ID => $Points) {
454            $Color = [
455                "R" => $Palette[$ID]["R"],
456                "G" => $Palette[$ID]["G"],
457                "B" => $Palette[$ID]["B"],
458                "Alpha" => $Palette[$ID]["Alpha"],
459                "Surrounding" => $PointSurrounding
460            ];
461
462            /* Draw the polygons */
463            if ($DrawPoly) {
464                if ($PolyAlpha != null) {
465                    $Color = [
466                        "R" => $Palette[$ID]["R"],
467                        "G" => $Palette[$ID]["G"],
468                        "B" => $Palette[$ID]["B"],
469                        "Alpha" => $PolyAlpha,
470                        "Surrounding" => $PointSurrounding
471                    ];
472                }
473                $PointsArray = [];
474                for ($i = 0; $i < count($Points); $i++) {
475                    $PointsArray[] = $Points[$i][0];
476                    $PointsArray[] = $Points[$i][1];
477                }
478                $Object->drawPolygon($PointsArray, $Color);
479            }
480
481            $Color = [
482                "R" => $Palette[$ID]["R"],
483                "G" => $Palette[$ID]["G"],
484                "B" => $Palette[$ID]["B"],
485                "Alpha" => $Palette[$ID]["Alpha"],
486                "Surrounding" => $PointSurrounding
487            ];
488
489            /* Bubble and labels settings */
490            $TextSettings = [
491                "Align"  => TEXT_ALIGN_MIDDLEMIDDLE,
492                "FontName" => $ValueFontName,
493                "FontSize" => $ValueFontSize,
494                "R"  => $Palette[$ID]["R"],
495                "G"  => $Palette[$ID]["G"],
496                "B"  => $Palette[$ID]["B"]
497            ];
498            $InnerColor = [
499                "R" => $InnerBubbleR,
500                "G" => $InnerBubbleG,
501                "B" => $InnerBubbleB,
502                "Alpha" => $InnerBubbleAlpha
503            ];
504            if ($OuterBubbleR != VOID) {
505                $OuterColor = [
506                    "R" => $OuterBubbleR,
507                    "G" => $OuterBubbleG,
508                    "B" => $OuterBubbleB,
509                    "Alpha" => $OuterBubbleAlpha
510                ];
511            } else {
512                $OuterColor = [
513                    "R" => $Palette[$ID]["R"] + 20,
514                    "G" => $Palette[$ID]["G"] + 20,
515                    "B" => $Palette[$ID]["B"] + 20,
516                    "Alpha" => $Palette[$ID]["Alpha"]
517                ];
518            }
519            /* Loop to the starting points if asked */
520            if ($LineLoopStart && $DrawLines) {
521                $Object->drawLine(
522                    $Points[count($Points) - 1][0],
523                    $Points[count($Points) - 1][1],
524                    $Points[0][0],
525                    $Points[0][1],
526                    $Color + (isset($Format['LineWeight']) ? [ 'Weight' => $Format['LineWeight'] ] : [] )
527                );
528            }
529
530            /* Draw the lines & points */
531            for ($i = 0; $i < count($Points); $i++) {
532                if ($DrawLines && $i < count($Points) - 1) {
533                    $Object->drawLine(
534                        $Points[$i][0],
535                        $Points[$i][1],
536                        $Points[$i + 1][0],
537                        $Points[$i + 1][1],
538                        $Color + (isset($Format['LineWeight']) ? [ 'Weight' => $Format['LineWeight'] ] : [] )
539                    );
540                }
541                if ($DrawPoints) {
542                    $Object->drawShape(
543                        $Points[$i][0],
544                        $Points[$i][1],
545                        (isset($Series[$ID]['Shape']) ? $Series[$ID]['Shape'] : SERIE_SHAPE_CIRCLE),
546                        $PointRadius,
547                        true,
548                        1,
549                        $Color['R'],
550                        $Color['G'],
551                        $Color['B'],
552                        $Color['Alpha'],
553                        0,
554                        0,
555                        0,
556                        100
557                    );
558                }
559                if ($WriteValuesInBubble && $WriteValues) {
560                    $TxtPos = $this->pChartObject->getTextBox(
561                        $Points[$i][0],
562                        $Points[$i][1],
563                        $ValueFontName,
564                        $ValueFontSize,
565                        0,
566                        $Points[$i][2]
567                    );
568                    $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $ValuePadding * 2) / 2);
569
570                    $this->pChartObject->drawFilledCircle(
571                        $Points[$i][0],
572                        $Points[$i][1],
573                        $Radius + $OuterBubbleRadius,
574                        $OuterColor
575                    );
576                    $this->pChartObject->drawFilledCircle(
577                        $Points[$i][0],
578                        $Points[$i][1],
579                        $Radius,
580                        $InnerColor
581                    );
582                }
583
584                if ($WriteValues) {
585                    $this->pChartObject->drawText(
586                        $Points[$i][0] - 1,
587                        $Points[$i][1] - 1,
588                        $Points[$i][2],
589                        $TextSettings
590                    );
591                }
592            }
593        }
594    }
595
596    /**
597     * Draw a radar chart
598     * @param Image $Object
599     * @param Data $Values
600     * @param array $Format
601     */
602    public function drawPolar(Image $Object, Data $Values, array $Format = [])
603    {
604        $this->pChartObject = $Object;
605
606        $FixedMax = isset($Format["FixedMax"]) ? $Format["FixedMax"] : VOID;
607        $AxisR = isset($Format["AxisR"]) ? $Format["AxisR"] : 60;
608        $AxisG = isset($Format["AxisG"]) ? $Format["AxisG"] : 60;
609        $AxisB = isset($Format["AxisB"]) ? $Format["AxisB"] : 60;
610        $AxisAlpha = isset($Format["AxisAlpha"]) ? $Format["AxisAlpha"] : 50;
611        $AxisRotation = isset($Format["AxisRotation"]) ? $Format["AxisRotation"] : -90;
612        $DrawTicks = isset($Format["DrawTicks"]) ? $Format["DrawTicks"] : true;
613        $TicksLength = isset($Format["TicksLength"]) ? $Format["TicksLength"] : 2;
614        $DrawAxisValues = isset($Format["DrawAxisValues"]) ? $Format["DrawAxisValues"] : true;
615        $AxisBoxRounded = isset($Format["AxisBoxRounded"]) ? $Format["AxisBoxRounded"] : true;
616        $AxisFontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName;
617        $AxisFontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize;
618        $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : false;
619        $WriteValuesInBubble = isset($Format["WriteValuesInBubble"]) ? $Format["WriteValuesInBubble"] : true;
620        $ValueFontName = isset($Format["ValueFontName"])
621            ? $Format["ValueFontName"] : $this->pChartObject->FontName
622        ;
623        $ValueFontSize = isset($Format["ValueFontSize"])
624            ? $Format["ValueFontSize"] : $this->pChartObject->FontSize
625        ;
626        $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 4;
627        $OuterBubbleRadius = isset($Format["OuterBubbleRadius"]) ? $Format["OuterBubbleRadius"] : 2;
628        $OuterBubbleR = isset($Format["OuterBubbleR"]) ? $Format["OuterBubbleR"] : VOID;
629        $OuterBubbleG = isset($Format["OuterBubbleG"]) ? $Format["OuterBubbleG"] : VOID;
630        $OuterBubbleB = isset($Format["OuterBubbleB"]) ? $Format["OuterBubbleB"] : VOID;
631        $OuterBubbleAlpha = isset($Format["OuterBubbleAlpha"]) ? $Format["OuterBubbleAlpha"] : 100;
632        $InnerBubbleR = isset($Format["InnerBubbleR"]) ? $Format["InnerBubbleR"] : 255;
633        $InnerBubbleG = isset($Format["InnerBubbleG"]) ? $Format["InnerBubbleG"] : 255;
634        $InnerBubbleB = isset($Format["InnerBubbleB"]) ? $Format["InnerBubbleB"] : 255;
635        $InnerBubbleAlpha = isset($Format["InnerBubbleAlpha"]) ? $Format["InnerBubbleAlpha"] : 100;
636        $DrawBackground = isset($Format["DrawBackground"]) ? $Format["DrawBackground"] : true;
637        $BackgroundR = isset($Format["BackgroundR"]) ? $Format["BackgroundR"] : 255;
638        $BackgroundG = isset($Format["BackgroundG"]) ? $Format["BackgroundG"] : 255;
639        $BackgroundB = isset($Format["BackgroundB"]) ? $Format["BackgroundB"] : 255;
640        $BackgroundAlpha = isset($Format["BackgroundAlpha"]) ? $Format["BackgroundAlpha"] : 50;
641        $BackgroundGradient = isset($Format["BackgroundGradient"]) ? $Format["BackgroundGradient"] : null;
642        $AxisSteps = isset($Format["AxisSteps"]) ? $Format["AxisSteps"] : 20;
643        $SegmentHeight = isset($Format["SegmentHeight"]) ? $Format["SegmentHeight"] : SEGMENT_HEIGHT_AUTO;
644        $Segments = isset($Format["Segments"]) ? $Format["Segments"] : 4;
645        $WriteLabels = isset($Format["WriteLabels"]) ? $Format["WriteLabels"] : true;
646        $LabelsBackground = isset($Format["LabelsBackground"]) ? $Format["LabelsBackground"] : true;
647        $LabelsBGR = isset($Format["LabelsBGR"]) ? $Format["LabelsBGR"] : 255;
648        $LabelsBGG = isset($Format["LabelsBGR"]) ? $Format["LabelsBGG"] : 255;
649        $LabelsBGB = isset($Format["LabelsBGR"]) ? $Format["LabelsBGB"] : 255;
650        $LabelsBGAlpha = isset($Format["LabelsBGAlpha"]) ? $Format["LabelsBGAlpha"] : 50;
651        $LabelPos = isset($Format["LabelPos"]) ? $Format["LabelPos"] : RADAR_LABELS_ROTATED;
652        $LabelPadding = isset($Format["LabelPadding"]) ? $Format["LabelPadding"] : 4;
653        $DrawPoints = isset($Format["DrawPoints"]) ? $Format["DrawPoints"] : true;
654        $PointRadius = isset($Format["PointRadius"]) ? $Format["PointRadius"] : 4;
655        $PointSurrounding = isset($Format["PointRadius"]) ? $Format["PointRadius"] : -30;
656        $DrawLines = isset($Format["DrawLines"]) ? $Format["DrawLines"] : true;
657        $LineLoopStart = isset($Format["LineLoopStart"]) ? $Format["LineLoopStart"] : false;
658        $DrawPoly = isset($Format["DrawPoly"]) ? $Format["DrawPoly"] : false;
659        $PolyAlpha = isset($Format["PolyAlpha"]) ? $Format["PolyAlpha"] : null;
660        $FontSize = $Object->FontSize;
661        $X1 = $Object->GraphAreaX1;
662        $Y1 = $Object->GraphAreaY1;
663        $X2 = $Object->GraphAreaX2;
664        $Y2 = $Object->GraphAreaY2;
665        $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : false;
666
667        if ($AxisBoxRounded) {
668            $DrawAxisValues = true;
669        }
670
671        /* Cancel default tick length if ticks not enabled */
672        if ($DrawTicks == false) {
673            $TicksLength = 0;
674        }
675
676        /* Data Processing */
677        $Data = $Values->getData();
678        $Palette = $Values->getPalette();
679
680        /* Catch the number of required axis */
681        $LabelSerie = $Data["Abscissa"];
682        if ($LabelSerie) {
683            $Points = count($Data["Series"][$LabelSerie]["Data"]);
684        } else {
685            $Points = 0;
686            foreach ($Data["Series"] as $SerieName => $DataArray) {
687                if (count($DataArray["Data"]) > $Points) {
688                    $Points = count($DataArray["Data"]);
689                }
690            }
691        }
692
693        /* Draw the axis */
694        $CenterX = ($X2 - $X1) / 2 + $X1;
695        $CenterY = ($Y2 - $Y1) / 2 + $Y1;
696
697        $EdgeHeight = min(($X2 - $X1) / 2, ($Y2 - $Y1) / 2);
698        if ($WriteLabels) {
699            $EdgeHeight = $EdgeHeight - $FontSize - $LabelPadding - $TicksLength;
700        }
701
702        /* Determine the scale if set to automatic */
703        if ($SegmentHeight == SEGMENT_HEIGHT_AUTO) {
704            if ($FixedMax != VOID) {
705                $Max = $FixedMax;
706            } else {
707                $Max = 0;
708                foreach ($Data["Series"] as $SerieName => $DataArray) {
709                    if ($SerieName != $LabelSerie) {
710                        if (max($DataArray["Data"]) > $Max) {
711                            $Max = max($DataArray["Data"]);
712                        }
713                    }
714                }
715            }
716            $MaxSegments = $EdgeHeight / 20;
717            $Scale = $Object->computeScale(0, $Max, $MaxSegments, [1, 2, 5]);
718
719            $Segments = $Scale["Rows"];
720            $SegmentHeight = $Scale["RowHeight"];
721        }
722
723
724        /* Background processing */
725        if ($DrawBackground) {
726            $RestoreShadow = $Object->Shadow;
727            $Object->Shadow = false;
728
729            if ($BackgroundGradient == null) {
730                $Color = [
731                    "R" => $BackgroundR,
732                    "G" => $BackgroundG,
733                    "B" => $BackgroundB,
734                    "Alpha" => $BackgroundAlpha
735                ];
736                $Object->drawFilledCircle(
737                    $CenterX,
738                    $CenterY,
739                    $EdgeHeight,
740                    $Color
741                );
742            } else {
743                $GradientROffset = ($BackgroundGradient["EndR"] - $BackgroundGradient["StartR"]) / $Segments;
744                $GradientGOffset = ($BackgroundGradient["EndG"] - $BackgroundGradient["StartG"]) / $Segments;
745                $GradientBOffset = ($BackgroundGradient["EndB"] - $BackgroundGradient["StartB"]) / $Segments;
746                $GradientAlphaOffset = ($BackgroundGradient["EndAlpha"] - $BackgroundGradient["StartAlpha"])
747                    / $Segments
748                ;
749
750                for ($j = $Segments; $j >= 1; $j--) {
751                    $Color = [
752                        "R" => $BackgroundGradient["StartR"] + $GradientROffset * $j,
753                        "G" => $BackgroundGradient["StartG"] + $GradientGOffset * $j,
754                        "B" => $BackgroundGradient["StartB"] + $GradientBOffset * $j,
755                        "Alpha" => $BackgroundGradient["StartAlpha"] + $GradientAlphaOffset * $j
756                    ];
757                    $Object->drawFilledCircle(
758                        $CenterX,
759                        $CenterY,
760                        ($EdgeHeight / $Segments) * $j,
761                        $Color
762                    );
763                }
764            }
765            $Object->Shadow = $RestoreShadow;
766        }
767
768        /* Axis to axis lines */
769        $Color = ["R" => $AxisR, "G" => $AxisG, "B" => $AxisB, "Alpha" => $AxisAlpha];
770        for ($j = 1; $j <= $Segments; $j++) {
771            $Radius = ($EdgeHeight / $Segments) * $j;
772            $Object->drawCircle($CenterX, $CenterY, $Radius, $Radius, $Color);
773        }
774
775        if ($DrawAxisValues) {
776            if ($LabelsBackground) {
777                $Options = [
778                    "DrawBox"  => true,
779                    "Align"  => TEXT_ALIGN_MIDDLEMIDDLE,
780                    "BoxR" => $LabelsBGR,
781                    "BoxG" => $LabelsBGG,
782                    "BoxB" => $LabelsBGB,
783                    "BoxAlpha" => $LabelsBGAlpha
784                ];
785            } else {
786                $Options = ["Align" => TEXT_ALIGN_MIDDLEMIDDLE];
787            }
788
789            if ($AxisBoxRounded) {
790                $Options["BoxRounded"] = true;
791            }
792
793            $Options["FontName"] = $AxisFontName;
794            $Options["FontSize"] = $AxisFontSize;
795
796            $Angle = 360 / ($Points * 2);
797            for ($j = 1; $j <= $Segments; $j++) {
798                $EdgeX1 = cos(deg2rad($Angle + $AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterX;
799                $EdgeY1 = sin(deg2rad($Angle + $AxisRotation)) * ($EdgeHeight / $Segments) * $j + $CenterY;
800                $Label = $j * $SegmentHeight;
801
802                $Object->drawText($EdgeX1, $EdgeY1, $Label, $Options);
803            }
804        }
805
806        /* Axis lines */
807        $ID = 0;
808        for ($i = 0; $i <= 359; $i = $i + $AxisSteps) {
809            $EdgeX = cos(deg2rad($i + $AxisRotation)) * ($EdgeHeight + $TicksLength) + $CenterX;
810            $EdgeY = sin(deg2rad($i + $AxisRotation)) * ($EdgeHeight + $TicksLength) + $CenterY;
811
812            $Object->drawLine($CenterX, $CenterY, $EdgeX, $EdgeY, $Color);
813
814            if ($WriteLabels) {
815                $LabelX = cos(deg2rad($i + $AxisRotation))
816                    * ($EdgeHeight + $LabelPadding + $TicksLength) + $CenterX
817                ;
818                $LabelY = sin(deg2rad($i + $AxisRotation))
819                    * ($EdgeHeight + $LabelPadding + $TicksLength) + $CenterY
820                ;
821                $Label = $i . "°";
822
823                if ($LabelPos == RADAR_LABELS_ROTATED) {
824                    $Object->drawText(
825                        $LabelX,
826                        $LabelY,
827                        $Label,
828                        ["Angle" => (360 - $i), "Align" => TEXT_ALIGN_BOTTOMMIDDLE]
829                    );
830                } else {
831                    if ((floor($LabelX) == floor($CenterX)) && (floor($LabelY) < floor($CenterY))) {
832                        $Object->drawText(
833                            $LabelX,
834                            $LabelY,
835                            $Label,
836                            ["Align" => TEXT_ALIGN_BOTTOMMIDDLE]
837                        );
838                    }
839                    if ((floor($LabelX) > floor($CenterX)) && (floor($LabelY) < floor($CenterY))) {
840                        $Object->drawText(
841                            $LabelX,
842                            $LabelY,
843                            $Label,
844                            ["Align" => TEXT_ALIGN_BOTTOMLEFT]
845                        );
846                    }
847                    if ((floor($LabelX) > floor($CenterX)) && (floor($LabelY) == floor($CenterY))) {
848                        $Object->drawText(
849                            $LabelX,
850                            $LabelY,
851                            $Label,
852                            ["Align" => TEXT_ALIGN_MIDDLELEFT]
853                        );
854                    }
855                    if ((floor($LabelX) > floor($CenterX)) && (floor($LabelY) > floor($CenterY))) {
856                        $Object->drawText(
857                            $LabelX,
858                            $LabelY,
859                            $Label,
860                            ["Align" => TEXT_ALIGN_TOPLEFT]
861                        );
862                    }
863                    if ((floor($LabelX) < floor($CenterX)) && (floor($LabelY) < floor($CenterY))) {
864                        $Object->drawText(
865                            $LabelX,
866                            $LabelY,
867                            $Label,
868                            ["Align" => TEXT_ALIGN_BOTTOMRIGHT]
869                        );
870                    }
871                    if ((floor($LabelX) < floor($CenterX)) && (floor($LabelY) == floor($CenterY))) {
872                        $Object->drawText(
873                            $LabelX,
874                            $LabelY,
875                            $Label,
876                            ["Align" => TEXT_ALIGN_MIDDLERIGHT]
877                        );
878                    }
879                    if ((floor($LabelX) < floor($CenterX)) && (floor($LabelY) > floor($CenterY))) {
880                        $Object->drawText(
881                            $LabelX,
882                            $LabelY,
883                            $Label,
884                            ["Align" => TEXT_ALIGN_TOPRIGHT]
885                        );
886                    }
887                    if ((floor($LabelX) == floor($CenterX)) && (floor($LabelY) > floor($CenterY))) {
888                        $Object->drawText(
889                            $LabelX,
890                            $LabelY,
891                            $Label,
892                            ["Align" => TEXT_ALIGN_TOPMIDDLE]
893                        );
894                    }
895                }
896            }
897            $ID++;
898        }
899
900        /* Compute the plots position */
901        $ID = 0;
902        $Plot = [];
903        foreach ($Data["Series"] as $SerieName => $DataSet) {
904            if ($SerieName != $LabelSerie) {
905                $Color = [
906                    "R" => $Palette[$ID]["R"],
907                    "G" => $Palette[$ID]["G"],
908                    "B" => $Palette[$ID]["B"],
909                    "Alpha" => $Palette[$ID]["Alpha"],
910                    "Surrounding" => $PointSurrounding
911                ];
912                foreach ($DataSet["Data"] as $Key => $Value) {
913                    $Angle = $Data["Series"][$LabelSerie]["Data"][$Key];
914                    $Length = ($EdgeHeight / ($Segments * $SegmentHeight)) * $Value;
915
916                    $X = cos(deg2rad($Angle + $AxisRotation)) * $Length + $CenterX;
917                    $Y = sin(deg2rad($Angle + $AxisRotation)) * $Length + $CenterY;
918
919                    if ($RecordImageMap) {
920                        $this->pChartObject->addToImageMap(
921                            "CIRCLE",
922                            sprintf("%s,%s,%s", floor($X), floor($Y), floor($PointRadius)),
923                            $this->pChartObject->toHTMLColor(
924                                $Palette[$ID]["R"],
925                                $Palette[$ID]["G"],
926                                $Palette[$ID]["B"]
927                            ),
928                            $DataSet["Description"],
929                            $Data["Series"][$LabelSerie]["Data"][$Key] . "&deg = " . $Value
930                        );
931                    }
932
933                    $Plot[$ID][] = [$X, $Y, $Value];
934                }
935                $ID++;
936            }
937        }
938
939        /* Draw all that stuff! */
940        foreach ($Plot as $ID => $Points) {
941            $Color = [
942                "R" => $Palette[$ID]["R"],
943                "G" => $Palette[$ID]["G"],
944                "B" => $Palette[$ID]["B"],
945                "Alpha" => $Palette[$ID]["Alpha"],
946                "Surrounding" => $PointSurrounding
947            ];
948
949            /* Draw the polygons */
950            if ($DrawPoly) {
951                if ($PolyAlpha != null) {
952                    $Color = [
953                        "R" => $Palette[$ID]["R"],
954                        "G" => $Palette[$ID]["G"],
955                        "B" => $Palette[$ID]["B"],
956                        "Alpha" => $PolyAlpha,
957                        "Surrounding" => $PointSurrounding
958                    ];
959                }
960                $PointsArray = [];
961                for ($i = 0; $i < count($Points); $i++) {
962                    $PointsArray[] = $Points[$i][0];
963                    $PointsArray[] = $Points[$i][1];
964                }
965
966                $Object->drawPolygon($PointsArray, $Color);
967            }
968
969            $Color = [
970                "R" => $Palette[$ID]["R"],
971                "G" => $Palette[$ID]["G"],
972                "B" => $Palette[$ID]["B"],
973                "Alpha" => $Palette[$ID]["Alpha"],
974                "Surrounding" => $PointSurrounding
975            ];
976
977            /* Bubble and labels settings */
978            $TextSettings = [
979                "Align"  => TEXT_ALIGN_MIDDLEMIDDLE,
980                "FontName" => $ValueFontName,
981                "FontSize" => $ValueFontSize,
982                "R"  => $Palette[$ID]["R"],
983                "G"  => $Palette[$ID]["G"],
984                "B"  => $Palette[$ID]["B"]
985            ];
986            $InnerColor = [
987                "R" => $InnerBubbleR,
988                "G" => $InnerBubbleG,
989                "B" => $InnerBubbleB,
990                "Alpha" => $InnerBubbleAlpha
991            ];
992            if ($OuterBubbleR != VOID) {
993                $OuterColor = [
994                    "R" => $OuterBubbleR,
995                    "G" => $OuterBubbleG,
996                    "B" => $OuterBubbleB,
997                    "Alpha" => $OuterBubbleAlpha
998                ];
999            } else {
1000                $OuterColor = [
1001                    "R" => $Palette[$ID]["R"] + 20,
1002                    "G" => $Palette[$ID]["G"] + 20,
1003                    "B" => $Palette[$ID]["B"] + 20,
1004                    "Alpha" => $Palette[$ID]["Alpha"]
1005                ];
1006            }
1007            /* Loop to the starting points if asked */
1008            if ($LineLoopStart && $DrawLines) {
1009                $Object->drawLine(
1010                    $Points[count($Points) - 1][0],
1011                    $Points[count($Points) - 1][1],
1012                    $Points[0][0],
1013                    $Points[0][1],
1014                    $Color
1015                );
1016            }
1017            /* Draw the lines & points */
1018            for ($i = 0; $i < count($Points); $i++) {
1019                if ($DrawLines && $i < count($Points) - 1) {
1020                    $Object->drawLine(
1021                        $Points[$i][0],
1022                        $Points[$i][1],
1023                        $Points[$i + 1][0],
1024                        $Points[$i + 1][1],
1025                        $Color
1026                    );
1027                }
1028                if ($DrawPoints) {
1029                    $Object->drawFilledCircle(
1030                        $Points[$i][0],
1031                        $Points[$i][1],
1032                        $PointRadius,
1033                        $Color
1034                    );
1035                }
1036                if ($WriteValuesInBubble && $WriteValues) {
1037                    $TxtPos = $this->pChartObject->getTextBox(
1038                        $Points[$i][0],
1039                        $Points[$i][1],
1040                        $ValueFontName,
1041                        $ValueFontSize,
1042                        0,
1043                        $Points[$i][2]
1044                    );
1045                    $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $ValuePadding * 2) / 2);
1046
1047                    $this->pChartObject->drawFilledCircle(
1048                        $Points[$i][0],
1049                        $Points[$i][1],
1050                        $Radius + $OuterBubbleRadius,
1051                        $OuterColor
1052                    );
1053                    $this->pChartObject->drawFilledCircle(
1054                        $Points[$i][0],
1055                        $Points[$i][1],
1056                        $Radius,
1057                        $InnerColor
1058                    );
1059                }
1060
1061                if ($WriteValues) {
1062                    $this->pChartObject->drawText(
1063                        $Points[$i][0] - 1,
1064                        $Points[$i][1] - 1,
1065                        $Points[$i][2],
1066                        $TextSettings
1067                    );
1068                }
1069            }
1070        }
1071    }
1072}
1073