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