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

Last change on this file since 1439 was 1439, checked in by roux, 11 years ago

legende over sur graphes, laborieeux sur multigraphes donc retiré

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