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] + 0; 655 $this->VMax = $Data[0][$YSerieName] + 0; 656 657 foreach ( $Data as $Key => $Values ) 658 { 659 if (isset($Data[$Key][$YSerieName])) 660 { 661 $Value = $Data[$Key][$YSerieName] + 0; 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] + 0; 762 $this->VXMax = $Data[0][$XSerieName] + 0; 763 764 foreach ( $Data as $Key => $Values ) 765 { 766 if (isset($Data[$Key][$XSerieName])) 767 { 768 $Value = $Data[$Key][$XSerieName] + 0; 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 /* Draw the data legends */ 981 function drawLegend($XPos,$YPos,$DataDescription,$R,$G,$B,$Rs=-1,$Gs=-1,$Bs=-1,$Rt=0,$Gt=0,$Bt=0,$Border=TRUE) 982 { 983 /* Validate the Data and DataDescription array */ 984 $this->validateDataDescription("drawLegend",$DataDescription); 985 986 if ( !isset($DataDescription["Description"]) ) 987 return(-1); 988 989 $C_TextColor =$this->AllocateColor($this->Picture,$Rt,$Gt,$Bt); 990 991 /* <-10->[8]<-4->Text<-10-> */ 992 $MaxWidth = 0; $MaxHeight = 8; 993 foreach($DataDescription["Description"] as $Key => $Value) 994 { 995 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); 996 $TextWidth = $Position[2]-$Position[0]; 997 $TextHeight = $Position[1]-$Position[7]; 998 if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; } 999 $MaxHeight = $MaxHeight + $TextHeight + 4; 1000 } 1001 $MaxHeight = $MaxHeight - 5; 1002 $MaxWidth = $MaxWidth + 32; 1003 1004 if ( $Rs == -1 || $Gs == -1 || $Bs == -1 ) 1005 { $Rs = $R-30; $Gs = $G-30; $Bs = $B-30; } 1006 1007 if ( $Border ) 1008 { 1009 $this->drawFilledRoundedRectangle($XPos+1,$YPos+1,$XPos+$MaxWidth+1,$YPos+$MaxHeight+1,5,$Rs,$Gs,$Bs); 1010 $this->drawFilledRoundedRectangle($XPos,$YPos,$XPos+$MaxWidth,$YPos+$MaxHeight,5,$R,$G,$B); 1011 } 1012 1013 $YOffset = 4 + $this->FontSize; $ID = 0; 1014 foreach($DataDescription["Description"] as $Key => $Value) 1015 { 1016 $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"]); 1017 imagettftext($this->Picture,$this->FontSize,0,$XPos+22,$YPos+$YOffset,$C_TextColor,$this->FontName,$Value); 1018 1019 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); 1020 $TextHeight = $Position[1]-$Position[7]; 1021 1022 $YOffset = $YOffset + $TextHeight + 4; 1023 $ID++; 1024 } 1025 } 1026 1027 /* Draw the data legends */ 1028 function drawPieLegend($XPos,$YPos,$Data,$DataDescription,$R,$G,$B) 1029 { 1030 /* Validate the Data and DataDescription array */ 1031 $this->validateDataDescription("drawPieLegend",$DataDescription,FALSE); 1032 $this->validateData("drawPieLegend",$Data); 1033 1034 if ( !isset($DataDescription["Position"]) ) 1035 return(-1); 1036 1037 $C_TextColor =$this->AllocateColor($this->Picture,0,0,0); 1038 1039 /* <-10->[8]<-4->Text<-10-> */ 1040 $MaxWidth = 0; $MaxHeight = 8; 1041 foreach($Data as $Key => $Value) 1042 { 1043 $Value2 = $Value[$DataDescription["Position"]]; 1044 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value2); 1045 $TextWidth = $Position[2]-$Position[0]; 1046 $TextHeight = $Position[1]-$Position[7]; 1047 if ( $TextWidth > $MaxWidth) { $MaxWidth = $TextWidth; } 1048 1049 $MaxHeight = $MaxHeight + $TextHeight + 4; 1050 } 1051 $MaxHeight = $MaxHeight - 3; 1052 $MaxWidth = $MaxWidth + 32; 1053 1054 $this->drawFilledRoundedRectangle($XPos+1,$YPos+1,$XPos+$MaxWidth+1,$YPos+$MaxHeight+1,5,$R-30,$G-30,$B-30); 1055 $this->drawFilledRoundedRectangle($XPos,$YPos,$XPos+$MaxWidth,$YPos+$MaxHeight,5,$R,$G,$B); 1056 1057 $YOffset = 4 + $this->FontSize; $ID = 0; 1058 foreach($Data as $Key => $Value) 1059 { 1060 $Value2 = $Value[$DataDescription["Position"]]; 1061 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value2); 1062 $TextHeight = $Position[1]-$Position[7]; 1063 $this->drawFilledRectangle($XPos+10,$YPos+$YOffset-6,$XPos+14,$YPos+$YOffset-2,$this->Palette[$ID]["R"],$this->Palette[$ID]["G"],$this->Palette[$ID]["B"]); 1064 1065 imagettftext($this->Picture,$this->FontSize,0,$XPos+22,$YPos+$YOffset,$C_TextColor,$this->FontName,$Value2); 1066 $YOffset = $YOffset + $TextHeight + 4; 1067 $ID++; 1068 } 1069 } 1070 1071 /* Draw the graph title */ 1072 function drawTitle($XPos,$YPos,$Value,$R,$G,$B,$XPos2=-1,$YPos2=-1,$Shadow=FALSE) 1073 { 1074 $C_TextColor = $this->AllocateColor($this->Picture,$R,$G,$B); 1075 1076 if ( $XPos2 != -1 ) 1077 { 1078 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); 1079 $TextWidth = $Position[2]-$Position[0]; 1080 $XPos = floor(( $XPos2 - $XPos - $TextWidth ) / 2 ) + $XPos; 1081 } 1082 1083 if ( $YPos2 != -1 ) 1084 { 1085 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value); 1086 $TextHeight = $Position[5]-$Position[3]; 1087 $YPos = floor(( $YPos2 - $YPos - $TextHeight ) / 2 ) + $YPos; 1088 } 1089 1090 if ( $Shadow ) 1091 { 1092 $C_ShadowColor = $this->AllocateColor($this->Picture,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor); 1093 imagettftext($this->Picture,$this->FontSize,0,$XPos+$this->ShadowXDistance,$YPos+$this->ShadowYDistance,$C_ShadowColor,$this->FontName,$Value); 1094 } 1095 1096 imagettftext($this->Picture,$this->FontSize,0,$XPos,$YPos,$C_TextColor,$this->FontName,$Value); 1097 } 1098 1099 /* Draw a text box with text align & alpha properties */ 1100 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) 1101 { 1102 $Position = imageftbbox($this->FontSize,$Angle,$this->FontName,$Text); 1103 $TextWidth = $Position[2]-$Position[0]; 1104 $TextHeight = $Position[5]-$Position[3]; 1105 $AreaWidth = $X2 - $X1; 1106 $AreaHeight = $Y2 - $Y1; 1107 1108 if ( $BgR != -1 && $BgG != -1 && $BgB != -1 ) 1109 $this->drawFilledRectangle($X1,$Y1,$X2,$Y2,$BgR,$BgG,$BgB,FALSE,$Alpha); 1110 1111 if ( $Align == ALIGN_TOP_LEFT ) { $X = $X1+1; $Y = $Y1+$this->FontSize+1; } 1112 if ( $Align == ALIGN_TOP_CENTER ) { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y1+$this->FontSize+1; } 1113 if ( $Align == ALIGN_TOP_RIGHT ) { $X = $X2-$TextWidth-1; $Y = $Y1+$this->FontSize+1; } 1114 if ( $Align == ALIGN_LEFT ) { $X = $X1+1; $Y = $Y1+($AreaHeight/2)-($TextHeight/2); } 1115 if ( $Align == ALIGN_CENTER ) { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y1+($AreaHeight/2)-($TextHeight/2); } 1116 if ( $Align == ALIGN_RIGHT ) { $X = $X2-$TextWidth-1; $Y = $Y1+($AreaHeight/2)-($TextHeight/2); } 1117 if ( $Align == ALIGN_BOTTOM_LEFT ) { $X = $X1+1; $Y = $Y2-1; } 1118 if ( $Align == ALIGN_BOTTOM_CENTER ) { $X = $X1+($AreaWidth/2)-($TextWidth/2); $Y = $Y2-1; } 1119 if ( $Align == ALIGN_BOTTOM_RIGHT ) { $X = $X2-$TextWidth-1; $Y = $Y2-1; } 1120 1121 $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B); 1122 $C_ShadowColor =$this->AllocateColor($this->Picture,0,0,0); 1123 if ( $Shadow ) 1124 imagettftext($this->Picture,$this->FontSize,$Angle,$X+1,$Y+1,$C_ShadowColor,$this->FontName,$Text); 1125 1126 imagettftext($this->Picture,$this->FontSize,$Angle,$X,$Y,$C_TextColor,$this->FontName,$Text); 1127 } 1128 1129 /* Compute and draw the scale */ 1130 function drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnRight=FALSE,$TickWidth=4,$FreeText=NULL) 1131 { 1132 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 1133 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 1134 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 1135 1136 $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B); 1137 $Y = $this->GArea_Y2 - ($Value - $this->VMin) * $this->DivisionRatio; 1138 1139 if ( $Y <= $this->GArea_Y1 || $Y >= $this->GArea_Y2 ) 1140 return(-1); 1141 1142 if ( $TickWidth == 0 ) 1143 $this->drawLine($this->GArea_X1,$Y,$this->GArea_X2,$Y,$R,$G,$B); 1144 else 1145 $this->drawDottedLine($this->GArea_X1,$Y,$this->GArea_X2,$Y,$TickWidth,$R,$G,$B); 1146 1147 if ( $ShowLabel ) 1148 { 1149 if ( $FreeText == NULL ) 1150 { $Label = $Value; } else { $Label = $FreeText; } 1151 1152 if ( $ShowOnRight ) 1153 imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X2+2,$Y+($this->FontSize/2),$C_TextColor,$this->FontName,$Label); 1154 else 1155 imagettftext($this->Picture,$this->FontSize,0,$this->GArea_X1+2,$Y-($this->FontSize/2),$C_TextColor,$this->FontName,$Label); 1156 } 1157 } 1158 1159 /* This function put a label on a specific point */ 1160 function setLabel($Data,$DataDescription,$SerieName,$ValueName,$Caption,$R=210,$G=210,$B=210) 1161 { 1162 /* Validate the Data and DataDescription array */ 1163 $this->validateDataDescription("setLabel",$DataDescription); 1164 $this->validateData("setLabel",$Data); 1165 $ShadowFactor = 100; 1166 $C_Label =$this->AllocateColor($this->Picture,$R,$G,$B); 1167 $C_Shadow =$this->AllocateColor($this->Picture,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); 1168 $C_TextColor =$this->AllocateColor($this->Picture,0,0,0); 1169 1170 $Cp = 0; $Found = FALSE; 1171 foreach ( $Data as $Key => $Value ) 1172 { 1173 if ( $Data[$Key][$DataDescription["Position"]] == $ValueName ) 1174 { $NumericalValue = $Data[$Key][$SerieName]; $Found = TRUE; } 1175 if ( !$Found ) 1176 $Cp++; 1177 } 1178 1179 $XPos = $this->GArea_X1 + $this->GAreaXOffset + ( $this->DivisionWidth * $Cp ) + 2; 1180 $YPos = $this->GArea_Y2 - ($NumericalValue - $this->VMin) * $this->DivisionRatio; 1181 1182 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); 1183 $TextHeight = $Position[3] - $Position[5]; 1184 $TextWidth = $Position[2]-$Position[0] + 2; 1185 $TextOffset = floor($TextHeight/2); 1186 1187 // Shadow 1188 $Poly = array($XPos+1,$YPos+1,$XPos + 9,$YPos - $TextOffset,$XPos + 8,$YPos + $TextOffset + 2); 1189 imagefilledpolygon($this->Picture,$Poly,3,$C_Shadow); 1190 $this->drawLine($XPos,$YPos+1,$XPos + 9,$YPos - $TextOffset - .2,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); 1191 $this->drawLine($XPos,$YPos+1,$XPos + 9,$YPos + $TextOffset + 2.2,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); 1192 $this->drawFilledRectangle($XPos + 9,$YPos - $TextOffset-.2,$XPos + 13 + $TextWidth,$YPos + $TextOffset + 2.2,$R-$ShadowFactor,$G-$ShadowFactor,$B-$ShadowFactor); 1193 1194 // Label background 1195 $Poly = array($XPos,$YPos,$XPos + 8,$YPos - $TextOffset - 1,$XPos + 8,$YPos + $TextOffset + 1); 1196 imagefilledpolygon($this->Picture,$Poly,3,$C_Label); 1197 $this->drawLine($XPos-1,$YPos,$XPos + 8,$YPos - $TextOffset - 1.2,$R,$G,$B); 1198 $this->drawLine($XPos-1,$YPos,$XPos + 8,$YPos + $TextOffset + 1.2,$R,$G,$B); 1199 $this->drawFilledRectangle($XPos + 8,$YPos - $TextOffset - 1.2,$XPos + 12 + $TextWidth,$YPos + $TextOffset + 1.2,$R,$G,$B); 1200 1201 imagettftext($this->Picture,$this->FontSize,0,$XPos + 10,$YPos + $TextOffset,$C_TextColor,$this->FontName,$Caption); 1202 } 1203 1204 /* This function draw a plot graph */ 1205 function drawPlotGraph($Data,$DataDescription,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1,$Shadow=FALSE) 1206 { 1207 /* Validate the Data and DataDescription array */ 1208 $this->validateDataDescription("drawPlotGraph",$DataDescription); 1209 $this->validateData("drawPlotGraph",$Data); 1210 1211 $GraphID = 0; 1212 $Ro = $R2; $Go = $G2; $Bo = $B2; 1213 1214 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1215 { 1216 $ID = 0; 1217 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1218 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1219 1220 $R = $this->Palette[$ColorID]["R"]; 1221 $G = $this->Palette[$ColorID]["G"]; 1222 $B = $this->Palette[$ColorID]["B"]; 1223 $R2 = $Ro; $G2 = $Go; $B2 = $Bo; 1224 1225 if ( isset($DataDescription["Symbol"][$ColName]) ) 1226 { 1227 $Is_Alpha = ((ord ( file_get_contents ($DataDescription["Symbol"][$ColName], false, null, 25, 1)) & 6) & 4) == 4; 1228 1229 $Infos = getimagesize($DataDescription["Symbol"][$ColName]); 1230 $ImageWidth = $Infos[0]; 1231 $ImageHeight = $Infos[1]; 1232 $Symbol = imagecreatefromgif($DataDescription["Symbol"][$ColName]); 1233 } 1234 1235 $XPos = $this->GArea_X1 + $this->GAreaXOffset; 1236 $Hsize = round($BigRadius/2); 1237 $R3 = -1; $G3 = -1; $B3 = -1; 1238 foreach ( $Data as $Key => $Values ) 1239 { 1240 $Value = $Data[$Key][$ColName]; 1241 $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); 1242 1243 /* Save point into the image map if option activated */ 1244 if ( $this->BuildMap ) 1245 $this->addToImageMap($XPos-$Hsize,$YPos-$Hsize,$XPos+1+$Hsize,$YPos+$Hsize+1,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Plot"); 1246 1247 if ( is_numeric($Value) ) 1248 { 1249 if ( !isset($DataDescription["Symbol"][$ColName]) ) 1250 { 1251 1252 if ( $Shadow ) 1253 { 1254 if ( $R3 !=-1 && $G3 !=-1 && $B3 !=-1 ) 1255 $this->drawFilledCircle($XPos+2,$YPos+2,$BigRadius,$R3,$G3,$B3); 1256 else 1257 { 1258 $R3 = $this->Palette[$ColorID]["R"]-20; if ( $R3 < 0 ) { $R3 = 0; } 1259 $G3 = $this->Palette[$ColorID]["G"]-20; if ( $G3 < 0 ) { $G3 = 0; } 1260 $B3 = $this->Palette[$ColorID]["B"]-20; if ( $B3 < 0 ) { $B3 = 0; } 1261 $this->drawFilledCircle($XPos+2,$YPos+2,$BigRadius,$R3,$G3,$B3); 1262 } 1263 } 1264 1265 $this->drawFilledCircle($XPos+1,$YPos+1,$BigRadius,$R,$G,$B); 1266 1267 if ( $SmallRadius != 0 ) 1268 { 1269 if ( $R2 !=-1 && $G2 !=-1 && $B2 !=-1 ) 1270 $this->drawFilledCircle($XPos+1,$YPos+1,$SmallRadius,$R2,$G2,$B2); 1271 else 1272 { 1273 $R2 = $this->Palette[$ColorID]["R"]-15; if ( $R2 < 0 ) { $R2 = 0; } 1274 $G2 = $this->Palette[$ColorID]["G"]-15; if ( $G2 < 0 ) { $G2 = 0; } 1275 $B2 = $this->Palette[$ColorID]["B"]-15; if ( $B2 < 0 ) { $B2 = 0; } 1276 1277 $this->drawFilledCircle($XPos+1,$YPos+1,$SmallRadius,$R2,$G2,$B2); 1278 } 1279 } 1280 } 1281 else 1282 { 1283 imagecopymerge($this->Picture,$Symbol,$XPos+1-$ImageWidth/2,$YPos+1-$ImageHeight/2,0,0,$ImageWidth,$ImageHeight,100); 1284 } 1285 } 1286 1287 $XPos = $XPos + $this->DivisionWidth; 1288 } 1289 $GraphID++; 1290 } 1291 } 1292 1293 /* This function draw a plot graph in an X/Y space */ 1294 function drawXYPlotGraph($Data,$DataDescription,$YSerieName,$XSerieName,$PaletteID=0,$BigRadius=5,$SmallRadius=2,$R2=-1,$G2=-1,$B2=-1,$Shadow=TRUE) 1295 { 1296 $R = $this->Palette[$PaletteID]["R"]; 1297 $G = $this->Palette[$PaletteID]["G"]; 1298 $B = $this->Palette[$PaletteID]["B"]; 1299 $R3 = -1; $G3 = -1; $B3 = -1; 1300 1301 $YLast = -1; $XLast = -1; 1302 foreach ( $Data as $Key => $Values ) 1303 { 1304 if ( isset($Data[$Key][$YSerieName]) && isset($Data[$Key][$XSerieName]) ) 1305 { 1306 $X = $Data[$Key][$XSerieName]; 1307 $Y = $Data[$Key][$YSerieName]; 1308 1309 $Y = $this->GArea_Y2 - (($Y-$this->VMin) * $this->DivisionRatio); 1310 $X = $this->GArea_X1 + (($X-$this->VXMin) * $this->XDivisionRatio); 1311 1312 1313 if ( $Shadow ) 1314 { 1315 if ( $R3 !=-1 && $G3 !=-1 && $B3 !=-1 ) 1316 $this->drawFilledCircle($X+2,$Y+2,$BigRadius,$R3,$G3,$B3); 1317 else 1318 { 1319 $R3 = $this->Palette[$PaletteID]["R"]-20; if ( $R < 0 ) { $R = 0; } 1320 $G3 = $this->Palette[$PaletteID]["G"]-20; if ( $G < 0 ) { $G = 0; } 1321 $B3 = $this->Palette[$PaletteID]["B"]-20; if ( $B < 0 ) { $B = 0; } 1322 $this->drawFilledCircle($X+2,$Y+2,$BigRadius,$R3,$G3,$B3); 1323 } 1324 } 1325 1326 $this->drawFilledCircle($X+1,$Y+1,$BigRadius,$R,$G,$B); 1327 1328 if ( $R2 !=-1 && $G2 !=-1 && $B2 !=-1 ) 1329 $this->drawFilledCircle($X+1,$Y+1,$SmallRadius,$R2,$G2,$B2); 1330 else 1331 { 1332 $R2 = $this->Palette[$PaletteID]["R"]+20; if ( $R > 255 ) { $R = 255; } 1333 $G2 = $this->Palette[$PaletteID]["G"]+20; if ( $G > 255 ) { $G = 255; } 1334 $B2 = $this->Palette[$PaletteID]["B"]+20; if ( $B > 255 ) { $B = 255; } 1335 $this->drawFilledCircle($X+1,$Y+1,$SmallRadius,$R2,$G2,$B2); 1336 } 1337 } 1338 } 1339 1340 } 1341 1342 /* This function draw an area between two series */ 1343 function drawArea($Data,$Serie1,$Serie2,$R,$G,$B,$Alpha = 50) 1344 { 1345 /* Validate the Data and DataDescription array */ 1346 $this->validateData("drawArea",$Data); 1347 1348 $LayerWidth = $this->GArea_X2-$this->GArea_X1; 1349 $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; 1350 1351 $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); 1352 $C_White =$this->AllocateColor($this->Layers[0],255,255,255); 1353 imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); 1354 imagecolortransparent($this->Layers[0],$C_White); 1355 1356 $C_Graph =$this->AllocateColor($this->Layers[0],$R,$G,$B); 1357 1358 $XPos = $this->GAreaXOffset; 1359 $LastXPos = -1; 1360 foreach ( $Data as $Key => $Values ) 1361 { 1362 $Value1 = $Data[$Key][$Serie1]; 1363 $Value2 = $Data[$Key][$Serie2]; 1364 $YPos1 = $LayerHeight - (($Value1-$this->VMin) * $this->DivisionRatio); 1365 $YPos2 = $LayerHeight - (($Value2-$this->VMin) * $this->DivisionRatio); 1366 1367 if ( $LastXPos != -1 ) 1368 { 1369 $Points = ""; 1370 $Points[] = $LastXPos; $Points[] = $LastYPos1; 1371 $Points[] = $LastXPos; $Points[] = $LastYPos2; 1372 $Points[] = $XPos; $Points[] = $YPos2; 1373 $Points[] = $XPos; $Points[] = $YPos1; 1374 1375 imagefilledpolygon($this->Layers[0],$Points,4,$C_Graph); 1376 } 1377 1378 $LastYPos1 = $YPos1; 1379 $LastYPos2 = $YPos2; 1380 $LastXPos = $XPos; 1381 1382 $XPos = $XPos + $this->DivisionWidth; 1383 } 1384 1385 imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); 1386 imagedestroy($this->Layers[0]); 1387 } 1388 1389 1390 /* This function write the values of the specified series */ 1391 function writeValues($Data,$DataDescription,$Series) 1392 { 1393 /* Validate the Data and DataDescription array */ 1394 $this->validateDataDescription("writeValues",$DataDescription); 1395 $this->validateData("writeValues",$Data); 1396 1397 if ( !is_array($Series) ) { $Series = array($Series); } 1398 1399 foreach($Series as $Key => $Serie) 1400 { 1401 $ID = 0; 1402 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1403 { if ( $keyI == $Serie ) { $ColorID = $ID; }; $ID++; } 1404 1405 $XPos = $this->GArea_X1 + $this->GAreaXOffset; 1406 $XLast = -1; 1407 foreach ( $Data as $Key => $Values ) 1408 { 1409 if ( isset($Data[$Key][$Serie]) && is_numeric($Data[$Key][$Serie])) 1410 { 1411 $Value = $Data[$Key][$Serie]; 1412 $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); 1413 1414 $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Value); 1415 $Width = $Positions[2] - $Positions[6]; $XOffset = $XPos - ($Width/2); 1416 $Height = $Positions[3] - $Positions[7]; $YOffset = $YPos - 4; 1417 1418 $C_TextColor =$this->AllocateColor($this->Picture,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 1419 imagettftext($this->Picture,$this->FontSize,0,$XOffset,$YOffset,$C_TextColor,$this->FontName,$Value); 1420 } 1421 $XPos = $XPos + $this->DivisionWidth; 1422 } 1423 1424 } 1425 } 1426 1427 /* This function draw a line graph */ 1428 function drawLineGraph($Data,$DataDescription,$SerieName="") 1429 { 1430 /* Validate the Data and DataDescription array */ 1431 $this->validateDataDescription("drawLineGraph",$DataDescription); 1432 $this->validateData("drawLineGraph",$Data); 1433 1434 $GraphID = 0; 1435 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1436 { 1437 $ID = 0; 1438 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1439 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1440 1441 if ( $SerieName == "" || $SerieName == $ColName ) 1442 { 1443 $XPos = $this->GArea_X1 + $this->GAreaXOffset; 1444 $XLast = -1; 1445 foreach ( $Data as $Key => $Values ) 1446 { 1447 if ( isset($Data[$Key][$ColName])) 1448 { 1449 $Value = $Data[$Key][$ColName]; 1450 $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); 1451 1452 /* Save point into the image map if option activated */ 1453 if ( $this->BuildMap ) 1454 $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Line"); 1455 1456 if (!is_numeric($Value)) { $XLast = -1; } 1457 if ( $XLast != -1 ) 1458 $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); 1459 1460 $XLast = $XPos; 1461 $YLast = $YPos; 1462 if (!is_numeric($Value)) { $XLast = -1; } 1463 } 1464 $XPos = $XPos + $this->DivisionWidth; 1465 } 1466 $GraphID++; 1467 } 1468 } 1469 } 1470 1471 /* This function draw a line graph */ 1472 function drawXYGraph($Data,$DataDescription,$YSerieName,$XSerieName,$PaletteID=0) 1473 { 1474 $YLast = -1; $XLast = -1; 1475 foreach ( $Data as $Key => $Values ) 1476 { 1477 if ( isset($Data[$Key][$YSerieName]) && isset($Data[$Key][$XSerieName]) ) 1478 { 1479 $X = $Data[$Key][$XSerieName]; 1480 $Y = $Data[$Key][$YSerieName]; 1481 1482 $Y = $this->GArea_Y2 - (($Y-$this->VMin) * $this->DivisionRatio); 1483 $X = $this->GArea_X1 + (($X-$this->VXMin) * $this->XDivisionRatio); 1484 if ($XLast != -1 && $YLast != -1) 1485 { 1486 $this->drawLine($XLast,$YLast,$X,$Y,$this->Palette[$PaletteID]["R"],$this->Palette[$PaletteID]["G"],$this->Palette[$PaletteID]["B"],TRUE); 1487 } 1488 1489 $XLast = $X; 1490 $YLast = $Y; 1491 } 1492 } 1493 } 1494 1495 /* This function draw a cubic curve */ 1496 function drawCubicCurve($Data,$DataDescription,$Accuracy=.1,$SerieName="") 1497 { 1498 /* Validate the Data and DataDescription array */ 1499 $this->validateDataDescription("drawCubicCurve",$DataDescription); 1500 $this->validateData("drawCubicCurve",$Data); 1501 1502 $GraphID = 0; 1503 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1504 { 1505 if ( $SerieName == "" || $SerieName == $ColName ) 1506 { 1507 $XIn = ""; $Yin = ""; $Yt = ""; $U = ""; 1508 $XIn[0] = 0; $YIn[0] = 0; 1509 1510 $ID = 0; 1511 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1512 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1513 1514 $Index = 1; 1515 $XLast = -1; $Missing = ""; 1516 foreach ( $Data as $Key => $Values ) 1517 { 1518 if ( isset($Data[$Key][$ColName]) ) 1519 { 1520 $Value = $Data[$Key][$ColName]; 1521 $XIn[$Index] = $Index; 1522 $YIn[$Index] = $Value; 1523 if ( !is_numeric($Value) ) { $Missing[$Index] = TRUE; } 1524 $Index++; 1525 } 1526 } 1527 $Index--; 1528 1529 $Yt[0] = 0; 1530 $Yt[1] = 0; 1531 $U[1] = 0; 1532 for($i=2;$i<=$Index-1;$i++) 1533 { 1534 $Sig = ($XIn[$i] - $XIn[$i-1]) / ($XIn[$i+1] - $XIn[$i-1]); 1535 $p = $Sig * $Yt[$i-1] + 2; 1536 $Yt[$i] = ($Sig - 1) / $p; 1537 $U[$i] = ($YIn[$i+1] - $YIn[$i]) / ($XIn[$i+1] - $XIn[$i]) - ($YIn[$i] - $YIn[$i-1]) / ($XIn[$i] - $XIn[$i-1]); 1538 $U[$i] = (6 * $U[$i] / ($XIn[$i+1] - $XIn[$i-1]) - $Sig * $U[$i-1]) / $p; 1539 } 1540 1541 $qn = 0; 1542 $un = 0; 1543 $Yt[$Index] = ($un - $qn * $U[$Index-1]) / ($qn * $Yt[$Index-1] + 1); 1544 1545 for($k=$Index-1;$k>=1;$k--) 1546 $Yt[$k] = $Yt[$k] * $Yt[$k+1] + $U[$k]; 1547 1548 $XPos = $this->GArea_X1 + $this->GAreaXOffset; 1549 for($X=1;$X<=$Index;$X=$X+$Accuracy) 1550 { 1551 $klo = 1; 1552 $khi = $Index; 1553 $k = $khi - $klo; 1554 while($k > 1) 1555 { 1556 $k = $khi - $klo; 1557 If ( $XIn[$k] >= $X ) 1558 $khi = $k; 1559 else 1560 $klo = $k; 1561 } 1562 $klo = $khi - 1; 1563 1564 $h = $XIn[$khi] - $XIn[$klo]; 1565 $a = ($XIn[$khi] - $X) / $h; 1566 $b = ($X - $XIn[$klo]) / $h; 1567 $Value = $a * $YIn[$klo] + $b * $YIn[$khi] + (($a*$a*$a - $a) * $Yt[$klo] + ($b*$b*$b - $b) * $Yt[$khi]) * ($h*$h) / 6; 1568 1569 $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); 1570 1571 if ( $XLast != -1 && !isset($Missing[floor($X)]) && !isset($Missing[floor($X+1)]) ) 1572 $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); 1573 1574 $XLast = $XPos; 1575 $YLast = $YPos; 1576 $XPos = $XPos + $this->DivisionWidth * $Accuracy; 1577 } 1578 1579 // Add potentialy missing values 1580 $XPos = $XPos - $this->DivisionWidth * $Accuracy; 1581 if ( $XPos < ($this->GArea_X2 - $this->GAreaXOffset) ) 1582 { 1583 $YPos = $this->GArea_Y2 - (($YIn[$Index]-$this->VMin) * $this->DivisionRatio); 1584 $this->drawLine($XLast,$YLast,$this->GArea_X2-$this->GAreaXOffset,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); 1585 } 1586 1587 $GraphID++; 1588 } 1589 } 1590 } 1591 1592 /* This function draw a filled cubic curve */ 1593 function drawFilledCubicCurve($Data,$DataDescription,$Accuracy=.1,$Alpha=100,$AroundZero=FALSE) 1594 { 1595 /* Validate the Data and DataDescription array */ 1596 $this->validateDataDescription("drawFilledCubicCurve",$DataDescription); 1597 $this->validateData("drawFilledCubicCurve",$Data); 1598 1599 $LayerWidth = $this->GArea_X2-$this->GArea_X1; 1600 $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; 1601 $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio); 1602 if ( $YZero > $LayerHeight ) { $YZero = $LayerHeight; } 1603 1604 $GraphID = 0; 1605 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1606 { 1607 $XIn = ""; $Yin = ""; $Yt = ""; $U = ""; 1608 $XIn[0] = 0; $YIn[0] = 0; 1609 1610 $ID = 0; 1611 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1612 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1613 1614 $Index = 1; 1615 $XLast = -1; $Missing = ""; 1616 foreach ( $Data as $Key => $Values ) 1617 { 1618 $Value = $Data[$Key][$ColName]; 1619 $XIn[$Index] = $Index; 1620 $YIn[$Index] = $Value; 1621 if ( !is_numeric($Value) ) { $Missing[$Index] = TRUE; } 1622 $Index++; 1623 } 1624 $Index--; 1625 1626 $Yt[0] = 0; 1627 $Yt[1] = 0; 1628 $U[1] = 0; 1629 for($i=2;$i<=$Index-1;$i++) 1630 { 1631 $Sig = ($XIn[$i] - $XIn[$i-1]) / ($XIn[$i+1] - $XIn[$i-1]); 1632 $p = $Sig * $Yt[$i-1] + 2; 1633 $Yt[$i] = ($Sig - 1) / $p; 1634 $U[$i] = ($YIn[$i+1] - $YIn[$i]) / ($XIn[$i+1] - $XIn[$i]) - ($YIn[$i] - $YIn[$i-1]) / ($XIn[$i] - $XIn[$i-1]); 1635 $U[$i] = (6 * $U[$i] / ($XIn[$i+1] - $XIn[$i-1]) - $Sig * $U[$i-1]) / $p; 1636 } 1637 1638 $qn = 0; 1639 $un = 0; 1640 $Yt[$Index] = ($un - $qn * $U[$Index-1]) / ($qn * $Yt[$Index-1] + 1); 1641 1642 for($k=$Index-1;$k>=1;$k--) 1643 $Yt[$k] = $Yt[$k] * $Yt[$k+1] + $U[$k]; 1644 1645 $Points = ""; 1646 $Points[] = $this->GAreaXOffset; 1647 $Points[] = $LayerHeight; 1648 1649 $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); 1650 $C_White =$this->AllocateColor($this->Layers[0],255,255,255); 1651 imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); 1652 imagecolortransparent($this->Layers[0],$C_White); 1653 1654 $YLast = NULL; 1655 $XPos = $this->GAreaXOffset; $PointsCount = 2; 1656 for($X=1;$X<=$Index;$X=$X+$Accuracy) 1657 { 1658 $klo = 1; 1659 $khi = $Index; 1660 $k = $khi - $klo; 1661 while($k > 1) 1662 { 1663 $k = $khi - $klo; 1664 If ( $XIn[$k] >= $X ) 1665 $khi = $k; 1666 else 1667 $klo = $k; 1668 } 1669 $klo = $khi - 1; 1670 1671 $h = $XIn[$khi] - $XIn[$klo]; 1672 $a = ($XIn[$khi] - $X) / $h; 1673 $b = ($X - $XIn[$klo]) / $h; 1674 $Value = $a * $YIn[$klo] + $b * $YIn[$khi] + (($a*$a*$a - $a) * $Yt[$klo] + ($b*$b*$b - $b) * $Yt[$khi]) * ($h*$h) / 6; 1675 1676 $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio); 1677 1678 if ( $YLast != NULL && $AroundZero && !isset($Missing[floor($X)]) && !isset($Missing[floor($X+1)])) 1679 { 1680 $aPoints = ""; 1681 $aPoints[] = $XLast; 1682 $aPoints[] = $YLast; 1683 $aPoints[] = $XPos; 1684 $aPoints[] = $YPos; 1685 $aPoints[] = $XPos; 1686 $aPoints[] = $YZero; 1687 $aPoints[] = $XLast; 1688 $aPoints[] = $YZero; 1689 1690 $C_Graph =$this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 1691 imagefilledpolygon($this->Layers[0],$aPoints,4,$C_Graph); 1692 } 1693 1694 if ( !isset($Missing[floor($X)]) || $YLast == NULL ) 1695 { 1696 $PointsCount++; 1697 $Points[] = $XPos; 1698 $Points[] = $YPos; 1699 } 1700 else 1701 { 1702 $PointsCount++; $Points[] = $XLast; $Points[] = $LayerHeight; 1703 } 1704 1705 $YLast = $YPos; $XLast = $XPos; 1706 $XPos = $XPos + $this->DivisionWidth * $Accuracy; 1707 } 1708 1709 // Add potentialy missing values 1710 $XPos = $XPos - $this->DivisionWidth * $Accuracy; 1711 if ( $XPos < ($LayerWidth-$this->GAreaXOffset) ) 1712 { 1713 $YPos = $LayerHeight - (($YIn[$Index]-$this->VMin) * $this->DivisionRatio); 1714 1715 if ( $YLast != NULL && $AroundZero ) 1716 { 1717 $aPoints = ""; 1718 $aPoints[] = $XLast; 1719 $aPoints[] = $YLast; 1720 $aPoints[] = $LayerWidth-$this->GAreaXOffset; 1721 $aPoints[] = $YPos; 1722 $aPoints[] = $LayerWidth-$this->GAreaXOffset; 1723 $aPoints[] = $YZero; 1724 $aPoints[] = $XLast; 1725 $aPoints[] = $YZero; 1726 1727 $C_Graph =$this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 1728 imagefilledpolygon($this->Layers[0],$aPoints,4,$C_Graph); 1729 } 1730 1731 if ( $YIn[$klo] != "" && $YIn[$khi] != "" || $YLast == NULL ) 1732 { 1733 $PointsCount++; 1734 $Points[] = $LayerWidth-$this->GAreaXOffset; 1735 $Points[] = $YPos; 1736 } 1737 } 1738 1739 $Points[] = $LayerWidth-$this->GAreaXOffset; 1740 $Points[] = $LayerHeight; 1741 1742 if ( !$AroundZero ) 1743 { 1744 $C_Graph =$this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 1745 imagefilledpolygon($this->Layers[0],$Points,$PointsCount,$C_Graph); 1746 } 1747 1748 imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); 1749 imagedestroy($this->Layers[0]); 1750 1751 $this->drawCubicCurve($Data,$DataDescription,$Accuracy,$ColName); 1752 1753 $GraphID++; 1754 } 1755 } 1756 1757 /* This function draw a filled line graph */ 1758 function drawFilledLineGraph($Data,$DataDescription,$Alpha=100,$AroundZero=FALSE) 1759 { 1760 $Empty = -2147483647; 1761 1762 /* Validate the Data and DataDescription array */ 1763 $this->validateDataDescription("drawFilledLineGraph",$DataDescription); 1764 $this->validateData("drawFilledLineGraph",$Data); 1765 1766 $LayerWidth = $this->GArea_X2-$this->GArea_X1; 1767 $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; 1768 1769 $GraphID = 0; 1770 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1771 { 1772 $ID = 0; 1773 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1774 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1775 1776 $aPoints = ""; 1777 $aPoints[] = $this->GAreaXOffset; 1778 $aPoints[] = $LayerHeight; 1779 1780 $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); 1781 $C_White = $this->AllocateColor($this->Layers[0],255,255,255); 1782 imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); 1783 imagecolortransparent($this->Layers[0],$C_White); 1784 1785 $XPos = $this->GAreaXOffset; 1786 $XLast = -1; $PointsCount = 2; 1787 $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio); 1788 if ( $YZero > $LayerHeight ) { $YZero = $LayerHeight; } 1789 1790 $YLast = $Empty; 1791 foreach ( $Data as $Key => $Values ) 1792 { 1793 $Value = $Data[$Key][$ColName]; 1794 $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio); 1795 1796 /* Save point into the image map if option activated */ 1797 if ( $this->BuildMap ) 1798 $this->addToImageMap($XPos-3,$YPos-3,$XPos+3,$YPos+3,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"FLine"); 1799 1800 if ( !is_numeric($Value) ) 1801 { 1802 $PointsCount++; 1803 $aPoints[] = $XLast; 1804 $aPoints[] = $LayerHeight; 1805 1806 $YLast = $Empty; 1807 } 1808 else 1809 { 1810 $PointsCount++; 1811 if ( $YLast <> $Empty ) 1812 { $aPoints[] = $XPos; $aPoints[] = $YPos; } 1813 else 1814 { $PointsCount++; $aPoints[] = $XPos; $aPoints[] = $LayerHeight; $aPoints[] = $XPos; $aPoints[] = $YPos; } 1815 1816 if ($YLast <> $Empty && $AroundZero) 1817 { 1818 $Points = ""; 1819 $Points[] = $XLast; $Points[] = $YLast; 1820 $Points[] = $XPos; 1821 $Points[] = $YPos; 1822 $Points[] = $XPos; 1823 $Points[] = $YZero; 1824 $Points[] = $XLast; 1825 $Points[] = $YZero; 1826 1827 $C_Graph = $this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 1828 imagefilledpolygon($this->Layers[0],$Points,4,$C_Graph); 1829 } 1830 $YLast = $YPos; 1831 } 1832 1833 $XLast = $XPos; 1834 $XPos = $XPos + $this->DivisionWidth; 1835 } 1836 $aPoints[] = $LayerWidth - $this->GAreaXOffset; 1837 $aPoints[] = $LayerHeight; 1838 1839 if ( $AroundZero == FALSE ) 1840 { 1841 $C_Graph = $this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 1842 imagefilledpolygon($this->Layers[0],$aPoints,$PointsCount,$C_Graph); 1843 } 1844 1845 imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); 1846 imagedestroy($this->Layers[0]); 1847 $GraphID++; 1848 $this->drawLineGraph($Data,$DataDescription,$ColName); 1849 } 1850 } 1851 1852 /* This function draw a bar graph */ 1853 function drawOverlayBarGraph($Data,$DataDescription,$Alpha=50) 1854 { 1855 /* Validate the Data and DataDescription array */ 1856 $this->validateDataDescription("drawOverlayBarGraph",$DataDescription); 1857 $this->validateData("drawOverlayBarGraph",$Data); 1858 1859 $LayerWidth = $this->GArea_X2-$this->GArea_X1; 1860 $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; 1861 1862 $GraphID = 0; 1863 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1864 { 1865 $ID = 0; 1866 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1867 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1868 1869 $this->Layers[$GraphID] = imagecreatetruecolor($LayerWidth,$LayerHeight); 1870 $C_White = $this->AllocateColor($this->Layers[$GraphID],255,255,255); 1871 $C_Graph = $this->AllocateColor($this->Layers[$GraphID],$this->Palette[$GraphID]["R"],$this->Palette[$GraphID]["G"],$this->Palette[$GraphID]["B"]); 1872 imagefilledrectangle($this->Layers[$GraphID],0,0,$LayerWidth,$LayerHeight,$C_White); 1873 imagecolortransparent($this->Layers[$GraphID],$C_White); 1874 1875 $XWidth = $this->DivisionWidth / 4; 1876 $XPos = $this->GAreaXOffset; 1877 $YZero = $LayerHeight - ((0-$this->VMin) * $this->DivisionRatio); 1878 $XLast = -1; $PointsCount = 2; 1879 foreach ( $Data as $Key => $Values ) 1880 { 1881 if ( isset($Data[$Key][$ColName]) ) 1882 { 1883 $Value = $Data[$Key][$ColName]; 1884 if ( is_numeric($Value) ) 1885 { 1886 $YPos = $LayerHeight - (($Value-$this->VMin) * $this->DivisionRatio); 1887 1888 imagefilledrectangle($this->Layers[$GraphID],$XPos-$XWidth,$YPos,$XPos+$XWidth,$YZero,$C_Graph); 1889 1890 $X1 = floor($XPos - $XWidth + $this->GArea_X1); $Y1 = floor($YPos+$this->GArea_Y1) + .2; 1891 $X2 = floor($XPos + $XWidth + $this->GArea_X1); $Y2 = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio); 1892 if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; } 1893 if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; } 1894 1895 /* Save point into the image map if option activated */ 1896 if ( $this->BuildMap ) 1897 $this->addToImageMap($X1,min($Y1,$Y2),$X2,max($Y1,$Y2),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"oBar"); 1898 1899 $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE); 1900 } 1901 } 1902 $XPos = $XPos + $this->DivisionWidth; 1903 } 1904 1905 $GraphID++; 1906 } 1907 1908 for($i=0;$i<=($GraphID-1);$i++) 1909 { 1910 imagecopymerge($this->Picture,$this->Layers[$i],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); 1911 imagedestroy($this->Layers[$i]); 1912 } 1913 } 1914 1915 /* This function draw a bar graph */ 1916 function drawBarGraph($Data,$DataDescription,$Shadow=FALSE,$Alpha=100) 1917 { 1918 /* Validate the Data and DataDescription array */ 1919 $this->validateDataDescription("drawBarGraph",$DataDescription); 1920 $this->validateData("drawBarGraph",$Data); 1921 1922 $GraphID = 0; 1923 $Series = count($DataDescription["Values"]); 1924 $SeriesWidth = $this->DivisionWidth / ($Series+1); 1925 $SerieXOffset = $this->DivisionWidth / 2 - $SeriesWidth / 2; 1926 1927 $YZero = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio); 1928 if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; } 1929 1930 $SerieID = 0; 1931 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1932 { 1933 $ID = 0; 1934 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1935 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1936 1937 $XPos = $this->GArea_X1 + $this->GAreaXOffset - $SerieXOffset + $SeriesWidth * $SerieID; 1938 $XLast = -1; 1939 foreach ( $Data as $Key => $Values ) 1940 { 1941 if ( isset($Data[$Key][$ColName])) 1942 { 1943 if ( is_numeric($Data[$Key][$ColName]) ) 1944 { 1945 $Value = $Data[$Key][$ColName]; 1946 $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); 1947 1948 /* Save point into the image map if option activated */ 1949 if ( $this->BuildMap ) 1950 { 1951 $this->addToImageMap($XPos+1,min($YZero,$YPos),$XPos+$SeriesWidth-1,max($YZero,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Bar"); 1952 } 1953 1954 if ( $Shadow && $Alpha == 100 ) 1955 $this->drawRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,25,25,25,TRUE,$Alpha); 1956 1957 $this->drawFilledRectangle($XPos+1,$YZero,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha); 1958 } 1959 } 1960 $XPos = $XPos + $this->DivisionWidth; 1961 } 1962 $SerieID++; 1963 } 1964 } 1965 1966 /* This function draw a stacked bar graph */ 1967 function drawStackedBarGraph($Data,$DataDescription,$Alpha=50,$Contiguous=FALSE) 1968 { 1969 /* Validate the Data and DataDescription array */ 1970 $this->validateDataDescription("drawBarGraph",$DataDescription); 1971 $this->validateData("drawBarGraph",$Data); 1972 1973 $GraphID = 0; 1974 $Series = count($DataDescription["Values"]); 1975 if ( $Contiguous ) 1976 $SeriesWidth = $this->DivisionWidth; 1977 else 1978 $SeriesWidth = $this->DivisionWidth * .8; 1979 1980 $YZero = $this->GArea_Y2 - ((0-$this->VMin) * $this->DivisionRatio); 1981 if ( $YZero > $this->GArea_Y2 ) { $YZero = $this->GArea_Y2; } 1982 1983 $SerieID = 0; $LastValue = ""; 1984 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 1985 { 1986 $ID = 0; 1987 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 1988 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 1989 1990 $XPos = $this->GArea_X1 + $this->GAreaXOffset - $SeriesWidth / 2; 1991 $XLast = -1; 1992 foreach ( $Data as $Key => $Values ) 1993 { 1994 if ( isset($Data[$Key][$ColName])) 1995 { 1996 if ( is_numeric($Data[$Key][$ColName]) ) 1997 { 1998 $Value = $Data[$Key][$ColName]; 1999 2000 if ( isset($LastValue[$Key]) ) 2001 { 2002 $YPos = $this->GArea_Y2 - ((($Value+$LastValue[$Key])-$this->VMin) * $this->DivisionRatio); 2003 $YBottom = $this->GArea_Y2 - (($LastValue[$Key]-$this->VMin) * $this->DivisionRatio); 2004 $LastValue[$Key] += $Value; 2005 } 2006 else 2007 { 2008 $YPos = $this->GArea_Y2 - (($Value-$this->VMin) * $this->DivisionRatio); 2009 $YBottom = $YZero; 2010 $LastValue[$Key] = $Value; 2011 } 2012 2013 /* Save point into the image map if option activated */ 2014 if ( $this->BuildMap ) 2015 $this->addToImageMap($XPos+1,min($YBottom,$YPos),$XPos+$SeriesWidth-1,max($YBottom,$YPos),$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"sBar"); 2016 2017 $this->drawFilledRectangle($XPos+1,$YBottom,$XPos+$SeriesWidth-1,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha); 2018 } 2019 } 2020 $XPos = $XPos + $this->DivisionWidth; 2021 } 2022 $SerieID++; 2023 } 2024 } 2025 2026 /* This function draw a limits bar graphs */ 2027 function drawLimitsGraph($Data,$DataDescription,$R=0,$G=0,$B=0) 2028 { 2029 /* Validate the Data and DataDescription array */ 2030 $this->validateDataDescription("drawLimitsGraph",$DataDescription); 2031 $this->validateData("drawLimitsGraph",$Data); 2032 2033 $XWidth = $this->DivisionWidth / 4; 2034 $XPos = $this->GArea_X1 + $this->GAreaXOffset; 2035 2036 foreach ( $Data as $Key => $Values ) 2037 { 2038 $Min = $Data[$Key][$DataDescription["Values"][0]]; 2039 $Max = $Data[$Key][$DataDescription["Values"][0]]; 2040 $GraphID = 0; $MaxID = 0; $MinID = 0; 2041 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2042 { 2043 if ( isset($Data[$Key][$ColName]) ) 2044 { 2045 if ( $Data[$Key][$ColName] > $Max && is_numeric($Data[$Key][$ColName])) 2046 { $Max = $Data[$Key][$ColName]; $MaxID = $GraphID; } 2047 } 2048 if ( isset($Data[$Key][$ColName]) && is_numeric($Data[$Key][$ColName])) 2049 { 2050 if ( $Data[$Key][$ColName] < $Min ) 2051 { $Min = $Data[$Key][$ColName]; $MinID = $GraphID; } 2052 $GraphID++; 2053 } 2054 } 2055 2056 $YPos = $this->GArea_Y2 - (($Max-$this->VMin) * $this->DivisionRatio); 2057 $X1 = floor($XPos - $XWidth); $Y1 = floor($YPos) - .2; 2058 $X2 = floor($XPos + $XWidth); 2059 if ( $X1 <= $this->GArea_X1 ) { $X1 = $this->GArea_X1 + 1; } 2060 if ( $X2 >= $this->GArea_X2 ) { $X2 = $this->GArea_X2 - 1; } 2061 2062 $YPos = $this->GArea_Y2 - (($Min-$this->VMin) * $this->DivisionRatio); 2063 $Y2 = floor($YPos) + .2; 2064 2065 $this->drawLine(floor($XPos)-.2,$Y1+1,floor($XPos)-.2,$Y2-1,$R,$G,$B,TRUE); 2066 $this->drawLine(floor($XPos)+.2,$Y1+1,floor($XPos)+.2,$Y2-1,$R,$G,$B,TRUE); 2067 $this->drawLine($X1,$Y1,$X2,$Y1,$this->Palette[$MaxID]["R"],$this->Palette[$MaxID]["G"],$this->Palette[$MaxID]["B"],FALSE); 2068 $this->drawLine($X1,$Y2,$X2,$Y2,$this->Palette[$MinID]["R"],$this->Palette[$MinID]["G"],$this->Palette[$MinID]["B"],FALSE); 2069 2070 $XPos = $XPos + $this->DivisionWidth; 2071 } 2072 } 2073 2074 /* This function draw radar axis centered on the graph area */ 2075 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) 2076 { 2077 /* Validate the Data and DataDescription array */ 2078 $this->validateDataDescription("drawRadarAxis",$DataDescription); 2079 $this->validateData("drawRadarAxis",$Data); 2080 2081 $C_TextColor = $this->AllocateColor($this->Picture,$A_R,$A_G,$A_B); 2082 2083 /* Draw radar axis */ 2084 $Points = count($Data); 2085 $Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset; 2086 $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1; 2087 $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1; 2088 2089 /* Search for the max value */ 2090 if ( $MaxValue == -1 ) 2091 { 2092 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2093 { 2094 foreach ( $Data as $Key => $Values ) 2095 { 2096 if ( isset($Data[$Key][$ColName])) 2097 if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; } 2098 } 2099 } 2100 } 2101 2102 /* Draw the mosaic */ 2103 if ( $Mosaic ) 2104 { 2105 $RadiusScale = $Radius / $MaxValue; 2106 for ( $t=1; $t<=$MaxValue-1; $t++) 2107 { 2108 $TRadius = $RadiusScale * $t; 2109 $LastX1 = -1; 2110 2111 for ( $i=0; $i<=$Points; $i++) 2112 { 2113 $Angle = -90 + $i * 360/$Points; 2114 $X1 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter; 2115 $Y1 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter; 2116 $X2 = cos($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $XCenter; 2117 $Y2 = sin($Angle * 3.1418 / 180 ) * ($TRadius+$RadiusScale) + $YCenter; 2118 2119 if ( $t % 2 == 1 && $LastX1 != -1) 2120 { 2121 $Plots = ""; 2122 $Plots[] = $X1; $Plots[] = $Y1; 2123 $Plots[] = $X2; $Plots[] = $Y2; 2124 $Plots[] = $LastX2; $Plots[] = $LastY2; 2125 $Plots[] = $LastX1; $Plots[] = $LastY1; 2126 2127 $C_Graph = $this->AllocateColor($this->Picture,250,250,250); 2128 imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_Graph); 2129 } 2130 2131 $LastX1 = $X1; $LastY1= $Y1; 2132 $LastX2 = $X2; $LastY2= $Y2; 2133 } 2134 } 2135 } 2136 2137 2138 /* Draw the spider web */ 2139 for ( $t=1; $t<=$MaxValue; $t++) 2140 { 2141 $TRadius = ( $Radius / $MaxValue ) * $t; 2142 $LastX = -1; 2143 2144 for ( $i=0; $i<=$Points; $i++) 2145 { 2146 $Angle = -90 + $i * 360/$Points; 2147 $X = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter; 2148 $Y = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter; 2149 2150 if ( $LastX != -1 ) 2151 $this->drawDottedLine($LastX,$LastY,$X,$Y,4,$S_R,$S_G,$S_B); 2152 2153 $LastX = $X; $LastY= $Y; 2154 } 2155 } 2156 2157 /* Draw the axis */ 2158 for ( $i=0; $i<=$Points; $i++) 2159 { 2160 $Angle = -90 + $i * 360/$Points; 2161 $X = cos($Angle * 3.1418 / 180 ) * $Radius + $XCenter; 2162 $Y = sin($Angle * 3.1418 / 180 ) * $Radius + $YCenter; 2163 2164 $this->drawLine($XCenter,$YCenter,$X,$Y,$A_R,$A_G,$A_B); 2165 2166 $XOffset = 0; $YOffset = 0; 2167 if (isset($Data[$i][$DataDescription["Position"]])) 2168 { 2169 $Label = $Data[$i][$DataDescription["Position"]]; 2170 2171 $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$Label); 2172 $Width = $Positions[2] - $Positions[6]; 2173 $Height = $Positions[3] - $Positions[7]; 2174 2175 if ( $Angle >= 0 && $Angle <= 90 ) 2176 $YOffset = $Height; 2177 2178 if ( $Angle > 90 && $Angle <= 180 ) 2179 { $YOffset = $Height; $XOffset = -$Width; } 2180 2181 if ( $Angle > 180 && $Angle <= 270 ) 2182 { $XOffset = -$Width; } 2183 2184 imagettftext($this->Picture,$this->FontSize,0,$X+$XOffset,$Y+$YOffset,$C_TextColor,$this->FontName,$Label); 2185 } 2186 } 2187 2188 /* Write the values */ 2189 for ( $t=1; $t<=$MaxValue; $t++) 2190 { 2191 $TRadius = ( $Radius / $MaxValue ) * $t; 2192 2193 $Angle = -90 + 360 / $Points; 2194 $X1 = $XCenter; 2195 $Y1 = $YCenter - $TRadius; 2196 $X2 = cos($Angle * 3.1418 / 180 ) * $TRadius + $XCenter; 2197 $Y2 = sin($Angle * 3.1418 / 180 ) * $TRadius + $YCenter; 2198 2199 $XPos = floor(($X2-$X1)/2) + $X1; 2200 $YPos = floor(($Y2-$Y1)/2) + $Y1; 2201 2202 $Positions = imagettfbbox($this->FontSize,0,$this->FontName,$t); 2203 $X = $XPos - ( $X+$Positions[2] - $X+$Positions[6] ) / 2; 2204 $Y = $YPos + $this->FontSize; 2205 2206 $this->drawFilledRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,240,240,240); 2207 $this->drawRoundedRectangle($X+$Positions[6]-2,$Y+$Positions[7]-1,$X+$Positions[2]+4,$Y+$Positions[3]+1,2,220,220,220); 2208 imagettftext($this->Picture,$this->FontSize,0,$X,$Y,$C_TextColor,$this->FontName,$t); 2209 } 2210 } 2211 2212 /* This function draw a radar graph centered on the graph area */ 2213 function drawRadar($Data,$DataDescription,$BorderOffset=10,$MaxValue=-1) 2214 { 2215 /* Validate the Data and DataDescription array */ 2216 $this->validateDataDescription("drawRadar",$DataDescription); 2217 $this->validateData("drawRadar",$Data); 2218 2219 $Points = count($Data); 2220 $Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset; 2221 $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2 + $this->GArea_X1; 2222 $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 + $this->GArea_Y1; 2223 2224 /* Search for the max value */ 2225 if ( $MaxValue == -1 ) 2226 { 2227 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2228 { 2229 foreach ( $Data as $Key => $Values ) 2230 { 2231 if ( isset($Data[$Key][$ColName])) 2232 if ( $Data[$Key][$ColName] > $MaxValue ) { $MaxValue = $Data[$Key][$ColName]; } 2233 } 2234 } 2235 } 2236 2237 $GraphID = 0; 2238 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2239 { 2240 $ID = 0; 2241 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 2242 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 2243 2244 $Angle = -90; 2245 $XLast = -1; 2246 foreach ( $Data as $Key => $Values ) 2247 { 2248 if ( isset($Data[$Key][$ColName])) 2249 { 2250 $Value = $Data[$Key][$ColName]; 2251 $Strength = ( $Radius / $MaxValue ) * $Value; 2252 2253 $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter; 2254 $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter; 2255 2256 if ( $XLast != -1 ) 2257 $this->drawLine($XLast,$YLast,$XPos,$YPos,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 2258 2259 if ( $XLast == -1 ) 2260 { $FirstX = $XPos; $FirstY = $YPos; } 2261 2262 $Angle = $Angle + (360/$Points); 2263 $XLast = $XPos; 2264 $YLast = $YPos; 2265 } 2266 } 2267 $this->drawLine($XPos,$YPos,$FirstX,$FirstY,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 2268 $GraphID++; 2269 } 2270 } 2271 2272 /* This function draw a radar graph centered on the graph area */ 2273 function drawFilledRadar($Data,$DataDescription,$Alpha=50,$BorderOffset=10,$MaxValue=-1) 2274 { 2275 /* Validate the Data and DataDescription array */ 2276 $this->validateDataDescription("drawFilledRadar",$DataDescription); 2277 $this->validateData("drawFilledRadar",$Data); 2278 2279 $Points = count($Data); 2280 $LayerWidth = $this->GArea_X2-$this->GArea_X1; 2281 $LayerHeight = $this->GArea_Y2-$this->GArea_Y1; 2282 $Radius = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2 - $BorderOffset; 2283 $XCenter = ( $this->GArea_X2 - $this->GArea_X1 ) / 2; 2284 $YCenter = ( $this->GArea_Y2 - $this->GArea_Y1 ) / 2; 2285 2286 /* Search for the max value */ 2287 if ( $MaxValue == -1 ) 2288 { 2289 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2290 { 2291 foreach ( $Data as $Key => $Values ) 2292 { 2293 if ( isset($Data[$Key][$ColName])) 2294 if ( $Data[$Key][$ColName] > $MaxValue && is_numeric($Data[$Key][$ColName])) { $MaxValue = $Data[$Key][$ColName]; } 2295 } 2296 } 2297 } 2298 2299 $GraphID = 0; 2300 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2301 { 2302 $ID = 0; 2303 foreach ( $DataDescription["Description"] as $keyI => $ValueI ) 2304 { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; } 2305 2306 $Angle = -90; 2307 $XLast = -1; 2308 $Plots = ""; 2309 foreach ( $Data as $Key => $Values ) 2310 { 2311 if ( isset($Data[$Key][$ColName])) 2312 { 2313 $Value = $Data[$Key][$ColName]; 2314 if ( !is_numeric($Value) ) { $Value = 0; } 2315 $Strength = ( $Radius / $MaxValue ) * $Value; 2316 2317 $XPos = cos($Angle * 3.1418 / 180 ) * $Strength + $XCenter; 2318 $YPos = sin($Angle * 3.1418 / 180 ) * $Strength + $YCenter; 2319 2320 $Plots[] = $XPos; 2321 $Plots[] = $YPos; 2322 2323 $Angle = $Angle + (360/$Points); 2324 $XLast = $XPos; 2325 $YLast = $YPos; 2326 } 2327 } 2328 2329 if (isset($Plots[0])) 2330 { 2331 $Plots[] = $Plots[0]; 2332 $Plots[] = $Plots[1]; 2333 2334 $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); 2335 $C_White = $this->AllocateColor($this->Layers[0],255,255,255); 2336 imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); 2337 imagecolortransparent($this->Layers[0],$C_White); 2338 2339 $C_Graph = $this->AllocateColor($this->Layers[0],$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"]); 2340 imagefilledpolygon($this->Layers[0],$Plots,(count($Plots)+1)/2,$C_Graph); 2341 2342 imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha); 2343 imagedestroy($this->Layers[0]); 2344 2345 for($i=0;$i<=count($Plots)-4;$i=$i+2) 2346 $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"]); 2347 } 2348 2349 $GraphID++; 2350 } 2351 } 2352 2353 /* This function draw a flat pie chart */ 2354 function drawBasicPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$R=255,$G=255,$B=255,$Decimals=0) 2355 { 2356 /* Validate the Data and DataDescription array */ 2357 $this->validateDataDescription("drawBasicPieGraph",$DataDescription,FALSE); 2358 $this->validateData("drawBasicPieGraph",$Data); 2359 2360 /* Determine pie sum */ 2361 $Series = 0; $PieSum = 0; 2362 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2363 { 2364 if ( $ColName != $DataDescription["Position"] ) 2365 { 2366 $Series++; 2367 foreach ( $Data as $Key => $Values ) 2368 { 2369 if ( isset($Data[$Key][$ColName])) 2370 $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; 2371 } 2372 } 2373 } 2374 2375 /* Validate serie */ 2376 if ( $Series != 1 ) 2377 RaiseFatal("Pie chart can only accept one serie of data."); 2378 2379 $SpliceRatio = 360 / $PieSum; 2380 $SplicePercent = 100 / $PieSum; 2381 2382 /* Calculate all polygons */ 2383 $Angle = 0; $TopPlots = ""; 2384 foreach($iValues as $Key => $Value) 2385 { 2386 $TopPlots[$Key][] = $XPos; 2387 $TopPlots[$Key][] = $YPos; 2388 2389 /* Process labels position & size */ 2390 $Caption = ""; 2391 if ( !($DrawLabels == PIE_NOLABEL) ) 2392 { 2393 $TAngle = $Angle+($Value*$SpliceRatio/2); 2394 if ($DrawLabels == PIE_PERCENTAGE) 2395 $Caption = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; 2396 elseif ($DrawLabels == PIE_LABELS) 2397 $Caption = $iLabels[$Key]; 2398 elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) 2399 $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; 2400 elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) 2401 $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; 2402 2403 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); 2404 $TextWidth = $Position[2]-$Position[0]; 2405 $TextHeight = abs($Position[1])+abs($Position[3]); 2406 2407 $TX = cos(($TAngle) * 3.1418 / 180 ) * ($Radius+10) + $XPos; 2408 2409 if ( $TAngle > 0 && $TAngle < 180 ) 2410 $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+10) + $YPos + 4; 2411 else 2412 $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+4) + $YPos - ($TextHeight/2); 2413 2414 if ( $TAngle > 90 && $TAngle < 270 ) 2415 $TX = $TX - $TextWidth; 2416 2417 $C_TextColor = $this->AllocateColor($this->Picture,70,70,70); 2418 imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption); 2419 } 2420 2421 /* Process pie slices */ 2422 for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5) 2423 { 2424 $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos; 2425 $TopY = sin($iAngle * 3.1418 / 180 ) * $Radius + $YPos; 2426 2427 $TopPlots[$Key][] = $TopX; 2428 $TopPlots[$Key][] = $TopY; 2429 } 2430 2431 $TopPlots[$Key][] = $XPos; 2432 $TopPlots[$Key][] = $YPos; 2433 2434 $Angle = $iAngle; 2435 } 2436 $PolyPlots = $TopPlots; 2437 2438 /* Set array values type to float --- PHP Bug with imagefilledpolygon casting to integer */ 2439 foreach ($TopPlots as $Key => $Value) 2440 { foreach ($TopPlots[$Key] as $Key2 => $Value2) { settype($TopPlots[$Key][$Key2],"float"); } } 2441 2442 /* Draw Top polygons */ 2443 foreach ($PolyPlots as $Key => $Value) 2444 { 2445 $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]); 2446 imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo); 2447 } 2448 2449 $this->drawCircle($XPos-.5,$YPos-.5,$Radius,$R,$G,$B); 2450 $this->drawCircle($XPos-.5,$YPos-.5,$Radius+.5,$R,$G,$B); 2451 2452 /* Draw Top polygons */ 2453 foreach ($TopPlots as $Key => $Value) 2454 { 2455 for($j=0;$j<=count($TopPlots[$Key])-4;$j=$j+2) 2456 $this->drawLine($TopPlots[$Key][$j],$TopPlots[$Key][$j+1],$TopPlots[$Key][$j+2],$TopPlots[$Key][$j+3],$R,$G,$B); 2457 } 2458 } 2459 2460 function drawFlatPieGraphWithShadow($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals=0) 2461 { 2462 $this->drawFlatPieGraph($Data,$DataDescription,$XPos+$this->ShadowXDistance,$YPos+$this->ShadowYDistance,$Radius,PIE_NOLABEL,$SpliceDistance,$Decimals,TRUE); 2463 $this->drawFlatPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius,$DrawLabels,$SpliceDistance,$Decimals,FALSE); 2464 } 2465 2466 /* This function draw a flat pie chart */ 2467 function drawFlatPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$SpliceDistance=0,$Decimals=0,$AllBlack=FALSE) 2468 { 2469 /* Validate the Data and DataDescription array */ 2470 $this->validateDataDescription("drawFlatPieGraph",$DataDescription,FALSE); 2471 $this->validateData("drawFlatPieGraph",$Data); 2472 2473 $ShadowStatus = $this->ShadowActive ; $this->ShadowActive = FALSE; 2474 2475 /* Determine pie sum */ 2476 $Series = 0; $PieSum = 0; 2477 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2478 { 2479 if ( $ColName != $DataDescription["Position"] ) 2480 { 2481 $Series++; 2482 foreach ( $Data as $Key => $Values ) 2483 { 2484 if ( isset($Data[$Key][$ColName])) 2485 $PieSum = $PieSum + $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; 2486 } 2487 } 2488 } 2489 2490 /* Validate serie */ 2491 if ( $Series != 1 ) 2492 { 2493 RaiseFatal("Pie chart can only accept one serie of data."); 2494 return(0); 2495 } 2496 2497 $SpliceRatio = 360 / $PieSum; 2498 $SplicePercent = 100 / $PieSum; 2499 2500 /* Calculate all polygons */ 2501 $Angle = 0; $TopPlots = ""; 2502 foreach($iValues as $Key => $Value) 2503 { 2504 $XOffset = cos(($Angle+($Value/2*$SpliceRatio)) * 3.1418 / 180 ) * $SpliceDistance; 2505 $YOffset = sin(($Angle+($Value/2*$SpliceRatio)) * 3.1418 / 180 ) * $SpliceDistance; 2506 2507 $TopPlots[$Key][] = round($XPos + $XOffset); 2508 $TopPlots[$Key][] = round($YPos + $YOffset); 2509 2510 if ( $AllBlack ) 2511 { $Rc = $this->ShadowRColor; $Gc = $this->ShadowGColor; $Bc = $this->ShadowBColor; } 2512 else 2513 { $Rc = $this->Palette[$Key]["R"]; $Gc = $this->Palette[$Key]["G"]; $Bc = $this->Palette[$Key]["B"]; } 2514 2515 $XLineLast = ""; $YLineLast = ""; 2516 2517 /* Process labels position & size */ 2518 $Caption = ""; 2519 if ( !($DrawLabels == PIE_NOLABEL) ) 2520 { 2521 $TAngle = $Angle+($Value*$SpliceRatio/2); 2522 if ($DrawLabels == PIE_PERCENTAGE) 2523 $Caption = (round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; 2524 elseif ($DrawLabels == PIE_LABELS) 2525 $Caption = $iLabels[$Key]; 2526 elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) 2527 $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; 2528 elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) 2529 $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; 2530 2531 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); 2532 $TextWidth = $Position[2]-$Position[0]; 2533 $TextHeight = abs($Position[1])+abs($Position[3]); 2534 2535 $TX = cos(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance) + $XPos; 2536 2537 if ( $TAngle > 0 && $TAngle < 180 ) 2538 $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+10+$SpliceDistance) + $YPos + 4; 2539 else 2540 $TY = sin(($TAngle) * 3.1418 / 180 ) * ($Radius+$SpliceDistance+4) + $YPos - ($TextHeight/2); 2541 2542 if ( $TAngle > 90 && $TAngle < 270 ) 2543 $TX = $TX - $TextWidth; 2544 2545 $C_TextColor = $this->AllocateColor($this->Picture,70,70,70); 2546 imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption); 2547 } 2548 2549 /* Process pie slices */ 2550 if ( !$AllBlack ) 2551 $LineColor = $this->AllocateColor($this->Picture,$Rc,$Gc,$Bc); 2552 else 2553 $LineColor = $this->AllocateColor($this->Picture,$Rc,$Gc,$Bc); 2554 2555 $XLineLast = ""; $YLineLast = ""; 2556 for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5) 2557 { 2558 $PosX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos + $XOffset; 2559 $PosY = sin($iAngle * 3.1418 / 180 ) * $Radius + $YPos + $YOffset; 2560 2561 $TopPlots[$Key][] = round($PosX); $TopPlots[$Key][] = round($PosY); 2562 2563 if ( $iAngle == $Angle || $iAngle == $Angle+$Value*$SpliceRatio || $iAngle +.5 > $Angle+$Value*$SpliceRatio) 2564 $this->drawLine($XPos+$XOffset,$YPos+$YOffset,$PosX,$PosY,$Rc,$Gc,$Bc); 2565 2566 if ( $XLineLast != "" ) 2567 $this->drawLine($XLineLast,$YLineLast,$PosX,$PosY,$Rc,$Gc,$Bc); 2568 2569 $XLineLast = $PosX; $YLineLast = $PosY; 2570 } 2571 2572 $TopPlots[$Key][] = round($XPos + $XOffset); $TopPlots[$Key][] = round($YPos + $YOffset); 2573 2574 $Angle = $iAngle; 2575 } 2576 $PolyPlots = $TopPlots; 2577 2578 /* Draw Top polygons */ 2579 foreach ($PolyPlots as $Key => $Value) 2580 { 2581 if ( !$AllBlack ) 2582 $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]); 2583 else 2584 $C_GraphLo = $this->AllocateColor($this->Picture,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor); 2585 2586 imagefilledpolygon($this->Picture,$PolyPlots[$Key],(count($PolyPlots[$Key])+1)/2,$C_GraphLo); 2587 } 2588 $this->ShadowActive = $ShadowStatus; 2589 } 2590 2591 /* This function draw a pseudo-3D pie chart */ 2592 function drawPieGraph($Data,$DataDescription,$XPos,$YPos,$Radius=100,$DrawLabels=PIE_NOLABEL,$EnhanceColors=TRUE,$Skew=60,$SpliceHeight=20,$SpliceDistance=0,$Decimals=0) 2593 { 2594 /* Validate the Data and DataDescription array */ 2595 $this->validateDataDescription("drawPieGraph",$DataDescription,FALSE); 2596 $this->validateData("drawPieGraph",$Data); 2597 2598 /* Determine pie sum */ 2599 $Series = 0; $PieSum = 0; $rPieSum = 0; 2600 foreach ( $DataDescription["Values"] as $Key2 => $ColName ) 2601 { 2602 if ( $ColName != $DataDescription["Position"] ) 2603 { 2604 $Series++; 2605 foreach ( $Data as $Key => $Values ) 2606 if ( isset($Data[$Key][$ColName])) 2607 { 2608 if ( $Data[$Key][$ColName] == 0 ) 2609 { $iValues[] = 0; $rValues[] = 0; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; } 2610 // Removed : $PieSum++; $rValues[] = 1; 2611 else 2612 { $PieSum += $Data[$Key][$ColName]; $iValues[] = $Data[$Key][$ColName]; $iLabels[] = $Data[$Key][$DataDescription["Position"]]; $rValues[] = $Data[$Key][$ColName]; $rPieSum += $Data[$Key][$ColName];} 2613 } 2614 } 2615 } 2616 2617 /* Validate serie */ 2618 if ( $Series != 1 ) 2619 RaiseFatal("Pie chart can only accept one serie of data."); 2620 2621 $SpliceDistanceRatio = $SpliceDistance; 2622 $SkewHeight = ($Radius * $Skew) / 100; 2623 $SpliceRatio = (360 - $SpliceDistanceRatio * count($iValues) ) / $PieSum; 2624 $SplicePercent = 100 / $PieSum; 2625 $rSplicePercent = 100 / $rPieSum; 2626 2627 /* Calculate all polygons */ 2628 $Angle = 0; $CDev = 5; 2629 $TopPlots = ""; $BotPlots = ""; 2630 $aTopPlots = ""; $aBotPlots = ""; 2631 foreach($iValues as $Key => $Value) 2632 { 2633 $XCenterPos = cos(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos; 2634 $YCenterPos = sin(($Angle-$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos; 2635 $XCenterPos2 = cos(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $XPos; 2636 $YCenterPos2 = sin(($Angle+$CDev+($Value*$SpliceRatio+$SpliceDistanceRatio)/2) * 3.1418 / 180 ) * $SpliceDistance + $YPos; 2637 2638 $TopPlots[$Key][] = round($XCenterPos); $BotPlots[$Key][] = round($XCenterPos); 2639 $TopPlots[$Key][] = round($YCenterPos); $BotPlots[$Key][] = round($YCenterPos + $SpliceHeight); 2640 $aTopPlots[$Key][] = $XCenterPos; $aBotPlots[$Key][] = $XCenterPos; 2641 $aTopPlots[$Key][] = $YCenterPos; $aBotPlots[$Key][] = $YCenterPos + $SpliceHeight; 2642 2643 /* Process labels position & size */ 2644 $Caption = ""; 2645 if ( !($DrawLabels == PIE_NOLABEL) ) 2646 { 2647 $TAngle = $Angle+($Value*$SpliceRatio/2); 2648 if ($DrawLabels == PIE_PERCENTAGE) 2649 $Caption = (round($rValues[$Key] * pow(10,$Decimals) * $rSplicePercent)/pow(10,$Decimals))."%"; 2650 elseif ($DrawLabels == PIE_LABELS) 2651 $Caption = $iLabels[$Key]; 2652 elseif ($DrawLabels == PIE_PERCENTAGE_LABEL) 2653 $Caption = $iLabels[$Key]."\r\n".(round($Value * pow(10,$Decimals) * $SplicePercent)/pow(10,$Decimals))."%"; 2654 2655 $Position = imageftbbox($this->FontSize,0,$this->FontName,$Caption); 2656 $TextWidth = $Position[2]-$Position[0]; 2657 $TextHeight = abs($Position[1])+abs($Position[3]); 2658 2659 $TX = cos(($TAngle) * 3.1418 / 180 ) * ($Radius + 10)+ $XPos; 2660 2661 if ( $TAngle > 0 && $TAngle < 180 ) 2662 $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 10) + $YPos + $SpliceHeight + 4; 2663 else 2664 $TY = sin(($TAngle) * 3.1418 / 180 ) * ($SkewHeight + 4) + $YPos - ($TextHeight/2); 2665 2666 if ( $TAngle > 90 && $TAngle < 270 ) 2667 $TX = $TX - $TextWidth; 2668 2669 $C_TextColor = $this->AllocateColor($this->Picture,70,70,70); 2670 imagettftext($this->Picture,$this->FontSize,0,$TX,$TY,$C_TextColor,$this->FontName,$Caption); 2671 } 2672 2673 /* Process pie slices */ 2674 for($iAngle=$Angle;$iAngle<=$Angle+$Value*$SpliceRatio;$iAngle=$iAngle+.5) 2675 { 2676 $TopX = cos($iAngle * 3.1418 / 180 ) * $Radius + $XPos; 2677 $TopY = sin($iAngle * 3.1418 / 180 ) * $SkewHeight + $YPos; 2678 2679 $TopPlots[$Key][] = round($TopX); $BotPlots[$Key][] = round($TopX); 2680 $TopPlots[$Key][] = round($TopY); $BotPlots[$Key][] = round($TopY + $SpliceHeight); 2681 $aTopPlots[$Key][] = $TopX; $aBotPlots[$Key][] = $TopX; 2682 $aTopPlots[$Key][] = $TopY; $aBotPlots[$Key][] = $TopY + $SpliceHeight; 2683 } 2684 2685 $TopPlots[$Key][] = round($XCenterPos2); $BotPlots[$Key][] = round($XCenterPos2); 2686 $TopPlots[$Key][] = round($YCenterPos2); $BotPlots[$Key][] = round($YCenterPos2 + $SpliceHeight); 2687 $aTopPlots[$Key][] = $XCenterPos2; $aBotPlots[$Key][] = $XCenterPos2; 2688 $aTopPlots[$Key][] = $YCenterPos2; $aBotPlots[$Key][] = $YCenterPos2 + $SpliceHeight; 2689 2690 $Angle = $iAngle + $SpliceDistanceRatio; 2691 } 2692 2693 /* Draw Bottom polygons */ 2694 foreach($iValues as $Key => $Value) 2695 { 2696 $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-20); 2697 imagefilledpolygon($this->Picture,$BotPlots[$Key],(count($BotPlots[$Key])+1)/2,$C_GraphLo); 2698 2699 if ( $EnhanceColors ) { $En = -10; } else { $En = 0; } 2700 2701 for($j=0;$j<=count($aBotPlots[$Key])-4;$j=$j+2) 2702 $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); 2703 } 2704 2705 /* Draw pie layers */ 2706 if ( $EnhanceColors ) { $ColorRatio = 30 / $SpliceHeight; } else { $ColorRatio = 25 / $SpliceHeight; } 2707 for($i=$SpliceHeight-1;$i>=1;$i--) 2708 { 2709 foreach($iValues as $Key => $Value) 2710 { 2711 $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"],-10); 2712 $Plots = ""; $Plot = 0; 2713 foreach($TopPlots[$Key] as $Key2 => $Value2) 2714 { 2715 $Plot++; 2716 if ( $Plot % 2 == 1 ) 2717 $Plots[] = $Value2; 2718 else 2719 $Plots[] = $Value2+$i; 2720 } 2721 imagefilledpolygon($this->Picture,$Plots,(count($Plots)+1)/2,$C_GraphLo); 2722 2723 $Index = count($Plots); 2724 if ($EnhanceColors ) {$ColorFactor = -20 + ($SpliceHeight - $i) * $ColorRatio; } else { $ColorFactor = 0; } 2725 2726 $this->drawAntialiasPixel($Plots[0],$Plots[1],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor); 2727 $this->drawAntialiasPixel($Plots[2],$Plots[3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor); 2728 $this->drawAntialiasPixel($Plots[$Index-4],$Plots[$Index-3],$this->Palette[$Key]["R"]+$ColorFactor,$this->Palette[$Key]["G"]+$ColorFactor,$this->Palette[$Key]["B"]+$ColorFactor); 2729 } 2730 } 2731 2732 /* Draw Top polygons */ 2733 for($Key=count($iValues)-1;$Key>=0;$Key--) 2734 { 2735 $C_GraphLo = $this->AllocateColor($this->Picture,$this->Palette[$Key]["R"],$this->Palette[$Key]["G"],$this->Palette[$Key]["B"]); 2736 imagefilledpolygon($this->Picture,$TopPlots[$Key],(count($TopPlots[$Key])+1)/2,$C_GraphLo); 2737 2738 if ( $EnhanceColors ) { $En = 10; } else { $En = 0; } 2739 for($j=0;$j<=count($aTopPlots[$Key])-4;$j=$j+2) 2740 $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); 2741 } 2742 } 2743 2744 /* This function can be used to set the background color */ 2745 function drawBackground($R,$G,$B) 2746 { 2747 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2748 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2749 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2750 2751 $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B); 2752 imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_Background); 2753 } 2754 2755 /* This function can be used to set the background color */ 2756 function drawGraphAreaGradient($R,$G,$B,$Decay,$Target=TARGET_GRAPHAREA) 2757 { 2758 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2759 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2760 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2761 2762 if ( $Target == TARGET_GRAPHAREA ) { $X1 = $this->GArea_X1+1; $X2 = $this->GArea_X2-1; $Y1 = $this->GArea_Y1+1; $Y2 = $this->GArea_Y2; } 2763 if ( $Target == TARGET_BACKGROUND ) { $X1 = 0; $X2 = $this->XSize; $Y1 = 0; $Y2 = $this->YSize; } 2764 2765 /* Positive gradient */ 2766 if ( $Decay > 0 ) 2767 { 2768 $YStep = ($Y2 - $Y1 - 2) / $Decay; 2769 for($i=0;$i<=$Decay;$i++) 2770 { 2771 $R-=1;$G-=1;$B-=1; 2772 $Yi1 = $Y1 + ( $i * $YStep ); 2773 $Yi2 = ceil( $Yi1 + ( $i * $YStep ) + $YStep ); 2774 if ( $Yi2 >= $Yi2 ) { $Yi2 = $Y2-1; } 2775 2776 $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B); 2777 imagefilledrectangle($this->Picture,$X1,$Yi1,$X2,$Yi2,$C_Background); 2778 } 2779 } 2780 2781 /* Negative gradient */ 2782 if ( $Decay < 0 ) 2783 { 2784 $YStep = ($Y2 - $Y1 - 2) / -$Decay; 2785 $Yi1 = $Y1; $Yi2 = $Y1+$YStep; 2786 for($i=-$Decay;$i>=0;$i--) 2787 { 2788 $R+=1;$G+=1;$B+=1; 2789 $C_Background = $this->AllocateColor($this->Picture,$R,$G,$B); 2790 imagefilledrectangle($this->Picture,$X1,$Yi1,$X2,$Yi2,$C_Background); 2791 2792 $Yi1+= $YStep; 2793 $Yi2+= $YStep; 2794 if ( $Yi2 >= $Yi2 ) { $Yi2 = $Y2-1; } 2795 } 2796 } 2797 } 2798 2799 /* This function create a rectangle with antialias */ 2800 function drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B) 2801 { 2802 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2803 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2804 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2805 2806 $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); 2807 2808 $X1=$X1-.2;$Y1=$Y1-.2; 2809 $X2=$X2+.2;$Y2=$Y2+.2; 2810 $this->drawLine($X1,$Y1,$X2,$Y1,$R,$G,$B); 2811 $this->drawLine($X2,$Y1,$X2,$Y2,$R,$G,$B); 2812 $this->drawLine($X2,$Y2,$X1,$Y2,$R,$G,$B); 2813 $this->drawLine($X1,$Y2,$X1,$Y1,$R,$G,$B); 2814 } 2815 2816 /* This function create a filled rectangle with antialias */ 2817 function drawFilledRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B,$DrawBorder=TRUE,$Alpha=100,$NoFallBack=FALSE) 2818 { 2819 if ( $X2 < $X1 ) { list($X1, $X2) = array($X2, $X1); } 2820 if ( $Y2 < $Y1 ) { list($Y1, $Y2) = array($Y2, $Y1); } 2821 2822 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2823 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2824 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2825 2826 if ( $Alpha == 100 ) 2827 { 2828 /* Process shadows */ 2829 if ( $this->ShadowActive && !$NoFallBack ) 2830 { 2831 $this->drawFilledRectangle($X1+$this->ShadowXDistance,$Y1+$this->ShadowYDistance,$X2+$this->ShadowXDistance,$Y2+$this->ShadowYDistance,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,FALSE,$this->ShadowAlpha,TRUE); 2832 if ( $this->ShadowBlur != 0 ) 2833 { 2834 $AlphaDecay = ($this->ShadowAlpha / $this->ShadowBlur); 2835 2836 for($i=1; $i<=$this->ShadowBlur; $i++) 2837 $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); 2838 for($i=1; $i<=$this->ShadowBlur; $i++) 2839 $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); 2840 } 2841 } 2842 2843 $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); 2844 imagefilledrectangle($this->Picture,round($X1),round($Y1),round($X2),round($Y2),$C_Rectangle); 2845 } 2846 else 2847 { 2848 $LayerWidth = abs($X2-$X1)+2; 2849 $LayerHeight = abs($Y2-$Y1)+2; 2850 2851 $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight); 2852 $C_White = $this->AllocateColor($this->Layers[0],255,255,255); 2853 imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White); 2854 imagecolortransparent($this->Layers[0],$C_White); 2855 2856 $C_Rectangle = $this->AllocateColor($this->Layers[0],$R,$G,$B); 2857 imagefilledrectangle($this->Layers[0],round(1),round(1),round($LayerWidth-1),round($LayerHeight-1),$C_Rectangle); 2858 2859 imagecopymerge($this->Picture,$this->Layers[0],round(min($X1,$X2)-1),round(min($Y1,$Y2)-1),0,0,$LayerWidth,$LayerHeight,$Alpha); 2860 imagedestroy($this->Layers[0]); 2861 } 2862 2863 if ( $DrawBorder ) 2864 { 2865 $ShadowSettings = $this->ShadowActive; $this->ShadowActive = FALSE; 2866 $this->drawRectangle($X1,$Y1,$X2,$Y2,$R,$G,$B); 2867 $this->ShadowActive = $ShadowSettings; 2868 } 2869 } 2870 2871 /* This function create a rectangle with rounded corners and antialias */ 2872 function drawRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B) 2873 { 2874 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2875 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2876 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2877 2878 $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); 2879 2880 $Step = 90 / ((3.1418 * $Radius)/2); 2881 2882 for($i=0;$i<=90;$i=$i+$Step) 2883 { 2884 $X = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius; 2885 $Y = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius; 2886 $this->drawAntialiasPixel($X,$Y,$R,$G,$B); 2887 2888 $X = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius; 2889 $Y = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius; 2890 $this->drawAntialiasPixel($X,$Y,$R,$G,$B); 2891 2892 $X = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius; 2893 $Y = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius; 2894 $this->drawAntialiasPixel($X,$Y,$R,$G,$B); 2895 2896 $X = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius; 2897 $Y = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius; 2898 $this->drawAntialiasPixel($X,$Y,$R,$G,$B); 2899 } 2900 2901 $X1=$X1-.2;$Y1=$Y1-.2; 2902 $X2=$X2+.2;$Y2=$Y2+.2; 2903 $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B); 2904 $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B); 2905 $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B); 2906 $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B); 2907 } 2908 2909 /* This function create a filled rectangle with rounded corners and antialias */ 2910 function drawFilledRoundedRectangle($X1,$Y1,$X2,$Y2,$Radius,$R,$G,$B) 2911 { 2912 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2913 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2914 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2915 2916 $C_Rectangle = $this->AllocateColor($this->Picture,$R,$G,$B); 2917 2918 $Step = 90 / ((3.1418 * $Radius)/2); 2919 2920 for($i=0;$i<=90;$i=$i+$Step) 2921 { 2922 $Xi1 = cos(($i+180)*3.1418/180) * $Radius + $X1 + $Radius; 2923 $Yi1 = sin(($i+180)*3.1418/180) * $Radius + $Y1 + $Radius; 2924 2925 $Xi2 = cos(($i-90)*3.1418/180) * $Radius + $X2 - $Radius; 2926 $Yi2 = sin(($i-90)*3.1418/180) * $Radius + $Y1 + $Radius; 2927 2928 $Xi3 = cos(($i)*3.1418/180) * $Radius + $X2 - $Radius; 2929 $Yi3 = sin(($i)*3.1418/180) * $Radius + $Y2 - $Radius; 2930 2931 $Xi4 = cos(($i+90)*3.1418/180) * $Radius + $X1 + $Radius; 2932 $Yi4 = sin(($i+90)*3.1418/180) * $Radius + $Y2 - $Radius; 2933 2934 imageline($this->Picture,$Xi1,$Yi1,$X1+$Radius,$Yi1,$C_Rectangle); 2935 imageline($this->Picture,$X2-$Radius,$Yi2,$Xi2,$Yi2,$C_Rectangle); 2936 imageline($this->Picture,$X2-$Radius,$Yi3,$Xi3,$Yi3,$C_Rectangle); 2937 imageline($this->Picture,$Xi4,$Yi4,$X1+$Radius,$Yi4,$C_Rectangle); 2938 2939 $this->drawAntialiasPixel($Xi1,$Yi1,$R,$G,$B); 2940 $this->drawAntialiasPixel($Xi2,$Yi2,$R,$G,$B); 2941 $this->drawAntialiasPixel($Xi3,$Yi3,$R,$G,$B); 2942 $this->drawAntialiasPixel($Xi4,$Yi4,$R,$G,$B); 2943 } 2944 2945 imagefilledrectangle($this->Picture,$X1,$Y1+$Radius,$X2,$Y2-$Radius,$C_Rectangle); 2946 imagefilledrectangle($this->Picture,$X1+$Radius,$Y1,$X2-$Radius,$Y2,$C_Rectangle); 2947 2948 $X1=$X1-.2;$Y1=$Y1-.2; 2949 $X2=$X2+.2;$Y2=$Y2+.2; 2950 $this->drawLine($X1+$Radius,$Y1,$X2-$Radius,$Y1,$R,$G,$B); 2951 $this->drawLine($X2,$Y1+$Radius,$X2,$Y2-$Radius,$R,$G,$B); 2952 $this->drawLine($X2-$Radius,$Y2,$X1+$Radius,$Y2,$R,$G,$B); 2953 $this->drawLine($X1,$Y2-$Radius,$X1,$Y1+$Radius,$R,$G,$B); 2954 } 2955 2956 /* This function create a circle with antialias */ 2957 function drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0) 2958 { 2959 if ( $Width == 0 ) { $Width = $Height; } 2960 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2961 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2962 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2963 2964 $C_Circle = $this->AllocateColor($this->Picture,$R,$G,$B); 2965 $Step = 360 / (2 * 3.1418 * max($Width,$Height)); 2966 2967 for($i=0;$i<=360;$i=$i+$Step) 2968 { 2969 $X = cos($i*3.1418/180) * $Height + $Xc; 2970 $Y = sin($i*3.1418/180) * $Width + $Yc; 2971 $this->drawAntialiasPixel($X,$Y,$R,$G,$B); 2972 } 2973 } 2974 2975 /* This function create a filled circle/ellipse with antialias */ 2976 function drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width=0) 2977 { 2978 if ( $Width == 0 ) { $Width = $Height; } 2979 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 2980 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 2981 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 2982 2983 $C_Circle = $this->AllocateColor($this->Picture,$R,$G,$B); 2984 $Step = 360 / (2 * 3.1418 * max($Width,$Height)); 2985 2986 for($i=90;$i<=270;$i=$i+$Step) 2987 { 2988 $X1 = cos($i*3.1418/180) * $Height + $Xc; 2989 $Y1 = sin($i*3.1418/180) * $Width + $Yc; 2990 $X2 = cos((180-$i)*3.1418/180) * $Height + $Xc; 2991 $Y2 = sin((180-$i)*3.1418/180) * $Width + $Yc; 2992 2993 $this->drawAntialiasPixel($X1-1,$Y1-1,$R,$G,$B); 2994 $this->drawAntialiasPixel($X2-1,$Y2-1,$R,$G,$B); 2995 2996 if ( ($Y1-1) > $Yc - max($Width,$Height) ) 2997 imageline($this->Picture,$X1,$Y1-1,$X2-1,$Y2-1,$C_Circle); 2998 } 2999 } 3000 3001 /* This function will draw a filled ellipse */ 3002 function drawEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B) 3003 { $this->drawCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); } 3004 3005 /* This function will draw an ellipse */ 3006 function drawFilledEllipse($Xc,$Yc,$Height,$Width,$R,$G,$B) 3007 { $this->drawFilledCircle($Xc,$Yc,$Height,$R,$G,$B,$Width); } 3008 3009 /* This function create a line with antialias */ 3010 function drawLine($X1,$Y1,$X2,$Y2,$R,$G,$B,$GraphFunction=FALSE) 3011 { 3012 if ( $this->LineDotSize > 1 ) { $this->drawDottedLine($X1,$Y1,$X2,$Y2,$this->LineDotSize,$R,$G,$B,$GraphFunction); return(0); } 3013 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 3014 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 3015 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 3016 3017 $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); 3018 if ( $Distance == 0 ) 3019 return(-1); 3020 $XStep = ($X2-$X1) / $Distance; 3021 $YStep = ($Y2-$Y1) / $Distance; 3022 3023 for($i=0;$i<=$Distance;$i++) 3024 { 3025 $X = $i * $XStep + $X1; 3026 $Y = $i * $YStep + $Y1; 3027 3028 if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction ) 3029 { 3030 if ( $this->LineWidth == 1 ) 3031 $this->drawAntialiasPixel($X,$Y,$R,$G,$B); 3032 else 3033 { 3034 $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2); 3035 for($j=$StartOffset;$j<=$EndOffset;$j++) 3036 $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B); 3037 } 3038 } 3039 } 3040 } 3041 3042 /* This function create a line with antialias */ 3043 function drawDottedLine($X1,$Y1,$X2,$Y2,$DotSize,$R,$G,$B,$GraphFunction=FALSE) 3044 { 3045 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 3046 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 3047 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 3048 3049 $Distance = sqrt(($X2-$X1)*($X2-$X1)+($Y2-$Y1)*($Y2-$Y1)); 3050 3051 $XStep = ($X2-$X1) / $Distance; 3052 $YStep = ($Y2-$Y1) / $Distance; 3053 3054 $DotIndex = 0; 3055 for($i=0;$i<=$Distance;$i++) 3056 { 3057 $X = $i * $XStep + $X1; 3058 $Y = $i * $YStep + $Y1; 3059 3060 if ( $DotIndex <= $DotSize) 3061 { 3062 if ( ($X >= $this->GArea_X1 && $X <= $this->GArea_X2 && $Y >= $this->GArea_Y1 && $Y <= $this->GArea_Y2) || !$GraphFunction ) 3063 { 3064 if ( $this->LineWidth == 1 ) 3065 $this->drawAntialiasPixel($X,$Y,$R,$G,$B); 3066 else 3067 { 3068 $StartOffset = -($this->LineWidth/2); $EndOffset = ($this->LineWidth/2); 3069 for($j=$StartOffset;$j<=$EndOffset;$j++) 3070 $this->drawAntialiasPixel($X+$j,$Y+$j,$R,$G,$B); 3071 } 3072 } 3073 } 3074 3075 $DotIndex++; 3076 if ( $DotIndex == $DotSize * 2 ) 3077 $DotIndex = 0; 3078 } 3079 } 3080 3081 /* Load a PNG file and draw it over the chart */ 3082 function drawFromPNG($FileName,$X,$Y,$Alpha=100) 3083 { $this->drawFromPicture(1,$FileName,$X,$Y,$Alpha); } 3084 3085 /* Load a GIF file and draw it over the chart */ 3086 function drawFromGIF($FileName,$X,$Y,$Alpha=100) 3087 { $this->drawFromPicture(2,$FileName,$X,$Y,$Alpha); } 3088 3089 /* Load a JPEG file and draw it over the chart */ 3090 function drawFromJPG($FileName,$X,$Y,$Alpha=100) 3091 { $this->drawFromPicture(3,$FileName,$X,$Y,$Alpha); } 3092 3093 /* Generic loader function for external pictures */ 3094 function drawFromPicture($PicType,$FileName,$X,$Y,$Alpha=100) 3095 { 3096 if ( file_exists($FileName)) 3097 { 3098 $Infos = getimagesize($FileName); 3099 $Width = $Infos[0]; 3100 $Height = $Infos[1]; 3101 if ( $PicType == 1 ) { $Raster = imagecreatefrompng($FileName); } 3102 if ( $PicType == 2 ) { $Raster = imagecreatefromgif($FileName); } 3103 if ( $PicType == 3 ) { $Raster = imagecreatefromjpeg($FileName); } 3104 3105 imagecopymerge($this->Picture,$Raster,$X,$Y,0,0,$Width,$Height,$Alpha); 3106 imagedestroy($Raster); 3107 } 3108 } 3109 3110 /* Draw an alpha pixel */ 3111 function drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B) 3112 { 3113 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 3114 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 3115 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 3116 3117 if ( $X < 0 || $Y < 0 || $X >= $this->XSize || $Y >= $this->YSize ) 3118 return(-1); 3119 3120 $RGB2 = imagecolorat($this->Picture, $X, $Y); 3121 $R2 = ($RGB2 >> 16) & 0xFF; 3122 $G2 = ($RGB2 >> 8) & 0xFF; 3123 $B2 = $RGB2 & 0xFF; 3124 3125 $iAlpha = (100 - $Alpha)/100; 3126 $Alpha = $Alpha / 100; 3127 3128 $Ra = floor($R*$Alpha+$R2*$iAlpha); 3129 $Ga = floor($G*$Alpha+$G2*$iAlpha); 3130 $Ba = floor($B*$Alpha+$B2*$iAlpha); 3131 3132 $C_Aliased = $this->AllocateColor($this->Picture,$Ra,$Ga,$Ba); 3133 imagesetpixel($this->Picture,$X,$Y,$C_Aliased); 3134 } 3135 3136 /* Color helper */ 3137 function AllocateColor($Picture,$R,$G,$B,$Factor=0) 3138 { 3139 $R = $R + $Factor; 3140 $G = $G + $Factor; 3141 $B = $B + $Factor; 3142 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 3143 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 3144 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 3145 3146 return(imagecolorallocate($Picture,$R,$G,$B)); 3147 } 3148 3149 /* Add a border to the picture */ 3150 function addBorder($Size=3,$R=0,$G=0,$B=0) 3151 { 3152 $Width = $this->XSize+2*$Size; 3153 $Height = $this->YSize+2*$Size; 3154 3155 $Resampled = imagecreatetruecolor($Width,$Height); 3156 $C_Background = $this->AllocateColor($Resampled,$R,$G,$B); 3157 imagefilledrectangle($Resampled,0,0,$Width,$Height,$C_Background); 3158 3159 imagecopy($Resampled,$this->Picture,$Size,$Size,0,0,$this->XSize,$this->YSize); 3160 imagedestroy($this->Picture); 3161 3162 $this->XSize = $Width; 3163 $this->YSize = $Height; 3164 3165 $this->Picture = imagecreatetruecolor($this->XSize,$this->YSize); 3166 $C_White = $this->AllocateColor($this->Picture,255,255,255); 3167 imagefilledrectangle($this->Picture,0,0,$this->XSize,$this->YSize,$C_White); 3168 imagecolortransparent($this->Picture,$C_White); 3169 imagecopy($this->Picture,$Resampled,0,0,0,0,$this->XSize,$this->YSize); 3170 } 3171 3172 /* Render the current picture to a file */ 3173 function Render($FileName) 3174 { 3175 if ( $this->ErrorReporting ) 3176 $this->printErrors($this->ErrorInterface); 3177 3178 /* Save image map if requested */ 3179 if ( $this->BuildMap ) 3180 $this->SaveImageMap(); 3181 3182 imagepng($this->Picture,$FileName); 3183 } 3184 3185 /* Render the current picture to STDOUT */ 3186 function Stroke() 3187 { 3188 if ( $this->ErrorReporting ) 3189 $this->printErrors("GD"); 3190 3191 /* Save image map if requested */ 3192 if ( $this->BuildMap ) 3193 $this->SaveImageMap(); 3194 3195 header('Content-type: image/png'); 3196 imagepng($this->Picture); 3197 } 3198 3199 /* Private functions for internal processing */ 3200 function drawAntialiasPixel($X,$Y,$R,$G,$B,$Alpha=100,$NoFallBack=FALSE) 3201 { 3202 /* Process shadows */ 3203 if ( $this->ShadowActive && !$NoFallBack ) 3204 { 3205 $this->drawAntialiasPixel($X+$this->ShadowXDistance,$Y+$this->ShadowYDistance,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,$this->ShadowAlpha,TRUE); 3206 if ( $this->ShadowBlur != 0 ) 3207 { 3208 $AlphaDecay = ($this->ShadowAlpha / $this->ShadowBlur); 3209 3210 for($i=1; $i<=$this->ShadowBlur; $i++) 3211 $this->drawAntialiasPixel($X+$this->ShadowXDistance-$i/2,$Y+$this->ShadowYDistance-$i/2,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,$this->ShadowAlpha-$AlphaDecay*$i,TRUE); 3212 for($i=1; $i<=$this->ShadowBlur; $i++) 3213 $this->drawAntialiasPixel($X+$this->ShadowXDistance+$i/2,$Y+$this->ShadowYDistance+$i/2,$this->ShadowRColor,$this->ShadowGColor,$this->ShadowBColor,$this->ShadowAlpha-$AlphaDecay*$i,TRUE); 3214 } 3215 } 3216 3217 if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; } 3218 if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; } 3219 if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; } 3220 3221 $Plot = ""; 3222 $Xi = floor($X); 3223 $Yi = floor($Y); 3224 3225 if ( $Xi == $X && $Yi == $Y) 3226 { 3227 if ( $Alpha == 100 ) 3228 { 3229 $C_Aliased = $this->AllocateColor($this->Picture,$R,$G,$B); 3230 imagesetpixel($this->Picture,$X,$Y,$C_Aliased); 3231 } 3232 else 3233 $this->drawAlphaPixel($X,$Y,$Alpha,$R,$G,$B); 3234 } 3235 else 3236 { 3237 $Alpha1 = (((1 - ($X - floor($X))) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; 3238 if ( $Alpha1 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi,$Alpha1,$R,$G,$B); } 3239 3240 $Alpha2 = ((($X - floor($X)) * (1 - ($Y - floor($Y))) * 100) / 100) * $Alpha; 3241 if ( $Alpha2 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi,$Alpha2,$R,$G,$B); } 3242 3243 $Alpha3 = (((1 - ($X - floor($X))) * ($Y - floor($Y)) * 100) / 100) * $Alpha; 3244 if ( $Alpha3 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi,$Yi+1,$Alpha3,$R,$G,$B); } 3245 3246 $Alpha4 = ((($X - floor($X)) * ($Y - floor($Y)) * 100) / 100) * $Alpha; 3247 if ( $Alpha4 > $this->AntialiasQuality ) { $this->drawAlphaPixel($Xi+1,$Yi+1,$Alpha4,$R,$G,$B); } 3248 } 3249 } 3250 3251 /* Validate data contained in the description array */ 3252 function validateDataDescription($FunctionName,&$DataDescription,$DescriptionRequired=TRUE) 3253 { 3254 if (!isset($DataDescription["Position"])) 3255 { 3256 $this->Errors[] = "[Warning] ".$FunctionName." - Y Labels are not set."; 3257 $DataDescription["Position"] = "Name"; 3258 } 3259 3260 if ( $DescriptionRequired ) 3261 { 3262 if (!isset($DataDescription["Description"])) 3263 { 3264 $this->Errors[] = "[Warning] ".$FunctionName." - Series descriptions are not set."; 3265 foreach($DataDescription["Values"] as $key => $Value) 3266 { 3267 $DataDescription["Description"][$Value] = $Value; 3268 } 3269 } 3270 3271 if (count($DataDescription["Description"]) < count($DataDescription["Values"])) 3272 { 3273 $this->Errors[] = "[Warning] ".$FunctionName." - Some series descriptions are not set."; 3274 foreach($DataDescription["Values"] as $key => $Value) 3275 { 3276 if ( !isset($DataDescription["Description"][$Value])) 3277 $DataDescription["Description"][$Value] = $Value; 3278 } 3279 } 3280 } 3281 } 3282 3283 /* Validate data contained in the data array */ 3284 function validateData($FunctionName,&$Data) 3285 { 3286 $DataSummary = array(); 3287 3288 foreach($Data as $key => $Values) 3289 { 3290 foreach($Values as $key2 => $Value) 3291 { 3292 if (!isset($DataSummary[$key2])) 3293 $DataSummary[$key2] = 1; 3294 else 3295 $DataSummary[$key2]++; 3296 } 3297 } 3298 3299 if ( max($DataSummary) == 0 ) 3300 $this->Errors[] = "[Warning] ".$FunctionName." - No data set."; 3301 3302 foreach($DataSummary as $key => $Value) 3303 { 3304 if ($Value < max($DataSummary)) 3305 { 3306 $this->Errors[] = "[Warning] ".$FunctionName." - Missing data in serie ".$key."."; 3307 } 3308 } 3309 } 3310 3311 /* Print all error messages on the CLI or graphically */ 3312 function printErrors($Mode="CLI") 3313 { 3314 if (count($this->Errors) == 0) 3315 return(0); 3316 3317 if ( $Mode == "CLI" ) 3318 { 3319 foreach($this->Errors as $key => $Value) 3320 echo $Value."\r\n"; 3321 } 3322 elseif ( $Mode == "GD" ) 3323 { 3324 $this->setLineStyle($Width=1); 3325 $MaxWidth = 0; 3326 foreach($this->Errors as $key => $Value) 3327 { 3328 $Position = imageftbbox($this->ErrorFontSize,0,$this->ErrorFontName,$Value); 3329 $TextWidth = $Position[2]-$Position[0]; 3330 if ( $TextWidth > $MaxWidth ) { $MaxWidth = $TextWidth; } 3331 } 3332 $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); 3333 $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); 3334 3335 $C_TextColor = $this->AllocateColor($this->Picture,133,85,85); 3336 $YPos = $this->YSize - (18 + (count($this->Errors)-1) * ($this->ErrorFontSize + 4)); 3337 foreach($this->Errors as $key => $Value) 3338 { 3339 imagettftext($this->Picture,$this->ErrorFontSize,0,$this->XSize-($MaxWidth+15),$YPos,$C_TextColor,$this->ErrorFontName,$Value); 3340 $YPos = $YPos + ($this->ErrorFontSize + 4); 3341 } 3342 } 3343 } 3344 3345 /* Activate the image map creation process */ 3346 function setImageMap($Mode=TRUE,$GraphID="MyGraph") 3347 { 3348 $this->BuildMap = $Mode; 3349 $this->MapID = $GraphID; 3350 } 3351 3352 /* Add a box into the image map */ 3353 function addToImageMap($X1,$Y1,$X2,$Y2,$SerieName,$Value,$CallerFunction) 3354 { 3355 if ( $this->MapFunction == NULL || $this->MapFunction == $CallerFunction ) 3356 { 3357 $this->ImageMap[] = round($X1).",".round($Y1).",".round($X2).",".round($Y2).",".$SerieName.",".$Value; 3358 $this->MapFunction = $CallerFunction; 3359 } 3360 } 3361 3362 /* Load and cleanup the image map from disk */ 3363 function getImageMap($MapName,$Flush=TRUE) 3364 { 3365 /* Strip HTML query strings */ 3366 $Values = $this->tmpFolder.$MapName; 3367 $Value = split("\?",$Values); 3368 $FileName = $Value[0]; 3369 3370 if ( file_exists($FileName) ) 3371 { 3372 $Handle = fopen($FileName, "r"); 3373 $MapContent = fread($Handle, filesize($FileName)); 3374 fclose($Handle); 3375 echo $MapContent; 3376 3377 if ( $Flush ) 3378 unlink($FileName); 3379 3380 exit(); 3381 } 3382 else 3383 { 3384 header("HTTP/1.0 404 Not Found"); 3385 exit(); 3386 } 3387 } 3388 3389 /* Save the image map to the disk */ 3390 function SaveImageMap() 3391 { 3392 if ( !$this->BuildMap ) { return(-1); } 3393 3394 if ( $this->ImageMap == NULL ) 3395 { 3396 $this->Errors[] = "[Warning] SaveImageMap - Image map is empty."; 3397 return(-1); 3398 } 3399 3400 $Handle = fopen($this->tmpFolder.$this->MapID, 'w'); 3401 if ( !$Handle ) 3402 { 3403 $this->Errors[] = "[Warning] SaveImageMap - Cannot save the image map."; 3404 return(-1); 3405 } 3406 else 3407 { 3408 foreach($this->ImageMap as $Key => $Value) 3409 fwrite($Handle, htmlentities($Value)."\r"); 3410 } 3411 fclose ($Handle); 3412 } 3413 3414 /* Convert seconds to a time format string */ 3415 function ToTime($Value) 3416 { 3417 $Hour = floor($Value/3600); 3418 $Minute = floor(($Value - $Hour*3600)/60); 3419 $Second = floor($Value - $Hour*3600 - $Minute*60); 3420 3421 if (strlen($Hour) == 1 ) { $Hour = "0".$Hour; } 3422 if (strlen($Minute) == 1 ) { $Minute = "0".$Minute; } 3423 if (strlen($Second) == 1 ) { $Second = "0".$Second; } 3424 3425 return($Hour.":".$Minute.":".$Second); 3426 } 3427 3428 /* Convert to metric system */ 3429 function ToMetric($Value) 3430 { 3431 $Go = floor($Value/1000000000); 3432 $Mo = floor(($Value - $Go*1000000000)/1000000); 3433 $Ko = floor(($Value - $Go*1000000000 - $Mo*1000000)/1000); 3434 $o = floor($Value - $Go*1000000000 - $Mo*1000000 - $Ko*1000); 3435 3436 if ($Go != 0) { return($Go.".".$Mo."g"); } 3437 if ($Mo != 0) { return($Mo.".".$ko."m"); } 3438 if ($Ko != 0) { return($Ko.".".$o)."k"; } 3439 return($o); 3440 } 3441 3442 /* Convert to curency */ 3443 function ToCurrency($Value) 3444 { 3445 $Go = floor($Value/1000000000); 3446 $Mo = floor(($Value - $Go*1000000000)/1000000); 3447 $Ko = floor(($Value - $Go*1000000000 - $Mo*1000000)/1000); 3448 $o = floor($Value - $Go*1000000000 - $Mo*1000000 - $Ko*1000); 3449 3450 if ( strlen($o) == 1 ) { $o = "00".$o; } 3451 if ( strlen($o) == 2 ) { $o = "0".$o; } 3452 3453 $ResultString = $o; 3454 if ( $Ko != 0 ) { $ResultString = $Ko.".".$ResultString; } 3455 if ( $Mo != 0 ) { $ResultString = $Mo.".".$ResultString; } 3456 if ( $Go != 0 ) { $ResultString = $Go.".".$ResultString; } 3457 3458 $ResultString = $this->Currency.$ResultString; 3459 return($ResultString); 3460 } 3461 3462 /* Set date format for axis labels */ 3463 function setDateFormat($Format) 3464 { 3465 $this->DateFormat = $Format; 3466 } 3467 3468 /* Convert TS to a date format string */ 3469 function ToDate($Value) 3470 { 3471 return(date($this->DateFormat,$Value)); 3472 } 3473 3474 /* Check if a number is a full integer (for scaling) */ 3475 function isRealInt($Value) 3476 { 3477 if ($Value == floor($Value)) 3478 return(TRUE); 3479 return(FALSE); 3480 } 3481 } 3482 3483 function RaiseFatal($Message) 3484 { 3485 echo "[FATAL] ".$Message."\r\n"; 3486 exit(); 3487 } 3488?>