source: cpc/trunk/project/plugins/xsPChartPlugin/lib/pChart/pChart/pChart.class @ 1472

Last change on this file since 1472 was 1472, checked in by goya, 11 years ago

graphe d'accueil

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