Removed /usr/local from CDPATH
[clearscm.git] / clients / GD / FSMon / pChart / pChart.class
1 <?php\r
2  /*\r
3      pChart - a PHP class to build charts!\r
4      Copyright (C) 2008 Jean-Damien POGOLOTTI\r
5      Version  1.27b last updated on 08/21/08\r
6 \r
7      http://pchart.sourceforge.net\r
8 \r
9      This program is free software: you can redistribute it and/or modify\r
10      it under the terms of the GNU General Public License as published by\r
11      the Free Software Foundation, either version 1,2,3 of the License, or\r
12      (at your option) any later version.\r
13 \r
14      This program is distributed in the hope that it will be useful,\r
15      but WITHOUT ANY WARRANTY; without even the implied warranty of\r
16      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
17      GNU General Public License for more details.\r
18 \r
19      You should have received a copy of the GNU General Public License\r
20      along with this program.  If not, see <http://www.gnu.org/licenses/>.\r
21 \r
22      Class initialisation :\r
23       pChart($XSize,$YSize)\r
24      Draw methods :\r
25       drawBackground($R,$G,$B)\r
26       drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B)\r
27       drawFilledRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B,$DrawBorder=TRUE,$Alpha=100)\r
28       drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B)\r
29       drawFilledRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B)\r
30       drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0)\r
31       drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0)\r
32       drawEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B)\r
33       drawFilledEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B)\r
34       drawLine($X1,$Y1,$X2,$Y2,$R,$G,$B,$GraphFunction=FALSE)\r
35       drawDottedLine($X1,$Y1,$X2,$Y2,$DotSize,$R,$G,$B)\r
36       drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B)\r
37       drawFromPNG($FileName,$X,$Y,$Alpha=100)\r
38       drawFromGIF($FileName,$X,$Y,$Alpha=100)\r
39       drawFromJPG($FileName,$X,$Y,$Alpha=100)\r
40      Graph setup methods :\r
41       addBorder($Width=3,$R=0,$G=0,$B=0)\r
42       drawGraphArea($R,$G,$B,$Stripe=FALSE)\r
43       drawScale(&$Data,&$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1)\r
44       drawGrid($LineWidth,$Mosaic=TRUE,$R=220,$G=220,$B=220,$Alpha=100)\r
45       drawLegend($XPos,$YPos,&$DataDescription,$R,$G,$B,$Rs=-1,$Gs=-1,$Bs=-1)\r
46       drawPieLegend($XPos,$YPos,$Data,$DataDescription,$R,$G,$B)\r
47       drawTitle($XPos,$YPos,$Value,$R,$G,$B,$XPos2=-1,$YPos2=-1)\r
48       drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnRight=FALSE,$TickWidth=4,$FreeText=NULL)\r
49       drawArea(&$Data,$Serie1,$Serie2,$R,$G,$B,$Alpha = 50)\r
50       drawRadarAxis(&$Data,&$DataDescription,$Mosaic=TRUE,$BorderOffset=10,$A_R=60,$A_G=60,$A_B=60,$S_R=200,$S_G=200,$S_B=200,$MaxValue=-1)\r
51       drawGraphAreaGradient($R,$G,$B,$Decay,$Target=TARGET_GRAPHAREA)\r
52       drawTextBox($X1,$Y1,$X2,$Y2,$Text,$Angle=0,$R=255,$G=255,$B=255,$Align=ALIGN_LEFT,$Shadow=TRUE,$BgR=-1,$BgG=-1,$BgB=-1,$Alpha=100)\r
53       getLegendBoxSize($DataDescription)\r
54       loadColorPalette($FileName,$Delimiter=",")\r
55       reportWarnings($Interface="CLI")\r
56       setGraphArea($X1,$Y1,$X2,$Y2)\r
57       setFixedScale($VMin,$VMax)\r
58       setLabel(&$Data,&$DataDescription,$SerieName,$ValueName,$Caption,$R=210,$G=210,$B=210)\r
59       setColorPalette($ID,$R,$G,$B)\r
60       setDateFormat($Format)\r
61       setFontProperties($FontName,$FontSize)\r
62       setLineStyle($Width=1,$DotSize=0)\r
63       setFixedScale($VMin,$VMax,$Divisions=5)\r
64       writeValues(&$Data,&$DataDescription,$Series)\r
65     Graphs methods :\r
66       drawPlotGraph(&$Data,&$DataDescription,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1)\r
67       drawLineGraph(&$Data,&$DataDescription,$SerieName="")\r
68       drawFilledLineGraph(&$Data,&$DataDescription,$Alpha=100,$AroundZero=FALSE)\r
69       drawCubicCurve(&$Data,&$DataDescription,$Accuracy=.1,$SerieName="")\r
70       drawFilledCubicCurve(&$Data,&$DataDescription,$Accuracy=.1,$Alpha=100,$AroundZero=FALSE)\r
71       drawOverlayBarGraph(&$Data,&$DataDescription,$Alpha=50)\r
72       drawBarGraph(&$Data,&$DataDescription,$Shadow=FALSE)\r
73       drawStackedBarGraph(&$Data,&$DataDescription,$Alpha=50)\r
74       drawLimitsGraph(&$Data,&$DataDescription,$R=0,$G=0,$B=0)\r
75       drawRadar(&$Data,&$DataDescription,$BorderOffset=10,$MaxValue=-1)\r
76       drawFilledRadar(&$Data,&$DataDescription,$Alpha=50,$BorderOffset=10,$MaxValue=-1)\r
77       drawBasicPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$R=255,$G=255,$B=255,$Decimals=0)\r
78       drawFlatPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals = 0)\r
79       drawPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$EnhanceColors=TRUE,$Skew=60,$SpliceHeight=20,$SpliceDistance=0,$Decimals=0)\r
80      Other methods :\r
81       setImageMap($Mode=TRUE,$GraphID="MyGraph")\r
82       getImageMap($MapName,$Flush=TRUE)\r
83       Render($FileName)\r
84       Stroke()\r
85  */\r
86  \r
87  /* Andrew@DeFaria.com: Empty array for imageftbbox call\r
88                         See http://bugs.php.net/bug.php?id=26309\r
89  */\r
90  /* Declare some script wide constants */\r
91  define("SCALE_NORMAL",1);\r
92  define("SCALE_ADDALL",2);\r
93  define("SCALE_START0",3);\r
94  define("SCALE_ADDALLSTART0",4);\r
95  define("PIE_PERCENTAGE", 1);\r
96  define("PIE_LABELS",2);\r
97  define("PIE_NOLABEL",3);\r
98  define("TARGET_GRAPHAREA",1);\r
99  define("TARGET_BACKGROUND",2);\r
100  define("ALIGN_TOP_LEFT",1);\r
101  define("ALIGN_TOP_CENTER",2);\r
102  define("ALIGN_TOP_RIGHT",3);\r
103  define("ALIGN_LEFT",4);\r
104  define("ALIGN_CENTER",5);\r
105  define("ALIGN_RIGHT",6);\r
106  define("ALIGN_BOTTOM_LEFT",7);\r
107  define("ALIGN_BOTTOM_CENTER",8);\r
108  define("ALIGN_BOTTOM_RIGHT",9);\r
109 \r
110  /* pChart class definition */\r
111  class pChart\r
112   {\r
113    /* Palettes definition */\r
114    var $Palette = array("0"=>array("R"=>188,"G"=>224,"B"=>46),\r
115                         "1"=>array("R"=>224,"G"=>100,"B"=>46),\r
116                         "2"=>array("R"=>224,"G"=>214,"B"=>46),\r
117                         "3"=>array("R"=>46,"G"=>151,"B"=>224),\r
118                         "4"=>array("R"=>176,"G"=>46,"B"=>224),\r
119                         "5"=>array("R"=>224,"G"=>46,"B"=>117),\r
120                         "6"=>array("R"=>92,"G"=>224,"B"=>46),\r
121                         "7"=>array("R"=>224,"G"=>176,"B"=>46));\r
122 \r
123    /* Some static vars used in the class */\r
124    var $XSize          = NULL;\r
125    var $YSize          = NULL;\r
126    var $Picture        = NULL;\r
127    var $ImageMap       = NULL;\r
128 \r
129    /* Error management */\r
130    var $ErrorReporting = FALSE;\r
131    var $ErrorInterface = "CLI";\r
132    var $Errors         = NULL;\r
133    var $ErrorFontName  = "Fonts/pf_arma_five.ttf";\r
134    var $ErrorFontSize  = 6;\r
135 \r
136    /* vars related to the graphing area */\r
137    var $GArea_X1       = NULL;\r
138    var $GArea_Y1       = NULL;\r
139    var $GArea_X2       = NULL;\r
140    var $GArea_Y2       = NULL;\r
141    var $GAreaXOffset   = NULL;\r
142    var $VMax           = NULL;\r
143    var $VMin           = NULL;\r
144    var $Divisions      = NULL;\r
145    var $DivisionHeight = NULL;\r
146    var $DivisionCount  = NULL;\r
147    var $DivisionRatio  = NULL;\r
148    var $DivisionWidth  = NULL;\r
149    var $DataCount      = NULL;\r
150 \r
151    /* Text format related vars */\r
152    var $FontName       = NULL;\r
153    var $FontSize       = NULL;\r
154    var $DateFormat     = "d/m/Y";\r
155 \r
156    /* Lines format related vars */\r
157    var $LineWidth      = 1;\r
158    var $LineDotSize    = 0;\r
159 \r
160    /* Layer related vars */\r
161    var $Layers         = NULL;\r
162 \r
163    /* Set antialias quality : 0 is maximum, 100 minimum*/\r
164    var $AntialiasQuality = 10;\r
165 \r
166    /* Image Map settings */\r
167    var $BuildMap         = FALSE;\r
168    var $MapFunction      = NULL;\r
169    var $tmpFolder        = "tmp/";\r
170    var $MapID            = NULL;\r
171 \r
172    /* This function create the background picture */\r
173    function pChart($XSize,$YSize)\r
174     {\r
175      $this->XSize   = $XSize;\r
176      $this->YSize   = $YSize;\r
177      $this->Picture = imagecreatetruecolor($XSize,$YSize);\r
178 \r
179      $C_White = imagecolorallocate($this->Picture,255,255,255);\r
180      imagefilledrectangle($this->Picture,0,0,$XSize,$YSize,$C_White);\r
181      imagecolortransparent($this->Picture,$C_White);\r
182 \r
183      $this->setFontProperties("tahoma.ttf",8);\r
184     }\r
185 \r
186   /* Set if warnings should be reported */\r
187   function reportWarnings($Interface="CLI")\r
188    {\r
189     $this->ErrorReporting = TRUE;\r
190     $this->ErrorInterface = $Interface;\r
191     }\r
192 \r
193    /* Set the font properties */\r
194    function setFontProperties($FontName,$FontSize)\r
195     {\r
196      $this->FontName = $FontName;\r
197      $this->FontSize = $FontSize;\r
198     }\r
199 \r
200    /* Set Palette color */\r
201    function setColorPalette($ID,$R,$G,$B)\r
202     {\r
203      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
204      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
205      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
206 \r
207      $this->Palette[$ID]["R"] = $R;\r
208      $this->Palette[$ID]["G"] = $G;\r
209      $this->Palette[$ID]["B"] = $B;\r
210     }\r
211 \r
212    /* Load Color Palette from file */\r
213    function loadColorPalette($FileName,$Delimiter=",")\r
214     {\r
215      $handle  = @fopen($FileName,"r");\r
216      $ColorID = 0;\r
217      if ($handle)\r
218       {\r
219        while (!feof($handle))\r
220         {\r
221          $buffer = fgets($handle, 4096);\r
222          $buffer = str_replace(chr(10),"",$buffer);\r
223          $buffer = str_replace(chr(13),"",$buffer);\r
224          $Values = split($Delimiter,$buffer);\r
225          if ( count($Values) == 3 )\r
226           {\r
227            $this->Palette[$ColorID]["R"] = $Values[0];\r
228            $this->Palette[$ColorID]["G"] = $Values[1];\r
229            $this->Palette[$ColorID]["B"] = $Values[2];\r
230            $ColorID++;\r
231           }\r
232         }\r
233       }\r
234     }\r
235 \r
236    /* Set line style */\r
237   function setLineStyle($Width=1,$DotSize=0)\r
238    {\r
239     $this->LineWidth   = $Width;\r
240     $this->LineDotSize = $DotSize;\r
241    }\r
242 \r
243    /* Set the graph area location */\r
244    function setGraphArea($X1,$Y1,$X2,$Y2)\r
245     {\r
246      $this->GArea_X1 = $X1;\r
247      $this->GArea_Y1 = $Y1;\r
248      $this->GArea_X2 = $X2;\r
249      $this->GArea_Y2 = $Y2;\r
250     }\r
251 \r
252    /* Prepare the graph area */\r
253    function drawGraphArea($R,$G,$B,$Stripe=FALSE)\r
254     {\r
255      $this->drawFilledRectangle($this->GArea_X1,$this->GArea_Y1,$this->GArea_X2,$this->GArea_Y2,$R,$G,$B,FALSE);\r
256      $this->drawRectangle($this->GArea_X1,$this->GArea_Y1,$this->GArea_X2,$this->GArea_Y2,$R-40,$G-40,$B-40);\r
257 \r
258      if ( $Stripe )\r
259       {\r
260        $R2 = $R-15; if ( $R2 < 0 ) { $R2 = 0; }\r
261        $G2 = $R-15; if ( $G2 < 0 ) { $G2 = 0; }\r
262        $B2 = $R-15; if ( $B2 < 0 ) { $B2 = 0; }\r
263 \r
264        $LineColor = imagecolorallocate($this->Picture,$R2,$G2,$B2);\r
265        $SkewWidth = $this->GArea_Y2-$this->GArea_Y1-1;\r
266 \r
267        for($i=$this->GArea_X1-$SkewWidth;$i<=$this->GArea_X2;$i=$i+4)\r
268         {\r
269          $X1 = $i;            $Y1 = $this->GArea_Y2;\r
270          $X2 = $i+$SkewWidth; $Y2 = $this->GArea_Y1;\r
271 \r
272 \r
273          if ( $X1 < $this->GArea_X1 )\r
274           { $X1 = $this->GArea_X1; $Y1 = $this->GArea_Y1 + $X2 - $this->GArea_X1 + 1; }\r
275 \r
276          if ( $X2 >= $this->GArea_X2 )\r
277           { $Y2 = $this->GArea_Y1 + $X2 - $this->GArea_X2 +1; $X2 = $this->GArea_X2 - 1; }\r
278 // * Fixed in 1.27 *         { $X2 = $this->GArea_X2 - 1; $Y2 = $this->GArea_Y2 - ($this->GArea_X2 - $X1); }\r
279 \r
280          imageline($this->Picture,$X1,$Y1,$X2,$Y2+1,$LineColor);\r
281         }\r
282       }\r
283     }\r
284 \r
285    /* Allow you to fix the scale, use this to bypass the automatic scaling */\r
286    function setFixedScale($VMin,$VMax,$Divisions=5)\r
287     {\r
288      $this->VMin      = $VMin;\r
289      $this->VMax      = $VMax;\r
290      $this->Divisions = $Divisions;\r
291     }\r
292 \r
293    /* Compute and draw the scale */\r
294    function drawScale(&$Data,&$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1)\r
295     {\r
296      /* Validate the Data and DataDescription array */\r
297      $this->validateData("drawScale",$Data);\r
298 \r
299      $C_TextColor         = imagecolorallocate($this->Picture,$R,$G,$B);\r
300 \r
301      $this->drawLine($this->GArea_X1,$this->GArea_Y1,$this->GArea_X1,$this->GArea_Y2,$R,$G,$B);\r
302      $this->drawLine($this->GArea_X1,$this->GArea_Y2,$this->GArea_X2,$this->GArea_Y2,$R,$G,$B);\r
303 \r
304      if ( $this->VMin == NULL && $this->VMax == NULL)\r
305       {\r
306        if (isset($DataDescription["Values"][0]))\r
307         {\r
308          $this->VMin = $Data[0][$DataDescription["Values"][0]];\r
309          $this->VMax = $Data[0][$DataDescription["Values"][0]];\r
310         }\r
311        else { $this->VMin = 2147483647; $this->VMax = -2147483647; }\r
312 \r
313        /* Compute Min and Max values */\r
314        if ( $ScaleMode == SCALE_NORMAL || $ScaleMode == SCALE_START0 )\r
315         {\r
316          if ( $ScaleMode == SCALE_START0 ) { $this->VMin = 0; }\r
317 \r
318          foreach ( $Data as $Key => $Values )\r
319           {\r
320            foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
321             {\r
322              if (isset($Data[$Key][$ColName]))\r
323               {\r
324                $Value = $Data[$Key][$ColName];\r
325 \r
326                if ( is_numeric($Value) )\r
327                 {\r
328                  if ( $this->VMax < $Value) { $this->VMax = $Value; }\r
329                  if ( $this->VMin > $Value) { $this->VMin = $Value; }\r
330                 }\r
331               }\r
332             }\r
333           }\r
334         }\r
335        elseif ( $ScaleMode == SCALE_ADDALL || $ScaleMode == SCALE_ADDALLSTART0 ) /* Experimental */\r
336         {\r
337          if ( $ScaleMode == SCALE_ADDALLSTART0 ) { $this->VMin = 0; }\r
338 \r
339          foreach ( $Data as $Key => $Values )\r
340           {\r
341            $Sum = 0;\r
342            foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
343             {\r
344              if (isset($Data[$Key][$ColName]))\r
345               {\r
346                $Value = $Data[$Key][$ColName];\r
347                if ( is_numeric($Value) )\r
348                 $Sum  += $Value;\r
349               }\r
350             }\r
351            if ( $this->VMax < $Sum) { $this->VMax = $Sum; }\r
352            if ( $this->VMin > $Sum) { $this->VMin = $Sum; }\r
353           }\r
354         }\r
355 \r
356        $DataRange = $this->VMax - $this->VMin;\r
357        if ( $DataRange == 0 ) { $DataRange = .1; }\r
358 \r
359        /* Compute automatic scaling */\r
360        $ScaleOk = FALSE; $Factor = 1;\r
361        $MinDivHeight = 25; $MaxDivs = ($this->GArea_Y2 - $this->GArea_Y1) / $MinDivHeight;\r
362        if ($MaxDivs > 1)\r
363         {\r
364          while(!$ScaleOk)\r
365           {\r
366            $Scale1 = ( $this->VMax - $this->VMin ) / $Factor;\r
367            $Scale2 = ( $this->VMax - $this->VMin ) / $Factor / 2;\r
368            $Scale4 = ( $this->VMax - $this->VMin ) / $Factor / 4;\r
369 \r
370            if ( $Scale1 > 1 && $Scale1 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale1); $Scale = 1;}\r
371            if ( $Scale2 > 1 && $Scale2 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale2); $Scale = 2;}\r
372            if (!$ScaleOk)\r
373             {\r
374              if ( $Scale2 > 1 ) { $Factor = $Factor * 10; }\r
375              if ( $Scale2 < 1 ) { $Factor = $Factor / 10; }\r
376             }\r
377           }\r
378 \r
379          if ( floor($this->VMax / $Scale / $Factor) != $this->VMax / $Scale / $Factor)\r
380           {\r
381            $GridID     = floor ( $this->VMax / $Scale / $Factor) + 1;\r
382            $this->VMax = $GridID * $Scale * $Factor;\r
383            $Divisions++;\r
384           }\r
385 \r
386          if ( floor($this->VMin / $Scale / $Factor) != $this->VMin / $Scale / $Factor)\r
387           {\r
388            $GridID     = floor( $this->VMin / $Scale / $Factor);\r
389            $this->VMin = $GridID * $Scale * $Factor;\r
390            $Divisions++;\r
391           }\r
392         }\r
393        else /* Can occurs for small graphs */\r
394         $Scale = 1;\r
395 \r
396        if ( !isset($Divisions) )\r
397         $Divisions = 2;\r
398 \r
399        if ($Scale == 1 && $Divisions%2 == 1)\r
400         $Divisions--;\r
401       }\r
402      else\r
403       $Divisions = $this->Divisions;\r
404 \r
405      $this->DivisionCount = $Divisions;\r
406 \r
407      $DataRange = $this->VMax - $this->VMin;\r
408      if ( $DataRange == 0 ) { $DataRange = .1; }\r
409 \r
410      $this->DivisionHeight = ( $this->GArea_Y2 - $this->GArea_Y1 ) / $Divisions;\r
411      $this->DivisionRatio  = ( $this->GArea_Y2 - $this->GArea_Y1 ) / $DataRange;\r
412 \r
413      $this->GAreaXOffset  = 0;\r
414      if ( count($Data) > 1 )\r
415       {\r
416        if ( $WithMargin == FALSE )\r
417         $this->DivisionWidth = ( $this->GArea_X2 - $this->GArea_X1 ) / (count($Data)-1);\r
418        else\r
419         {\r
420          $this->DivisionWidth = ( $this->GArea_X2 - $this->GArea_X1 ) / (count($Data));\r
421          $this->GAreaXOffset  = $this->DivisionWidth / 2;\r
422         }\r
423       }\r
424      else\r
425       {\r
426        $this->DivisionWidth = $this->GArea_X2 - $this->GArea_X1;\r
427        $this->GAreaXOffset  = $this->DivisionWidth / 2;\r
428       }\r
429 \r
430      $this->DataCount = count($Data);\r
431 \r
432      if ( $DrawTicks == FALSE )\r
433       return(0);\r
434 \r
435      $YPos = $this->GArea_Y2; $XMin = NULL;\r
436      for($i=1;$i<=$Divisions+1;$i++)\r
437       {\r
438        $this->drawLine($this->GArea_X1,$YPos,$this->GArea_X1-5,$YPos,$R,$G,$B);\r
439        $Value     = $this->VMin + ($i-1) * (( $this->VMax - $this->VMin ) / $Divisions);\r
440        $Value     = round($Value * pow(10,$Decimals)) / pow(10,$Decimals);\r
441        if ( $DataDescription["Format"]["Y"] == "number" )\r
442         $Value = $Value.$DataDescription["Unit"]["Y"];\r
443        if ( $DataDescription["Format"]["Y"] == "time" )\r
444         $Value = $this->ToTime($Value);        \r
445        if ( $DataDescription["Format"]["Y"] == "date" )\r
446         $Value = $this->ToDate($Value);        \r
447        if ( $DataDescription["Format"]["Y"] == "metric" )\r
448         $Value = $this->ToMetric($Value);        \r
449 \r
450        $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Value,$bogus);\r
451        $TextWidth = $Position[2]-$Position[0];\r
452        imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X1-10-$TextWidth,$YPos+($this->FontSize/2),$C_TextColor,$this->FontName,$Value);\r
453 \r
454        if ( $XMin > $this->GArea_X1-10-$TextWidth || $XMin == NULL ) { $XMin = $this->GArea_X1-10-$TextWidth; }\r
455 \r
456        $YPos = $YPos - $this->DivisionHeight;\r
457       }\r
458 \r
459      /* Write the Y Axis caption if set */ \r
460      if ( isset($DataDescription["Axis"]["Y"]) )\r
461       {\r
462        $Position   = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["Y"],$bogus);\r
463        $TextHeight = abs($Position[1])+abs($Position[3]);\r
464        $TextTop    = (($this->GArea_Y2 - $this->GArea_Y1) / 2) + $this->GArea_Y1 + ($TextHeight/2);\r
465        imagettftext($this->Picture,$this->FontSize,90,$XMin-$this->FontSize,$TextTop,$C_TextColor,$this->FontName,$DataDescription["Axis"]["Y"]);\r
466       }\r
467 \r
468      /* Horizontal Axis */\r
469      $XPos = $this->GArea_X1 + $this->GAreaXOffset;\r
470      $ID = 1; $YMax = NULL;\r
471      foreach ( $Data as $Key => $Values )\r
472       {\r
473        if ( $ID % $SkipLabels == 0 )\r
474         {\r
475          $this->drawLine(floor($XPos),$this->GArea_Y2,floor($XPos),$this->GArea_Y2+5,$R,$G,$B);\r
476          $Value      = $Data[$Key][$DataDescription["Position"]];\r
477          if ( $DataDescription["Format"]["X"] == "number" )\r
478           $Value = $Value.$DataDescription["Unit"]["X"];\r
479          if ( $DataDescription["Format"]["X"] == "time" )\r
480           $Value = $this->ToTime($Value);        \r
481          if ( $DataDescription["Format"]["X"] == "date" )\r
482           $Value = $this->ToDate($Value);        \r
483          if ( $DataDescription["Format"]["X"] == "metric" )\r
484           $Value = $this->ToMetric($Value);        \r
485 \r
486          $Position   = imageftbbox($this->FontSize,$Angle,$this->FontName,$Value,$bogus);\r
487          $TextWidth  = abs($Position[2])+abs($Position[0]);\r
488          $TextHeight = abs($Position[1])+abs($Position[3]);\r
489 \r
490          if ( $Angle == 0 )\r
491           {\r
492            $YPos = $this->GArea_Y2+18;\r
493            imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)-floor($TextWidth/2),$YPos,$C_TextColor,$this->FontName,$Value);\r
494           }\r
495          else\r
496           {\r
497            $YPos = $this->GArea_Y2+10+$TextHeight;\r
498            if ( $Angle <= 90 )\r
499             imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)-$TextWidth+5,$YPos,$C_TextColor,$this->FontName,$Value);\r
500            else\r
501             imagettftext($this->Picture,$this->FontSize,$Angle,floor($XPos)+$TextWidth+5,$YPos,$C_TextColor,$this->FontName,$Value);\r
502           }\r
503          if ( $YMax < $YPos || $YMax == NULL ) { $YMax = $YPos; }\r
504         }\r
505 \r
506        $XPos = $XPos + $this->DivisionWidth;\r
507        $ID++;\r
508       }\r
509 \r
510     /* Write the X Axis caption if set */ \r
511     if ( isset($DataDescription["Axis"]["X"]) )\r
512       {\r
513        $Position   = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["X"],$bogus);\r
514        $TextWidth  = abs($Position[2])+abs($Position[0]);\r
515        $TextLeft   = (($this->GArea_X2 - $this->GArea_X1) / 2) + $this->GArea_X1 + ($TextWidth/2);\r
516        imagettftext($this->Picture,$this->FontSize,0,$TextLeft,$YMax+$this->FontSize+5,$C_TextColor,$this->FontName,$DataDescription["Axis"]["X"]);\r
517       }\r
518     }\r
519 \r
520    /* Compute and draw the scale */\r
521    function drawGrid($LineWidth,$Mosaic=TRUE,$R=220,$G=220,$B=220,$Alpha=100)\r
522     {\r
523      /* Draw mosaic */\r
524      if ( $Mosaic )\r
525       {\r
526        $LayerWidth  = $this->GArea_X2-$this->GArea_X1;\r
527        $LayerHeight = $this->GArea_Y2-$this->GArea_Y1;\r
528 \r
529        $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);\r
530        $C_White         = imagecolorallocate($this->Layers[0],255,255,255);\r
531        imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);\r
532        imagecolortransparent($this->Layers[0],$C_White);\r
533 \r
534        $C_Rectangle = imagecolorallocate($this->Layers[0],250,250,250);\r
535 \r
536        $YPos  = $LayerHeight; //$this->GArea_Y2-1;\r
537        $LastY = $YPos;\r
538        for($i=0;$i<=$this->DivisionCount;$i++)\r
539         {\r
540          $LastY = $YPos;\r
541          $YPos  = $YPos - $this->DivisionHeight;\r
542 \r
543          if ( $YPos <= 0 ) { $YPos = 1; }\r
544 \r
545          if ( $i % 2 == 0 )\r
546           {\r
547            imagefilledrectangle($this->Layers[0],1,$YPos,$LayerWidth-1,$LastY,$C_Rectangle);\r
548           }\r
549         }\r
550        imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);\r
551        imagedestroy($this->Layers[0]);\r
552       }\r
553 \r
554      /* Horizontal lines */\r
555      $YPos = $this->GArea_Y2 - $this->DivisionHeight;\r
556      for($i=1;$i<=$this->DivisionCount;$i++)\r
557       {\r
558        if ( $YPos > $this->GArea_Y1 && $YPos < $this->GArea_Y2 )\r
559         $this->drawDottedLine($this->GArea_X1,$YPos,$this->GArea_X2,$YPos,$LineWidth,$R,$G,$B);\r
560         \r
561        $YPos = $YPos - $this->DivisionHeight;\r
562       }\r
563 \r
564      /* Vertical lines */\r
565      if ( $this->GAreaXOffset == 0 )\r
566       { $XPos = $this->GArea_X1 + $this->DivisionWidth + $this->GAreaXOffset; $ColCount = $this->DataCount-2; }\r
567      else\r
568       { $XPos = $this->GArea_X1 + $this->GAreaXOffset; $ColCount = $this->DataCount; }\r
569 \r
570      for($i=1;$i<=$ColCount;$i++)\r
571       {\r
572        if ( $XPos > $this->GArea_X1 && $XPos < $this->GArea_X2 )\r
573         $this->drawDottedLine(floor($XPos),$this->GArea_Y1,floor($XPos),$this->GArea_Y2,$LineWidth,$R,$G,$B);\r
574        $XPos = $XPos + $this->DivisionWidth;\r
575       }\r
576     }\r
577 \r
578    /* retrieve the legends size */\r
579    function getLegendBoxSize($DataDescription)\r
580     {\r
581      if ( !isset($DataDescription["Description"]) )\r
582       return(-1);\r
583 \r
584      /* <-10->[8]<-4->Text<-10-> */\r
585      $MaxWidth = 0; $MaxHeight = 8;\r
586      foreach($DataDescription["Description"] as $Key => $Value)\r
587       {\r
588        $Position   = imageftbbox($this->FontSize,0,$this->FontName,$Value,$bogus);\r
589        $TextWidth  = $Position[2]-$Position[0];\r
590        $TextHeight = $Position[1]-$Position[7];\r
591        if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; }\r
592        $MaxHeight = $MaxHeight + $TextHeight + 4;\r
593       }\r
594      $MaxHeight = $MaxHeight - 3;\r
595      $MaxWidth  = $MaxWidth + 32;\r
596 \r
597      return(array($MaxWidth,$MaxHeight));\r
598     }\r
599 \r
600    /* Draw the data legends */\r
601    function drawLegend($XPos,$YPos,&$DataDescription,$R,$G,$B,$Rs=-1,$Gs=-1,$Bs=-1)\r
602     {\r
603      /* Validate the Data and DataDescription array */\r
604      $this->validateDataDescription("drawLegend",$DataDescription);\r
605 \r
606      if ( !isset($DataDescription["Description"]) )\r
607       return(-1);\r
608 \r
609      $C_TextColor = imagecolorallocate($this->Picture,0,0,0);\r
610 \r
611      /* <-10->[8]<-4->Text<-10-> */\r
612      $MaxWidth = 0; $MaxHeight = 8;\r
613      foreach($DataDescription["Description"] as $Key => $Value)\r
614       {\r
615        $Position   = imageftbbox($this->FontSize,0,$this->FontName,$Value,$bogus);\r
616        $TextWidth  = $Position[2]-$Position[0];\r
617        $TextHeight = $Position[1]-$Position[7];\r
618        if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; }\r
619        $MaxHeight = $MaxHeight + $TextHeight + 4;\r
620       }\r
621      $MaxHeight = $MaxHeight - 5;\r
622      $MaxWidth  = $MaxWidth + 32;\r
623 \r
624      if ( $Rs == -1 || $Gs == -1 || $Bs == -1 )\r
625       { $Rs = $R-30; $Gs = $G-30; $Bs = $B-30; }\r
626 \r
627      $this->drawFilledRoundedRectangle($XPos+1,$YPos+1,$XPos+$MaxWidth+1,$YPos+$MaxHeight+1,5,$Rs,$Gs,$Bs);\r
628      $this->drawFilledRoundedRectangle($XPos,$YPos,$XPos+$MaxWidth,$YPos+$MaxHeight,5,$R,$G,$B);\r
629 \r
630      $YOffset = 4 + $this->FontSize; $ID = 0;\r
631      foreach($DataDescription["Description"] as $Key => $Value)\r
632       {\r
633        $this->drawFilledRoundedRectangle($XPos+10,$YPos+$YOffset-4,$XPos+14,$YPos+$YOffset-4,2,$this->Palette[$ID]["R"],$this->Palette[$ID]["G"],$this->Palette[$ID]["B"]);\r
634        imagettftext($this->Picture,$this->FontSize,0,$XPos+22,$YPos+$YOffset,$C_TextColor,$this->FontName,$Value);\r
635 \r
636        $Position   = imageftbbox($this->FontSize,0,$this->FontName,$Value,$bogus);\r
637        $TextHeight = $Position[1]-$Position[7];\r
638 \r
639        $YOffset = $YOffset + $TextHeight + 4;\r
640        $ID++;\r
641       }\r
642     }\r
643 \r
644    /* Draw the data legends */\r
645    function drawPieLegend($XPos,$YPos,&$Data,&$DataDescription,$R,$G,$B)\r
646     {\r
647      /* Validate the Data and DataDescription array */\r
648      $this->validateDataDescription("drawPieLegend",$DataDescription,FALSE);\r
649      $this->validateData("drawPieLegend",$Data);\r
650 \r
651      if ( !isset($DataDescription["Position"]) )\r
652       return(-1);\r
653 \r
654      $C_TextColor = imagecolorallocate($this->Picture,0,0,0);\r
655 \r
656      /* <-10->[8]<-4->Text<-10-> */\r
657      $MaxWidth = 0; $MaxHeight = 8;\r
658      foreach($Data as $Key => $Value)\r
659       {\r
660        $Value2 = $Value[$DataDescription["Position"]];\r
661        $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Value2,$bogus);\r
662        $TextWidth = $Position[2]-$Position[0];\r
663        $TextHeight = $Position[1]-$Position[7];\r
664        if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; }\r
665 \r
666        $MaxHeight = $MaxHeight + $TextHeight + 4;\r
667       }\r
668      $MaxHeight = $MaxHeight - 3;\r
669      $MaxWidth  = $MaxWidth + 32;\r
670 \r
671      $this->drawFilledRoundedRectangle($XPos+1,$YPos+1,$XPos+$MaxWidth+1,$YPos+$MaxHeight+1,5,$R-30,$G-30,$B-30);\r
672      $this->drawFilledRoundedRectangle($XPos,$YPos,$XPos+$MaxWidth,$YPos+$MaxHeight,5,$R,$G,$B);\r
673 \r
674      $YOffset = 4 + $this->FontSize; $ID = 0;\r
675      foreach($Data as $Key => $Value)\r
676       {\r
677        $Value2     = $Value[$DataDescription["Position"]];\r
678        $Position   = imageftbbox($this->FontSize,0,$this->FontName,$Value2,$bogus);\r
679        $TextHeight = $Position[1]-$Position[7];\r
680        $this->drawFilledRectangle($XPos+10,$YPos+$YOffset-6,$XPos+14,$YPos+$YOffset-2,$this->Palette[$ID]["R"],$this->Palette[$ID]["G"],$this->Palette[$ID]["B"]);\r
681 \r
682        imagettftext($this->Picture,$this->FontSize,0,$XPos+22,$YPos+$YOffset,$C_TextColor,$this->FontName,$Value2);\r
683        $YOffset = $YOffset + $TextHeight + 4;\r
684        $ID++;\r
685       }\r
686     }\r
687 \r
688    /* Draw the graph title */\r
689    function drawTitle($XPos,$YPos,$Value,$R,$G,$B,$XPos2 = -1, $YPos2 = -1)\r
690     {\r
691      $C_TextColor = imagecolorallocate($this->Picture,$R,$G,$B);\r
692 \r
693      if ( $XPos2 != -1 )\r
694       {\r
695        $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Value,$bogus);\r
696        $TextWidth = $Position[2]-$Position[0];\r
697        $XPos      = floor(( $XPos2 - $XPos - $TextWidth ) / 2 ) + $XPos;\r
698       }\r
699 \r
700      if ( $YPos2 != -1 )\r
701       {\r
702        $Position   = imageftbbox($this->FontSize,0,$this->FontName,$Value,$bogus);\r
703        $TextHeight = $Position[5]-$Position[3];\r
704        $YPos       = floor(( $YPos2 - $YPos - $TextHeight ) / 2 ) + $YPos;\r
705       }\r
706 \r
707      imagettftext($this->Picture,$this->FontSize,0,$XPos,$YPos,$C_TextColor,$this->FontName,$Value);     \r
708     }\r
709 \r
710    /* Draw a text box with text align & alpha properties */\r
711    function drawTextBox($X1,$Y1,$X2,$Y2,$Text,$Angle=0,$R=255,$G=255,$B=255,$Align=ALIGN_LEFT,$Shadow=TRUE,$BgR=-1,$BgG=-1,$BgB=-1,$Alpha=100)\r
712     {\r
713      $Position   = imageftbbox($this->FontSize,$Angle,$this->FontName,$Text,$bogus);\r
714      $TextWidth  = $Position[2]-$Position[0];\r
715      $TextHeight = $Position[5]-$Position[3];\r
716      $AreaWidth  = $X2 - $X1;\r
717      $AreaHeight = $Y2 - $Y1;\r
718 \r
719      if ( $BgR != -1 && $BgG != -1 && $BgB != -1 )\r
720       $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$BgR,$BgG,$BgB,FALSE,$Alpha);\r
721 \r
722      if ( $Align == ALIGN_TOP_LEFT )      { $X = $X1+1; $Y = $Y1+$this->FontSize+1; }\r
723      if ( $Align == ALIGN_TOP_CENTER )    { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y1+$this->FontSize+1; }\r
724      if ( $Align == ALIGN_TOP_RIGHT )     { $X = $X2-$TextWidth-1; $Y = $Y1+$this->FontSize+1; }\r
725      if ( $Align == ALIGN_LEFT )          { $X = $X1+1; $Y = $Y1+($AreaHeight/2)-($TextHeight/2); }\r
726      if ( $Align == ALIGN_CENTER )        { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y1+($AreaHeight/2)-($TextHeight/2); }\r
727      if ( $Align == ALIGN_RIGHT )         { $X = $X2-$TextWidth-1; $Y = $Y1+($AreaHeight/2)-($TextHeight/2); }\r
728      if ( $Align == ALIGN_BOTTOM_LEFT )   { $X = $X1+1; $Y = $Y2-1; }\r
729      if ( $Align == ALIGN_BOTTOM_CENTER ) { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y2-1; }\r
730      if ( $Align == ALIGN_BOTTOM_RIGHT )  { $X = $X2-$TextWidth-1; $Y = $Y2-1; }\r
731 \r
732      $C_TextColor   = imagecolorallocate($this->Picture,$R,$G,$B);\r
733      $C_ShadowColor = imagecolorallocate($this->Picture,0,0,0);\r
734      if ( $Shadow )\r
735       imagettftext($this->Picture,$this->FontSize,$Angle,$X+1,$Y+1,$C_ShadowColor,$this->FontName,$Text);     \r
736 \r
737      imagettftext($this->Picture,$this->FontSize,$Angle,$X,$Y,$C_TextColor,$this->FontName,$Text);     \r
738     }\r
739 \r
740    /* Compute and draw the scale */\r
741    function drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnRight=FALSE,$TickWidth=4,$FreeText=NULL)\r
742     {\r
743      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
744      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
745      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
746 \r
747      $C_TextColor = imagecolorallocate($this->Picture,$R,$G,$B);\r
748      $Y = $this->GArea_Y2 - ($Value - $this->VMin) * $this->DivisionRatio;\r
749 \r
750      if ( $Y <= $this->GArea_Y1 || $Y >= $this->GArea_Y2 )\r
751       return(-1);\r
752 \r
753      if ( $TickWidth == 0 )\r
754       $this->drawLine($this->GArea_X1,$Y,$this->GArea_X2,$Y,$R,$G,$B);\r
755      else\r
756       $this->drawDottedLine($this->GArea_X1,$Y,$this->GArea_X2,$Y,$TickWidth,$R,$G,$B);\r
757 \r
758      if ( $ShowLabel )\r
759       {\r
760        if ( $FreeText == NULL )\r
761         { $Label = $Value; } else { $Label = $FreeText; }\r
762 \r
763        if ( $ShowOnRight )\r
764         imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X2+2,$Y+($this->FontSize/2),$C_TextColor,$this->FontName,$Label);\r
765        else\r
766         imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X1+2,$Y-($this->FontSize/2),$C_TextColor,$this->FontName,$Label);\r
767       }\r
768     }\r
769 \r
770    /* This function put a label on a specific point */\r
771    function setLabel(&$Data,&$DataDescription,$SerieName,$ValueName,$Caption,$R=210,$G=210,$B=210)\r
772     {\r
773      /* Validate the Data and DataDescription array */\r
774      $this->validateDataDescription("setLabel",$DataDescription);\r
775      $this->validateData("setLabel",$Data);\r
776 \r
777      $C_Label     = imagecolorallocate($this->Picture,$R,$G,$B);\r
778      $C_Shadow    = imagecolorallocate($this->Picture,$R-30,$G-30,$B-30);\r
779      $C_TextColor = imagecolorallocate($this->Picture,0,0,0);\r
780 \r
781      $Cp = 0; $Found = FALSE;\r
782      foreach ( $Data as $Key => $Value )\r
783       {\r
784        if ( $Data[$Key][$DataDescription["Position"]] == $ValueName )\r
785         { $NumericalValue = $Data[$Key][$SerieName]; $Found = TRUE; }\r
786        if ( !$Found )\r
787         $Cp++;\r
788       }\r
789 \r
790      $XPos = $this->GArea_X1 + $this->GAreaXOffset + ( $this->DivisionWidth * $Cp ) + 2;\r
791      $YPos = $this->GArea_Y2 - ($NumericalValue - $this->VMin) * $this->DivisionRatio;\r
792 \r
793      $Position   = imageftbbox($this->FontSize,0,$this->FontName,$Caption,$bogus);\r
794      $TextHeight = $Position[3] - $Position[5];\r
795      $TextWidth = $Position[2]-$Position[0];\r
796      $TextOffset = floor($TextHeight/2);\r
797 \r
798      // Shadow\r
799      $Poly = array($XPos+1,$YPos+1,$XPos + 9,$YPos - $TextOffset,$XPos + 8,$YPos + $TextOffset + 2);\r
800      imagefilledpolygon($this->Picture,$Poly,3,$C_Shadow);\r
801      $this->drawLine($XPos,$YPos+1,$XPos + 9,$YPos - $TextOffset - 1,$R-30,$G-30,$B-30);\r
802      $this->drawLine($XPos,$YPos+1,$XPos + 9,$YPos + $TextOffset + 3,$R-30,$G-30,$B-30);\r
803      $this->drawFilledRectangle($XPos + 9,$YPos - $TextOffset,$XPos + 13 + $TextWidth,$YPos + $TextOffset + 2,$R-30,$G-30,$B-30);\r
804 \r
805      // Label background\r
806      $Poly = array($XPos,$YPos,$XPos + 8,$YPos - $TextOffset - 1,$XPos + 8,$YPos + $TextOffset + 1);\r
807      imagefilledpolygon($this->Picture,$Poly,3,$C_Label);\r
808      $this->drawLine($XPos-1,$YPos,$XPos + 8,$YPos - $TextOffset - 2,$R,$G,$B);\r
809      $this->drawLine($XPos-1,$YPos,$XPos + 8,$YPos + $TextOffset + 2,$R,$G,$B);\r
810      $this->drawFilledRectangle($XPos + 8,$YPos - $TextOffset - 1,$XPos + 12 + $TextWidth,$YPos + $TextOffset + 1,$R,$G,$B);\r
811 \r
812      imagettftext($this->Picture,$this->FontSize,0,$XPos + 10,$YPos + $TextOffset,$C_TextColor,$this->FontName,$Caption);\r
813     }\r
814 \r
815    /* This function draw a line graph */\r
816    function drawPlotGraph(&$Data,&$DataDescription,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1)\r
817     {\r
818      /* Validate the Data and DataDescription array */\r
819      $this->validateDataDescription("drawPlotGraph",$DataDescription);\r
820      $this->validateData("drawPlotGraph",$Data);\r
821 \r
822      $GraphID = 0;\r
823 \r
824      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
825       {\r
826        $ID = 0;\r
827        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
828         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
829 \r
830        $R = $this->Palette[$ColorID]["R"];\r
831        $G = $this->Palette[$ColorID]["G"];\r
832        $B = $this->Palette[$ColorID]["B"];\r
833 \r
834        if ( isset($DataDescription["Symbol"][$ColName]) )\r
835         {\r
836          //$Is_Alpha = ((ord ( file_get_contents ($DataDescription["Symbol"][$ColName], false, null, 25, 1)) & 6) & 4) == 4;\r
837          $Is_Alpha = ((ord ( file_get_contents ($DataDescription["Symbol"][$ColName], false)) & 6) & 4) == 4;\r
838 \r
839          $Infos       = getimagesize($DataDescription["Symbol"][$ColName]);\r
840          $ImageWidth  = $Infos[0];\r
841          $ImageHeight = $Infos[1];\r
842          $Symbol      = imagecreatefromgif($DataDescription["Symbol"][$ColName]);\r
843         }\r
844 \r
845        $XPos  = $this->GArea_X1 + $this->GAreaXOffset;\r
846        $Hsize = round($BigRadius/2);\r
847        foreach ( $Data as $Key => $Values )\r
848         {\r
849          $Value = $Data[$Key][$ColName];\r
850          $YPos  = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);\r
851 \r
852          /* Save point into the image map if option activated */\r
853          if ( $this->BuildMap )\r
854           $this->addToImageMap($XPos-$Hsize,$YPos-$Hsize,$XPos+1+$Hsize,$YPos+$Hsize+1,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Plot");\r
855 \r
856          if ( is_numeric($Value) )\r
857           {\r
858            if ( !isset($DataDescription["Symbol"][$ColName]) )\r
859             {\r
860              $this->drawFilledCircle($XPos+1,$YPos+1,$BigRadius,$R,$G,$B);\r
861 \r
862              if ( $R2 !=-1 && $G2 !=-1 && $B2 !=-1 )\r
863               $this->drawFilledCircle($XPos+1,$YPos+1,$SmallRadius,$R2,$G2,$B2);\r
864              else\r
865               {\r
866                $R = $this->Palette[$ColorID]["R"]-5; if ( $R < 0 ) { $R = 0; }\r
867                $G = $this->Palette[$ColorID]["G"]-5; if ( $G < 0 ) { $G = 0; }\r
868                $B = $this->Palette[$ColorID]["B"]-5; if ( $B < 0 ) { $B = 0; }\r
869 \r
870                $this->drawFilledCircle($XPos+1,$YPos+1,$SmallRadius,$R,$G,$B);\r
871               }\r
872             }\r
873            else\r
874             {\r
875              imagecopymerge($this->Picture,$Symbol,$XPos+1-$ImageWidth/2,$YPos+1-$ImageHeight/2,0,0,$ImageWidth,$ImageHeight,100);\r
876             }\r
877           }\r
878 \r
879          $XPos = $XPos + $this->DivisionWidth;\r
880         }\r
881        $GraphID++;\r
882       }\r
883     }\r
884 \r
885 \r
886    /* This function draw an area between two series */\r
887    function drawArea(&$Data,$Serie1,$Serie2,$R,$G,$B,$Alpha = 50)\r
888     {\r
889      /* Validate the Data and DataDescription array */\r
890      $this->validateData("drawArea",$Data);\r
891 \r
892      $LayerWidth  = $this->GArea_X2-$this->GArea_X1;\r
893      $LayerHeight = $this->GArea_Y2-$this->GArea_Y1;\r
894 \r
895      $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);\r
896      $C_White         = imagecolorallocate($this->Layers[0],255,255,255);\r
897      imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);\r
898      imagecolortransparent($this->Layers[0],$C_White);\r
899 \r
900      $C_Graph = imagecolorallocate($this->Layers[0],$R,$G,$B);\r
901 \r
902      $XPos     = $this->GAreaXOffset;\r
903      $LastXPos = -1;\r
904      foreach ( $Data as $Key => $Values )\r
905       {\r
906        $Value1 = $Data[$Key][$Serie1];\r
907        $Value2 = $Data[$Key][$Serie2];\r
908        $YPos1  = $LayerHeight - (($Value1-$this->VMin) * $this->DivisionRatio);\r
909        $YPos2  = $LayerHeight - (($Value2-$this->VMin) * $this->DivisionRatio);\r
910 \r
911        if ( $LastXPos != -1 )\r
912         {\r
913          $Points   = "";\r
914          $Points[] = $LastXPos; $Points[] = $LastYPos1;\r
915          $Points[] = $LastXPos; $Points[] = $LastYPos2;\r
916          $Points[] = $XPos; $Points[] = $YPos2;\r
917          $Points[] = $XPos; $Points[] = $YPos1;\r
918 \r
919          imagefilledpolygon($this->Layers[0],$Points,4,$C_Graph);\r
920         }\r
921 \r
922        $LastYPos1 = $YPos1;\r
923        $LastYPos2 = $YPos2;\r
924        $LastXPos  = $XPos;\r
925 \r
926        $XPos = $XPos + $this->DivisionWidth;\r
927       }\r
928 \r
929      imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);\r
930      imagedestroy($this->Layers[0]);\r
931     }\r
932 \r
933 \r
934    /* This function write the values of the specified series */\r
935    function writeValues(&$Data,&$DataDescription,$Series)\r
936     {\r
937      /* Validate the Data and DataDescription array */\r
938      $this->validateDataDescription("writeValues",$DataDescription);\r
939      $this->validateData("writeValues",$Data);\r
940 \r
941      if ( !is_array($Series) ) { $Series = array($Series); }     \r
942 \r
943      foreach($Series as $Key => $Serie)\r
944       {\r
945        $ID = 0;\r
946        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
947         { if ( $keyI == $Serie ) { $ColorID = $ID; }; $ID++; }\r
948 \r
949        $XPos  = $this->GArea_X1 + $this->GAreaXOffset;\r
950        $XLast = -1;\r
951        foreach ( $Data as $Key => $Values )\r
952         {\r
953          if ( isset($Data[$Key][$Serie]) && is_numeric($Data[$Key][$Serie]))\r
954           {\r
955            $Value = $Data[$Key][$Serie];\r
956            $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);\r
957 \r
958            $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Value);\r
959            $Width  = $Positions[2] - $Positions[6]; $XOffset = $XPos - ($Width/2); \r
960            $Height = $Positions[3] - $Positions[7]; $YOffset = $YPos - 4;\r
961 \r
962            $C_TextColor = imagecolorallocate($this->Picture,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
963            imagettftext($this->Picture,$this->FontSize,0,$XOffset,$YOffset,$C_TextColor,$this->FontName,$Value);\r
964           }\r
965          $XPos = $XPos + $this->DivisionWidth;\r
966         }\r
967 \r
968       }\r
969     }\r
970 \r
971    /* This function draw a line graph */\r
972    function drawLineGraph(&$Data,&$DataDescription,$SerieName="")\r
973     {\r
974      /* Validate the Data and DataDescription array */\r
975      $this->validateDataDescription("drawLineGraph",$DataDescription);\r
976      $this->validateData("drawLineGraph",$Data);\r
977 \r
978      $GraphID = 0;\r
979      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
980       {\r
981        $ID = 0;\r
982        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
983         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
984 \r
985        if ( $SerieName == "" || $SerieName == $ColName )\r
986         {\r
987          $XPos  = $this->GArea_X1 + $this->GAreaXOffset;\r
988          $XLast = -1;\r
989          foreach ( $Data as $Key => $Values )\r
990           {\r
991            if ( isset($Data[$Key][$ColName]))\r
992             {\r
993              $Value = $Data[$Key][$ColName];\r
994              $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);\r
995 \r
996              /* Save point into the image map if option activated */\r
997              if ( $this->BuildMap )\r
998               $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Line");\r
999 \r
1000              if (!is_numeric($Value)) { $XLast = -1; }\r
1001              if ( $XLast != -1 )\r
1002               $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE);\r
1003 \r
1004              $XLast = $XPos;\r
1005              $YLast = $YPos;\r
1006              if (!is_numeric($Value)) { $XLast = -1; }\r
1007             }\r
1008            $XPos = $XPos + $this->DivisionWidth;\r
1009           }\r
1010          $GraphID++;\r
1011         }\r
1012       }\r
1013     }\r
1014 \r
1015    /* This function draw a cubic curve */\r
1016    function drawCubicCurve(&$Data,&$DataDescription,$Accuracy=.1,$SerieName="")\r
1017     {\r
1018      /* Validate the Data and DataDescription array */\r
1019      $this->validateDataDescription("drawCubicCurve",$DataDescription);\r
1020      $this->validateData("drawCubicCurve",$Data);\r
1021 \r
1022      $GraphID = 0;\r
1023      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1024       {\r
1025        if ( $SerieName == "" || $SerieName == $ColName )\r
1026         {\r
1027          $XIn = ""; $Yin = ""; $Yt = ""; $U = "";\r
1028          $XIn[0] = 0; $YIn[0] = 0;\r
1029 \r
1030          $ID = 0;\r
1031          foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1032           { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1033 \r
1034          $Index = 1;\r
1035          $XLast = -1; $Missing = "";\r
1036          foreach ( $Data as $Key => $Values )\r
1037           {\r
1038            if ( isset($Data[$Key][$ColName]) )\r
1039             {\r
1040              $Value = $Data[$Key][$ColName];\r
1041              $XIn[$Index] = $Index;\r
1042              $YIn[$Index] = $Value;\r
1043              if ( !is_numeric($Value) ) { $Missing[$Index] = TRUE; }\r
1044              $Index++;\r
1045             }\r
1046           }\r
1047          $Index--;\r
1048 \r
1049          $Yt[0] = 0;\r
1050          $Yt[1] = 0;\r
1051          $U[1]  = 0;\r
1052          for($i=2;$i<=$Index-1;$i++)\r
1053           {\r
1054            $Sig    = ($XIn[$i] - $XIn[$i-1]) / ($XIn[$i+1] - $XIn[$i-1]);\r
1055            $p      = $Sig * $Yt[$i-1] + 2;\r
1056            $Yt[$i] = ($Sig - 1) / $p;\r
1057            $U[$i]  = ($YIn[$i+1] - $YIn[$i]) / ($XIn[$i+1] - $XIn[$i]) - ($YIn[$i] - $YIn[$i-1]) / ($XIn[$i] - $XIn[$i-1]);\r
1058            $U[$i]  = (6 * $U[$i] / ($XIn[$i+1] - $XIn[$i-1]) - $Sig * $U[$i-1]) / $p;\r
1059           }\r
1060 \r
1061          $qn = 0;\r
1062          $un = 0;\r
1063          $Yt[$Index] = ($un - $qn * $U[$Index-1]) / ($qn * $Yt[$Index-1] + 1);\r
1064 \r
1065          for($k=$Index-1;$k>=1;$k--)\r
1066           $Yt[$k] = $Yt[$k] * $Yt[$k+1] + $U[$k];\r
1067 \r
1068          $XPos  = $this->GArea_X1 + $this->GAreaXOffset;\r
1069          for($X=1;$X<=$Index;$X=$X+$Accuracy)\r
1070           {\r
1071            $klo = 1;\r
1072            $khi = $Index;\r
1073            $k   = $khi - $klo;\r
1074            while($k > 1)\r
1075             {\r
1076              $k = $khi - $klo;\r
1077              If ( $XIn[$k] >= $X )\r
1078               $khi = $k;\r
1079              else\r
1080               $klo = $k;\r
1081             }\r
1082            $klo = $khi - 1;\r
1083 \r
1084            $h     = $XIn[$khi] - $XIn[$klo];\r
1085            $a     = ($XIn[$khi] - $X) / $h;\r
1086            $b     = ($X - $XIn[$klo]) / $h;\r
1087            $Value = $a * $YIn[$klo] + $b * $YIn[$khi] + (($a*$a*$a - $a) * $Yt[$klo] + ($b*$b*$b - $b) * $Yt[$khi]) * ($h*$h) / 6;\r
1088 \r
1089            $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);\r
1090 \r
1091            if ( $XLast != -1 && !isset($Missing[floor($X)]) && !isset($Missing[floor($X+1)]) )\r
1092             $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE);\r
1093 \r
1094            $XLast = $XPos;\r
1095            $YLast = $YPos;\r
1096            $XPos  = $XPos + $this->DivisionWidth * $Accuracy;\r
1097           }\r
1098 \r
1099          // Add potentialy missing values\r
1100          $XPos  = $XPos - $this->DivisionWidth * $Accuracy;\r
1101          if ( $XPos < ($this->GArea_X2 - $this->GAreaXOffset) )\r
1102           {\r
1103            $YPos = $this->GArea_Y2 - (($YIn[$Index]-$this->VMin) * $this->DivisionRatio);\r
1104            $this->drawLine($XLast,$YLast,$this->GArea_X2-$this->GAreaXOffset,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE);\r
1105           }\r
1106 \r
1107          $GraphID++;\r
1108         }\r
1109       }\r
1110     }\r
1111 \r
1112    /* This function draw a filled cubic curve */\r
1113    function drawFilledCubicCurve(&$Data,&$DataDescription,$Accuracy=.1,$Alpha=100,$AroundZero=FALSE)\r
1114     {\r
1115      /* Validate the Data and DataDescription array */\r
1116      $this->validateDataDescription("drawFilledCubicCurve",$DataDescription);\r
1117      $this->validateData("drawFilledCubicCurve",$Data);\r
1118 \r
1119      $LayerWidth  = $this->GArea_X2-$this->GArea_X1;\r
1120      $LayerHeight = $this->GArea_Y2-$this->GArea_Y1;\r
1121      $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio);\r
1122      if ( $YZero > $LayerHeight ) { $YZero = $LayerHeight; }\r
1123 \r
1124      $GraphID = 0;\r
1125      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1126       {\r
1127        $XIn = ""; $Yin = ""; $Yt = ""; $U = "";\r
1128        $XIn[0] = 0; $YIn[0] = 0;\r
1129 \r
1130        $ID = 0;\r
1131        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1132         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1133 \r
1134        $Index = 1;\r
1135        $XLast = -1; $Missing = "";\r
1136        foreach ( $Data as $Key => $Values )\r
1137         {\r
1138          $Value = $Data[$Key][$ColName];\r
1139          $XIn[$Index] = $Index;\r
1140          $YIn[$Index] = $Value;\r
1141          if ( !is_numeric($Value) ) { $Missing[$Index] = TRUE; }\r
1142          $Index++;\r
1143         }\r
1144        $Index--;\r
1145  \r
1146        $Yt[0] = 0;\r
1147        $Yt[1] = 0;\r
1148        $U[1]  = 0;\r
1149        for($i=2;$i<=$Index-1;$i++)\r
1150         {\r
1151          $Sig    = ($XIn[$i] - $XIn[$i-1]) / ($XIn[$i+1] - $XIn[$i-1]);\r
1152          $p      = $Sig * $Yt[$i-1] + 2;\r
1153          $Yt[$i] = ($Sig - 1) / $p;\r
1154          $U[$i]  = ($YIn[$i+1] - $YIn[$i]) / ($XIn[$i+1] - $XIn[$i]) - ($YIn[$i] - $YIn[$i-1]) / ($XIn[$i] - $XIn[$i-1]);\r
1155          $U[$i]  = (6 * $U[$i] / ($XIn[$i+1] - $XIn[$i-1]) - $Sig * $U[$i-1]) / $p;\r
1156         }\r
1157 \r
1158        $qn = 0;\r
1159        $un = 0;\r
1160        $Yt[$Index] = ($un - $qn * $U[$Index-1]) / ($qn * $Yt[$Index-1] + 1);\r
1161 \r
1162        for($k=$Index-1;$k>=1;$k--)\r
1163         $Yt[$k] = $Yt[$k] * $Yt[$k+1] + $U[$k];\r
1164 \r
1165        $Points   = "";\r
1166        $Points[] = $this->GAreaXOffset;\r
1167        $Points[] = $LayerHeight;\r
1168 \r
1169        $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);\r
1170        $C_White         = imagecolorallocate($this->Layers[0],255,255,255);\r
1171        imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);\r
1172        imagecolortransparent($this->Layers[0],$C_White);\r
1173 \r
1174        $YLast = NULL;\r
1175        $XPos  = $this->GAreaXOffset; $PointsCount = 2;\r
1176        for($X=1;$X<=$Index;$X=$X+$Accuracy)\r
1177         {\r
1178          $klo = 1;\r
1179          $khi = $Index;\r
1180          $k   = $khi - $klo;\r
1181          while($k > 1)\r
1182           {\r
1183            $k = $khi - $klo;\r
1184            If ( $XIn[$k] >= $X )\r
1185             $khi = $k;\r
1186            else\r
1187             $klo = $k;\r
1188           }\r
1189          $klo = $khi - 1;\r
1190 \r
1191          $h     = $XIn[$khi] - $XIn[$klo];\r
1192          $a     = ($XIn[$khi] - $X) / $h;\r
1193          $b     = ($X - $XIn[$klo]) / $h;\r
1194          $Value = $a * $YIn[$klo] + $b * $YIn[$khi] + (($a*$a*$a - $a) * $Yt[$klo] + ($b*$b*$b - $b) * $Yt[$khi]) * ($h*$h) / 6;\r
1195 \r
1196          $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio);\r
1197 \r
1198          if ( $YLast != NULL && $AroundZero && !isset($Missing[floor($X)]) && !isset($Missing[floor($X+1)]))\r
1199           {\r
1200            $aPoints   = "";\r
1201            $aPoints[] = $XLast;\r
1202            $aPoints[] = $YLast;\r
1203            $aPoints[] = $XPos;\r
1204            $aPoints[] = $YPos;\r
1205            $aPoints[] = $XPos;\r
1206            $aPoints[] = $YZero;\r
1207            $aPoints[] = $XLast;\r
1208            $aPoints[] = $YZero;\r
1209 \r
1210            $C_Graph = imagecolorallocate($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1211            imagefilledpolygon($this->Layers[0],$aPoints,4,$C_Graph);\r
1212           }\r
1213 \r
1214          if ( !isset($Missing[floor($X)]) || $YLast == NULL )\r
1215           {\r
1216            $PointsCount++;\r
1217            $Points[] = $XPos;\r
1218            $Points[] = $YPos;\r
1219           }\r
1220          else\r
1221           {\r
1222            $PointsCount++; $Points[] = $XLast; $Points[] = $LayerHeight;\r
1223           }\r
1224 \r
1225          $YLast = $YPos; $XLast = $XPos; \r
1226          $XPos  = $XPos + $this->DivisionWidth * $Accuracy;\r
1227         }\r
1228 \r
1229        // Add potentialy missing values\r
1230        $XPos  = $XPos - $this->DivisionWidth * $Accuracy;\r
1231        if ( $XPos < ($LayerWidth-$this->GAreaXOffset) )\r
1232         {\r
1233          $YPos = $LayerHeight - (($YIn[$Index]-$this->VMin) * $this->DivisionRatio);\r
1234 \r
1235          if ( $YLast != NULL && $AroundZero )\r
1236           {\r
1237            $aPoints   = "";\r
1238            $aPoints[] = $XLast;\r
1239            $aPoints[] = $YLast;\r
1240            $aPoints[] = $LayerWidth-$this->GAreaXOffset;\r
1241            $aPoints[] = $YPos;\r
1242            $aPoints[] = $LayerWidth-$this->GAreaXOffset;\r
1243            $aPoints[] = $YZero;\r
1244            $aPoints[] = $XLast;\r
1245            $aPoints[] = $YZero;\r
1246 \r
1247            $C_Graph = imagecolorallocate($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1248            imagefilledpolygon($this->Layers[0],$aPoints,4,$C_Graph);\r
1249           }\r
1250 \r
1251          if ( $YIn[$klo] != "" && $YIn[$khi] != "" || $YLast == NULL )\r
1252           {\r
1253            $PointsCount++;\r
1254            $Points[] = $LayerWidth-$this->GAreaXOffset;\r
1255            $Points[] = $YPos;\r
1256           }\r
1257         }\r
1258 \r
1259        $Points[] = $LayerWidth-$this->GAreaXOffset;\r
1260        $Points[] = $LayerHeight;\r
1261 \r
1262        if ( !$AroundZero )\r
1263         {\r
1264          $C_Graph = imagecolorallocate($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1265          imagefilledpolygon($this->Layers[0],$Points,$PointsCount,$C_Graph);\r
1266         }\r
1267 \r
1268        imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);\r
1269        imagedestroy($this->Layers[0]);\r
1270 \r
1271        $this->drawCubicCurve($Data,$DataDescription,$Accuracy,$ColName);\r
1272 \r
1273        $GraphID++;\r
1274       }\r
1275     }\r
1276 \r
1277    /* This function draw a filled line graph */\r
1278    function drawFilledLineGraph(&$Data,&$DataDescription,$Alpha=100,$AroundZero=FALSE)\r
1279     {\r
1280      $Empty = -2147483647;\r
1281 \r
1282      /* Validate the Data and DataDescription array */\r
1283      $this->validateDataDescription("drawFilledLineGraph",$DataDescription);\r
1284      $this->validateData("drawFilledLineGraph",$Data);\r
1285 \r
1286      $LayerWidth  = $this->GArea_X2-$this->GArea_X1;\r
1287      $LayerHeight = $this->GArea_Y2-$this->GArea_Y1;\r
1288 \r
1289      $GraphID = 0;\r
1290      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1291       {\r
1292        $ID = 0;\r
1293        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1294         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1295 \r
1296        $aPoints   = "";\r
1297        $aPoints[] = $this->GAreaXOffset;\r
1298        $aPoints[] = $LayerHeight;\r
1299 \r
1300        $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);\r
1301        $C_White         = imagecolorallocate($this->Layers[0],255,255,255);\r
1302        imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);\r
1303        imagecolortransparent($this->Layers[0],$C_White);\r
1304 \r
1305        $XPos  = $this->GAreaXOffset;\r
1306        $XLast = -1; $PointsCount = 2;\r
1307        $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio);\r
1308        if ( $YZero > $LayerHeight ) { $YZero = $LayerHeight; }\r
1309 \r
1310        $YLast = $Empty;\r
1311        foreach ( $Data as $Key => $Values )\r
1312         {\r
1313          $Value = $Data[$Key][$ColName];\r
1314          $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio);\r
1315 \r
1316          /* Save point into the image map if option activated */\r
1317          if ( $this->BuildMap )\r
1318           $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"FLine");\r
1319 \r
1320          if ( !is_numeric($Value) )\r
1321           {\r
1322            $PointsCount++;\r
1323            $aPoints[] = $XLast;\r
1324            $aPoints[] = $LayerHeight;\r
1325 \r
1326            $YLast = $Empty;\r
1327           }\r
1328          else\r
1329           {\r
1330            $PointsCount++;\r
1331            if ( $YLast <> $Empty )\r
1332             { $aPoints[] = $XPos; $aPoints[] = $YPos; }\r
1333            else\r
1334             { $PointsCount++; $aPoints[] = $XPos; $aPoints[] = $LayerHeight; $aPoints[] = $XPos; $aPoints[] = $YPos; }\r
1335 \r
1336            if ($YLast <> $Empty && $AroundZero)\r
1337             {\r
1338              $Points   = "";\r
1339              $Points[] = $XLast; $Points[] = $YLast;\r
1340              $Points[] = $XPos;\r
1341              $Points[] = $YPos;\r
1342              $Points[] = $XPos;\r
1343              $Points[] = $YZero;\r
1344              $Points[] = $XLast;\r
1345              $Points[] = $YZero;\r
1346 \r
1347              $C_Graph = imagecolorallocate($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1348              imagefilledpolygon($this->Layers[0],$Points,4,$C_Graph);\r
1349             }\r
1350            $YLast = $YPos;\r
1351           }\r
1352 \r
1353          $XLast = $XPos;\r
1354          $XPos  = $XPos + $this->DivisionWidth;\r
1355         }\r
1356        $aPoints[] = $LayerWidth - $this->GAreaXOffset;\r
1357        $aPoints[] = $LayerHeight;\r
1358 \r
1359        if ( $AroundZero == FALSE )\r
1360         {\r
1361          $C_Graph = imagecolorallocate($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1362          imagefilledpolygon($this->Layers[0],$aPoints,$PointsCount,$C_Graph);\r
1363         }\r
1364 \r
1365        imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);\r
1366        imagedestroy($this->Layers[0]);\r
1367        $GraphID++;\r
1368        $this->drawLineGraph($Data,$DataDescription,$ColName);\r
1369       }\r
1370     }\r
1371 \r
1372    /* This function draw a bar graph */\r
1373    function drawOverlayBarGraph(&$Data,&$DataDescription,$Alpha=50)\r
1374     {\r
1375      /* Validate the Data and DataDescription array */\r
1376      $this->validateDataDescription("drawOverlayBarGraph",$DataDescription);\r
1377      $this->validateData("drawOverlayBarGraph",$Data);\r
1378 \r
1379      $LayerWidth  = $this->GArea_X2-$this->GArea_X1;\r
1380      $LayerHeight = $this->GArea_Y2-$this->GArea_Y1;\r
1381 \r
1382      $GraphID = 0;\r
1383      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1384       {\r
1385        $ID = 0;\r
1386        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1387         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1388 \r
1389        $this->Layers[$GraphID] = imagecreatetruecolor($LayerWidth,$LayerHeight);\r
1390        $C_White                = imagecolorallocate($this->Layers[$GraphID],255,255,255);\r
1391        $C_Graph                = imagecolorallocate($this->Layers[$GraphID],$this->Palette[$GraphID]["R"],$this->Palette[$GraphID]["G"],$this->Palette[$GraphID]["B"]);\r
1392        imagefilledrectangle($this->Layers[$GraphID],0,0,$LayerWidth,$LayerHeight,$C_White);\r
1393        imagecolortransparent($this->Layers[$GraphID],$C_White);\r
1394 \r
1395        $XWidth = $this->DivisionWidth / 4;\r
1396        $XPos   = $this->GAreaXOffset;\r
1397        $YZero  = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio);\r
1398        $XLast  = -1; $PointsCount = 2;\r
1399        foreach ( $Data as $Key => $Values )\r
1400         {\r
1401          if ( isset($Data[$Key][$ColName]) )\r
1402           {\r
1403            $Value = $Data[$Key][$ColName];\r
1404            if ( is_numeric($Value) )\r
1405             {\r
1406              $YPos  = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio);\r
1407 \r
1408              imagefilledrectangle($this->Layers[$GraphID],$XPos-$XWidth,$YPos,$XPos+$XWidth,$YZero,$C_Graph);\r
1409 \r
1410              $X1 = floor($XPos - $XWidth + $this->GArea_X1); $Y1 = floor($YPos+$this->GArea_Y1) + .2;\r
1411              $X2 = floor($XPos + $XWidth + $this->GArea_X1); $Y2 = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio);\r
1412              if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; }\r
1413              if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; }\r
1414 \r
1415              /* Save point into the image map if option activated */\r
1416              if ( $this->BuildMap )\r
1417               $this->addToImageMap($X1,min($Y1,$Y2),$X2,max($Y1,$Y2),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"oBar");\r
1418 \r
1419              $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE);\r
1420             }\r
1421           }\r
1422          $XPos = $XPos + $this->DivisionWidth;\r
1423         }\r
1424 \r
1425        $GraphID++;\r
1426       }\r
1427 \r
1428      for($i=0;$i<=($GraphID-1);$i++)\r
1429       {\r
1430        imagecopymerge($this->Picture,$this->Layers[$i],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);\r
1431        imagedestroy($this->Layers[$i]);\r
1432       }\r
1433     }\r
1434 \r
1435    /* This function draw a bar graph */\r
1436    function drawBarGraph(&$Data,&$DataDescription,$Shadow=FALSE,$Alpha=100)\r
1437     {\r
1438      /* Validate the Data and DataDescription array */\r
1439      $this->validateDataDescription("drawBarGraph",$DataDescription);\r
1440      $this->validateData("drawBarGraph",$Data);\r
1441 \r
1442      $GraphID      = 0;\r
1443      $Series       = count($DataDescription["Values"]);\r
1444      $SeriesWidth  = $this->DivisionWidth / ($Series+1);\r
1445      $SerieXOffset = $this->DivisionWidth / 2 - $SeriesWidth / 2;\r
1446 \r
1447      $YZero  = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio);\r
1448      if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; }\r
1449 \r
1450      $SerieID = 0;\r
1451      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1452       {\r
1453        $ID = 0;\r
1454        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1455         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1456 \r
1457        $XPos  = $this->GArea_X1 + $this->GAreaXOffset - $SerieXOffset + $SeriesWidth * $SerieID;\r
1458        $XLast = -1;\r
1459        foreach ( $Data as $Key => $Values )\r
1460         {\r
1461          if ( isset($Data[$Key][$ColName]))\r
1462           {\r
1463            if ( is_numeric($Data[$Key][$ColName]) )\r
1464             {\r
1465              $Value = $Data[$Key][$ColName];\r
1466              $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);\r
1467 \r
1468              /* Save point into the image map if option activated */\r
1469              if ( $this->BuildMap )\r
1470               {\r
1471                $this->addToImageMap($XPos+1,min($YZero,$YPos),$XPos+$SeriesWidth-1,max($YZero,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Bar");\r
1472               }\r
1473            \r
1474              if ( $Shadow && $Alpha == 100 )\r
1475               $this->drawRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,25,25,25,TRUE,$Alpha);\r
1476 \r
1477              $this->drawFilledRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha);\r
1478             }\r
1479           }\r
1480          $XPos = $XPos + $this->DivisionWidth;\r
1481         }\r
1482        $SerieID++;\r
1483       }\r
1484     }\r
1485 \r
1486    /* This function draw a stacked bar graph */\r
1487    function drawStackedBarGraph(&$Data,&$DataDescription,$Alpha=50)\r
1488     {\r
1489      /* Validate the Data and DataDescription array */\r
1490      $this->validateDataDescription("drawBarGraph",$DataDescription);\r
1491      $this->validateData("drawBarGraph",$Data);\r
1492 \r
1493      $GraphID      = 0;\r
1494      $Series       = count($DataDescription["Values"]);\r
1495      $SeriesWidth  = $this->DivisionWidth * .8;\r
1496 \r
1497      $YZero  = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio);\r
1498      if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; }\r
1499 \r
1500      $SerieID = 0; $LastValue = "";\r
1501      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1502       {\r
1503        $ID = 0;\r
1504        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1505         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1506 \r
1507        $XPos  = $this->GArea_X1 + $this->GAreaXOffset - $SeriesWidth / 2;\r
1508        $XLast = -1; \r
1509        foreach ( $Data as $Key => $Values )\r
1510         {\r
1511          if ( isset($Data[$Key][$ColName]))\r
1512           {\r
1513            if ( is_numeric($Data[$Key][$ColName]) )\r
1514             {\r
1515              $Value = $Data[$Key][$ColName];\r
1516 \r
1517              if ( isset($LastValue[$Key]) )\r
1518               {\r
1519                $YPos    = $this->GArea_Y2 - ((($Value+$LastValue[$Key])-$this->VMin) * $this->DivisionRatio);\r
1520                $YBottom = $this->GArea_Y2 - (($LastValue[$Key]-$this->VMin) * $this->DivisionRatio);\r
1521                $LastValue[$Key] += $Value;\r
1522               }\r
1523              else\r
1524               {\r
1525                $YPos    = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);\r
1526                $YBottom = $YZero;\r
1527                $LastValue[$Key] = $Value;\r
1528               }\r
1529 \r
1530              /* Save point into the image map if option activated */\r
1531              if ( $this->BuildMap )\r
1532               $this->addToImageMap($XPos+1,min($YBottom,$YPos),$XPos+$SeriesWidth-1,max($YBottom,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"sBar");\r
1533 \r
1534              $this->drawFilledRectangle($XPos+1,$YBottom,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha);\r
1535             }\r
1536           }\r
1537          $XPos = $XPos + $this->DivisionWidth;\r
1538         }\r
1539        $SerieID++;\r
1540       }\r
1541     }\r
1542 \r
1543    /* This function draw a limits bar graphs */\r
1544    function drawLimitsGraph(&$Data,&$DataDescription,$R=0,$G=0,$B=0)\r
1545     {\r
1546      /* Validate the Data and DataDescription array */\r
1547      $this->validateDataDescription("drawLimitsGraph",$DataDescription);\r
1548      $this->validateData("drawLimitsGraph",$Data);\r
1549 \r
1550      $XWidth = $this->DivisionWidth / 4;\r
1551      $XPos   = $this->GArea_X1 + $this->GAreaXOffset;\r
1552 \r
1553      foreach ( $Data as $Key => $Values )\r
1554       {\r
1555        $Min     = $Data[$Key][$DataDescription["Values"][0]];\r
1556        $Max     = $Data[$Key][$DataDescription["Values"][0]];\r
1557        $GraphID = 0; $MaxID = 0; $MinID = 0;\r
1558        foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1559         {\r
1560          if ( isset($Data[$Key][$ColName]) )\r
1561           {\r
1562            if ( $Data[$Key][$ColName] > $Max && is_numeric($Data[$Key][$ColName]))\r
1563             { $Max = $Data[$Key][$ColName]; $MaxID = $GraphID; }\r
1564           }\r
1565          if ( isset($Data[$Key][$ColName]) && is_numeric($Data[$Key][$ColName]))\r
1566           {\r
1567            if ( $Data[$Key][$ColName] < $Min )\r
1568             { $Min = $Data[$Key][$ColName]; $MinID = $GraphID; }\r
1569            $GraphID++;\r
1570           }\r
1571         }\r
1572 \r
1573        $YPos = $this->GArea_Y2 - (($Max-$this->VMin) * $this->DivisionRatio);\r
1574        $X1 = floor($XPos - $XWidth); $Y1 = floor($YPos) - .2;\r
1575        $X2 = floor($XPos + $XWidth);\r
1576        if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; }\r
1577        if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; }\r
1578 \r
1579        $YPos = $this->GArea_Y2 - (($Min-$this->VMin) * $this->DivisionRatio);\r
1580        $Y2 = floor($YPos) + .2;\r
1581 \r
1582        $this->drawLine(floor($XPos)-.2,$Y1+1,floor($XPos)-.2,$Y2-1,$R,$G,$B,TRUE);\r
1583        $this->drawLine(floor($XPos)+.2,$Y1+1,floor($XPos)+.2,$Y2-1,$R,$G,$B,TRUE);\r
1584        $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$MaxID]["R"],$this->Palette[$MaxID]["G"],$this->Palette[$MaxID]["B"],FALSE);\r
1585        $this->drawLine($X1,$Y2,$X2,$Y2,$this->Palette[$MinID]["R"],$this->Palette[$MinID]["G"],$this->Palette[$MinID]["B"],FALSE);\r
1586 \r
1587        $XPos = $XPos + $this->DivisionWidth;\r
1588       }\r
1589     }\r
1590 \r
1591    /* This function draw radar axis centered on the graph area */\r
1592    function drawRadarAxis(&$Data,&$DataDescription,$Mosaic=TRUE,$BorderOffset=10,$A_R=60,$A_G=60,$A_B=60,$S_R=200,$S_G=200,$S_B=200,$MaxValue=-1)\r
1593     {\r
1594      /* Validate the Data and DataDescription array */\r
1595      $this->validateDataDescription("drawRadarAxis",$DataDescription);\r
1596      $this->validateData("drawRadarAxis",$Data);\r
1597 \r
1598      $C_TextColor = imagecolorallocate($this->Picture,$A_R,$A_G,$A_B);\r
1599 \r
1600      /* Draw radar axis */\r
1601      $Points  = count($Data);\r
1602      $Radius  = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset;\r
1603      $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1;\r
1604      $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1;\r
1605 \r
1606      /* Search for the max value */\r
1607      if ( $MaxValue == -1 )\r
1608       {\r
1609        foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1610         {\r
1611          foreach ( $Data as $Key => $Values )\r
1612           {\r
1613            if ( isset($Data[$Key][$ColName]))\r
1614             if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; }\r
1615           }\r
1616         }\r
1617       }\r
1618 \r
1619      /* Draw the mosaic */\r
1620      if ( $Mosaic )\r
1621       {\r
1622        $RadiusScale = $Radius / $MaxValue;\r
1623        for ( $t=1; $t<=$MaxValue-1; $t++)\r
1624         {\r
1625          $TRadius  = $RadiusScale * $t;\r
1626          $LastX1   = -1;\r
1627 \r
1628          for ( $i=0; $i<=$Points; $i++)\r
1629           {\r
1630            $Angle = -90 + $i * 360/$Points;\r
1631            $X1 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter;\r
1632            $Y1 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter;\r
1633            $X2 = cos($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $XCenter;\r
1634            $Y2 = sin($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $YCenter;\r
1635 \r
1636            if ( $t % 2 == 1 && $LastX1 != -1)\r
1637             {\r
1638              $Plots   = "";\r
1639              $Plots[] = $X1; $Plots[] = $Y1;\r
1640              $Plots[] = $X2; $Plots[] = $Y2;\r
1641              $Plots[] = $LastX2; $Plots[] = $LastY2;\r
1642              $Plots[] = $LastX1; $Plots[] = $LastY1;\r
1643 \r
1644              $C_Graph = imagecolorallocate($this->Picture,250,250,250);\r
1645              imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_Graph);\r
1646             }\r
1647 \r
1648            $LastX1 = $X1; $LastY1= $Y1;\r
1649            $LastX2 = $X2; $LastY2= $Y2;\r
1650           }\r
1651         }\r
1652       }\r
1653 \r
1654 \r
1655      /* Draw the spider web */\r
1656      for ( $t=1; $t<=$MaxValue; $t++)\r
1657       {\r
1658        $TRadius = ( $Radius / $MaxValue ) * $t;\r
1659        $LastX   = -1;\r
1660 \r
1661        for ( $i=0; $i<=$Points; $i++)\r
1662         {\r
1663          $Angle = -90 + $i * 360/$Points;\r
1664          $X = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter;\r
1665          $Y = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter;\r
1666 \r
1667          if ( $LastX != -1 )\r
1668           $this->drawDottedLine($LastX,$LastY,$X,$Y,4,$S_R,$S_G,$S_B);\r
1669 \r
1670          $LastX = $X; $LastY= $Y;\r
1671         }\r
1672       }\r
1673 \r
1674      /* Draw the axis */\r
1675      for ( $i=0; $i<=$Points; $i++)\r
1676       {\r
1677        $Angle = -90 + $i * 360/$Points;\r
1678        $X = cos($Angle * 3.1418 / 180 ) * $Radius + $XCenter;\r
1679        $Y = sin($Angle * 3.1418 / 180 ) * $Radius + $YCenter;\r
1680 \r
1681        $this->drawLine($XCenter,$YCenter,$X,$Y,$A_R,$A_G,$A_B);\r
1682 \r
1683        $XOffset = 0; $YOffset = 0;\r
1684        if (isset($Data[$i][$DataDescription["Position"]]))\r
1685         {\r
1686          $Label = $Data[$i][$DataDescription["Position"]];\r
1687 \r
1688          $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Label);\r
1689          $Width  = $Positions[2] - $Positions[6];\r
1690          $Height = $Positions[3] - $Positions[7];\r
1691 \r
1692          if ( $Angle >= 0 && $Angle <= 90 )\r
1693           $YOffset = $Height;\r
1694 \r
1695          if ( $Angle > 90 && $Angle <= 180 )\r
1696           { $YOffset = $Height; $XOffset = -$Width; }\r
1697 \r
1698          if ( $Angle > 180 && $Angle <= 270 )\r
1699           { $XOffset = -$Width; }\r
1700 \r
1701          imagettftext($this->Picture,$this->FontSize,0,$X+$XOffset,$Y+$YOffset,$C_TextColor,$this->FontName,$Label);\r
1702         }\r
1703       }\r
1704 \r
1705      /* Write the values */\r
1706      for ( $t=1; $t<=$MaxValue; $t++)\r
1707       {\r
1708        $TRadius = ( $Radius / $MaxValue ) * $t;\r
1709 \r
1710        $Angle = -90 + 360 / $Points;\r
1711        $X1 = $XCenter;\r
1712        $Y1 = $YCenter - $TRadius;\r
1713        $X2 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter;\r
1714        $Y2 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter;\r
1715 \r
1716        $XPos = floor(($X2-$X1)/2) + $X1;\r
1717        $YPos = floor(($Y2-$Y1)/2) + $Y1;\r
1718 \r
1719        $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$t);\r
1720        $X = $XPos - ( $X+$Positions[2] - $X+$Positions[6] ) / 2;\r
1721        $Y = $YPos + $this->FontSize;\r
1722 \r
1723        $this->drawFilledRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,240,240,240);\r
1724        $this->drawRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,220,220,220);\r
1725        imagettftext($this->Picture,$this->FontSize,0,$X,$Y,$C_TextColor,$this->FontName,$t);\r
1726       }\r
1727     }\r
1728 \r
1729    /* This function draw a radar graph centered on the graph area */\r
1730    function drawRadar(&$Data,&$DataDescription,$BorderOffset=10,$MaxValue=-1)\r
1731     {\r
1732      /* Validate the Data and DataDescription array */\r
1733      $this->validateDataDescription("drawRadar",$DataDescription);\r
1734      $this->validateData("drawRadar",$Data);\r
1735 \r
1736      $Points  = count($Data);\r
1737      $Radius  = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset;\r
1738      $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1;\r
1739      $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1;\r
1740 \r
1741      /* Search for the max value */\r
1742      if ( $MaxValue == -1 )\r
1743       {\r
1744        foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1745         {\r
1746          foreach ( $Data as $Key => $Values )\r
1747           {\r
1748            if ( isset($Data[$Key][$ColName]))\r
1749             if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; }\r
1750           }\r
1751         }\r
1752       }\r
1753 \r
1754      $GraphID = 0;\r
1755      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1756       {\r
1757        $ID = 0;\r
1758        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1759         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1760 \r
1761        $Angle = -90;\r
1762        $XLast = -1;\r
1763        foreach ( $Data as $Key => $Values )\r
1764         {\r
1765          if ( isset($Data[$Key][$ColName]))\r
1766           {\r
1767            $Value    = $Data[$Key][$ColName];\r
1768            $Strength = ( $Radius / $MaxValue ) * $Value;\r
1769 \r
1770            $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter;\r
1771            $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter;\r
1772 \r
1773            if ( $XLast != -1 )\r
1774             $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1775 \r
1776            if ( $XLast == -1 )\r
1777             { $FirstX = $XPos; $FirstY = $YPos; }\r
1778 \r
1779            $Angle = $Angle + (360/$Points);\r
1780            $XLast = $XPos;\r
1781            $YLast = $YPos;\r
1782           }\r
1783         }\r
1784        $this->drawLine($XPos,$YPos,$FirstX,$FirstY,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1785        $GraphID++;\r
1786       }\r
1787     }\r
1788 \r
1789    /* This function draw a radar graph centered on the graph area */\r
1790    function drawFilledRadar(&$Data,&$DataDescription,$Alpha=50,$BorderOffset=10,$MaxValue=-1)\r
1791     {\r
1792      /* Validate the Data and DataDescription array */\r
1793      $this->validateDataDescription("drawFilledRadar",$DataDescription);\r
1794      $this->validateData("drawFilledRadar",$Data);\r
1795 \r
1796      $Points      = count($Data);\r
1797      $LayerWidth  = $this->GArea_X2-$this->GArea_X1;\r
1798      $LayerHeight = $this->GArea_Y2-$this->GArea_Y1;\r
1799      $Radius      = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset;\r
1800      $XCenter     = ( $this->GArea_X2 - $this->GArea_X1 ) / 2;\r
1801      $YCenter     = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2;\r
1802 \r
1803      /* Search for the max value */\r
1804      if ( $MaxValue == -1 )\r
1805       {\r
1806        foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1807         {\r
1808          foreach ( $Data as $Key => $Values )\r
1809           {\r
1810            if ( isset($Data[$Key][$ColName]))\r
1811             if ( $Data[$Key][$ColName] > $MaxValue && is_numeric($Data[$Key][$ColName])) { $MaxValue = $Data[$Key][$ColName]; }\r
1812           }\r
1813         }\r
1814       }\r
1815 \r
1816      $GraphID = 0;\r
1817      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1818       {\r
1819        $ID = 0;\r
1820        foreach ( $DataDescription["Description"] as $keyI => $ValueI )\r
1821         { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }\r
1822 \r
1823        $Angle = -90;\r
1824        $XLast = -1;\r
1825        $Plots = "";\r
1826        foreach ( $Data as $Key => $Values )\r
1827         {\r
1828          if ( isset($Data[$Key][$ColName]))\r
1829           {\r
1830            $Value    = $Data[$Key][$ColName];\r
1831            if ( !is_numeric($Value) ) { $Value = 0; }\r
1832            $Strength = ( $Radius / $MaxValue ) * $Value;\r
1833 \r
1834            $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter;\r
1835            $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter;\r
1836 \r
1837            $Plots[] = $XPos;\r
1838            $Plots[] = $YPos;\r
1839 \r
1840            $Angle = $Angle + (360/$Points);\r
1841            $XLast = $XPos;\r
1842            $YLast = $YPos;\r
1843           }\r
1844         }\r
1845 \r
1846        if (isset($Plots[0]))\r
1847         {\r
1848          $Plots[] = $Plots[0];\r
1849          $Plots[] = $Plots[1];\r
1850 \r
1851          $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);\r
1852          $C_White         = imagecolorallocate($this->Layers[0],255,255,255);\r
1853          imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);\r
1854          imagecolortransparent($this->Layers[0],$C_White);\r
1855 \r
1856          $C_Graph = imagecolorallocate($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1857          imagefilledpolygon($this->Layers[0],$Plots,(count($Plots)+1)/2,$C_Graph);\r
1858 \r
1859          imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);\r
1860          imagedestroy($this->Layers[0]);\r
1861 \r
1862          for($i=0;$i<=count($Plots)-4;$i=$i+2)\r
1863           $this->drawLine($Plots[$i]+$this->GArea_X1,$Plots[$i+1]+$this->GArea_Y1,$Plots[$i+2]+$this->GArea_X1,$Plots[$i+3]+$this->GArea_Y1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);\r
1864         }\r
1865 \r
1866        $GraphID++;\r
1867       }\r
1868     }\r
1869 \r
1870    /* This function draw a flat pie chart */\r
1871    function drawBasicPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$R=255,$G=255,$B=255,$Decimals=0)\r
1872     {\r
1873      /* Validate the Data and DataDescription array */\r
1874      $this->validateDataDescription("drawBasicPieGraph",$DataDescription,FALSE);\r
1875      $this->validateData("drawBasicPieGraph",$Data);\r
1876 \r
1877      /* Determine pie sum */\r
1878      $Series = 0; $PieSum = 0;\r
1879      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1880       {\r
1881        if ( $ColName != $DataDescription["Position"] )\r
1882         {\r
1883          $Series++;\r
1884          foreach ( $Data as $Key => $Values )\r
1885           {\r
1886            if ( isset($Data[$Key][$ColName]))\r
1887             $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]];\r
1888           }\r
1889         }\r
1890       }\r
1891 \r
1892      /* Validate serie */\r
1893      if ( $Series != 1 )\r
1894       RaiseFatal("Pie chart can only accept one serie of data.");\r
1895 \r
1896      $SpliceRatio         = 360 / $PieSum;\r
1897      $SplicePercent       = 100 / $PieSum;\r
1898 \r
1899      /* Calculate all polygons */\r
1900      $Angle    = 0; $TopPlots = "";\r
1901      foreach($iValues as $Key => $Value)\r
1902       {\r
1903        $TopPlots[$Key][] = $XPos;\r
1904        $TopPlots[$Key][] = $YPos;\r
1905 \r
1906        /* Process labels position & size */\r
1907        if ( !($DrawLabels == PIE_NOLABEL) )\r
1908         {\r
1909          $TAngle   = $Angle+($Value*$SpliceRatio/2);\r
1910          if ($DrawLabels == PIE_PERCENTAGE)\r
1911           $Caption  = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%";\r
1912          elseif ($DrawLabels == PIE_LABELS)\r
1913           $Caption  = $iLabels[$Key];\r
1914          $TX       = cos(($TAngle) * 3.1418 / 180 ) * ($Radius + 10)+ $XPos;\r
1915          $TY       = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+ 10) + $YPos + 4;\r
1916 \r
1917          if ( $TAngle > 90 && $TAngle < 270 )\r
1918           {\r
1919            $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Caption,$bogus);\r
1920            $TextWidth = $Position[2]-$Position[0];\r
1921            $TX = $TX - $TextWidth;\r
1922           }\r
1923 \r
1924          $C_TextColor = imagecolorallocate($this->Picture,70,70,70);\r
1925          imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption);\r
1926         }\r
1927 \r
1928        /* Process pie slices */\r
1929        for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5)\r
1930         {\r
1931          $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos;\r
1932          $TopY = sin($iAngle * 3.1418 / 180 ) * $Radius + $YPos;\r
1933 \r
1934          $TopPlots[$Key][] = $TopX; \r
1935          $TopPlots[$Key][] = $TopY;\r
1936         }\r
1937 \r
1938        $TopPlots[$Key][] = $XPos;\r
1939        $TopPlots[$Key][] = $YPos;\r
1940 \r
1941        $Angle = $iAngle;\r
1942       }\r
1943      $PolyPlots = $TopPlots;\r
1944 \r
1945      /* Set array values type to float --- PHP Bug with imagefilledpolygon casting to integer */\r
1946      foreach ($TopPlots as $Key => $Value)\r
1947       { foreach ($TopPlots[$Key] as $Key2 => $Value2) { settype($TopPlots[$Key][$Key2],"float"); } }\r
1948 \r
1949      /* Draw Top polygons */\r
1950      foreach ($PolyPlots as $Key => $Value)\r
1951       { \r
1952        $C_GraphLo = imagecolorallocate($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);\r
1953        imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo);\r
1954       }\r
1955 \r
1956      $this->drawCircle($XPos-.5,$YPos-.5,$Radius,$R,$G,$B);\r
1957      $this->drawCircle($XPos-.5,$YPos-.5,$Radius+.5,$R,$G,$B);\r
1958 \r
1959      /* Draw Top polygons */\r
1960      foreach ($TopPlots as $Key => $Value)\r
1961       { \r
1962        for($j=0;$j<=count($TopPlots[$Key])-4;$j=$j+2)\r
1963         $this->drawLine($TopPlots[$Key][$j],$TopPlots[$Key][$j+1],$TopPlots[$Key][$j+2],$TopPlots[$Key][$j+3],$R,$G,$B);\r
1964       }\r
1965     }\r
1966 \r
1967    /* This function draw a flat pie chart */\r
1968    function drawFlatPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals = 0)\r
1969     {\r
1970      /* Validate the Data and DataDescription array */\r
1971      $this->validateDataDescription("drawFlatPieGraph",$DataDescription,FALSE);\r
1972      $this->validateData("drawFlatPieGraph",$Data);\r
1973 \r
1974      /* Determine pie sum */\r
1975      $Series = 0; $PieSum = 0;\r
1976      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
1977       {\r
1978        if ( $ColName != $DataDescription["Position"] )\r
1979         {\r
1980          $Series++;\r
1981          foreach ( $Data as $Key => $Values )\r
1982           {\r
1983            if ( isset($Data[$Key][$ColName]))\r
1984             $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]];\r
1985           }\r
1986         }\r
1987       }\r
1988 \r
1989      /* Validate serie */\r
1990      if ( $Series != 1 )\r
1991       RaiseFatal("Pie chart can only accept one serie of data.");\r
1992 \r
1993      $SpliceDistanceRatio = $SpliceDistance;\r
1994      $SpliceRatio         = (360 - $SpliceDistanceRatio * count($iValues) ) / $PieSum;\r
1995      $SplicePercent       = 100 / $PieSum;\r
1996 \r
1997      /* Calculate all polygons */\r
1998      $Angle    = 0; $TopPlots = "";\r
1999      foreach($iValues as $Key => $Value)\r
2000       {\r
2001        $XCenterPos = cos(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos;\r
2002        $YCenterPos = sin(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos;\r
2003 \r
2004        $TopPlots[$Key][] = $XCenterPos;\r
2005        $TopPlots[$Key][] = $YCenterPos;\r
2006 \r
2007        /* Process labels position & size */\r
2008        if ( !($DrawLabels == PIE_NOLABEL) )\r
2009         {\r
2010          $TAngle   = $Angle+($Value*$SpliceRatio/2);\r
2011          if ($DrawLabels == PIE_PERCENTAGE)\r
2012           $Caption  = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%";\r
2013          elseif ($DrawLabels == PIE_LABELS)\r
2014           $Caption  = $iLabels[$Key];\r
2015          $TX       = cos(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance)+$XPos;\r
2016          $TY       = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance) + $YPos + 4;\r
2017 \r
2018          if ( $TAngle > 90 && $TAngle < 270 )\r
2019           {\r
2020            $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Caption,$bogus);\r
2021            $TextWidth = $Position[2]-$Position[0];\r
2022            $TX = $TX - $TextWidth;\r
2023           }\r
2024 \r
2025          $C_TextColor = imagecolorallocate($this->Picture,70,70,70);\r
2026          imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption);\r
2027         }\r
2028 \r
2029        /* Draw borders to correct imagefilledpolygon bug */\r
2030        $BMax = 2;\r
2031        for($i=-1;$i<=$BMax;$i++)\r
2032         {\r
2033          $BorderX1 = cos(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $XPos;\r
2034          $BorderY1 = sin(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $YPos;\r
2035          $BorderX2 = cos(($Angle+$i*.5) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $XPos;\r
2036          $BorderY2 = sin(($Angle+$i*.5) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $YPos;\r
2037          $this->drawLine($BorderX1,$BorderY1,$BorderX2,$BorderY2,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);\r
2038 \r
2039          $BorderX1 = cos(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $XPos;\r
2040          $BorderY1 = sin(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $YPos;\r
2041          $BorderX2 = cos(($Angle-$i*.5+$Value*$SpliceRatio) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $XPos;\r
2042          $BorderY2 = sin(($Angle-$i*.5+$Value*$SpliceRatio) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $YPos;\r
2043          $this->drawLine($BorderX1,$BorderY1,$BorderX2,$BorderY2,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);\r
2044         }\r
2045 \r
2046        /* Process pie slices */\r
2047        for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5)\r
2048         {\r
2049          $TopX = cos($iAngle * 3.1418 / 180 ) * ($Radius+$SpliceDistance) + $XPos;\r
2050          $TopY = sin($iAngle * 3.1418 / 180 ) * ($Radius+$SpliceDistance) + $YPos;\r
2051 \r
2052          $TopPlots[$Key][] = $TopX;\r
2053          $TopPlots[$Key][] = $TopY;\r
2054 \r
2055          if ( $iAngle != $Angle )\r
2056           {\r
2057            for($i=-1;$i<=2;$i++)\r
2058             {\r
2059              $BorderX1 = cos(($iAngle-.5) * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $XPos;\r
2060              $BorderY1 = sin(($iAngle-.5) * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $YPos;\r
2061              $BorderX2 = cos($iAngle * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $XPos;\r
2062              $BorderY2 = sin($iAngle * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $YPos;\r
2063 \r
2064              $this->drawLine($BorderX1,$BorderY1,$BorderX2,$BorderY2,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);\r
2065             }\r
2066           }\r
2067         }\r
2068 \r
2069        $TopPlots[$Key][] = $XCenterPos;\r
2070        $TopPlots[$Key][] = $YCenterPos;\r
2071 \r
2072        $Angle = $iAngle + $SpliceDistanceRatio;\r
2073       }\r
2074      $PolyPlots = $TopPlots;\r
2075 \r
2076      /* Set array values type to float --- PHP Bug with imagefilledpolygon casting to integer */\r
2077      foreach ($TopPlots as $Key => $Value)\r
2078       { foreach ($TopPlots[$Key] as $Key2 => $Value2) { settype($TopPlots[$Key][$Key2],"float"); } }\r
2079 \r
2080      /* Draw Top polygons */\r
2081      foreach ($TopPlots as $Key => $Value)\r
2082       { \r
2083        $C_GraphLo = imagecolorallocate($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);\r
2084        imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo);\r
2085       }\r
2086     }\r
2087 \r
2088    /* This function draw a pseudo-3D pie chart */\r
2089    function drawPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$EnhanceColors=TRUE,$Skew=60,$SpliceHeight=20,$SpliceDistance=0,$Decimals=0)\r
2090     {\r
2091      /* Validate the Data and DataDescription array */\r
2092      $this->validateDataDescription("drawPieGraph",$DataDescription,FALSE);\r
2093      $this->validateData("drawPieGraph",$Data);\r
2094 \r
2095      /* Determine pie sum */\r
2096      $Series = 0; $PieSum = 0; $rPieSum = 0;\r
2097      foreach ( $DataDescription["Values"] as $Key2 => $ColName )\r
2098       {\r
2099        if ( $ColName != $DataDescription["Position"] )\r
2100         {\r
2101          $Series++;\r
2102          foreach ( $Data as $Key => $Values )\r
2103           if ( isset($Data[$Key][$ColName]))\r
2104            {\r
2105             if ( $Data[$Key][$ColName] == 0 )\r
2106              { $PieSum++; $iValues[] = 1; $rValues[] = 0; }\r
2107             else\r
2108              { $PieSum += $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; $rValues[] = $Data[$Key][$ColName]; $rPieSum += $Data[$Key][$ColName];}\r
2109            }\r
2110         }\r
2111       }\r
2112 \r
2113      /* Validate serie */\r
2114      if ( $Series != 1 )\r
2115       RaiseFatal("Pie chart can only accept one serie of data.");\r
2116 \r
2117      $SpliceDistanceRatio = $SpliceDistance;\r
2118      $SkewHeight          = ($Radius * $Skew) / 100;\r
2119      $SpliceRatio         = (360 - $SpliceDistanceRatio * count($iValues) ) / $PieSum;\r
2120      $SplicePercent       = 100 / $PieSum;\r
2121      $rSplicePercent      = 100 / $rPieSum;\r
2122 \r
2123      /* Calculate all polygons */\r
2124      $Angle    = 0; $TopPlots = ""; $BotPlots = ""; $CDev = 5;\r
2125      foreach($iValues as $Key => $Value)\r
2126       {\r
2127        $XCenterPos = cos(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos;\r
2128        $YCenterPos = sin(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos;\r
2129        $XCenterPos2 = cos(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos;\r
2130        $YCenterPos2 = sin(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos;\r
2131 \r
2132        $TopPlots[$Key][] = $XCenterPos; $BotPlots[$Key][] = $XCenterPos;\r
2133        $TopPlots[$Key][] = $YCenterPos; $BotPlots[$Key][] = $YCenterPos + $SpliceHeight;\r
2134 \r
2135        /* Process labels position & size */\r
2136        if ( !($DrawLabels == PIE_NOLABEL) )\r
2137         {\r
2138          $TAngle   = $Angle+($Value*$SpliceRatio/2);\r
2139          if ($DrawLabels == PIE_PERCENTAGE)\r
2140           $Caption  = (round($rValues[$Key] * pow(10,$Decimals) * $rSplicePercent)/pow(10,$Decimals))."%";\r
2141          elseif ($DrawLabels == PIE_LABELS)\r
2142           $Caption  = $iLabels[$Key];\r
2143 \r
2144          $TX       = cos(($TAngle) * 3.1418 / 180 ) * ($Radius + 10)+ $XPos;\r
2145 \r
2146          if ( $TAngle > 0 && $TAngle < 180 )\r
2147           $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 10) + $YPos + $SpliceHeight + 4;\r
2148          else\r
2149           $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 10) + $YPos + 4;\r
2150 \r
2151          if ( $TAngle > 90 && $TAngle < 270 )\r
2152           {\r
2153            $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Caption,$bogus);\r
2154            $TextWidth = $Position[2]-$Position[0];\r
2155            $TX = $TX - $TextWidth;\r
2156           }\r
2157 \r
2158          $C_TextColor = imagecolorallocate($this->Picture,70,70,70);\r
2159          imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption);\r
2160         }\r
2161 \r
2162        /* Process pie slices */\r
2163        for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5)\r
2164         {\r
2165          $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos;\r
2166          $TopY = sin($iAngle * 3.1418 / 180 ) * $SkewHeight + $YPos;\r
2167 \r
2168          $TopPlots[$Key][] = $TopX; $BotPlots[$Key][] = $TopX;\r
2169          $TopPlots[$Key][] = $TopY; $BotPlots[$Key][] = $TopY + $SpliceHeight;\r
2170         }\r
2171 \r
2172        $TopPlots[$Key][] = $XCenterPos2; $BotPlots[$Key][] = $XCenterPos2;\r
2173        $TopPlots[$Key][] = $YCenterPos2; $BotPlots[$Key][] = $YCenterPos2 + $SpliceHeight;\r
2174 \r
2175        $Angle = $iAngle + $SpliceDistanceRatio;\r
2176       }\r
2177 \r
2178      /* Draw Bottom polygons */\r
2179      foreach($iValues as $Key => $Value)\r
2180       {\r
2181        $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-20);\r
2182        imagefilledpolygon($this->Picture,$BotPlots[$Key],(count($BotPlots[$Key])+1)/2,$C_GraphLo);\r
2183 \r
2184        for($j=0;$j<=count($BotPlots[$Key])-4;$j=$j+2)\r
2185         $this->drawLine($BotPlots[$Key][$j],$BotPlots[$Key][$j+1],$BotPlots[$Key][$j+2],$BotPlots[$Key][$j+3],$this->Palette[$Key]["R"]-20,$this->Palette[$Key]["G"]-20,$this->Palette[$Key]["B"]-20);\r
2186       }\r
2187 \r
2188      /* Draw pie layers */\r
2189      if ( $EnhanceColors ) { $ColorRatio = 30 / $SpliceHeight; } else { $ColorRatio = 25 / $SpliceHeight; }\r
2190      for($i=$SpliceHeight-1;$i>=1;$i--)\r
2191       {\r
2192        foreach($iValues as $Key => $Value)\r
2193         {\r
2194          $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-10);\r
2195          $Plots = ""; $Plot = 0;\r
2196          foreach($TopPlots[$Key] as $Key2 => $Value2)\r
2197           {\r
2198            $Plot++;\r
2199            if ( $Plot % 2 == 1 )\r
2200             $Plots[] = $Value2;\r
2201            else\r
2202             $Plots[] = $Value2+$i;\r
2203           }\r
2204          imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_GraphLo);\r
2205 \r
2206          $Index       = count($Plots);\r
2207          $ColorFactor = -20 + ($SpliceHeight - $i) * $ColorRatio;\r
2208          $this->drawAntialiasPixel($Plots[0],$Plots[1],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor);\r
2209          $this->drawAntialiasPixel($Plots[2],$Plots[3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor);\r
2210          $this->drawAntialiasPixel($Plots[$Index-4],$Plots[$Index-3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor);\r
2211         }\r
2212       }\r
2213 \r
2214      /* Draw Top polygons */\r
2215      for($Key=count($iValues)-1;$Key>=0;$Key--)\r
2216       { \r
2217        $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);\r
2218        imagefilledpolygon($this->Picture,$TopPlots[$Key],(count($TopPlots[$Key])+1)/2,$C_GraphLo);\r
2219 \r
2220        if ( $EnhanceColors ) { $En = 10; } else { $En = 5; }\r
2221        for($j=0;$j<=count($TopPlots[$Key])-4;$j=$j+2)\r
2222         $this->drawLine($TopPlots[$Key][$j],$TopPlots[$Key][$j+1],$TopPlots[$Key][$j+2],$TopPlots[$Key][$j+3],$this->Palette[$Key]["R"]+$En,$this->Palette[$Key]["G"]+$En,$this->Palette[$Key]["B"]+$En);\r
2223       }\r
2224     }\r
2225 \r
2226    /* This function can be used to set the background color */\r
2227    function drawBackground($R,$G,$B)\r
2228     {\r
2229      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2230      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2231      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2232 \r
2233      $C_Background = imagecolorallocate($this->Picture,$R,$G,$B);\r
2234      imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_Background);\r
2235     }\r
2236 \r
2237    /* This function can be used to set the background color */\r
2238    function drawGraphAreaGradient($R,$G,$B,$Decay,$Target=TARGET_GRAPHAREA)\r
2239     {\r
2240      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2241      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2242      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2243 \r
2244      if ( $Target == TARGET_GRAPHAREA )  { $X1 = $this->GArea_X1+1; $X2 = $this->GArea_X2-1; $Y1 = $this->GArea_Y1+1; $Y2 = $this->GArea_Y2; }\r
2245      if ( $Target == TARGET_BACKGROUND ) { $X1 = 0; $X2 = $this->XSize; $Y1 = 0; $Y2 = $this->YSize; }\r
2246 \r
2247      $YStep = ($Y2 - $Y1 - 2) / $Decay;\r
2248      for($i=0;$i<=$Decay;$i++)\r
2249       {\r
2250        $R-=1;$G-=1;$B-=1;\r
2251        $Yi1 = $Y1 + ( $i * $YStep );\r
2252        $Yi2 = ceil( $Yi1 + ( $i * $YStep ) + $YStep );\r
2253        if ( $Yi2 >= $Yi2 ) { $Yi2 = $Y2-1; }\r
2254 \r
2255        $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B);\r
2256        imagefilledrectangle($this->Picture,$X1,$Yi1,$X2,$Yi2,$C_Background);\r
2257       }\r
2258     }\r
2259 \r
2260    /* This function create a rectangle with antialias */\r
2261    function drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B)\r
2262     {\r
2263      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2264      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2265      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2266 \r
2267      $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);\r
2268 \r
2269      $X1=$X1-.2;$Y1=$Y1-.2;\r
2270      $X2=$X2+.2;$Y2=$Y2+.2;\r
2271      $this->drawLine($X1,$Y1,$X2,$Y1,$R,$G,$B);\r
2272      $this->drawLine($X2,$Y1,$X2,$Y2,$R,$G,$B);\r
2273      $this->drawLine($X2,$Y2,$X1,$Y2,$R,$G,$B);\r
2274      $this->drawLine($X1,$Y2,$X1,$Y1,$R,$G,$B);\r
2275     }\r
2276 \r
2277    /* This function create a filled rectangle with antialias */\r
2278    function drawFilledRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B,$DrawBorder=TRUE,$Alpha=100)\r
2279     {\r
2280      if ( $X2 > $X1 ) { list($X1, $X2) = array($X2, $X1); }\r
2281      if ( $Y2 > $Y1 ) { list($Y1, $Y2) = array($Y2, $Y1); }\r
2282 \r
2283      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2284      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2285      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2286 \r
2287      if ( $Alpha == 100 )\r
2288       {\r
2289        $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);\r
2290        imagefilledrectangle($this->Picture,$X1,$Y1,$X2,$Y2,$C_Rectangle);\r
2291       }\r
2292      else\r
2293       {\r
2294        $LayerWidth  = abs($X2-$X1)+2;\r
2295        $LayerHeight = abs($Y2-$Y1)+2;\r
2296 \r
2297        $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);\r
2298        $C_White         = imagecolorallocate($this->Layers[0],255,255,255);\r
2299        imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);\r
2300        imagecolortransparent($this->Layers[0],$C_White);\r
2301 \r
2302        $C_Rectangle = imagecolorallocate($this->Layers[0],$R,$G,$B);\r
2303        imagefilledrectangle($this->Layers[0],1,1,$LayerWidth-1,$LayerHeight-1,$C_Rectangle);\r
2304 \r
2305        imagecopymerge($this->Picture,$this->Layers[0],min($X1,$X2)-1,min($Y1,$Y2)-1,0,0,$LayerWidth,$LayerHeight,$Alpha);\r
2306        imagedestroy($this->Layers[0]);\r
2307       }\r
2308 \r
2309      if ( $DrawBorder )\r
2310       $this->drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B);\r
2311     }\r
2312 \r
2313    /* This function create a rectangle with rounded corners and antialias */\r
2314    function drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B)\r
2315     {\r
2316      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2317      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2318      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2319 \r
2320      $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);\r
2321 \r
2322      $Step = 90 / ((3.1418 * $Radius)/2);\r
2323 \r
2324      for($i=0;$i<=90;$i=$i+$Step)\r
2325       {\r
2326        $X = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius;\r
2327        $Y = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius;\r
2328        $this->drawAntialiasPixel($X,$Y,$R,$G,$B);\r
2329 \r
2330        $X = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius;\r
2331        $Y = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius;\r
2332        $this->drawAntialiasPixel($X,$Y,$R,$G,$B);\r
2333 \r
2334        $X = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius;\r
2335        $Y = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius;\r
2336        $this->drawAntialiasPixel($X,$Y,$R,$G,$B);\r
2337 \r
2338        $X = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius;\r
2339        $Y = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius;\r
2340        $this->drawAntialiasPixel($X,$Y,$R,$G,$B);\r
2341       }\r
2342 \r
2343      $X1=$X1-.2;$Y1=$Y1-.2;\r
2344      $X2=$X2+.2;$Y2=$Y2+.2;\r
2345      $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B);\r
2346      $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B);\r
2347      $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B);\r
2348      $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B);\r
2349     }\r
2350 \r
2351    /* This function create a filled rectangle with rounded corners and antialias */\r
2352    function drawFilledRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B)\r
2353     {\r
2354      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2355      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2356      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2357 \r
2358      $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);\r
2359 \r
2360      $Step = 90 / ((3.1418 * $Radius)/2);\r
2361 \r
2362      for($i=0;$i<=90;$i=$i+$Step)\r
2363       {\r
2364        $Xi1 = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius;\r
2365        $Yi1 = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius;\r
2366 \r
2367        $Xi2 = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius;\r
2368        $Yi2 = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius;\r
2369 \r
2370        $Xi3 = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius;\r
2371        $Yi3 = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius;\r
2372 \r
2373        $Xi4 = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius;\r
2374        $Yi4 = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius;\r
2375 \r
2376        imageline($this->Picture,$Xi1,$Yi1,$X1+$Radius,$Yi1,$C_Rectangle);\r
2377        imageline($this->Picture,$X2-$Radius,$Yi2,$Xi2,$Yi2,$C_Rectangle);\r
2378        imageline($this->Picture,$X2-$Radius,$Yi3,$Xi3,$Yi3,$C_Rectangle);\r
2379        imageline($this->Picture,$Xi4,$Yi4,$X1+$Radius,$Yi4,$C_Rectangle);\r
2380 \r
2381        $this->drawAntialiasPixel($Xi1,$Yi1,$R,$G,$B);\r
2382        $this->drawAntialiasPixel($Xi2,$Yi2,$R,$G,$B);\r
2383        $this->drawAntialiasPixel($Xi3,$Yi3,$R,$G,$B);\r
2384        $this->drawAntialiasPixel($Xi4,$Yi4,$R,$G,$B);\r
2385       }\r
2386 \r
2387      imagefilledrectangle($this->Picture,$X1,$Y1+$Radius,$X2,$Y2-$Radius,$C_Rectangle);\r
2388      imagefilledrectangle($this->Picture,$X1+$Radius,$Y1,$X2-$Radius,$Y2,$C_Rectangle);\r
2389 \r
2390      $X1=$X1-.2;$Y1=$Y1-.2;\r
2391      $X2=$X2+.2;$Y2=$Y2+.2;\r
2392      $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B);\r
2393      $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B);\r
2394      $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B);\r
2395      $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B);\r
2396     }\r
2397 \r
2398    /* This function create a circle with antialias */\r
2399    function drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0)\r
2400     {\r
2401      if ( $Width == 0 ) { $Width = $Height; }\r
2402      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2403      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2404      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2405 \r
2406      $C_Circle = imagecolorallocate($this->Picture,$R,$G,$B);\r
2407      $Step     = 360 / (2 * 3.1418 * max($Width,$Height));\r
2408 \r
2409      for($i=0;$i<=360;$i=$i+$Step)\r
2410       {\r
2411        $X = cos($i*3.1418/180) * $Height + $Xc;\r
2412        $Y = sin($i*3.1418/180) * $Width + $Yc;\r
2413        $this->drawAntialiasPixel($X,$Y,$R,$G,$B);\r
2414       }\r
2415     }\r
2416 \r
2417    /* This function create a filled circle/ellipse with antialias */\r
2418    function drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0)\r
2419     {\r
2420      if ( $Width == 0 ) { $Width = $Height; }\r
2421      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2422      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2423      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2424 \r
2425      $C_Circle = imagecolorallocate($this->Picture,$R,$G,$B);\r
2426      $Step     = 360 / (2 * 3.1418 * max($Width,$Height));\r
2427 \r
2428      for($i=90;$i<=270;$i=$i+$Step)\r
2429       {\r
2430        $X1 = cos($i*3.1418/180) * $Height + $Xc;\r
2431        $Y1 = sin($i*3.1418/180) * $Width + $Yc;\r
2432        $X2 = cos((180-$i)*3.1418/180) * $Height + $Xc;\r
2433        $Y2 = sin((180-$i)*3.1418/180) * $Width + $Yc;\r
2434 \r
2435        $this->drawAntialiasPixel($X1-1,$Y1-1,$R,$G,$B);\r
2436        $this->drawAntialiasPixel($X2-1,$Y2-1,$R,$G,$B);\r
2437 \r
2438        if ( ($Y1-1) > $Yc - max($Width,$Height) )\r
2439         imageline($this->Picture,$X1,$Y1-1,$X2-1,$Y2-1,$C_Circle);\r
2440       }\r
2441     }\r
2442 \r
2443    /* This function will draw a filled ellipse */\r
2444    function drawEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B)\r
2445     { $this->drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); }\r
2446 \r
2447    /* This function will draw an ellipse */\r
2448    function drawFilledEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B)\r
2449     { $this->drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); }\r
2450 \r
2451    /* This function create a line with antialias */\r
2452    function drawLine($X1,$Y1,$X2,$Y2,$R,$G,$B,$GraphFunction=FALSE)\r
2453     {\r
2454      if ( $this->LineDotSize > 1 ) { $this->drawDottedLine($X1,$Y1,$X2,$Y2,$this->LineDotSize,$R,$G,$B,$GraphFunction); return(0); }\r
2455      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2456      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2457      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2458 \r
2459      $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1));  \r
2460      if ( $Distance == 0 )\r
2461       return(-1);\r
2462      $XStep = ($X2-$X1) / $Distance;\r
2463      $YStep = ($Y2-$Y1) / $Distance;\r
2464 \r
2465      for($i=0;$i<=$Distance;$i++)\r
2466       {\r
2467        $X = $i * $XStep + $X1;\r
2468        $Y = $i * $YStep + $Y1;\r
2469 \r
2470        if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction )\r
2471         {\r
2472          if ( $this->LineWidth == 1 )\r
2473           $this->drawAntialiasPixel($X,$Y,$R,$G,$B);\r
2474          else\r
2475           {\r
2476            $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2);\r
2477            for($j=$StartOffset;$j<=$EndOffset;$j++)\r
2478             $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B);\r
2479           }\r
2480         }\r
2481       }\r
2482     }\r
2483 \r
2484    /* This function create a line with antialias */\r
2485    function drawDottedLine($X1,$Y1,$X2,$Y2,$DotSize,$R,$G,$B,$GraphFunction=FALSE)\r
2486     {\r
2487      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2488      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2489      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2490 \r
2491      $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1));  \r
2492 \r
2493      $XStep = ($X2-$X1) / $Distance;\r
2494      $YStep = ($Y2-$Y1) / $Distance;\r
2495 \r
2496      $DotIndex = 0;\r
2497      for($i=0;$i<=$Distance;$i++)\r
2498       {\r
2499        $X = $i * $XStep + $X1;\r
2500        $Y = $i * $YStep + $Y1;\r
2501 \r
2502        if ( $DotIndex <= $DotSize)\r
2503         {\r
2504          if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction )\r
2505           {\r
2506            if ( $this->LineWidth == 1 )\r
2507             $this->drawAntialiasPixel($X,$Y,$R,$G,$B);\r
2508            else\r
2509             {\r
2510              $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2);\r
2511              for($j=$StartOffset;$j<=$EndOffset;$j++)\r
2512               $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B);\r
2513             }\r
2514           }\r
2515         }\r
2516 \r
2517        $DotIndex++;\r
2518        if ( $DotIndex == $DotSize * 2 )\r
2519         $DotIndex = 0;        \r
2520       }\r
2521     }\r
2522 \r
2523    /* Load a PNG file and draw it over the chart */\r
2524    function drawFromPNG($FileName,$X,$Y,$Alpha=100)\r
2525     { $this->drawFromPicture(1,$FileName,$X,$Y,$Alpha); }\r
2526 \r
2527    /* Load a GIF file and draw it over the chart */\r
2528    function drawFromGIF($FileName,$X,$Y,$Alpha=100)\r
2529     { $this->drawFromPicture(2,$FileName,$X,$Y,$Alpha); }\r
2530 \r
2531    /* Load a JPEG file and draw it over the chart */\r
2532    function drawFromJPG($FileName,$X,$Y,$Alpha=100)\r
2533     { $this->drawFromPicture(3,$FileName,$X,$Y,$Alpha); }\r
2534 \r
2535    /* Generic loader function for external pictures */\r
2536    function drawFromPicture($PicType,$FileName,$X,$Y,$Alpha=100)\r
2537     {\r
2538      if ( file_exists($FileName))\r
2539       {\r
2540        $Infos  = getimagesize($FileName);\r
2541        $Width  = $Infos[0];\r
2542        $Height = $Infos[1];\r
2543        if ( $PicType == 1 ) { $Raster = imagecreatefrompng($FileName); }\r
2544        if ( $PicType == 2 ) { $Raster = imagecreatefromgif($FileName); }\r
2545        if ( $PicType == 3 ) { $Raster = imagecreatefromjpeg($FileName); }\r
2546 \r
2547        imagecopymerge($this->Picture,$Raster,$X,$Y,0,0,$Width,$Height,$Alpha);\r
2548        imagedestroy($Raster);\r
2549       }\r
2550     }\r
2551 \r
2552    /* Draw an alpha pixel */\r
2553    function drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B)\r
2554     {\r
2555      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2556      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2557      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2558 \r
2559      if ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize )\r
2560       return(-1);\r
2561 \r
2562      $RGB2 = imagecolorat($this->Picture, $X, $Y);\r
2563      $R2   = ($RGB2 >> 16) & 0xFF;\r
2564      $G2   = ($RGB2 >> 8) & 0xFF;\r
2565      $B2   = $RGB2 & 0xFF;\r
2566 \r
2567      $iAlpha = (100 - $Alpha)/100;\r
2568      $Alpha  = $Alpha / 100;\r
2569 \r
2570      $Ra   = floor($R*$Alpha+$R2*$iAlpha);\r
2571      $Ga   = floor($G*$Alpha+$G2*$iAlpha);\r
2572      $Ba   = floor($B*$Alpha+$B2*$iAlpha);\r
2573 \r
2574      $C_Aliased = imagecolorallocate($this->Picture,$Ra,$Ga,$Ba);\r
2575      imagesetpixel($this->Picture,$X,$Y,$C_Aliased);\r
2576     }\r
2577 \r
2578    /* Color helper */\r
2579    function AllocateColor($Picture,$R,$G,$B,$Factor=0)\r
2580     {\r
2581      $R = $R + $Factor;\r
2582      $G = $G + $Factor;\r
2583      $B = $B + $Factor;\r
2584      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2585      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2586      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2587 \r
2588      return(imagecolorallocate($Picture,$R,$G,$B));\r
2589     }\r
2590 \r
2591    /* Add a border to the picture */\r
2592    function addBorder($Size=3,$R=0,$G=0,$B=0)\r
2593     {\r
2594      $Width  = $this->XSize+2*$Size;\r
2595      $Height = $this->YSize+2*$Size;\r
2596 \r
2597      $Resampled    = imagecreatetruecolor($Width,$Height);\r
2598      $C_Background = imagecolorallocate($Resampled,$R,$G,$B);\r
2599      imagefilledrectangle($Resampled,0,0,$Width,$Height,$C_Background);\r
2600 \r
2601      imagecopy($Resampled,$this->Picture,$Size,$Size,0,0,$this->XSize,$this->YSize);\r
2602      imagedestroy($this->Picture);\r
2603 \r
2604      $this->XSize = $Width;\r
2605      $this->YSize = $Height;\r
2606 \r
2607      $this->Picture = imagecreatetruecolor($this->XSize,$this->YSize);\r
2608      $C_White = imagecolorallocate($this->Picture,255,255,255);\r
2609      imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_White);\r
2610      imagecolortransparent($this->Picture,$C_White);\r
2611      imagecopy($this->Picture,$Resampled,0,0,0,0,$this->XSize,$this->YSize);\r
2612     }\r
2613 \r
2614    /* Render the current picture to a file */\r
2615    function Render($FileName)\r
2616     {\r
2617      if ( $this->ErrorReporting )\r
2618       $this->printErrors($this->ErrorInterface);\r
2619 \r
2620      /* Save image map if requested */\r
2621      if ( $this->BuildMap )\r
2622       $this->SaveImageMap();\r
2623 \r
2624      imagepng($this->Picture,$FileName);\r
2625     }\r
2626 \r
2627    /* Render the current picture to STDOUT */\r
2628    function Stroke()\r
2629     {\r
2630      if ( $this->ErrorReporting )\r
2631       $this->printErrors("GD");\r
2632 \r
2633      /* Save image map if requested */\r
2634      if ( $this->BuildMap )\r
2635       $this->SaveImageMap();\r
2636 \r
2637      header('Content-type: image/png');\r
2638      imagepng($this->Picture);\r
2639     }\r
2640 \r
2641    /* Private functions for internal processing */\r
2642    function drawAntialiasPixel($X,$Y,$R,$G,$B)\r
2643     {\r
2644      if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }\r
2645      if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }\r
2646      if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }\r
2647 \r
2648      $Plot = "";\r
2649      $Xi   = floor($X);\r
2650      $Yi   = floor($Y);\r
2651 \r
2652      if ( $Xi == $X && $Yi == $Y)\r
2653       {\r
2654        /* $this->drawAlphaPixel($Xi,$Yi,0,$R,$G,$B); */\r
2655        $C_Aliased = imagecolorallocate($this->Picture,$R,$G,$B);\r
2656        imagesetpixel($this->Picture,$X,$Y,$C_Aliased);\r
2657       }\r
2658      else\r
2659       {\r
2660        $Alpha1 = (1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100;\r
2661        if ( $Alpha1 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi,$Alpha1,$R,$G,$B); }\r
2662 \r
2663        $Alpha2 = ($X - floor($X)) * (1 - ($Y - floor($Y))) * 100;\r
2664        if ( $Alpha2 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi,$Alpha2,$R,$G,$B); }\r
2665 \r
2666        $Alpha3 = (1 - ($X - floor($X))) * ($Y - floor($Y)) * 100;\r
2667        if ( $Alpha3 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi+1,$Alpha3,$R,$G,$B); }\r
2668 \r
2669        $Alpha4 = ($X - floor($X)) * ($Y - floor($Y)) * 100;\r
2670        if ( $Alpha4 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi+1,$Alpha4,$R,$G,$B); }\r
2671       }\r
2672     }\r
2673 \r
2674    /* Validate data contained in the description array */\r
2675    function validateDataDescription($FunctionName,&$DataDescription,$DescriptionRequired=TRUE)\r
2676     {\r
2677      if (!isset($DataDescription["Position"]))\r
2678       {\r
2679        $this->Errors[] = "[Warning] ".$FunctionName." - Y Labels are not set.";\r
2680        $DataDescription["Position"] = "Name";\r
2681       }\r
2682 \r
2683      if ( $DescriptionRequired )\r
2684       {\r
2685        if (!isset($DataDescription["Description"]))\r
2686         {\r
2687          $this->Errors[] = "[Warning] ".$FunctionName." - Series descriptions are not set.";\r
2688          foreach($DataDescription["Values"] as $key => $Value)\r
2689           {\r
2690            $DataDescription["Description"][$Value] = $Value;\r
2691           }\r
2692         }\r
2693 \r
2694        if (count($DataDescription["Description"]) < count($DataDescription["Values"]))\r
2695         {\r
2696          $this->Errors[] = "[Warning] ".$FunctionName." - Some series descriptions are not set.";\r
2697          foreach($DataDescription["Values"] as $key => $Value)\r
2698           {\r
2699            if ( !isset($DataDescription["Description"][$Value]))\r
2700             $DataDescription["Description"][$Value] = $Value;\r
2701           }\r
2702         }\r
2703       }\r
2704     }\r
2705 \r
2706    /* Validate data contained in the data array */\r
2707    function validateData($FunctionName,&$Data)\r
2708     {\r
2709      $DataSummary = "";\r
2710 \r
2711      foreach($Data as $key => $Values)\r
2712       {\r
2713        foreach($Values as $key2 => $Value)\r
2714         {\r
2715          if (!isset($DataSummary[$key2]))\r
2716           $DataSummary[$key2] = 1;\r
2717          else\r
2718           $DataSummary[$key2]++;\r
2719         }\r
2720       }\r
2721 \r
2722      if ( max($DataSummary) == 0 )\r
2723       $this->Errors[] = "[Warning] ".$FunctionName." - No data set.";\r
2724 \r
2725      foreach($DataSummary as $key => $Value)\r
2726       {\r
2727        if ($Value < max($DataSummary))\r
2728         {\r
2729          $this->Errors[] = "[Warning] ".$FunctionName." - Missing data in serie ".$key.".";\r
2730         }\r
2731       }\r
2732     }\r
2733 \r
2734    /* Print all error messages on the CLI or graphically */\r
2735    function printErrors($Mode="CLI")\r
2736     {\r
2737      if (count($this->Errors) == 0)\r
2738       return(0);\r
2739 \r
2740      if ( $Mode == "CLI" )\r
2741       {\r
2742        foreach($this->Errors as $key => $Value)\r
2743         echo $Value."\r\n";\r
2744       }\r
2745      elseif ( $Mode == "GD" )\r
2746       {\r
2747        $this->setLineStyle($Width=1);\r
2748        $MaxWidth = 0;\r
2749        foreach($this->Errors as $key => $Value)\r
2750         {\r
2751          $Position  = imageftbbox($this->ErrorFontSize,0,$this->ErrorFontName,$Value,$bogus);\r
2752          $TextWidth = $Position[2]-$Position[0];\r
2753          if ( $TextWidth > $MaxWidth ) { $MaxWidth = $TextWidth; }\r
2754         }\r
2755        $this->drawFilledRoundedRectangle($this->XSize-($MaxWidth+20),$this->YSize-(20+(($this->ErrorFontSize+4)*count($this->Errors))),$this->XSize-10,$this->YSize-10,6,233,185,185);\r
2756        $this->drawRoundedRectangle($this->XSize-($MaxWidth+20),$this->YSize-(20+(($this->ErrorFontSize+4)*count($this->Errors))),$this->XSize-10,$this->YSize-10,6,193,145,145);\r
2757 \r
2758        $C_TextColor = imagecolorallocate($this->Picture,133,85,85);\r
2759        $YPos        = $this->YSize - (18 + (count($this->Errors)-1) * ($this->ErrorFontSize + 4));\r
2760        foreach($this->Errors as $key => $Value)\r
2761         {\r
2762          imagettftext($this->Picture,$this->ErrorFontSize,0,$this->XSize-($MaxWidth+15),$YPos,$C_TextColor,$this->ErrorFontName,$Value);\r
2763          $YPos = $YPos + ($this->ErrorFontSize + 4);\r
2764         }\r
2765       }\r
2766     }\r
2767 \r
2768    /* Activate the image map creation process */\r
2769    function setImageMap($Mode=TRUE,$GraphID="MyGraph")\r
2770     {\r
2771      $this->BuildMap = $Mode;\r
2772      $this->MapID    = $GraphID;\r
2773     }\r
2774 \r
2775    /* Add a box into the image map */\r
2776    function addToImageMap($X1,$Y1,$X2,$Y2,$SerieName,$Value,$CallerFunction)\r
2777     {\r
2778      if ( $this->MapFunction == NULL || $this->MapFunction == $CallerFunction )\r
2779       {\r
2780        $this->ImageMap[]  = round($X1).",".round($Y1).",".round($X2).",".round($Y2).",".$SerieName.",".$Value;\r
2781        $this->MapFunction = $CallerFunction;\r
2782       }\r
2783     }\r
2784 \r
2785    /* Load and cleanup the image map from disk */\r
2786    function getImageMap($MapName,$Flush=TRUE)\r
2787     {\r
2788      /* Strip HTML query strings */\r
2789      $Values   = $this->tmpFolder.$MapName;\r
2790      $Value    = split("\?",$Values);\r
2791      $FileName = $Value[0];\r
2792 \r
2793      if ( file_exists($FileName) )\r
2794       {\r
2795        $Handle     = fopen($FileName, "r");\r
2796        $MapContent = fread($Handle, filesize($FileName));\r
2797        fclose($Handle);\r
2798        echo $MapContent;\r
2799 \r
2800        if ( $Flush )\r
2801         unlink($FileName);\r
2802 \r
2803        exit();\r
2804       }\r
2805      else\r
2806       {\r
2807        header("HTTP/1.0 404 Not Found");\r
2808        exit();\r
2809       }\r
2810     }\r
2811 \r
2812    /* Save the image map to the disk */\r
2813    function SaveImageMap()\r
2814     {\r
2815      if ( !$this->BuildMap ) { return(-1); }\r
2816 \r
2817      if ( $this->ImageMap == NULL )\r
2818       {\r
2819        $this->Errors[] = "[Warning] SaveImageMap - Image map is empty.";\r
2820        return(-1);\r
2821       }\r
2822 \r
2823      $Handle = fopen($this->tmpFolder.$this->MapID, 'w');\r
2824      if ( !$Handle )\r
2825       {\r
2826        $this->Errors[] = "[Warning] SaveImageMap - Cannot save the image map.";\r
2827        return(-1);\r
2828       }\r
2829      else\r
2830       {\r
2831        foreach($this->ImageMap as $Key => $Value)\r
2832         fwrite($Handle, htmlentities($Value)."\r");\r
2833       }\r
2834      fclose ($Handle);\r
2835     }\r
2836 \r
2837    /* Convert seconds to a time format string */\r
2838    function ToTime($Value)\r
2839     {\r
2840      $Hour   = floor($Value/3600);\r
2841      $Minute = floor(($Value - $Hour*3600)/60);\r
2842      $Second = floor($Value - $Hour*3600 - $Minute*60);\r
2843 \r
2844      if (strlen($Hour) == 1 )   { $Hour = "0".$Hour; }\r
2845      if (strlen($Minute) == 1 ) { $Minute = "0".$Minute; }\r
2846      if (strlen($Second) == 1 ) { $Second = "0".$Second; }\r
2847 \r
2848      return($Hour.":".$Minute.":".$Second);\r
2849     }\r
2850 \r
2851    /* Convert to metric system */\r
2852    function ToMetric($Value)\r
2853     {\r
2854      $Go = floor($Value/1000000000);\r
2855      $Mo = floor(($Value - $Go*1000000000)/1000000);\r
2856      $Ko = floor(($Value - $Go*1000000000 - $Mo*1000000)/1000);\r
2857      $o  = floor($Value - $Go*1000000000 - $Mo*1000000 - $Ko*1000);\r
2858 \r
2859      if ($Go != 0)   { return($Go.".".$Mo."g"); }\r
2860      if ($Mo != 0)   { return($Mo.".".$ko."m"); }\r
2861      if ($Ko != 0)   { return($Ko.".".$o)."k"; }\r
2862      return($o);\r
2863     }\r
2864 \r
2865    /* Set date format for axis labels */\r
2866    function setDateFormat($Format)\r
2867     {\r
2868      $this->DateFormat = $Format;\r
2869     }\r
2870 \r
2871    /* Convert TS to a date format string */\r
2872    function ToDate($Value)\r
2873     {\r
2874      return(date($this->DateFormat,$Value));\r
2875     }\r
2876   }\r
2877 \r
2878  function RaiseFatal($Message)\r
2879   {\r
2880    echo "[FATAL] ".$Message."\r\n";\r
2881    exit();\r
2882   }\r
2883 ?>\r