1<?php 2 3/** 4 * pChart - a PHP class to build charts! 5 * Copyright (C) 2008 Jean-Damien POGOLOTTI 6 * Version 2.0 7 * Copyright (C) 2010 Tim Martin 8 * 9 * http://pchart.sourceforge.net 10 * 11 * This program is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License as published by 13 * the Free Software Foundation, either version 1,2,3 of the License, or 14 * (at your option) any later version. 15 * 16 * This program is distributed in the hope that it will be useful, 17 * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 * GNU General Public License for more details. 20 * 21 * You should have received a copy of the GNU General Public License 22 * along with this program. If not, see <http://www.gnu.org/licenses/>. 23 */ 24 25define ("PIE_PERCENTAGE", 1); 26define ("PIE_LABELS", 2); 27define ("PIE_NOLABEL", 3); 28define ("PIE_PERCENTAGE_LABEL", 4); 29 30/** 31 * This is an attempt to separate out the pie chart drawing code from 32 * the rest of the chart code, since pie charts are very different 33 * from charts that use 2D Cartesian coordinates. 34 * 35 * The inheritance hierarchy here probably isn't the finished article; 36 * separating out in this way is an intermediate form that I hope will 37 * shed light on the real dependency structure. 38 */ 39class PieChart extends pChart { 40 /** 41 * Draw the data legends 42 * 43 * @param int X-Position 44 * @param int Y-Position 45 * @param array Data pData->getData 46 * @param array DataDescription pData->getDataDescription 47 * @param Color 48 * @param ShadowProperties 49 * @access public 50 */ 51 public function drawPieLegend($XPos, $YPos, $Data, $DataDescription, Color $color, ShadowProperties $shadowProperties = null) { 52 if($shadowProperties == null) { 53 $shadowProperties = ShadowProperties::FromDefaults(); 54 } 55 56 /* Validate the Data and DataDescription array */ 57 $this->validateDataDescription("drawPieLegend", $DataDescription, FALSE); 58 $this->validateData("drawPieLegend", $Data); 59 60 if($DataDescription->getPosition() == '') 61 return (-1); 62 63 /* <-10->[8]<-4->Text<-10-> */ 64 $MaxWidth = 0; 65 $MaxHeight = 8; 66 foreach($Data as $Key => $Value) { 67 $Value2 = $Value [$DataDescription->getPosition()]; 68 $Position = imageftbbox($this->FontSize, 0, $this->FontName, $Value2); 69 $TextWidth = $Position [2] - $Position [0]; 70 $TextHeight = $Position [1] - $Position [7]; 71 if($TextWidth > $MaxWidth) { 72 $MaxWidth = $TextWidth; 73 } 74 75 $MaxHeight = $MaxHeight + $TextHeight + 4; 76 } 77 $MaxHeight = $MaxHeight - 3; 78 $MaxWidth = $MaxWidth + 32; 79 80 $this->canvas->drawFilledRoundedRectangle( 81 new Point($XPos + 1, $YPos + 1), 82 new Point($XPos + $MaxWidth + 1, 83 $YPos + $MaxHeight + 1), 84 5, 85 $color->addRGBIncrement(-30), 86 $this->LineWidth, 87 $this->LineDotSize, 88 $shadowProperties 89 ); 90 91 $this->canvas->drawFilledRoundedRectangle( 92 new Point($XPos, $YPos), 93 new Point($XPos + $MaxWidth, 94 $YPos + $MaxHeight), 95 5, $color, 96 $this->LineWidth, 97 $this->LineDotSize, 98 $shadowProperties 99 ); 100 101 $YOffset = 4 + $this->FontSize; 102 $ID = 0; 103 foreach($Data as $Key => $Value) { 104 $Value2 = $Value [$DataDescription->getPosition()]; 105 $Position = imageftbbox($this->FontSize, 0, $this->FontName, $Value2); 106 $TextHeight = $Position [1] - $Position [7]; 107 $this->canvas->drawFilledRectangle( 108 new Point($XPos + 10, 109 $YPos + $YOffset - 6), 110 new Point($XPos + 14, 111 $YPos + $YOffset - 2), 112 $this->palette->colors[$ID], 113 $shadowProperties 114 ); 115 116 $this->canvas->drawText( 117 $this->FontSize, 118 0, 119 new Point($XPos + 22, 120 $YPos + $YOffset), 121 new Color(0, 0, 0), 122 $this->FontName, 123 $Value2, 124 $shadowProperties 125 ); 126 $YOffset = $YOffset + $TextHeight + 4; 127 $ID++; 128 } 129 } 130 131 /** 132 * This function draw a flat pie chart 133 * 134 * @param array Data (PieChart->getData()) 135 * @param array Description (PieChart->getDataDescription()) 136 * @param int X-Position of the Center 137 * @param int Y-Position of the Center 138 * @param int Radius of the cake 139 * @param const int Draw the Labels to the pies? PIE_LABELS, PIE_NOLABEL, PIE_PERCENTAGE, PIE_PERCENATGE_LABEL 140 * @param int Distance between the splices 141 * @param int number of decimals 142 * @param ShadowProperties 143 * @access public 144 */ 145 public function drawBasicPieGraph($Data, $DataDescription, $XPos, $YPos, $Radius = 100, $DrawLabels = PIE_NOLABEL, Color $color = null, $Decimals = 0, ShadowProperties $shadowProperties = null) { 146 if($shadowProperties == null) { 147 $shadowProperties = ShadowProperties::NoShadow(); 148 } 149 150 if(empty($DataDescription->values)) { 151 throw new Exception("No values available in data description in drawBasicPieGraph()"); 152 } 153 154 if($color == null) { 155 $color = new Color(255, 255, 255); 156 } 157 158 /* Validate the Data and DataDescription array */ 159 $this->validateDataDescription("drawBasicPieGraph", $DataDescription, FALSE); 160 $this->validateData("drawBasicPieGraph", $Data); 161 162 /* Determine pie sum */ 163 $Series = 0; 164 $PieSum = 0; 165 foreach($DataDescription->values as $Key2 => $ColName) { 166 if($ColName != $DataDescription->getPosition()) { 167 $Series++; 168 foreach(array_keys($Data) as $Key) { 169 if(isset ($Data [$Key] [$ColName])) 170 $PieSum = $PieSum + $Data [$Key] [$ColName]; 171 $iValues [] = $Data [$Key] [$ColName]; 172 } 173 } 174 } 175 176 /* Validate serie */ 177 if($Series != 1) 178 throw new Exception("Pie chart can only accept one serie of data."); 179 /** @todo Proper exception type needed here */ 180 181 $SpliceRatio = 360 / $PieSum; 182 $SplicePercent = 100 / $PieSum; 183 184 /* Calculate all polygons */ 185 $Angle = 0; 186 $TopPlots = []; 187 foreach($iValues as $Key => $Value) { 188 $TopPlots [$Key] [] = $XPos; 189 $TopPlots [$Key] [] = $YPos; 190 191 /* Process labels position & size */ 192 $this->processLabelsPositionAndSize($DrawLabels, $Angle, $Value, $SpliceRatio, $SplicePercent, 0, $Decimals, $Radius, $XPos, $YPos, $shadowProperties); 193 194 /* Process pie slices */ 195 for($iAngle = $Angle; $iAngle <= $Angle + $Value * $SpliceRatio; $iAngle = $iAngle + .5) { 196 $TopX = cos($iAngle * M_PI / 180) * $Radius + $XPos; 197 $TopY = sin($iAngle * M_PI / 180) * $Radius + $YPos; 198 199 $TopPlots [$Key] [] = $TopX; 200 $TopPlots [$Key] [] = $TopY; 201 } 202 203 $TopPlots [$Key] [] = $XPos; 204 $TopPlots [$Key] [] = $YPos; 205 206 $Angle = $iAngle; 207 } 208 $PolyPlots = $TopPlots; 209 210 /* Set array values type to float --- PHP Bug with 211 * imagefilledpolygon casting to integer */ 212 foreach($TopPlots as $Key => $Value) { 213 foreach(array_keys($TopPlots[$Key]) as $Key2) { 214 settype($TopPlots [$Key] [$Key2], "float"); 215 } 216 } 217 218 /* Draw Top polygons */ 219 foreach($PolyPlots as $Key => $Value) { 220 $this->canvas->drawFilledPolygon( 221 $PolyPlots [$Key], 222 (count($PolyPlots [$Key]) + 1) / 2, 223 $this->palette->colors[$Key] 224 ); 225 } 226 227 $this->canvas->drawCircle( 228 new Point($XPos - .5, $YPos - .5), 229 $Radius, 230 $color, 231 $shadowProperties 232 ); 233 $this->canvas->drawCircle( 234 new Point($XPos - .5, $YPos - .5), 235 $Radius + .5, 236 $color, 237 $shadowProperties 238 ); 239 240 /* Draw Top polygons */ 241 foreach($TopPlots as $Key => $Value) { 242 for($j = 0; $j <= count($TopPlots [$Key]) - 4; $j = $j + 2) 243 $this->canvas->drawLine( 244 new Point($TopPlots [$Key] [$j], 245 $TopPlots [$Key] [$j + 1]), 246 new Point($TopPlots [$Key] [$j + 2], 247 $TopPlots [$Key] [$j + 3]), 248 $color, 249 $this->LineWidth, 250 $this->LineDotSize, 251 $shadowProperties 252 ); 253 } 254 } 255 256 /** 257 * @todo This method was generated by pulling out a bunch of 258 * copy&paste duplication. It needs further work to improve the 259 * interface. 260 */ 261 private function processLabelsPositionAndSize($DrawLabels, $Angle, $Value, $SpliceRatio, $SplicePercent, $SpliceDistance, $Decimals, $Radius, $XPos, $YPos, ShadowProperties $shadowProperties) { 262 $Caption = ""; 263 if(!($DrawLabels == PIE_NOLABEL)) { 264 $TAngle = $Angle + ($Value * $SpliceRatio / 2); 265 if($DrawLabels == PIE_PERCENTAGE) 266 $Caption = (round($Value * pow(10, $Decimals) * $SplicePercent) / pow(10, $Decimals))."%"; 267 elseif($DrawLabels == PIE_LABELS) 268 $Caption = $iLabels [$Key]; 269 elseif($DrawLabels == PIE_PERCENTAGE_LABEL) 270 $Caption = $iLabels [$Key]."\r\n".(round($Value * pow(10, $Decimals) * $SplicePercent) / pow(10, $Decimals))."%"; 271 elseif($DrawLabels == PIE_PERCENTAGE_LABEL) 272 $Caption = $iLabels [$Key]."\r\n".(round($Value * pow(10, $Decimals) * $SplicePercent) / pow(10, $Decimals))."%"; 273 274 $Position = imageftbbox($this->FontSize, 0, $this->FontName, $Caption); 275 $TextWidth = $Position [2] - $Position [0]; 276 $TextHeight = abs($Position [1]) + abs($Position [3]); 277 278 $TX = cos(($TAngle) * M_PI / 180) * ($Radius + 10 + $SpliceDistance) + $XPos; 279 280 if($TAngle > 0 && $TAngle < 180) 281 $TY = sin(($TAngle) * M_PI / 180) * ($Radius + 10 + $SpliceDistance) + $YPos + 4; 282 else 283 $TY = sin(($TAngle) * M_PI / 180) * ($Radius + $SpliceDistance + 4) + $YPos - ($TextHeight / 2); 284 285 if($TAngle > 90 && $TAngle < 270) 286 $TX = $TX - $TextWidth; 287 288 $this->canvas->drawText( 289 $this->FontSize, 290 0, 291 new Point($TX, $TY), 292 new Color(70, 70, 70), 293 $this->FontName, 294 $Caption, 295 $shadowProperties 296 ); 297 } 298 } 299 300 /** 301 * This function draw a simple flat pie graph with shadows 302 * 303 * @param array Data (PieChart->getData()) 304 * @param array Description (PieChart->getDataDescription()) 305 * @param int X-Position of the Center 306 * @param int Y-Position of the Center 307 * @param int Radius of the cake 308 * @param const int Draw the Labels to the pies? PIE_LABELS, PIE_NOLABEL, PIE_PERCENTAGE, PIE_PERCENATGE_LABEL 309 * @param int Distance between the splices 310 * @param int number of decimals 311 * @param ShadowProperties 312 * @access public 313 */ 314 public function drawFlatPieGraphWithShadow($Data, $DataDescription, $XPos, $YPos, $Radius = 100, $DrawLabels = PIE_NOLABEL, $SpliceDistance = 0, $Decimals = 0, ShadowProperties $shadowProperties = NULL) { 315 /** 316 * @todo Slightly ugly code follows: We want to draw the graph 317 * with once to be the 'shadow', without itself having a 318 * shadow, and once again to be the actual graph. In fact, we 319 * can't pass ShadowProperties::NoShadow() into the first 320 * drawFlatPieGraph() call, since the method expects to use 321 * the color on the shadow properties, even though it is 322 * inactive. We do a clone to avoid mucking with the caller's 323 * copy of the shadow properties. 324 */ 325 $inactiveShadowProperties = ShadowProperties::Copy($shadowProperties); 326 $inactiveShadowProperties->active = false; 327 328 $this->drawFlatPieGraph( 329 $Data, 330 $DataDescription, 331 $XPos + $shadowProperties->xDistance, 332 $YPos + $shadowProperties->yDistance, 333 $Radius, 334 PIE_NOLABEL, 335 $SpliceDistance, $Decimals, TRUE, 336 $inactiveShadowProperties 337 ); 338 $this->drawFlatPieGraph( 339 $Data, $DataDescription, $XPos, $YPos, $Radius, $DrawLabels, $SpliceDistance, $Decimals, FALSE, 340 $inactiveShadowProperties 341 ); 342 } 343 344 /** 345 * This function draw a simple flat pie graph with shadows 346 * 347 * @param array Data (PieChart->getData()) 348 * @param array Description (PieChart->getDataDescription()) 349 * @param int X-Position of the Center 350 * @param int Y-Position of the Center 351 * @param int Radius of the cake 352 * @param const int Draw the Labels to the pies? PIE_LABELS, PIE_NOLABEL, PIE_PERCENTAGE, PIE_PERCENATGE_LABEL 353 * @param int Distance between the splices 354 * @param int number of decimals 355 * @param bool Should the Chart be gray? 356 * @param ShadowProperties 357 * @access public 358 */ 359 public function drawFlatPieGraph($Data, $DataDescription, $XPos, $YPos, $Radius = 100, $DrawLabels = PIE_NOLABEL, $SpliceDistance = 0, $Decimals = 0, $AllBlack = FALSE, ShadowProperties $shadowProperties = null) { 360 if($shadowProperties == null) { 361 $shadowProperties = ShadowProperties::FromDefaults(); 362 } 363 364 /* Validate the Data and DataDescription array */ 365 $this->validateDataDescription("drawFlatPieGraph", $DataDescription, FALSE); 366 $this->validateData("drawFlatPieGraph", $Data); 367 368 /* Determine pie sum */ 369 $Series = 0; 370 $PieSum = 0; 371 foreach($DataDescription->values as $ColName) { 372 if($ColName != $DataDescription->getPosition()) { 373 $Series++; 374 foreach(array_keys($Data) as $Key) { 375 if(isset ($Data [$Key] [$ColName])) 376 $PieSum = $PieSum + $Data [$Key] [$ColName]; 377 $iValues [] = $Data [$Key] [$ColName]; 378 } 379 } 380 } 381 382 /* Validate serie */ 383 if($Series != 1) { 384 /** 385 * @todo Proper exception type needed here 386 */ 387 throw new Exception("Pie chart can only accept one serie of data."); 388 } 389 390 $SpliceRatio = 360 / $PieSum; 391 $SplicePercent = 100 / $PieSum; 392 393 /* Calculate all polygons */ 394 $Angle = 0; 395 $TopPlots = ""; 396 foreach($iValues as $Key => $Value) { 397 $XOffset = cos(($Angle + ($Value / 2 * $SpliceRatio)) * M_PI / 180) * $SpliceDistance; 398 $YOffset = sin(($Angle + ($Value / 2 * $SpliceRatio)) * M_PI / 180) * $SpliceDistance; 399 400 $TopPlots [$Key] [] = round($XPos + $XOffset); 401 $TopPlots [$Key] [] = round($YPos + $YOffset); 402 403 if($AllBlack) { 404 $color = $shadowProperties->color; 405 } else { 406 $color = $this->palette->colors[$Key]; 407 } 408 409 /* Process labels position & size */ 410 $this->processLabelsPositionAndSize($DrawLabels, $Angle, $Value, $SpliceRatio, $SplicePercent, $SpliceDistance, $Decimals, $Radius, $XPos, $YPos, $shadowProperties); 411 412 /* Process pie slices */ 413 $this->processPieSlices($Angle, $SpliceRatio, $Value, $Radius, $XPos, $YPos, $XOffset, $YOffset, $color, $TopPlots[$Key], $shadowProperties); 414 415 $TopPlots [$Key] [] = round($XPos + $XOffset); 416 $TopPlots [$Key] [] = round($YPos + $YOffset); 417 } 418 $PolyPlots = $TopPlots; 419 420 /* Draw Top polygons */ 421 foreach($PolyPlots as $Key => $Value) { 422 if(!$AllBlack) 423 $polygonColor = $this->palette->colors[$Key]; 424 else 425 $polygonColor = $shadowProperties->color; 426 427 $this->canvas->drawFilledPolygon( 428 $PolyPlots [$Key], 429 (count($PolyPlots [$Key]) + 1) / 2, 430 $polygonColor 431 ); 432 } 433 } 434 435 /** 436 * This function draw a pseudo-3D pie chart 437 * 438 * @param pData 439 * @param int X-Position of the Center 440 * @param int Y-Position of the Center 441 * @param int Radius of the cake 442 * @param const int Draw the Labels to the pies? PIE_LABELS, PIE_NOLABEL, PIE_PERCENTAGE, PIE_PERCENATGE_LABEL 443 * @param bool Enhance colors? 444 * @param int Skew 445 * @param int Height of the splices 446 * @param int Distance between the splices 447 * @param int number of decimals 448 * @param ShadowProperties 449 * @access public 450 */ 451 public function drawPieGraph(pData $data, $XPos, $YPos, 452 $Radius = 100, $DrawLabels = PIE_NOLABEL, 453 $EnhanceColors = TRUE, $Skew = 60, 454 $SpliceHeight = 20, $SpliceDistance = 0, 455 $Decimals = 0, 456 ShadowProperties $shadowProperties = null) { 457 if($shadowProperties == null) { 458 $shadowProperties = ShadowProperties::FromDefaults(); 459 } 460 461 /* Validate the Data and DataDescription array */ 462 $this->validateDataDescription("drawPieGraph", $data->getDataDescription(), FALSE); 463 $this->validateData("drawPieGraph", $data->getData()); 464 465 /* Determine pie sum */ 466 $Series = 0; 467 $PieSum = 0; 468 $rPieSum = 0; 469 foreach($data->getDataDescription()->values as $ColName) { 470 if($ColName != $data->getDataDescription()->getPosition()) { 471 $Series++; 472 $dataArray = $data->getData(); 473 foreach(array_keys($dataArray) as $Key) { 474 if(isset ($dataArray[$Key] [$ColName])) { 475 if($dataArray[$Key] [$ColName] == 0) { 476 $iValues [] = 0; 477 $rValues [] = 0; 478 $iLabels [] = $dataArray[$Key] [$data->getDataDescription()->getPosition()]; 479 } // Removed : $PieSum++; $rValues[] = 1; 480 else { 481 $PieSum += $dataArray[$Key] [$ColName]; 482 $iValues [] = $dataArray[$Key] [$ColName]; 483 $iLabels [] = $dataArray[$Key] [$data->getDataDescription()->getPosition()]; 484 $rValues [] = $dataArray[$Key] [$ColName]; 485 $rPieSum += $dataArray[$Key] [$ColName]; 486 } 487 } 488 } 489 } 490 } 491 492 /* Validate serie */ 493 if($Series != 1) 494 throw new Exception("Pie chart can only accept one serie of data."); 495 /** @todo Proper exception type needed here */ 496 497 $SpliceDistanceRatio = $SpliceDistance; 498 $SkewHeight = ($Radius * $Skew) / 100; 499 $SpliceRatio = (360 - $SpliceDistanceRatio * count($iValues)) / $PieSum; 500 $SplicePercent = 100 / $PieSum; 501 $rSplicePercent = 100 / $rPieSum; 502 503 /* Calculate all polygons */ 504 $Angle = 0; 505 $CDev = 5; 506 $TopPlots = ""; 507 $BotPlots = ""; 508 $aTopPlots = ""; 509 $aBotPlots = ""; 510 foreach($iValues as $Key => $Value) { 511 $XCenterPos = cos(($Angle - $CDev + ($Value * $SpliceRatio + $SpliceDistanceRatio) / 2) * M_PI / 180) * $SpliceDistance + $XPos; 512 $YCenterPos = sin(($Angle - $CDev + ($Value * $SpliceRatio + $SpliceDistanceRatio) / 2) * M_PI / 180) * $SpliceDistance + $YPos; 513 $XCenterPos2 = cos(($Angle + $CDev + ($Value * $SpliceRatio + $SpliceDistanceRatio) / 2) * M_PI / 180) * $SpliceDistance + $XPos; 514 $YCenterPos2 = sin(($Angle + $CDev + ($Value * $SpliceRatio + $SpliceDistanceRatio) / 2) * M_PI / 180) * $SpliceDistance + $YPos; 515 516 $TopPlots [$Key] [] = round($XCenterPos); 517 $BotPlots [$Key] [] = round($XCenterPos); 518 $TopPlots [$Key] [] = round($YCenterPos); 519 $BotPlots [$Key] [] = round($YCenterPos + $SpliceHeight); 520 $aTopPlots [$Key] [] = $XCenterPos; 521 $aBotPlots [$Key] [] = $XCenterPos; 522 $aTopPlots [$Key] [] = $YCenterPos; 523 $aBotPlots [$Key] [] = $YCenterPos + $SpliceHeight; 524 525 /* Process labels position & size */ 526 $Caption = ""; 527 if(!($DrawLabels == PIE_NOLABEL)) { 528 $TAngle = $Angle + ($Value * $SpliceRatio / 2); 529 if($DrawLabels == PIE_PERCENTAGE) 530 $Caption = (round($rValues [$Key] * pow(10, $Decimals) * $rSplicePercent) / pow(10, $Decimals))."%"; 531 elseif($DrawLabels == PIE_LABELS) 532 $Caption = $iLabels [$Key]; 533 elseif($DrawLabels == PIE_PERCENTAGE_LABEL) 534 $Caption = $iLabels [$Key]."\r\n".(round($Value * pow(10, $Decimals) * $SplicePercent) / pow(10, $Decimals))."%"; 535 536 $Position = imageftbbox($this->FontSize, 0, $this->FontName, $Caption); 537 $TextWidth = $Position [2] - $Position [0]; 538 $TextHeight = abs($Position [1]) + abs($Position [3]); 539 540 $TX = cos(($TAngle) * M_PI / 180) * ($Radius + 10) + $XPos; 541 542 if($TAngle > 0 && $TAngle < 180) 543 $TY = sin(($TAngle) * M_PI / 180) * ($SkewHeight + 10) + $YPos + $SpliceHeight + 4; 544 else 545 $TY = sin(($TAngle) * M_PI / 180) * ($SkewHeight + 4) + $YPos - ($TextHeight / 2); 546 547 if($TAngle > 90 && $TAngle < 270) 548 $TX = $TX - $TextWidth; 549 550 $this->canvas->drawText( 551 $this->FontSize, 552 0, 553 new Point($TX, $TY), 554 new Color(70, 70, 70), 555 $this->FontName, 556 $Caption, 557 $shadowProperties 558 ); 559 } 560 561 /* Process pie slices */ 562 for($iAngle = $Angle; $iAngle <= $Angle + $Value * $SpliceRatio; $iAngle = $iAngle + .5) { 563 $TopX = cos($iAngle * M_PI / 180) * $Radius + $XPos; 564 $TopY = sin($iAngle * M_PI / 180) * $SkewHeight + $YPos; 565 566 $TopPlots [$Key] [] = round($TopX); 567 $BotPlots [$Key] [] = round($TopX); 568 $TopPlots [$Key] [] = round($TopY); 569 $BotPlots [$Key] [] = round($TopY + $SpliceHeight); 570 $aTopPlots [$Key] [] = $TopX; 571 $aBotPlots [$Key] [] = $TopX; 572 $aTopPlots [$Key] [] = $TopY; 573 $aBotPlots [$Key] [] = $TopY + $SpliceHeight; 574 } 575 576 $TopPlots [$Key] [] = round($XCenterPos2); 577 $BotPlots [$Key] [] = round($XCenterPos2); 578 $TopPlots [$Key] [] = round($YCenterPos2); 579 $BotPlots [$Key] [] = round($YCenterPos2 + $SpliceHeight); 580 $aTopPlots [$Key] [] = $XCenterPos2; 581 $aBotPlots [$Key] [] = $XCenterPos2; 582 $aTopPlots [$Key] [] = $YCenterPos2; 583 $aBotPlots [$Key] [] = $YCenterPos2 + $SpliceHeight; 584 585 $Angle = $iAngle + $SpliceDistanceRatio; 586 } 587 588 $this->drawPieGraphBottomPolygons( 589 $iValues, $BotPlots, 590 $EnhanceColors, $aBotPlots, 591 $shadowProperties 592 ); 593 594 $this->drawPieGraphLayers( 595 $iValues, $TopPlots, $EnhanceColors, 596 $SpliceHeight, $this->palette, $shadowProperties 597 ); 598 599 $this->drawPieGraphTopPolygons( 600 $iValues, $TopPlots, $EnhanceColors, 601 $aTopPlots, $shadowProperties 602 ); 603 } 604 605 /** 606 * @todo Not really sure what this does, it appears to do several 607 * things at once (it was generated by pulling code out of 608 * drawPieChart()) 609 */ 610 private function processPieSlices(& $Angle, $SpliceRatio, $Value, $Radius, $XPos, $YPos, $XOffset, $YOffset, Color $color, array & $plotArray, ShadowProperties $shadowProperties) { 611 $lastPos = null; 612 613 for($iAngle = $Angle; $iAngle <= $Angle + $Value * $SpliceRatio; $iAngle = $iAngle + .5) { 614 $PosX = cos($iAngle * M_PI / 180) * $Radius + $XPos + $XOffset; 615 $PosY = sin($iAngle * M_PI / 180) * $Radius + $YPos + $YOffset; 616 617 $plotArray[] = round($PosX); 618 $plotArray[] = round($PosY); 619 620 $currentPos = new Point($PosX, $PosY); 621 622 if($iAngle == $Angle || $iAngle == $Angle + $Value * $SpliceRatio || $iAngle + .5 > $Angle + $Value * $SpliceRatio) 623 $this->canvas->drawLine( 624 new Point($XPos + $XOffset, $YPos + $YOffset), 625 $currentPos, 626 $color, 627 $this->LineWidth, 628 $this->LineDotSize, 629 $shadowProperties 630 ); 631 632 if($lastPos != null) 633 $this->canvas->drawLine( 634 $lastPos, 635 $currentPos, 636 $color, 637 $this->LineWidth, 638 $this->LineDotSize, 639 $shadowProperties 640 ); 641 642 $lastPos = $currentPos; 643 } 644 645 /* Update the angle in the caller to the final angle we 646 * reached while processing */ 647 $Angle = $iAngle; 648 } 649 650 private function drawPieGraphBottomPolygons(array $iValues, array $BotPlots, $EnhanceColors, array $aBotPlots, ShadowProperties $shadowProperties) { 651 foreach(array_keys($iValues) as $Key) { 652 $this->canvas->drawFilledPolygon( 653 $BotPlots [$Key], 654 (count($BotPlots [$Key]) + 1) / 2, 655 $this->palette->colors[$Key]->addRGBIncrement(-20) 656 ); 657 658 if($EnhanceColors) { 659 $En = -10; 660 } else { 661 $En = 0; 662 } 663 664 for($j = 0; $j <= count($aBotPlots [$Key]) - 4; $j = $j + 2) { 665 $this->canvas->drawLine( 666 new Point($aBotPlots [$Key] [$j], 667 $aBotPlots [$Key] [$j + 1]), 668 new Point($aBotPlots [$Key] [$j + 2], 669 $aBotPlots [$Key] [$j + 3]), 670 $this->palette->colors[$Key]->addRGBIncrement($En), 671 $this->LineWidth, 672 $this->LineDotSize, 673 $shadowProperties 674 ); 675 } 676 } 677 } 678 679 private function drawPieGraphLayers($iValues, $TopPlots, $EnhanceColors, $SpliceHeight, Palette $palette, ShadowProperties $shadowProperties) { 680 if($EnhanceColors) { 681 $ColorRatio = 30 / $SpliceHeight; 682 } else { 683 $ColorRatio = 25 / $SpliceHeight; 684 } 685 for($i = $SpliceHeight - 1; $i >= 1; $i--) { 686 foreach(array_keys($iValues) as $Key) { 687 $Plots = ""; 688 $Plot = 0; 689 foreach($TopPlots [$Key] as $Value2) { 690 $Plot++; 691 if($Plot % 2 == 1) 692 $Plots [] = $Value2; 693 else 694 $Plots [] = $Value2 + $i; 695 } 696 $this->canvas->drawFilledPolygon( 697 $Plots, 698 (count($Plots) + 1) / 2, 699 $palette->colors[$Key]->addRGBIncrement(-10) 700 ); 701 702 $Index = count($Plots); 703 if($EnhanceColors) { 704 $ColorFactor = -20 + ($SpliceHeight - $i) * $ColorRatio; 705 } else { 706 $ColorFactor = 0; 707 } 708 709 $this->canvas->drawAntialiasPixel( 710 new Point($Plots[0], $Plots[1]), 711 $palette->colors[$Key]->addRGBIncrement($ColorFactor), 712 $shadowProperties 713 ); 714 715 $this->canvas->drawAntialiasPixel( 716 new Point($Plots[2], $Plots[3]), 717 $palette->colors[$Key]->addRGBIncrement($ColorFactor), 718 $shadowProperties 719 ); 720 721 $this->canvas->drawAntialiasPixel( 722 new Point($Plots[$Index - 4], $Plots [$Index - 3]), 723 $palette->colors[$Key]->addRGBIncrement($ColorFactor), 724 $shadowProperties 725 ); 726 } 727 } 728 } 729 730 /** 731 * @brief Draw the polygons that form the top of a 3D pie chart 732 */ 733 private function drawPieGraphTopPolygons($iValues, $TopPlots, $EnhanceColors, $aTopPlots, ShadowProperties $shadowProperties) { 734 for($Key = count($iValues) - 1; $Key >= 0; $Key--) { 735 $this->canvas->drawFilledPolygon( 736 $TopPlots [$Key], 737 (count($TopPlots [$Key]) + 1) / 2, 738 $this->palette->colors[$Key] 739 ); 740 741 if($EnhanceColors) { 742 $En = 10; 743 } else { 744 $En = 0; 745 } 746 for($j = 0; $j <= count($aTopPlots [$Key]) - 4; $j = $j + 2) 747 $this->canvas->drawLine( 748 new Point($aTopPlots[$Key][$j], 749 $aTopPlots[$Key][$j + 1]), 750 new Point($aTopPlots [$Key] [$j + 2], 751 $aTopPlots [$Key] [$j + 3]), 752 $this->palette->colors[$Key]->addRGBIncrement($En), 753 $this->LineWidth, 754 $this->LineDotSize, 755 $shadowProperties 756 ); 757 } 758 } 759} 760