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