xref: /plugin/statdisplay/vendor/szymach/c-pchart/src/Chart/Indicator.php (revision 03cdebb71906645bc452782ad23f052261c2cb18) !
1<?php
2
3namespace CpChart\Chart;
4
5use CpChart\Image;
6
7class Indicator
8{
9    /**
10     * @var Image
11     */
12    public $pChartObject;
13
14    public function __construct(Image $pChartObject)
15    {
16        $this->pChartObject = $pChartObject;
17    }
18
19    /**
20     * Draw an indicator
21     *
22     * @param int $X
23     * @param int $Y
24     * @param int $Width
25     * @param int $Height
26     * @param array $Format
27     * @return null|int
28     */
29    public function draw($X, $Y, $Width, $Height, array $Format = [])
30    {
31        $Values = isset($Format["Values"]) ? $Format["Values"] : VOID;
32        $IndicatorSections = isset($Format["IndicatorSections"]) ? $Format["IndicatorSections"] : null;
33        $ValueDisplay = isset($Format["ValueDisplay"]) ? $Format["ValueDisplay"] : INDICATOR_VALUE_BUBBLE;
34        $SectionsMargin = isset($Format["SectionsMargin"]) ? $Format["SectionsMargin"] : 4;
35        $DrawLeftHead = isset($Format["DrawLeftHead"]) ? $Format["DrawLeftHead"] : true;
36        $DrawRightHead = isset($Format["DrawRightHead"]) ? $Format["DrawRightHead"] : true;
37        $HeadSize = isset($Format["HeadSize"]) ? $Format["HeadSize"] : floor($Height / 4);
38        $TextPadding = isset($Format["TextPadding"]) ? $Format["TextPadding"] : 4;
39        $CaptionLayout = isset($Format["CaptionLayout"]) ? $Format["CaptionLayout"] : INDICATOR_CAPTION_EXTENDED;
40        $CaptionPosition = isset($Format["CaptionPosition"]) ? $Format["CaptionPosition"] : INDICATOR_CAPTION_INSIDE;
41        $CaptionColorFactor = isset($Format["CaptionColorFactor"]) ? $Format["CaptionColorFactor"] : null;
42        $CaptionR = isset($Format["CaptionR"]) ? $Format["CaptionR"] : 255;
43        $CaptionG = isset($Format["CaptionG"]) ? $Format["CaptionG"] : 255;
44        $CaptionB = isset($Format["CaptionB"]) ? $Format["CaptionB"] : 255;
45        $CaptionAlpha = isset($Format["CaptionAlpha"]) ? $Format["CaptionAlpha"] : 100;
46        $SubCaptionColorFactor = isset($Format["SubCaptionColorFactor"]) ? $Format["SubCaptionColorFactor"] : null;
47        $SubCaptionR = isset($Format["SubCaptionR"]) ? $Format["SubCaptionR"] : 50;
48        $SubCaptionG = isset($Format["SubCaptionG"]) ? $Format["SubCaptionG"] : 50;
49        $SubCaptionB = isset($Format["SubCaptionB"]) ? $Format["SubCaptionB"] : 50;
50        $SubCaptionAlpha = isset($Format["SubCaptionAlpha"]) ? $Format["SubCaptionAlpha"] : 100;
51        $ValueFontName = isset($Format["ValueFontName"]) ? $Format["ValueFontName"] : $this->pChartObject->FontName;
52        $ValueFontSize = isset($Format["ValueFontSize"]) ? $Format["ValueFontSize"] : $this->pChartObject->FontSize;
53        $CaptionFontName = isset($Format["CaptionFontName"])
54            ? $Format["CaptionFontName"] : $this->pChartObject->FontName
55        ;
56        $CaptionFontSize = isset($Format["CaptionFontSize"])
57            ? $Format["CaptionFontSize"] : $this->pChartObject->FontSize
58        ;
59        $Unit = isset($Format["Unit"]) ? $Format["Unit"] : "";
60
61        /* Convert the Values to display to an array if needed */
62        if (!is_array($Values)) {
63            $Values = [$Values];
64        }
65
66        /* No section, let's die */
67        if ($IndicatorSections == null) {
68            return 0;
69        }
70
71        /* Determine indicator visual configuration */
72        $OverallMin = $IndicatorSections[0]["End"];
73        $OverallMax = $IndicatorSections[0]["Start"];
74        foreach ($IndicatorSections as $Key => $Settings) {
75            if ($Settings["End"] > $OverallMax) {
76                $OverallMax = $Settings["End"];
77            }
78            if ($Settings["Start"] < $OverallMin) {
79                $OverallMin = $Settings["Start"];
80            }
81        }
82        $RealWidth = $Width - (count($IndicatorSections) - 1) * $SectionsMargin;
83        $XScale = $RealWidth / ($OverallMax - $OverallMin);
84
85        $X1 = $X;
86        $ValuesPos = [];
87        foreach ($IndicatorSections as $Key => $Settings) {
88            $Color = ["R" => $Settings["R"], "G" => $Settings["G"], "B" => $Settings["B"]];
89            $Caption = $Settings["Caption"];
90            $SubCaption = $Settings["Start"] . " - " . $Settings["End"];
91
92            $X2 = $X1 + ($Settings["End"] - $Settings["Start"]) * $XScale;
93
94            if ($Key == 0 && $DrawLeftHead) {
95                $Poly = [];
96                $Poly[] = $X1 - 1;
97                $Poly[] = $Y;
98                $Poly[] = $X1 - 1;
99                $Poly[] = $Y + $Height;
100                $Poly[] = $X1 - 1 - $HeadSize;
101                $Poly[] = $Y + ($Height / 2);
102                $this->pChartObject->drawPolygon($Poly, $Color);
103                $this->pChartObject->drawLine($X1 - 2, $Y, $X1 - 2 - $HeadSize, $Y + ($Height / 2), $Color);
104                $this->pChartObject->drawLine(
105                    $X1 - 2,
106                    $Y + $Height,
107                    $X1 - 2 - $HeadSize,
108                    $Y + ($Height / 2),
109                    $Color
110                );
111            }
112
113            /* Determine the position of the breaks */
114            $Break = [];
115            foreach ($Values as $iKey => $Value) {
116                if ($Value >= $Settings["Start"] && $Value <= $Settings["End"]) {
117                    $XBreak = $X1 + ($Value - $Settings["Start"]) * $XScale;
118                    $ValuesPos[$Value] = $XBreak;
119                    $Break[] = floor($XBreak);
120                }
121            }
122
123            if ($ValueDisplay == INDICATOR_VALUE_LABEL) {
124                if (!count($Break)) {
125                    $this->pChartObject->drawFilledRectangle($X1, $Y, $X2, $Y + $Height, $Color);
126                } else {
127                    sort($Break);
128                    $Poly = [];
129                    $Poly[] = $X1;
130                    $Poly[] = $Y;
131                    $LastPointWritten = false;
132                    foreach ($Break as $iKey => $Value) {
133                        if ($Value - 5 >= $X1) {
134                            $Poly[] = $Value - 5;
135                            $Poly[] = $Y;
136                        } elseif ($X1 - ($Value - 5) > 0) {
137                            $Offset = $X1 - ($Value - 5);
138                            $Poly = [$X1, $Y + $Offset];
139                        }
140
141                        $Poly[] = $Value;
142                        $Poly[] = $Y + 5;
143
144                        if ($Value + 5 <= $X2) {
145                            $Poly[] = $Value + 5;
146                            $Poly[] = $Y;
147                        } elseif (($Value + 5) > $X2) {
148                            $Offset = ($Value + 5) - $X2;
149                            $Poly[] = $X2;
150                            $Poly[] = $Y + $Offset;
151                            $LastPointWritten = true;
152                        }
153                    }
154                    if (!$LastPointWritten) {
155                        $Poly[] = $X2;
156                        $Poly[] = $Y;
157                    }
158                    $Poly[] = $X2;
159                    $Poly[] = $Y + $Height;
160                    $Poly[] = $X1;
161                    $Poly[] = $Y + $Height;
162
163                    $this->pChartObject->drawPolygon($Poly, $Color);
164                }
165            } else {
166                $this->pChartObject->drawFilledRectangle($X1, $Y, $X2, $Y + $Height, $Color);
167            }
168
169            if ($Key == count($IndicatorSections) - 1 && $DrawRightHead) {
170                $Poly = [];
171                $Poly[] = $X2 + 1;
172                $Poly[] = $Y;
173                $Poly[] = $X2 + 1;
174                $Poly[] = $Y + $Height;
175                $Poly[] = $X2 + 1 + $HeadSize;
176                $Poly[] = $Y + ($Height / 2);
177                $this->pChartObject->drawPolygon($Poly, $Color);
178                $this->pChartObject->drawLine($X2 + 1, $Y, $X2 + 1 + $HeadSize, $Y + ($Height / 2), $Color);
179                $this->pChartObject->drawLine(
180                    $X2 + 1,
181                    $Y + $Height,
182                    $X2 + 1 + $HeadSize,
183                    $Y + ($Height / 2),
184                    $Color
185                );
186            }
187
188            $YOffset = 0;
189            $XOffset = 0;
190            if ($CaptionPosition == INDICATOR_CAPTION_INSIDE) {
191                $TxtPos = $this->pChartObject->getTextBox(
192                    $X1,
193                    $Y + $Height + $TextPadding,
194                    $CaptionFontName,
195                    $CaptionFontSize,
196                    0,
197                    $Caption
198                );
199                $YOffset = ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]) + $TextPadding;
200
201                if ($CaptionLayout == INDICATOR_CAPTION_EXTENDED) {
202                    $TxtPos = $this->pChartObject->getTextBox(
203                        $X1,
204                        $Y + $Height + $TextPadding,
205                        $CaptionFontName,
206                        $CaptionFontSize,
207                        0,
208                        $SubCaption
209                    );
210                    $YOffset = $YOffset + ($TxtPos[0]["Y"] - $TxtPos[2]["Y"]) + $TextPadding * 2;
211                }
212                $XOffset = $TextPadding;
213            }
214
215            if ($CaptionColorFactor == null) {
216                $CaptionColor = [
217                    "Align" => TEXT_ALIGN_TOPLEFT,
218                    "FontName" => $CaptionFontName,
219                    "FontSize" => $CaptionFontSize,
220                    "R" => $CaptionR,
221                    "G" => $CaptionG,
222                    "B" => $CaptionB,
223                    "Alpha" => $CaptionAlpha
224                ];
225            } else {
226                $CaptionColor = [
227                    "Align" => TEXT_ALIGN_TOPLEFT,
228                    "FontName" => $CaptionFontName,
229                    "FontSize" => $CaptionFontSize,
230                    "R" => $Settings["R"] + $CaptionColorFactor,
231                    "G" => $Settings["G"] + $CaptionColorFactor,
232                    "B" => $Settings["B"] + $CaptionColorFactor
233                ];
234            }
235
236            if ($SubCaptionColorFactor == null) {
237                $SubCaptionColor = [
238                    "Align" => TEXT_ALIGN_TOPLEFT,
239                    "FontName" => $CaptionFontName,
240                    "FontSize" => $CaptionFontSize,
241                    "R" => $SubCaptionR,
242                    "G" => $SubCaptionG,
243                    "B" => $SubCaptionB,
244                    "Alpha" => $SubCaptionAlpha
245                ];
246            } else {
247                $SubCaptionColor = [
248                    "Align" => TEXT_ALIGN_TOPLEFT,
249                    "FontName" => $CaptionFontName,
250                    "FontSize" => $CaptionFontSize,
251                    "R" => $Settings["R"] + $SubCaptionColorFactor,
252                    "G" => $Settings["G"] + $SubCaptionColorFactor,
253                    "B" => $Settings["B"] + $SubCaptionColorFactor
254                ];
255            }
256
257            $RestoreShadow = $this->pChartObject->Shadow;
258            $this->pChartObject->Shadow = false;
259
260            if ($CaptionLayout == INDICATOR_CAPTION_DEFAULT) {
261                $this->pChartObject->drawText($X1, $Y + $Height + $TextPadding, $Caption, $CaptionColor);
262            } elseif ($CaptionLayout == INDICATOR_CAPTION_EXTENDED) {
263                $TxtPos = $this->pChartObject->getTextBox(
264                    $X1,
265                    $Y + $Height + $TextPadding,
266                    $CaptionFontName,
267                    $CaptionFontSize,
268                    0,
269                    $Caption
270                );
271                $CaptionHeight = $TxtPos[0]["Y"] - $TxtPos[2]["Y"];
272
273                $this->pChartObject->drawText(
274                    $X1 + $XOffset,
275                    $Y + $Height - $YOffset + $TextPadding,
276                    $Caption,
277                    $CaptionColor
278                );
279                $this->pChartObject->drawText(
280                    $X1 + $XOffset,
281                    $Y + $Height - $YOffset + $CaptionHeight + $TextPadding * 2,
282                    $SubCaption,
283                    $SubCaptionColor
284                );
285            }
286
287            $this->pChartObject->Shadow = $RestoreShadow;
288
289            $X1 = $X2 + $SectionsMargin;
290        }
291
292        $RestoreShadow = $this->pChartObject->Shadow;
293        $this->pChartObject->Shadow = false;
294
295        foreach ($Values as $Key => $Value) {
296            if ($Value >= $OverallMin && $Value <= $OverallMax) {
297                foreach ($IndicatorSections as $Key => $Settings) {
298                    if ($Value >= $Settings["Start"] && $Value <= $Settings["End"]) {
299                        $X1 = $ValuesPos[$Value]; //$X + $Key*$SectionsMargin + ($Value - $OverallMin) * $XScale;
300
301                        if ($ValueDisplay == INDICATOR_VALUE_BUBBLE) {
302                            $TxtPos = $this->pChartObject->getTextBox(
303                                $X1,
304                                $Y,
305                                $ValueFontName,
306                                $ValueFontSize,
307                                0,
308                                $Value . $Unit
309                            );
310                            $Radius = floor(($TxtPos[1]["X"] - $TxtPos[0]["X"] + $TextPadding * 4) / 2);
311
312                            $this->pChartObject->drawFilledCircle(
313                                $X1,
314                                $Y,
315                                $Radius + 4,
316                                [
317                                    "R" => $Settings["R"] + 20,
318                                    "G" => $Settings["G"] + 20,
319                                    "B" => $Settings["B"] + 20
320                                ]
321                            );
322                            $this->pChartObject->drawFilledCircle(
323                                $X1,
324                                $Y,
325                                $Radius,
326                                ["R" => 255, "G" => 255, "B" => 255]
327                            );
328
329                            $TextSettings = [
330                                "Align" => TEXT_ALIGN_MIDDLEMIDDLE,
331                                "FontName" => $ValueFontName,
332                                "FontSize" => $ValueFontSize
333                            ];
334                            $this->pChartObject->drawText($X1 - 1, $Y - 1, $Value . $Unit, $TextSettings);
335                        } elseif ($ValueDisplay == INDICATOR_VALUE_LABEL) {
336                            $Caption = [
337                                [
338                                    "Format" => [
339                                        "R" => $Settings["R"],
340                                        "G" => $Settings["G"],
341                                        "B" => $Settings["B"],
342                                        "Alpha" => 100
343                                    ],
344                                    "Caption" => $Value . $Unit
345                                ]
346                            ];
347                            $this->pChartObject->drawLabelBox(
348                                floor($X1),
349                                floor($Y) + 2,
350                                "Value - " . $Settings["Caption"],
351                                $Caption
352                            );
353                        }
354                    }
355                    $X1 = $X2 + $SectionsMargin;
356                }
357            }
358        }
359        $this->pChartObject->Shadow = $RestoreShadow;
360    }
361}
362