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

Last change on this file since 1425 was 1425, checked in by roux, 10 years ago

mise-à-jour pChart

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);
1410// $Y2 = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio);
1411             if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; }
1412             if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; }
1413
1414             /* Save point into the image map if option activated */
1415             if ( $this->BuildMap )
1416              $this->addToImageMap($X1,min($Y1,$Y2),$X2,max($Y1,$Y2),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"oBar");
1417
1418             $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE);
1419            }
1420          }
1421         $XPos = $XPos + $this->DivisionWidth;
1422        }
1423
1424       $GraphID++;
1425      }
1426
1427     for($i=0;$i<=($GraphID-1);$i++)
1428      {
1429       imagecopymerge($this->Picture,$this->Layers[$i],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);
1430       imagedestroy($this->Layers[$i]);
1431      }
1432    }
1433
1434   /* This function draw a bar graph */
1435   function drawBarGraph(&$Data,&$DataDescription,$Shadow=FALSE,$Alpha=100)
1436    {
1437     /* Validate the Data and DataDescription array */
1438     $this->validateDataDescription("drawBarGraph",$DataDescription);
1439     $this->validateData("drawBarGraph",$Data);
1440
1441     $GraphID      = 0;
1442     $Series       = count($DataDescription["Values"]);
1443     $SeriesWidth  = $this->DivisionWidth / ($Series+1);
1444     $SerieXOffset = $this->DivisionWidth / 2 - $SeriesWidth / 2;
1445
1446     $YZero  = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio);
1447     if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; }
1448
1449     $SerieID = 0;
1450     foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1451      {
1452       $ID = 0;
1453       foreach ( $DataDescription["Description"] as $keyI => $ValueI )
1454        { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }
1455
1456       $XPos  = $this->GArea_X1 + $this->GAreaXOffset - $SerieXOffset + $SeriesWidth * $SerieID;
1457       $XLast = -1;
1458       foreach ( $Data as $Key => $Values )
1459        {
1460         if ( isset($Data[$Key][$ColName]))
1461          {
1462           if ( is_numeric($Data[$Key][$ColName]) )
1463            {
1464             $Value = $Data[$Key][$ColName];
1465             $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);
1466
1467             /* Save point into the image map if option activated */
1468             if ( $this->BuildMap )
1469              {
1470               $this->addToImageMap($XPos+1,min($YZero,$YPos),$XPos+$SeriesWidth-1,max($YZero,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Bar");
1471              }
1472           
1473             if ( $Shadow && $Alpha == 100 )
1474              $this->drawRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,25,25,25,TRUE,$Alpha);
1475
1476             $this->drawFilledRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha);
1477            }
1478          }
1479         $XPos = $XPos + $this->DivisionWidth;
1480        }
1481       $SerieID++;
1482      }
1483    }
1484
1485   /* This function draw a stacked bar graph */
1486   function drawStackedBarGraph(&$Data,&$DataDescription,$Alpha=50)
1487    {
1488     /* Validate the Data and DataDescription array */
1489     $this->validateDataDescription("drawBarGraph",$DataDescription);
1490     $this->validateData("drawBarGraph",$Data);
1491
1492     $GraphID      = 0;
1493     $Series       = count($DataDescription["Values"]);
1494     $SeriesWidth  = $this->DivisionWidth * .8;
1495
1496     $YZero  = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio);
1497     if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; }
1498
1499     $SerieID = 0; $LastValue = "";
1500     foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1501      {
1502       $ID = 0;
1503       foreach ( $DataDescription["Description"] as $keyI => $ValueI )
1504        { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }
1505
1506       $XPos  = $this->GArea_X1 + $this->GAreaXOffset - $SeriesWidth / 2;
1507       $XLast = -1;
1508       foreach ( $Data as $Key => $Values )
1509        {
1510         if ( isset($Data[$Key][$ColName]))
1511          {
1512           if ( is_numeric($Data[$Key][$ColName]) )
1513            {
1514             $Value = $Data[$Key][$ColName];
1515
1516             if ( isset($LastValue[$Key]) )
1517              {
1518               $YPos    = $this->GArea_Y2 - ((($Value+$LastValue[$Key])-$this->VMin) * $this->DivisionRatio);
1519               $YBottom = $this->GArea_Y2 - (($LastValue[$Key]-$this->VMin) * $this->DivisionRatio);
1520               $LastValue[$Key] += $Value;
1521              }
1522             else
1523              {
1524               $YPos    = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio);
1525               $YBottom = $YZero;
1526               $LastValue[$Key] = $Value;
1527              }
1528
1529             /* Save point into the image map if option activated */
1530             if ( $this->BuildMap )
1531              $this->addToImageMap($XPos+1,min($YBottom,$YPos),$XPos+$SeriesWidth-1,max($YBottom,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"sBar");
1532
1533             $this->drawFilledRectangle($XPos+1,$YBottom,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha);
1534            }
1535          }
1536         $XPos = $XPos + $this->DivisionWidth;
1537        }
1538       $SerieID++;
1539      }
1540    }
1541
1542   /* This function draw a limits bar graphs */
1543   function drawLimitsGraph(&$Data,&$DataDescription,$R=0,$G=0,$B=0)
1544    {
1545     /* Validate the Data and DataDescription array */
1546     $this->validateDataDescription("drawLimitsGraph",$DataDescription);
1547     $this->validateData("drawLimitsGraph",$Data);
1548
1549     $XWidth = $this->DivisionWidth / 4;
1550     $XPos   = $this->GArea_X1 + $this->GAreaXOffset;
1551
1552     foreach ( $Data as $Key => $Values )
1553      {
1554       $Min     = $Data[$Key][$DataDescription["Values"][0]];
1555       $Max     = $Data[$Key][$DataDescription["Values"][0]];
1556       $GraphID = 0; $MaxID = 0; $MinID = 0;
1557       foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1558        {
1559         if ( isset($Data[$Key][$ColName]) )
1560          {
1561           if ( $Data[$Key][$ColName] > $Max && is_numeric($Data[$Key][$ColName]))
1562            { $Max = $Data[$Key][$ColName]; $MaxID = $GraphID; }
1563          }
1564         if ( isset($Data[$Key][$ColName]) && is_numeric($Data[$Key][$ColName]))
1565          {
1566           if ( $Data[$Key][$ColName] < $Min )
1567            { $Min = $Data[$Key][$ColName]; $MinID = $GraphID; }
1568           $GraphID++;
1569          }
1570        }
1571
1572       $YPos = $this->GArea_Y2 - (($Max-$this->VMin) * $this->DivisionRatio);
1573       $X1 = floor($XPos - $XWidth); $Y1 = floor($YPos) - .2;
1574       $X2 = floor($XPos + $XWidth);
1575       if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; }
1576       if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; }
1577
1578       $YPos = $this->GArea_Y2 - (($Min-$this->VMin) * $this->DivisionRatio);
1579       $Y2 = floor($YPos) + .2;
1580
1581       $this->drawLine(floor($XPos)-.2,$Y1+1,floor($XPos)-.2,$Y2-1,$R,$G,$B,TRUE);
1582       $this->drawLine(floor($XPos)+.2,$Y1+1,floor($XPos)+.2,$Y2-1,$R,$G,$B,TRUE);
1583       $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$MaxID]["R"],$this->Palette[$MaxID]["G"],$this->Palette[$MaxID]["B"],FALSE);
1584       $this->drawLine($X1,$Y2,$X2,$Y2,$this->Palette[$MinID]["R"],$this->Palette[$MinID]["G"],$this->Palette[$MinID]["B"],FALSE);
1585
1586       $XPos = $XPos + $this->DivisionWidth;
1587      }
1588    }
1589
1590   /* This function draw radar axis centered on the graph area */
1591   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)
1592    {
1593     /* Validate the Data and DataDescription array */
1594     $this->validateDataDescription("drawRadarAxis",$DataDescription);
1595     $this->validateData("drawRadarAxis",$Data);
1596
1597     $C_TextColor = imagecolorallocate($this->Picture,$A_R,$A_G,$A_B);
1598
1599     /* Draw radar axis */
1600     $Points  = count($Data);
1601     $Radius  = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset;
1602     $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1;
1603     $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1;
1604
1605     /* Search for the max value */
1606     if ( $MaxValue == -1 )
1607      {
1608       foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1609        {
1610         foreach ( $Data as $Key => $Values )
1611          {
1612           if ( isset($Data[$Key][$ColName]))
1613            if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; }
1614          }
1615        }
1616      }
1617
1618     /* Draw the mosaic */
1619     if ( $Mosaic )
1620      {
1621       $RadiusScale = $Radius / $MaxValue;
1622       for ( $t=1; $t<=$MaxValue-1; $t++)
1623        {
1624         $TRadius  = $RadiusScale * $t;
1625         $LastX1   = -1;
1626
1627         for ( $i=0; $i<=$Points; $i++)
1628          {
1629           $Angle = -90 + $i * 360/$Points;
1630           $X1 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter;
1631           $Y1 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter;
1632           $X2 = cos($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $XCenter;
1633           $Y2 = sin($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $YCenter;
1634
1635           if ( $t % 2 == 1 && $LastX1 != -1)
1636            {
1637             $Plots   = "";
1638             $Plots[] = $X1; $Plots[] = $Y1;
1639             $Plots[] = $X2; $Plots[] = $Y2;
1640             $Plots[] = $LastX2; $Plots[] = $LastY2;
1641             $Plots[] = $LastX1; $Plots[] = $LastY1;
1642
1643             $C_Graph = imagecolorallocate($this->Picture,250,250,250);
1644             imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_Graph);
1645            }
1646
1647           $LastX1 = $X1; $LastY1= $Y1;
1648           $LastX2 = $X2; $LastY2= $Y2;
1649          }
1650        }
1651      }
1652
1653
1654     /* Draw the spider web */
1655     for ( $t=1; $t<=$MaxValue; $t++)
1656      {
1657       $TRadius = ( $Radius / $MaxValue ) * $t;
1658       $LastX   = -1;
1659
1660       for ( $i=0; $i<=$Points; $i++)
1661        {
1662         $Angle = -90 + $i * 360/$Points;
1663         $X = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter;
1664         $Y = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter;
1665
1666         if ( $LastX != -1 )
1667          $this->drawDottedLine($LastX,$LastY,$X,$Y,4,$S_R,$S_G,$S_B);
1668
1669         $LastX = $X; $LastY= $Y;
1670        }
1671      }
1672
1673     /* Draw the axis */
1674     for ( $i=0; $i<=$Points; $i++)
1675      {
1676       $Angle = -90 + $i * 360/$Points;
1677       $X = cos($Angle * 3.1418 / 180 ) * $Radius + $XCenter;
1678       $Y = sin($Angle * 3.1418 / 180 ) * $Radius + $YCenter;
1679
1680       $this->drawLine($XCenter,$YCenter,$X,$Y,$A_R,$A_G,$A_B);
1681
1682       $XOffset = 0; $YOffset = 0;
1683       if (isset($Data[$i][$DataDescription["Position"]]))
1684        {
1685         $Label = $Data[$i][$DataDescription["Position"]];
1686
1687         $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Label);
1688         $Width  = $Positions[2] - $Positions[6];
1689         $Height = $Positions[3] - $Positions[7];
1690
1691         if ( $Angle >= 0 && $Angle <= 90 )
1692          $YOffset = $Height;
1693
1694         if ( $Angle > 90 && $Angle <= 180 )
1695          { $YOffset = $Height; $XOffset = -$Width; }
1696
1697         //if ( $Angle > 180 && $Angle <= 270 )
1698         if ( $Angle > 180 && $Angle <= 260 )
1699          { $XOffset = -$Width; }
1700
1701         imagettftext($this->Picture,$this->FontSize,0,$X+$XOffset,$Y+$YOffset,$C_TextColor,$this->FontName,$Label);
1702        }
1703      }
1704
1705     /* Write the values */
1706     for ( $t=1; $t<=$MaxValue; $t++)
1707      {
1708       $TRadius = ( $Radius / $MaxValue ) * $t;
1709
1710       $Angle = -90 + 360 / $Points;
1711       $X1 = $XCenter;
1712       $Y1 = $YCenter - $TRadius;
1713       $X2 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter;
1714       $Y2 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter;
1715
1716       $XPos = floor(($X2-$X1)/2) + $X1;
1717       $YPos = floor(($Y2-$Y1)/2) + $Y1;
1718
1719       $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$t);
1720       $X = $XPos - ( $X+$Positions[2] - $X+$Positions[6] ) / 2;
1721       $Y = $YPos + $this->FontSize;
1722
1723       $this->drawFilledRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,240,240,240);
1724       $this->drawRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,220,220,220);
1725       imagettftext($this->Picture,$this->FontSize,0,$X,$Y,$C_TextColor,$this->FontName,$t);
1726      }
1727    }
1728
1729   /* This function draw a radar graph centered on the graph area */
1730   function drawRadar(&$Data,&$DataDescription,$BorderOffset=10,$MaxValue=-1)
1731    {
1732     /* Validate the Data and DataDescription array */
1733     $this->validateDataDescription("drawRadar",$DataDescription);
1734     $this->validateData("drawRadar",$Data);
1735
1736     $Points  = count($Data);
1737     $Radius  = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset;
1738     $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1;
1739     $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1;
1740
1741     /* Search for the max value */
1742     if ( $MaxValue == -1 )
1743      {
1744       foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1745        {
1746         foreach ( $Data as $Key => $Values )
1747          {
1748           if ( isset($Data[$Key][$ColName]))
1749            if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; }
1750          }
1751        }
1752      }
1753
1754     $GraphID = 0;
1755     foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1756      {
1757       $ID = 0;
1758       foreach ( $DataDescription["Description"] as $keyI => $ValueI )
1759        { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }
1760
1761       $Angle = -90;
1762       $XLast = -1;
1763       foreach ( $Data as $Key => $Values )
1764        {
1765         if ( isset($Data[$Key][$ColName]))
1766          {
1767           $Value    = $Data[$Key][$ColName];
1768           $Strength = ( $Radius / $MaxValue ) * $Value;
1769
1770           $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter;
1771           $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter;
1772
1773           if ( $XLast != -1 )
1774            $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);
1775
1776           if ( $XLast == -1 )
1777            { $FirstX = $XPos; $FirstY = $YPos; }
1778
1779           $Angle = $Angle + (360/$Points);
1780           $XLast = $XPos;
1781           $YLast = $YPos;
1782          }
1783        }
1784       $this->drawLine($XPos,$YPos,$FirstX,$FirstY,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);
1785       $GraphID++;
1786      }
1787    }
1788
1789   /* This function draw a radar graph centered on the graph area */
1790   function drawFilledRadar(&$Data,&$DataDescription,$Alpha=50,$BorderOffset=10,$MaxValue=-1)
1791    {
1792     /* Validate the Data and DataDescription array */
1793     $this->validateDataDescription("drawFilledRadar",$DataDescription);
1794     $this->validateData("drawFilledRadar",$Data);
1795
1796     $Points      = count($Data);
1797     $LayerWidth  = $this->GArea_X2-$this->GArea_X1;
1798     $LayerHeight = $this->GArea_Y2-$this->GArea_Y1;
1799     $Radius      = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset;
1800     $XCenter     = ( $this->GArea_X2 - $this->GArea_X1 ) / 2;
1801     $YCenter     = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2;
1802
1803     /* Search for the max value */
1804     if ( $MaxValue == -1 )
1805      {
1806       foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1807        {
1808         foreach ( $Data as $Key => $Values )
1809          {
1810           if ( isset($Data[$Key][$ColName]))
1811            if ( $Data[$Key][$ColName] > $MaxValue && is_numeric($Data[$Key][$ColName])) { $MaxValue = $Data[$Key][$ColName]; }
1812          }
1813        }
1814      }
1815
1816     $GraphID = 0;
1817     foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1818      {
1819       $ID = 0;
1820       foreach ( $DataDescription["Description"] as $keyI => $ValueI )
1821        { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }
1822
1823       $Angle = -90;
1824       $XLast = -1;
1825       $Plots = "";
1826       foreach ( $Data as $Key => $Values )
1827        {
1828         if ( isset($Data[$Key][$ColName]))
1829          {
1830           $Value    = $Data[$Key][$ColName];
1831           if ( !is_numeric($Value) ) { $Value = 0; }
1832           $Strength = ( $Radius / $MaxValue ) * $Value;
1833
1834           $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter;
1835           $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter;
1836
1837           $Plots[] = $XPos;
1838           $Plots[] = $YPos;
1839
1840           $Angle = $Angle + (360/$Points);
1841           $XLast = $XPos;
1842           $YLast = $YPos;
1843          }
1844        }
1845
1846       if (isset($Plots[0]))
1847        {
1848         $Plots[] = $Plots[0];
1849         $Plots[] = $Plots[1];
1850
1851         $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);
1852         $C_White         = imagecolorallocate($this->Layers[0],255,255,255);
1853         imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);
1854         imagecolortransparent($this->Layers[0],$C_White);
1855
1856         $C_Graph = imagecolorallocate($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);
1857         imagefilledpolygon($this->Layers[0],$Plots,(count($Plots)+1)/2,$C_Graph);
1858
1859         imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);
1860         imagedestroy($this->Layers[0]);
1861
1862         for($i=0;$i<=count($Plots)-4;$i=$i+2)
1863          $this->drawLine($Plots[$i]+$this->GArea_X1,$Plots[$i+1]+$this->GArea_Y1,$Plots[$i+2]+$this->GArea_X1,$Plots[$i+3]+$this->GArea_Y1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]);
1864        }
1865
1866       $GraphID++;
1867      }
1868    }
1869
1870   /* This function draw a flat pie chart */
1871   function drawBasicPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$R=255,$G=255,$B=255,$Decimals=0)
1872    {
1873     /* Validate the Data and DataDescription array */
1874     $this->validateDataDescription("drawBasicPieGraph",$DataDescription,FALSE);
1875     $this->validateData("drawBasicPieGraph",$Data);
1876
1877     /* Determine pie sum */
1878     $Series = 0; $PieSum = 0;
1879     foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1880      {
1881       if ( $ColName != $DataDescription["Position"] )
1882        {
1883         $Series++;
1884         foreach ( $Data as $Key => $Values )
1885          {
1886           if ( isset($Data[$Key][$ColName]))
1887            $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]];
1888          }
1889        }
1890      }
1891
1892     /* Validate serie */
1893     if ( $Series != 1 )
1894      RaiseFatal("Pie chart can only accept one serie of data.");
1895
1896     $SpliceRatio         = 360 / $PieSum;
1897     $SplicePercent       = 100 / $PieSum;
1898
1899     /* Calculate all polygons */
1900     //$Angle    = 0; $TopPlots = "";
1901     $Angle    = 260; $TopPlots = "";
1902     foreach($iValues as $Key => $Value)
1903      {
1904       $TopPlots[$Key][] = $XPos;
1905       $TopPlots[$Key][] = $YPos;
1906
1907       /* Process labels position & size */
1908       if ( !($DrawLabels == PIE_NOLABEL) )
1909        {
1910         $TAngle   = $Angle+($Value*$SpliceRatio/2);
1911         if ($TAngle > 359) $TAngle -= 360;
1912         if ($DrawLabels == PIE_PERCENTAGE)
1913       //   $Caption  = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%";
1914          $Caption  = (floor($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%";
1915          elseif ($DrawLabels == PIE_VALUES)
1916           $Caption  = (floor($Value));
1917         elseif ($DrawLabels == PIE_LABELS)
1918          $Caption  = $iLabels[$Key];
1919         $TX       = cos(($TAngle) * 3.1418 / 180 ) * ($Radius + 10)+ $XPos;
1920         $TY       = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+ 10) + $YPos + 4;
1921
1922        // if ( $TAngle > 90 && $TAngle < 270 )
1923         if ( $TAngle > 90 && $TAngle < 260 )
1924          {
1925           $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Caption);
1926           $TextWidth = $Position[2]-$Position[0];
1927           $TX = $TX - $TextWidth;
1928          }
1929
1930         $C_TextColor = imagecolorallocate($this->Picture,70,70,70);
1931         imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption);
1932        }
1933
1934       /* Process pie slices */
1935       for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5)
1936        {
1937         $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos;
1938         $TopY = sin($iAngle * 3.1418 / 180 ) * $Radius + $YPos;
1939
1940         $TopPlots[$Key][] = $TopX;
1941         $TopPlots[$Key][] = $TopY;
1942        }
1943
1944       $TopPlots[$Key][] = $XPos;
1945       $TopPlots[$Key][] = $YPos;
1946
1947       $Angle = $iAngle;
1948      }
1949     $PolyPlots = $TopPlots;
1950
1951     /* Set array values type to float --- PHP Bug with imagefilledpolygon casting to integer */
1952     foreach ($TopPlots as $Key => $Value)
1953      { foreach ($TopPlots[$Key] as $Key2 => $Value2) { settype($TopPlots[$Key][$Key2],"float"); } }
1954
1955     /* Draw Top polygons */
1956     foreach ($PolyPlots as $Key => $Value)
1957      {
1958       $C_GraphLo = imagecolorallocate($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);
1959       imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo);
1960      }
1961
1962     $this->drawCircle($XPos-.5,$YPos-.5,$Radius,$R,$G,$B);
1963     $this->drawCircle($XPos-.5,$YPos-.5,$Radius+.5,$R,$G,$B);
1964
1965     /* Draw Top polygons */
1966     foreach ($TopPlots as $Key => $Value)
1967      {
1968       for($j=0;$j<=count($TopPlots[$Key])-4;$j=$j+2)
1969        $this->drawLine($TopPlots[$Key][$j],$TopPlots[$Key][$j+1],$TopPlots[$Key][$j+2],$TopPlots[$Key][$j+3],$R,$G,$B);
1970      }
1971    }
1972
1973   /* This function draw a flat pie chart */
1974   function drawFlatPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals = 0)
1975    {
1976     /* Validate the Data and DataDescription array */
1977     $this->validateDataDescription("drawFlatPieGraph",$DataDescription,FALSE);
1978     $this->validateData("drawFlatPieGraph",$Data);
1979
1980     /* Determine pie sum */
1981     $Series = 0; $PieSum = 0;
1982     foreach ( $DataDescription["Values"] as $Key2 => $ColName )
1983      {
1984       if ( $ColName != $DataDescription["Position"] )
1985        {
1986         $Series++;
1987         foreach ( $Data as $Key => $Values )
1988          {
1989           if ( isset($Data[$Key][$ColName]))
1990            $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]];
1991          }
1992        }
1993      }
1994
1995     /* Validate serie */
1996     if ( $Series != 1 )
1997      RaiseFatal("Pie chart can only accept one serie of data.");
1998
1999     $SpliceDistanceRatio = $SpliceDistance;
2000     $SpliceRatio         = (360 - $SpliceDistanceRatio * count($iValues) ) / $PieSum;
2001     $SplicePercent       = 100 / $PieSum;
2002
2003     /* Calculate all polygons */
2004     // $Angle    = 0; $TopPlots = "";
2005     $Angle    = 260; $TopPlots = "";
2006     foreach($iValues as $Key => $Value)
2007      {
2008       $XCenterPos = cos(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos;
2009       $YCenterPos = sin(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos;
2010
2011       $TopPlots[$Key][] = $XCenterPos;
2012       $TopPlots[$Key][] = $YCenterPos;
2013
2014       /* Process labels position & size */
2015       if ( !($DrawLabels == PIE_NOLABEL) )
2016        {
2017         $TAngle   = $Angle+($Value*$SpliceRatio/2);
2018         if ($TAngle > 359) $TAngle -= 360;
2019         if ($DrawLabels == PIE_PERCENTAGE)
2020        //  $Caption  = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%";
2021          $Caption  = (floor($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%";
2022          elseif ($DrawLabels == PIE_VALUES)
2023           $Caption  = (floor($Value));
2024         elseif ($DrawLabels == PIE_LABELS)
2025          $Caption  = $iLabels[$Key];
2026         $TX       = cos(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance)+$XPos;
2027         $TY       = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance) + $YPos + 4;
2028
2029//         if ( $TAngle > 90 && $TAngle < 270 )
2030         if ( $TAngle > 90 && $TAngle < 260 )
2031          {
2032           $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Caption);
2033           $TextWidth = $Position[2]-$Position[0];
2034           $TX = $TX - $TextWidth;
2035          }
2036
2037         $C_TextColor = imagecolorallocate($this->Picture,70,70,70);
2038         imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption);
2039        }
2040
2041       /* Draw borders to correct imagefilledpolygon bug */
2042       $BMax = 2;
2043       for($i=-1;$i<=$BMax;$i++)
2044        {
2045         $BorderX1 = cos(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $XPos;
2046         $BorderY1 = sin(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $YPos;
2047         $BorderX2 = cos(($Angle+$i*.5) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $XPos;
2048         $BorderY2 = sin(($Angle+$i*.5) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $YPos;
2049         $this->drawLine($BorderX1,$BorderY1,$BorderX2,$BorderY2,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);
2050
2051         $BorderX1 = cos(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $XPos;
2052         $BorderY1 = sin(($Angle+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * ($SpliceDistance+$i) + $YPos;
2053         $BorderX2 = cos(($Angle-$i*.5+$Value*$SpliceRatio) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $XPos;
2054         $BorderY2 = sin(($Angle-$i*.5+$Value*$SpliceRatio) * 3.1418 / 180 ) * (($Radius+$BMax)+$SpliceDistance) + $YPos;
2055         $this->drawLine($BorderX1,$BorderY1,$BorderX2,$BorderY2,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);
2056        }
2057
2058       /* Process pie slices */
2059       for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5)
2060        {
2061         $TopX = cos($iAngle * 3.1418 / 180 ) * ($Radius+$SpliceDistance) + $XPos;
2062         $TopY = sin($iAngle * 3.1418 / 180 ) * ($Radius+$SpliceDistance) + $YPos;
2063
2064         $TopPlots[$Key][] = $TopX;
2065         $TopPlots[$Key][] = $TopY;
2066
2067         if ( $iAngle != $Angle )
2068          {
2069           for($i=-1;$i<=2;$i++)
2070            {
2071             $BorderX1 = cos(($iAngle-.5) * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $XPos;
2072             $BorderY1 = sin(($iAngle-.5) * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $YPos;
2073             $BorderX2 = cos($iAngle * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $XPos;
2074             $BorderY2 = sin($iAngle * 3.1418 / 180 ) * (($Radius+$i)+$SpliceDistance) + $YPos;
2075
2076             $this->drawLine($BorderX1,$BorderY1,$BorderX2,$BorderY2,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);
2077            }
2078          }
2079        }
2080
2081       $TopPlots[$Key][] = $XCenterPos;
2082       $TopPlots[$Key][] = $YCenterPos;
2083
2084       $Angle = $iAngle + $SpliceDistanceRatio;
2085      }
2086     $PolyPlots = $TopPlots;
2087
2088     /* Set array values type to float --- PHP Bug with imagefilledpolygon casting to integer */
2089     foreach ($TopPlots as $Key => $Value)
2090      { foreach ($TopPlots[$Key] as $Key2 => $Value2) { settype($TopPlots[$Key][$Key2],"float"); } }
2091
2092     /* Draw Top polygons */
2093     foreach ($TopPlots as $Key => $Value)
2094      {
2095       $C_GraphLo = imagecolorallocate($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);
2096       imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo);
2097      }
2098    }
2099
2100   /* This function draw a pseudo-3D pie chart */
2101   function drawPieGraph(&$Data,&$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$EnhanceColors=TRUE,$Skew=60,$SpliceHeight=20,$SpliceDistance=0,$Decimals=0)
2102    {
2103     /* Validate the Data and DataDescription array */
2104     $this->validateDataDescription("drawPieGraph",$DataDescription,FALSE);
2105     $this->validateData("drawPieGraph",$Data);
2106
2107     /* Determine pie sum */
2108     $Series = 0; $PieSum = 0; $rPieSum = 0;
2109     foreach ( $DataDescription["Values"] as $Key2 => $ColName )
2110      {
2111       if ( $ColName != $DataDescription["Position"] )
2112        {
2113         $Series++;
2114         foreach ( $Data as $Key => $Values )
2115          if ( isset($Data[$Key][$ColName]))
2116           {
2117            if ( $Data[$Key][$ColName] == 0 )
2118           //  { $PieSum++; $iValues[] = 1; $rValues[] = 0; }
2119             { $PieSum += 0.00001; $iValues[] = 0.00001; $rValues[] = 0; }
2120            else
2121             { $PieSum += $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; $rValues[] = $Data[$Key][$ColName]; $rPieSum += $Data[$Key][$ColName];}
2122           }
2123        }
2124      }
2125
2126     /* Validate serie */
2127     if ( $Series != 1 )
2128      RaiseFatal("Pie chart can only accept one serie of data.");
2129
2130     $SpliceDistanceRatio = $SpliceDistance;
2131     $SkewHeight          = ($Radius * $Skew) / 100;
2132     $SpliceRatio         = (360 - $SpliceDistanceRatio * count($iValues) ) / $PieSum;
2133     $SplicePercent       = 100 / $PieSum;
2134     if ($rPieSum == 0) $rPieSum = 1;
2135     $rSplicePercent      = 100 / $rPieSum;
2136
2137     /* Calculate all polygons */
2138   // $Angle    = 0; $TopPlots = ""; $BotPlots = ""; $CDev = 5;
2139     $Angle    = 260; $TopPlots = ""; $BotPlots = ""; $CDev = 5;
2140     foreach($iValues as $Key => $Value)
2141      {
2142       $XCenterPos = cos(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos;
2143       $YCenterPos = sin(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos;
2144       $XCenterPos2 = cos(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos;
2145       $YCenterPos2 = sin(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos;
2146
2147       $TopPlots[$Key][] = $XCenterPos; $BotPlots[$Key][] = $XCenterPos;
2148       $TopPlots[$Key][] = $YCenterPos; $BotPlots[$Key][] = $YCenterPos + $SpliceHeight;
2149
2150       /* Process labels position & size */
2151       if ( !($DrawLabels == PIE_NOLABEL) )
2152        {
2153         $TAngle   = $Angle+($Value*$SpliceRatio/2);
2154         if ($TAngle > 359) $TAngle -= 360;
2155         if ($DrawLabels == PIE_PERCENTAGE)
2156        //  $Caption  = (round($rValues[$Key] * pow(10,$Decimals) * $rSplicePercent)/pow(10,$Decimals))."%";
2157          $Caption  = (floor($rValues[$Key] * pow(10,$Decimals) * $rSplicePercent)/pow(10,$Decimals))."%";
2158         elseif ($DrawLabels == PIE_VALUES) {
2159          if ($Value == 0) $Caption = '';
2160          else $Caption  = (floor($Value));
2161         } elseif ($DrawLabels == PIE_LABELS)
2162          $Caption  = $iLabels[$Key];
2163
2164        // $TX       = cos(($TAngle) * 3.1418 / 180 ) * ($Radius + 10)+ $XPos;
2165         $TX       = cos(($TAngle) * 3.1418 / 180 ) * ($Radius + 5)+ $XPos;
2166
2167         if ( $TAngle > 0 && $TAngle < 180 )
2168          $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 10) + $YPos + $SpliceHeight + 4;
2169         else
2170          $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 10) + $YPos + 4;
2171
2172        // if ( $TAngle > 90 && $TAngle < 270 )
2173         if ( $TAngle > 90 && $TAngle < 260 )
2174          {
2175           $Position  = imageftbbox($this->FontSize,0,$this->FontName,$Caption);
2176           $TextWidth = $Position[2]-$Position[0];
2177           $TX = $TX - $TextWidth;
2178          }
2179
2180        // $C_TextColor = imagecolorallocate($this->Picture,70,70,70);
2181         $C_TextColor = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-20);
2182         imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption);
2183        }
2184
2185       /* Process pie slices */
2186       for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5)
2187        {
2188         $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos;
2189         $TopY = sin($iAngle * 3.1418 / 180 ) * $SkewHeight + $YPos;
2190
2191         $TopPlots[$Key][] = $TopX; $BotPlots[$Key][] = $TopX;
2192         $TopPlots[$Key][] = $TopY; $BotPlots[$Key][] = $TopY + $SpliceHeight;
2193        }
2194
2195       $TopPlots[$Key][] = $XCenterPos2; $BotPlots[$Key][] = $XCenterPos2;
2196       $TopPlots[$Key][] = $YCenterPos2; $BotPlots[$Key][] = $YCenterPos2 + $SpliceHeight;
2197
2198       $Angle = $iAngle + $SpliceDistanceRatio;
2199      }
2200
2201     /* Draw Bottom polygons */
2202     foreach($iValues as $Key => $Value)
2203      {
2204       $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-20);
2205       imagefilledpolygon($this->Picture,$BotPlots[$Key],(count($BotPlots[$Key])+1)/2,$C_GraphLo);
2206
2207       for($j=0;$j<=count($BotPlots[$Key])-4;$j=$j+2)
2208        $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);
2209      }
2210
2211     /* Draw pie layers */
2212     if ( $EnhanceColors ) { $ColorRatio = 30 / $SpliceHeight; } else { $ColorRatio = 25 / $SpliceHeight; }
2213     for($i=$SpliceHeight-1;$i>=1;$i--)
2214      {
2215       foreach($iValues as $Key => $Value)
2216        {
2217         $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-10);
2218         $Plots = ""; $Plot = 0;
2219         foreach($TopPlots[$Key] as $Key2 => $Value2)
2220          {
2221           $Plot++;
2222           if ( $Plot % 2 == 1 )
2223            $Plots[] = $Value2;
2224           else
2225            $Plots[] = $Value2+$i;
2226          }
2227         imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_GraphLo);
2228
2229         $Index       = count($Plots);
2230         $ColorFactor = -20 + ($SpliceHeight - $i) * $ColorRatio;
2231         $this->drawAntialiasPixel($Plots[0],$Plots[1],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor);
2232         $this->drawAntialiasPixel($Plots[2],$Plots[3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor);
2233         $this->drawAntialiasPixel($Plots[$Index-4],$Plots[$Index-3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor);
2234        }
2235      }
2236
2237     /* Draw Top polygons */
2238     for($Key=count($iValues)-1;$Key>=0;$Key--)
2239      {
2240       $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]);
2241       imagefilledpolygon($this->Picture,$TopPlots[$Key],(count($TopPlots[$Key])+1)/2,$C_GraphLo);
2242
2243       if ( $EnhanceColors ) { $En = 10; } else { $En = 5; }
2244       for($j=0;$j<=count($TopPlots[$Key])-4;$j=$j+2)
2245        $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);
2246      }
2247    }
2248
2249   /* This function can be used to set the background color */
2250   function drawBackground($R,$G,$B)
2251    {
2252     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2253     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2254     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2255
2256     $C_Background = imagecolorallocate($this->Picture,$R,$G,$B);
2257     imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_Background);
2258    }
2259
2260   /* This function can be used to set the background color */
2261   function drawGraphAreaGradient($R,$G,$B,$Decay,$Target=TARGET_GRAPHAREA)
2262    {
2263     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2264     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2265     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2266
2267     if ( $Target == TARGET_GRAPHAREA )  { $X1 = $this->GArea_X1+1; $X2 = $this->GArea_X2-1; $Y1 = $this->GArea_Y1+1; $Y2 = $this->GArea_Y2; }
2268     if ( $Target == TARGET_BACKGROUND ) { $X1 = 0; $X2 = $this->XSize; $Y1 = 0; $Y2 = $this->YSize; }
2269
2270     $YStep = ($Y2 - $Y1 - 2) / $Decay;
2271     for($i=0;$i<=$Decay;$i++)
2272      {
2273       $R-=1;$G-=1;$B-=1;
2274       $Yi1 = $Y1 + ( $i * $YStep );
2275       $Yi2 = ceil( $Yi1 + ( $i * $YStep ) + $YStep );
2276       if ( $Yi2 >= $Yi2 ) { $Yi2 = $Y2-1; }
2277
2278       $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B);
2279       imagefilledrectangle($this->Picture,$X1,$Yi1,$X2,$Yi2,$C_Background);
2280      }
2281    }
2282
2283   /* This function create a rectangle with antialias */
2284   function drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B)
2285    {
2286     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2287     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2288     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2289
2290     $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);
2291
2292     $X1=$X1-.2;$Y1=$Y1-.2;
2293     $X2=$X2+.2;$Y2=$Y2+.2;
2294     $this->drawLine($X1,$Y1,$X2,$Y1,$R,$G,$B);
2295     $this->drawLine($X2,$Y1,$X2,$Y2,$R,$G,$B);
2296     $this->drawLine($X2,$Y2,$X1,$Y2,$R,$G,$B);
2297     $this->drawLine($X1,$Y2,$X1,$Y1,$R,$G,$B);
2298    }
2299
2300   /* This function create a filled rectangle with antialias */
2301   function drawFilledRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B,$DrawBorder=TRUE,$Alpha=100)
2302    {
2303     if ( $X2 > $X1 ) { list($X1, $X2) = array($X2, $X1); }
2304     if ( $Y2 > $Y1 ) { list($Y1, $Y2) = array($Y2, $Y1); }
2305
2306     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2307     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2308     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2309
2310     if ( $Alpha == 100 )
2311      {
2312       $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);
2313       imagefilledrectangle($this->Picture,$X1,$Y1,$X2,$Y2,$C_Rectangle);
2314      }
2315     else
2316      {
2317       $LayerWidth  = abs($X2-$X1)+2;
2318       $LayerHeight = abs($Y2-$Y1)+2;
2319
2320       $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);
2321       $C_White         = imagecolorallocate($this->Layers[0],255,255,255);
2322       imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);
2323       imagecolortransparent($this->Layers[0],$C_White);
2324
2325       $C_Rectangle = imagecolorallocate($this->Layers[0],$R,$G,$B);
2326       imagefilledrectangle($this->Layers[0],1,1,$LayerWidth-1,$LayerHeight-1,$C_Rectangle);
2327
2328       imagecopymerge($this->Picture,$this->Layers[0],min($X1,$X2)-1,min($Y1,$Y2)-1,0,0,$LayerWidth,$LayerHeight,$Alpha);
2329       imagedestroy($this->Layers[0]);
2330      }
2331
2332     if ( $DrawBorder )
2333      $this->drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B);
2334    }
2335
2336   /* This function create a rectangle with rounded corners and antialias */
2337   function drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B)
2338    {
2339     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2340     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2341     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2342
2343     $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);
2344
2345     $Step = 90 / ((3.1418 * $Radius)/2);
2346
2347     for($i=0;$i<=90;$i=$i+$Step)
2348      {
2349       $X = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius;
2350       $Y = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius;
2351       $this->drawAntialiasPixel($X,$Y,$R,$G,$B);
2352
2353       $X = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius;
2354       $Y = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius;
2355       $this->drawAntialiasPixel($X,$Y,$R,$G,$B);
2356
2357       $X = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius;
2358       $Y = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius;
2359       $this->drawAntialiasPixel($X,$Y,$R,$G,$B);
2360
2361       $X = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius;
2362       $Y = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius;
2363       $this->drawAntialiasPixel($X,$Y,$R,$G,$B);
2364      }
2365
2366     $X1=$X1-.2;$Y1=$Y1-.2;
2367     $X2=$X2+.2;$Y2=$Y2+.2;
2368     $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B);
2369     $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B);
2370     $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B);
2371     $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B);
2372    }
2373
2374   /* This function create a filled rectangle with rounded corners and antialias */
2375   function drawFilledRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B)
2376    {
2377     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2378     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2379     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2380
2381     $C_Rectangle = imagecolorallocate($this->Picture,$R,$G,$B);
2382
2383     $Step = 90 / ((3.1418 * $Radius)/2);
2384
2385     for($i=0;$i<=90;$i=$i+$Step)
2386      {
2387       $Xi1 = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius;
2388       $Yi1 = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius;
2389
2390       $Xi2 = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius;
2391       $Yi2 = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius;
2392
2393       $Xi3 = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius;
2394       $Yi3 = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius;
2395
2396       $Xi4 = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius;
2397       $Yi4 = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius;
2398
2399       imageline($this->Picture,$Xi1,$Yi1,$X1+$Radius,$Yi1,$C_Rectangle);
2400       imageline($this->Picture,$X2-$Radius,$Yi2,$Xi2,$Yi2,$C_Rectangle);
2401       imageline($this->Picture,$X2-$Radius,$Yi3,$Xi3,$Yi3,$C_Rectangle);
2402       imageline($this->Picture,$Xi4,$Yi4,$X1+$Radius,$Yi4,$C_Rectangle);
2403
2404       $this->drawAntialiasPixel($Xi1,$Yi1,$R,$G,$B);
2405       $this->drawAntialiasPixel($Xi2,$Yi2,$R,$G,$B);
2406       $this->drawAntialiasPixel($Xi3,$Yi3,$R,$G,$B);
2407       $this->drawAntialiasPixel($Xi4,$Yi4,$R,$G,$B);
2408      }
2409
2410     imagefilledrectangle($this->Picture,$X1,$Y1+$Radius,$X2,$Y2-$Radius,$C_Rectangle);
2411     imagefilledrectangle($this->Picture,$X1+$Radius,$Y1,$X2-$Radius,$Y2,$C_Rectangle);
2412
2413     $X1=$X1-.2;$Y1=$Y1-.2;
2414     $X2=$X2+.2;$Y2=$Y2+.2;
2415     $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B);
2416     $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B);
2417     $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B);
2418     $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B);
2419    }
2420
2421   /* This function create a circle with antialias */
2422   function drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0)
2423    {
2424     if ( $Width == 0 ) { $Width = $Height; }
2425     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2426     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2427     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2428
2429     $C_Circle = imagecolorallocate($this->Picture,$R,$G,$B);
2430     $Step     = 360 / (2 * 3.1418 * max($Width,$Height));
2431
2432     for($i=0;$i<=360;$i=$i+$Step)
2433      {
2434       $X = cos($i*3.1418/180) * $Height + $Xc;
2435       $Y = sin($i*3.1418/180) * $Width + $Yc;
2436       $this->drawAntialiasPixel($X,$Y,$R,$G,$B);
2437      }
2438    }
2439
2440   /* This function create a filled circle/ellipse with antialias */
2441   function drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0)
2442    {
2443     if ( $Width == 0 ) { $Width = $Height; }
2444     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2445     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2446     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2447
2448     $C_Circle = imagecolorallocate($this->Picture,$R,$G,$B);
2449     $Step     = 360 / (2 * 3.1418 * max($Width,$Height));
2450
2451     for($i=90;$i<=270;$i=$i+$Step)
2452      {
2453       $X1 = cos($i*3.1418/180) * $Height + $Xc;
2454       $Y1 = sin($i*3.1418/180) * $Width + $Yc;
2455       $X2 = cos((180-$i)*3.1418/180) * $Height + $Xc;
2456       $Y2 = sin((180-$i)*3.1418/180) * $Width + $Yc;
2457
2458       $this->drawAntialiasPixel($X1-1,$Y1-1,$R,$G,$B);
2459       $this->drawAntialiasPixel($X2-1,$Y2-1,$R,$G,$B);
2460
2461       if ( ($Y1-1) > $Yc - max($Width,$Height) )
2462        imageline($this->Picture,$X1,$Y1-1,$X2-1,$Y2-1,$C_Circle);
2463      }
2464    }
2465
2466   /* This function will draw a filled ellipse */
2467   function drawEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B)
2468    { $this->drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); }
2469
2470   /* This function will draw an ellipse */
2471   function drawFilledEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B)
2472    { $this->drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); }
2473
2474   /* This function create a line with antialias */
2475   function drawLine($X1,$Y1,$X2,$Y2,$R,$G,$B,$GraphFunction=FALSE)
2476    {
2477     if ( $this->LineDotSize > 1 ) { $this->drawDottedLine($X1,$Y1,$X2,$Y2,$this->LineDotSize,$R,$G,$B,$GraphFunction); return(0); }
2478     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2479     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2480     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2481
2482     $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); 
2483     if ( $Distance == 0 )
2484      return(-1);
2485     $XStep = ($X2-$X1) / $Distance;
2486     $YStep = ($Y2-$Y1) / $Distance;
2487
2488     for($i=0;$i<=$Distance;$i++)
2489      {
2490       $X = $i * $XStep + $X1;
2491       $Y = $i * $YStep + $Y1;
2492
2493       if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction )
2494        {
2495         if ( $this->LineWidth == 1 )
2496          $this->drawAntialiasPixel($X,$Y,$R,$G,$B);
2497         else
2498          {
2499           $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2);
2500           for($j=$StartOffset;$j<=$EndOffset;$j++)
2501            $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B);
2502          }
2503        }
2504      }
2505    }
2506
2507   /* This function create a line with antialias */
2508   function drawDottedLine($X1,$Y1,$X2,$Y2,$DotSize,$R,$G,$B,$GraphFunction=FALSE)
2509    {
2510     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2511     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2512     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2513
2514     $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); 
2515
2516     $XStep = ($X2-$X1) / $Distance;
2517     $YStep = ($Y2-$Y1) / $Distance;
2518
2519     $DotIndex = 0;
2520     for($i=0;$i<=$Distance;$i++)
2521      {
2522       $X = $i * $XStep + $X1;
2523       $Y = $i * $YStep + $Y1;
2524
2525       if ( $DotIndex <= $DotSize)
2526        {
2527         if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction )
2528          {
2529           if ( $this->LineWidth == 1 )
2530            $this->drawAntialiasPixel($X,$Y,$R,$G,$B);
2531           else
2532            {
2533             $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2);
2534             for($j=$StartOffset;$j<=$EndOffset;$j++)
2535              $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B);
2536            }
2537          }
2538        }
2539
2540       $DotIndex++;
2541       if ( $DotIndex == $DotSize * 2 )
2542        $DotIndex = 0;       
2543      }
2544    }
2545
2546   /* Load a PNG file and draw it over the chart */
2547   function drawFromPNG($FileName,$X,$Y,$Alpha=100)
2548    { $this->drawFromPicture(1,$FileName,$X,$Y,$Alpha); }
2549
2550   /* Load a GIF file and draw it over the chart */
2551   function drawFromGIF($FileName,$X,$Y,$Alpha=100)
2552    { $this->drawFromPicture(2,$FileName,$X,$Y,$Alpha); }
2553
2554   /* Load a JPEG file and draw it over the chart */
2555   function drawFromJPG($FileName,$X,$Y,$Alpha=100)
2556    { $this->drawFromPicture(3,$FileName,$X,$Y,$Alpha); }
2557
2558   /* Generic loader function for external pictures */
2559   function drawFromPicture($PicType,$FileName,$X,$Y,$Alpha=100)
2560    {
2561     if ( file_exists($FileName))
2562      {
2563       $Infos  = getimagesize($FileName);
2564       $Width  = $Infos[0];
2565       $Height = $Infos[1];
2566       if ( $PicType == 1 ) { $Raster = imagecreatefrompng($FileName); }
2567       if ( $PicType == 2 ) { $Raster = imagecreatefromgif($FileName); }
2568       if ( $PicType == 3 ) { $Raster = imagecreatefromjpeg($FileName); }
2569
2570       imagecopymerge($this->Picture,$Raster,$X,$Y,0,0,$Width,$Height,$Alpha);
2571       imagedestroy($Raster);
2572      }
2573    }
2574
2575   /* Draw an alpha pixel */
2576   function drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B)
2577    {
2578     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2579     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2580     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2581
2582     if ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize )
2583      return(-1);
2584
2585     $RGB2 = imagecolorat($this->Picture, $X, $Y);
2586     $R2   = ($RGB2 >> 16) & 0xFF;
2587     $G2   = ($RGB2 >> 8) & 0xFF;
2588     $B2   = $RGB2 & 0xFF;
2589
2590     $iAlpha = (100 - $Alpha)/100;
2591     $Alpha  = $Alpha / 100;
2592
2593     $Ra   = floor($R*$Alpha+$R2*$iAlpha);
2594     $Ga   = floor($G*$Alpha+$G2*$iAlpha);
2595     $Ba   = floor($B*$Alpha+$B2*$iAlpha);
2596
2597     $C_Aliased = imagecolorallocate($this->Picture,$Ra,$Ga,$Ba);
2598     imagesetpixel($this->Picture,$X,$Y,$C_Aliased);
2599    }
2600
2601   /* Color helper */
2602   function AllocateColor($Picture,$R,$G,$B,$Factor=0)
2603    {
2604     $R = $R + $Factor;
2605     $G = $G + $Factor;
2606     $B = $B + $Factor;
2607     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2608     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2609     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2610
2611     return(imagecolorallocate($Picture,$R,$G,$B));
2612    }
2613
2614   /* Add a border to the picture */
2615   function addBorder($Size=3,$R=0,$G=0,$B=0)
2616    {
2617     $Width  = $this->XSize+2*$Size;
2618     $Height = $this->YSize+2*$Size;
2619
2620     $Resampled    = imagecreatetruecolor($Width,$Height);
2621     $C_Background = imagecolorallocate($Resampled,$R,$G,$B);
2622     imagefilledrectangle($Resampled,0,0,$Width,$Height,$C_Background);
2623
2624     imagecopy($Resampled,$this->Picture,$Size,$Size,0,0,$this->XSize,$this->YSize);
2625     imagedestroy($this->Picture);
2626
2627     $this->XSize = $Width;
2628     $this->YSize = $Height;
2629
2630     $this->Picture = imagecreatetruecolor($this->XSize,$this->YSize);
2631     $C_White = imagecolorallocate($this->Picture,255,255,255);
2632     imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_White);
2633     imagecolortransparent($this->Picture,$C_White);
2634     imagecopy($this->Picture,$Resampled,0,0,0,0,$this->XSize,$this->YSize);
2635    }
2636
2637   /* Render the current picture to a file */
2638   function Render($FileName)
2639    {
2640     if ( $this->ErrorReporting )
2641      $this->printErrors($this->ErrorInterface);
2642
2643     /* Save image map if requested */
2644     if ( $this->BuildMap )
2645      $this->SaveImageMap();
2646
2647     imagepng($this->Picture,$FileName);
2648    }
2649
2650   /* Render the current picture to STDOUT */
2651   function Stroke()
2652    {
2653     if ( $this->ErrorReporting )
2654      $this->printErrors("GD");
2655
2656     /* Save image map if requested */
2657     if ( $this->BuildMap )
2658      $this->SaveImageMap();
2659
2660     header('Content-type: image/png');
2661     imagepng($this->Picture);
2662    }
2663
2664   /* Private functions for internal processing */
2665   function drawAntialiasPixel($X,$Y,$R,$G,$B)
2666    {
2667     if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
2668     if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
2669     if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
2670
2671     $Plot = "";
2672     $Xi   = floor($X);
2673     $Yi   = floor($Y);
2674
2675     if ( $Xi == $X && $Yi == $Y)
2676      {
2677       /* $this->drawAlphaPixel($Xi,$Yi,0,$R,$G,$B); */
2678       $C_Aliased = imagecolorallocate($this->Picture,$R,$G,$B);
2679       imagesetpixel($this->Picture,$X,$Y,$C_Aliased);
2680      }
2681     else
2682      {
2683       $Alpha1 = (1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100;
2684       if ( $Alpha1 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi,$Alpha1,$R,$G,$B); }
2685
2686       $Alpha2 = ($X - floor($X)) * (1 - ($Y - floor($Y))) * 100;
2687       if ( $Alpha2 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi,$Alpha2,$R,$G,$B); }
2688
2689       $Alpha3 = (1 - ($X - floor($X))) * ($Y - floor($Y)) * 100;
2690       if ( $Alpha3 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi+1,$Alpha3,$R,$G,$B); }
2691
2692       $Alpha4 = ($X - floor($X)) * ($Y - floor($Y)) * 100;
2693       if ( $Alpha4 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi+1,$Alpha4,$R,$G,$B); }
2694      }
2695    }
2696
2697   /* Validate data contained in the description array */
2698   function validateDataDescription($FunctionName,&$DataDescription,$DescriptionRequired=TRUE)
2699    {
2700     if (!isset($DataDescription["Position"]))
2701      {
2702       $this->Errors[] = "[Warning] ".$FunctionName." - Y Labels are not set.";
2703       $DataDescription["Position"] = "Name";
2704      }
2705
2706     if ( $DescriptionRequired )
2707      {
2708       if (!isset($DataDescription["Description"]))
2709        {
2710         $this->Errors[] = "[Warning] ".$FunctionName." - Series descriptions are not set.";
2711         foreach($DataDescription["Values"] as $key => $Value)
2712          {
2713           $DataDescription["Description"][$Value] = $Value;
2714          }
2715        }
2716
2717       if (count($DataDescription["Description"]) < count($DataDescription["Values"]))
2718        {
2719         $this->Errors[] = "[Warning] ".$FunctionName." - Some series descriptions are not set.";
2720         foreach($DataDescription["Values"] as $key => $Value)
2721          {
2722           if ( !isset($DataDescription["Description"][$Value]))
2723            $DataDescription["Description"][$Value] = $Value;
2724          }
2725        }
2726      }
2727    }
2728
2729   /* Validate data contained in the data array */
2730   function validateData($FunctionName,&$Data)
2731    {
2732     $DataSummary = "";
2733
2734     foreach($Data as $key => $Values)
2735      {
2736       foreach($Values as $key2 => $Value)
2737        {
2738         if (!isset($DataSummary[$key2]))
2739          $DataSummary[$key2] = 1;
2740         else
2741          $DataSummary[$key2]++;
2742        }
2743      }
2744
2745     if ( max($DataSummary) == 0 )
2746      $this->Errors[] = "[Warning] ".$FunctionName." - No data set.";
2747
2748     foreach($DataSummary as $key => $Value)
2749      {
2750       if ($Value < max($DataSummary))
2751        {
2752         $this->Errors[] = "[Warning] ".$FunctionName." - Missing data in serie ".$key.".";
2753        }
2754      }
2755    }
2756
2757   /* Print all error messages on the CLI or graphically */
2758   function printErrors($Mode="CLI")
2759    {
2760     if (count($this->Errors) == 0)
2761      return(0);
2762
2763     if ( $Mode == "CLI" )
2764      {
2765       foreach($this->Errors as $key => $Value)
2766        echo $Value."\r\n";
2767      }
2768     elseif ( $Mode == "GD" )
2769      {
2770       $this->setLineStyle($Width=1);
2771       $MaxWidth = 0;
2772       foreach($this->Errors as $key => $Value)
2773        {
2774         $Position  = imageftbbox($this->ErrorFontSize,0,$this->ErrorFontName,$Value);
2775         $TextWidth = $Position[2]-$Position[0];
2776         if ( $TextWidth > $MaxWidth ) { $MaxWidth = $TextWidth; }
2777        }
2778       $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);
2779       $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);
2780
2781       $C_TextColor = imagecolorallocate($this->Picture,133,85,85);
2782       $YPos        = $this->YSize - (18 + (count($this->Errors)-1) * ($this->ErrorFontSize + 4));
2783       foreach($this->Errors as $key => $Value)
2784        {
2785         imagettftext($this->Picture,$this->ErrorFontSize,0,$this->XSize-($MaxWidth+15),$YPos,$C_TextColor,$this->ErrorFontName,$Value);
2786         $YPos = $YPos + ($this->ErrorFontSize + 4);
2787        }
2788      }
2789    }
2790
2791   /* Activate the image map creation process */
2792   function setImageMap($Mode=TRUE,$GraphID="MyGraph")
2793    {
2794     $this->BuildMap = $Mode;
2795     $this->MapID    = $GraphID;
2796    }
2797
2798   /* Add a box into the image map */
2799   function addToImageMap($X1,$Y1,$X2,$Y2,$SerieName,$Value,$CallerFunction)
2800    {
2801     if ( $this->MapFunction == NULL || $this->MapFunction == $CallerFunction )
2802      {
2803       $this->ImageMap[]  = round($X1).",".round($Y1).",".round($X2).",".round($Y2).",".$SerieName.",".$Value;
2804       $this->MapFunction = $CallerFunction;
2805      }
2806    }
2807
2808   /* Load and cleanup the image map from disk */
2809   function getImageMap($MapName,$Flush=TRUE)
2810    {
2811     /* Strip HTML query strings */
2812     $Values   = $this->tmpFolder.$MapName;
2813     $Value    = split("\?",$Values);
2814     $FileName = $Value[0];
2815
2816     if ( file_exists($FileName) )
2817      {
2818       $Handle     = fopen($FileName, "r");
2819       $MapContent = fread($Handle, filesize($FileName));
2820       fclose($Handle);
2821       echo $MapContent;
2822
2823       if ( $Flush )
2824        unlink($FileName);
2825
2826       exit();
2827      }
2828     else
2829      {
2830       header("HTTP/1.0 404 Not Found");
2831       exit();
2832      }
2833    }
2834
2835   /* Save the image map to the disk */
2836   function SaveImageMap()
2837    {
2838     if ( !$this->BuildMap ) { return(-1); }
2839
2840     if ( $this->ImageMap == NULL )
2841      {
2842       $this->Errors[] = "[Warning] SaveImageMap - Image map is empty.";
2843       return(-1);
2844      }
2845
2846     $Handle = fopen($this->tmpFolder.$this->MapID, 'w');
2847     if ( !$Handle )
2848      {
2849       $this->Errors[] = "[Warning] SaveImageMap - Cannot save the image map.";
2850       return(-1);
2851      }
2852     else
2853      {
2854       foreach($this->ImageMap as $Key => $Value)
2855        fwrite($Handle, htmlentities($Value)."\r");
2856      }
2857     fclose ($Handle);
2858    }
2859
2860   /* Convert seconds to a time format string */
2861   function ToTime($Value)
2862    {
2863     $Hour   = floor($Value/3600);
2864     $Minute = floor(($Value - $Hour*3600)/60);
2865     $Second = floor($Value - $Hour*3600 - $Minute*60);
2866
2867     if (strlen($Hour) == 1 )   { $Hour = "0".$Hour; }
2868     if (strlen($Minute) == 1 ) { $Minute = "0".$Minute; }
2869     if (strlen($Second) == 1 ) { $Second = "0".$Second; }
2870
2871     return($Hour.":".$Minute.":".$Second);
2872    }
2873
2874   /* Convert to metric system */
2875   function ToMetric($Value)
2876    {
2877     $Go = floor($Value/1000000000);
2878     $Mo = floor(($Value - $Go*1000000000)/1000000);
2879     $Ko = floor(($Value - $Go*1000000000 - $Mo*1000000)/1000);
2880     $o  = floor($Value - $Go*1000000000 - $Mo*1000000 - $Ko*1000);
2881
2882     if ($Go != 0)   { return($Go.".".$Mo."g"); }
2883     if ($Mo != 0)   { return($Mo.".".$ko."m"); }
2884     if ($Ko != 0)   { return($Ko.".".$o)."k"; }
2885     return($o);
2886    }
2887
2888   /* Set date format for axis labels */
2889   function setDateFormat($Format)
2890    {
2891     $this->DateFormat = $Format;
2892    }
2893
2894   /* Convert TS to a date format string */
2895   function ToDate($Value)
2896    {
2897     return(date($this->DateFormat,$Value));
2898    }
2899  }
2900
2901 function RaiseFatal($Message)
2902  {
2903   echo "[FATAL] ".$Message."\r\n";
2904   exit();
2905  }
2906?>
Note: See TracBrowser for help on using the repository browser.