1<?php 2 /* 3 pPie - class to draw pie charts 4 5 Version : 2.1.3 6 Made by : Jean-Damien POGOLOTTI 7 Last Update : 09/09/11 8 9 This file can be distributed under the license you can find at : 10 11 http://www.pchart.net/license 12 13 You can find the whole class documentation on the pChart web site. 14 */ 15 16 /* Class return codes */ 17 define("PIE_NO_ABSCISSA" , 140001); 18 define("PIE_NO_DATASERIE" , 140002); 19 define("PIE_SUMISNULL" , 140003); 20 define("PIE_RENDERED" , 140000); 21 22 define("PIE_LABEL_COLOR_AUTO" , 140010); 23 define("PIE_LABEL_COLOR_MANUAL", 140011); 24 25 define("PIE_VALUE_NATURAL" , 140020); 26 define("PIE_VALUE_PERCENTAGE" , 140021); 27 28 define("PIE_VALUE_INSIDE" , 140030); 29 define("PIE_VALUE_OUTSIDE" , 140031); 30 31 /* pPie class definition */ 32 class pPie 33 { 34 var $pChartObject; 35 var $pDataObject; 36 var $LabelPos = "" ; 37 38 /* Class creator */ 39 function pPie($Object,$pDataObject) 40 { 41 /* Cache the pChart object reference */ 42 $this->pChartObject = $Object; 43 44 /* Cache the pData object reference */ 45 $this->pDataObject = $pDataObject; 46 } 47 48 /* Draw a pie chart */ 49 function draw2DPie($X,$Y,$Format="") 50 { 51 $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 60; 52 $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; 53 $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0; 54 $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0; 55 $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE; 56 $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; 57 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; 58 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; 59 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; 60 $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; 61 $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; 62 $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; 63 $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; 64 $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; 65 $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; 66 $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; 67 $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; 68 $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; 69 $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; 70 $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15; 71 $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; 72 $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; 73 $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; 74 $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; 75 $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; 76 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; 77 78 /* Data Processing */ 79 $Data = $this->pDataObject->getData(); 80 $Palette = $this->pDataObject->getPalette(); 81 82 /* Do we have an abscissa serie defined? */ 83 if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } 84 85 /* Try to find the data serie */ 86 $DataSerie = ""; 87 foreach ($Data["Series"] as $SerieName => $SerieData) 88 { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } 89 90 /* Do we have data to compute? */ 91 if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } 92 93 /* Remove unused data */ 94 list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); 95 96 /* Compute the pie sum */ 97 $SerieSum = $this->pDataObject->getSum($DataSerie); 98 99 /* Do we have data to draw? */ 100 if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } 101 102 /* Dump the real number of data to draw */ 103 $Values = ""; 104 foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) 105 { if ($Value != 0) { $Values[] = $Value; } } 106 107 /* Compute the wasted angular space between series */ 108 if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; } 109 110 /* Compute the scale */ 111 $ScaleFactor = (360 - $WastedAngular) / $SerieSum; 112 113 $RestoreShadow = $this->pChartObject->Shadow; 114 if ( $this->pChartObject->Shadow ) 115 { 116 $this->pChartObject->Shadow = FALSE; 117 118 $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE; 119 $this->draw2DPie($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat); 120 } 121 122 /* Draw the polygon pie elements */ 123 $Step = 360 / (2 * PI * $Radius); 124 $Offset = 0; $ID = 0; 125 foreach($Values as $Key => $Value) 126 { 127 if ( $Shadow ) 128 $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); 129 else 130 { 131 if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } 132 $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); 133 } 134 135 if ( !$SecondPass && !$Shadow ) 136 { 137 if ( !$Border ) 138 $Settings["Surrounding"] = 10; 139 else 140 { $Settings["BorderR"] = $BorderR; $Settings["BorderG"] = $BorderG; $Settings["BorderB"] = $BorderB; } 141 } 142 143 $Plots = ""; 144 $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; } 145 146 $Angle = ($EndAngle - $Offset)/2 + $Offset; 147 if ($DataGapAngle == 0) 148 { $X0 = $X; $Y0 = $Y; } 149 else 150 { 151 $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; 152 $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y; 153 } 154 155 $Plots[] = $X0; $Plots[] = $Y0; 156 157 158 for($i=$Offset;$i<=$EndAngle;$i=$i+$Step) 159 { 160 $Xc = cos(($i-90)*PI/180) * $Radius + $X; 161 $Yc = sin(($i-90)*PI/180) * $Radius + $Y; 162 163 if ( $SecondPass && ( $i<90 )) { $Yc++; } 164 if ( $SecondPass && ( $i>180 && $i<270 )) { $Xc++; } 165 if ( $SecondPass && ( $i>=270 )) { $Xc++; $Yc++; } 166 167 $Plots[] = $Xc; $Plots[] = $Yc; 168 } 169 170 $this->pChartObject->drawPolygon($Plots,$Settings); 171 if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); } 172 173 if ( $DrawLabels && !$Shadow && !$SecondPass ) 174 { 175 if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) 176 { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} 177 else 178 { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } 179 180 $Angle = ($EndAngle - $Offset)/2 + $Offset; 181 $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; 182 $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y; 183 184 $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; 185 186 if ( $LabelStacked ) 187 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius); 188 else 189 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); 190 } 191 192 $Offset = $i + $DataGapAngle; $ID++; 193 } 194 195 /* Second pass to smooth the angles */ 196 if ( $SecondPass ) 197 { 198 $Step = 360 / (2 * PI * $Radius); 199 $Offset = 0; $ID = 0; 200 foreach($Values as $Key => $Value) 201 { 202 $FirstPoint = TRUE; 203 if ( $Shadow ) 204 $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); 205 else 206 { 207 if ( $Border ) 208 $Settings = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB); 209 else 210 $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); 211 } 212 213 $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; } 214 215 if ($DataGapAngle == 0) 216 { $X0 = $X; $Y0 = $Y; } 217 else 218 { 219 $Angle = ($EndAngle - $Offset)/2 + $Offset; 220 $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; 221 $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius + $Y; 222 } 223 $Plots[] = $X0; $Plots[] = $Y0; 224 225 for($i=$Offset;$i<=$EndAngle;$i=$i+$Step) 226 { 227 $Xc = cos(($i-90)*PI/180) * $Radius + $X; 228 $Yc = sin(($i-90)*PI/180) * $Radius + $Y; 229 230 if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; } 231 232 $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); 233 } 234 $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); 235 236 if ( $DrawLabels && !$Shadow ) 237 { 238 if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) 239 { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} 240 else 241 { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } 242 243 $Angle = ($EndAngle - $Offset)/2 + $Offset; 244 $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; 245 $Yc = sin(($Angle-90)*PI/180) * $Radius + $Y; 246 247 $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; 248 249 if ( $LabelStacked ) 250 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius); 251 else 252 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); 253 } 254 255 $Offset = $i + $DataGapAngle; $ID++; 256 } 257 } 258 259 if ( $WriteValues != NULL && !$Shadow ) 260 { 261 $Step = 360 / (2 * PI * $Radius); 262 $Offset = 0; $ID = count($Values)-1; 263 $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha); 264 foreach($Values as $Key => $Value) 265 { 266 $EndAngle = ($Value*$ScaleFactor) + $Offset; if ( $EndAngle > 360 ) { $EndAngle = 0; } 267 $Angle = ($EndAngle - $Offset)/2 + $Offset; 268 269 if ( $ValuePosition == PIE_VALUE_OUTSIDE ) 270 { 271 $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X; 272 $Yc = sin(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $Y; 273 } 274 else 275 { 276 $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X; 277 $Yc = sin(($Angle-90)*PI/180) * ($Radius)/2 + $Y; 278 } 279 280 if ( $WriteValues == PIE_VALUE_PERCENTAGE ) 281 $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; 282 elseif ( $WriteValues == PIE_VALUE_NATURAL ) 283 $Display = $Value.$ValueSuffix; 284 285 $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings); 286 287 $Offset = $EndAngle + $DataGapAngle; $ID--; 288 } 289 } 290 291 if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } 292 293 $this->pChartObject->Shadow = $RestoreShadow; 294 295 return(PIE_RENDERED); 296 } 297 298 /* Draw a 3D pie chart */ 299 function draw3DPie($X,$Y,$Format="") 300 { 301 /* Rendering layout */ 302 $Radius = isset($Format["Radius"]) ? $Format["Radius"] : 80; 303 $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; 304 $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .5; 305 $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 20; 306 $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 0; 307 $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 0; 308 $SecondPass = isset($Format["SecondPass"]) ? $Format["SecondPass"] : TRUE; 309 $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; 310 $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; 311 $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; 312 $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; 313 $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; 314 $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; 315 $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; 316 $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; 317 $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; 318 $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE 319 $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_INSIDE; 320 $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 15; 321 $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; 322 $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; 323 $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; 324 $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; 325 $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; 326 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; 327 328 /* Error correction for overlaying rounded corners */ 329 if ( $SkewFactor < .5 ) { $SkewFactor = .5; } 330 331 /* Data Processing */ 332 $Data = $this->pDataObject->getData(); 333 $Palette = $this->pDataObject->getPalette(); 334 335 /* Do we have an abscissa serie defined? */ 336 if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } 337 338 /* Try to find the data serie */ 339 $DataSerie = ""; 340 foreach ($Data["Series"] as $SerieName => $SerieData) 341 { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } 342 343 /* Do we have data to compute? */ 344 if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } 345 346 /* Remove unused data */ 347 list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); 348 349 /* Compute the pie sum */ 350 $SerieSum = $this->pDataObject->getSum($DataSerie); 351 352 /* Do we have data to draw? */ 353 if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } 354 355 /* Dump the real number of data to draw */ 356 $Values = ""; 357 foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) 358 { if ($Value != 0) { $Values[] = $Value; } } 359 360 /* Compute the wasted angular space between series */ 361 if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; } 362 363 /* Compute the scale */ 364 $ScaleFactor = (360 - $WastedAngular) / $SerieSum; 365 366 $RestoreShadow = $this->pChartObject->Shadow; 367 if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; } 368 369 /* Draw the polygon pie elements */ 370 $Step = 360 / (2 * PI * $Radius); 371 $Offset = 360; $ID = count($Values)-1; 372 $Values = array_reverse($Values); 373 $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = ""; 374 foreach($Values as $Key => $Value) 375 { 376 if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } 377 $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); 378 379 $SliceColors[$Slice] = $Settings; 380 381 $StartAngle = $Offset; 382 $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } 383 384 if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; } 385 if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; } 386 387 if ($DataGapAngle == 0) 388 { $X0 = $X; $Y0 = $Y; } 389 else 390 { 391 $Angle = ($EndAngle - $Offset)/2 + $Offset; 392 $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; 393 $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y; 394 } 395 $Slices[$Slice][] = $X0; $Slices[$Slice][] = $Y0; $SliceAngle[$Slice][] = 0; 396 397 for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) 398 { 399 $Xc = cos(($i-90)*PI/180) * $Radius + $X; 400 $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y; 401 402 if ( ($SecondPass || $RestoreShadow ) && ( $i<90 )) { $Yc++; } 403 if ( ($SecondPass || $RestoreShadow ) && ( $i>90 && $i<180 )) { $Xc++; } 404 if ( ($SecondPass || $RestoreShadow ) && ( $i>180 && $i<270 )) { $Xc++; } 405 if ( ($SecondPass || $RestoreShadow ) && ( $i>=270 )) { $Xc++; $Yc++; } 406 407 $Slices[$Slice][] = $Xc; $Slices[$Slice][] = $Yc; $SliceAngle[$Slice][] = $i; 408 } 409 410 $Offset = $i - $DataGapAngle; $ID--; $Slice++; 411 } 412 413 /* Draw the bottom shadow if needed */ 414 if ( $RestoreShadow && ($this->pChartObject->ShadowX != 0 || $this->pChartObject->ShadowY !=0 )) 415 { 416 foreach($Slices as $SliceID => $Plots) 417 { 418 $ShadowPie = ""; 419 for($i=0;$i<count($Plots);$i=$i+2) 420 { $ShadowPie[] = $Plots[$i]+$this->pChartObject->ShadowX; $ShadowPie[] = $Plots[$i+1]+$this->pChartObject->ShadowY; } 421 422 $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa,"NoBorder"=>TRUE); 423 $this->pChartObject->drawPolygon($ShadowPie,$Settings); 424 } 425 426 $Step = 360 / (2 * PI * $Radius); 427 $Offset = 360; 428 foreach($Values as $Key => $Value) 429 { 430 $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } 431 432 for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) 433 { 434 $Xc = cos(($i-90)*PI/180) * $Radius + $X + $this->pChartObject->ShadowX; 435 $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y + $this->pChartObject->ShadowY; 436 437 $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); 438 } 439 440 $Offset = $i - $DataGapAngle; $ID--; 441 } 442 } 443 444 /* Draw the bottom pie splice */ 445 foreach($Slices as $SliceID => $Plots) 446 { 447 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 448 $this->pChartObject->drawPolygon($Plots,$Settings); 449 450 if ( $SecondPass ) 451 { 452 $Settings = $SliceColors[$SliceID]; 453 if ( $Border ) 454 { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30;; } 455 456 if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */ 457 { 458 $Angle = $SliceAngle[$SliceID][1]; 459 $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; 460 $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; 461 $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings); 462 463 $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1]; 464 $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; 465 $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; 466 $this->pChartObject->drawLine($Plots[0],$Plots[1],$Xc,$Yc,$Settings); 467 } 468 } 469 } 470 471 /* Draw the two vertical edges */ 472 $Slices = array_reverse($Slices); 473 $SliceColors = array_reverse($SliceColors); 474 foreach($Slices as $SliceID => $Plots) 475 { 476 $Settings = $SliceColors[$SliceID]; 477 $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE; 478 479 if ( $Visible[$SliceID]["Start"] && isset($Plots[2])) /* Empty error handling */ 480 { 481 $this->pChartObject->drawLine($Plots[2],$Plots[3],$Plots[2],$Plots[3]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"])); 482 $Border = ""; 483 $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight; 484 $Border[] = $Plots[2]; $Border[] = $Plots[3] - $SliceHeight; $Border[] = $Plots[2]; $Border[] = $Plots[3]; 485 $this->pChartObject->drawPolygon($Border,$Settings); 486 } 487 } 488 489 $Slices = array_reverse($Slices); 490 $SliceColors = array_reverse($SliceColors); 491 foreach($Slices as $SliceID => $Plots) 492 { 493 $Settings = $SliceColors[$SliceID]; 494 $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE; 495 if ( $Visible[$SliceID]["End"] ) 496 { 497 $this->pChartObject->drawLine($Plots[count($Plots)-2],$Plots[count($Plots)-1],$Plots[count($Plots)-2],$Plots[count($Plots)-1]- $SliceHeight,array("R"=>$Settings["R"],"G"=>$Settings["G"],"B"=>$Settings["B"])); 498 499 $Border = ""; 500 $Border[] = $Plots[0]; $Border[] = $Plots[1]; $Border[] = $Plots[0]; $Border[] = $Plots[1] - $SliceHeight; 501 $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1] - $SliceHeight; $Border[] = $Plots[count($Plots)-2]; $Border[] = $Plots[count($Plots)-1]; 502 $this->pChartObject->drawPolygon($Border,$Settings); 503 } 504 } 505 506 /* Draw the rounded edges */ 507 foreach($Slices as $SliceID => $Plots) 508 { 509 $Settings = $SliceColors[$SliceID]; 510 $Settings["R"]+= 10; $Settings["G"]+= 10; $Settings["B"]+= 10; $Settings["NoBorder"] = TRUE; 511 512 for ($j=2;$j<count($Plots)-2;$j=$j+2) 513 { 514 $Angle = $SliceAngle[$SliceID][$j/2]; 515 if ( $Angle < 270 && $Angle > 90 ) 516 { 517 $Border = ""; 518 $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1]; 519 $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3]; 520 $Border[] = $Plots[$j+2]; $Border[] = $Plots[$j+3] - $SliceHeight; 521 $Border[] = $Plots[$j]; $Border[] = $Plots[$j+1] - $SliceHeight; 522 $this->pChartObject->drawPolygon($Border,$Settings); 523 } 524 } 525 526 if ( $SecondPass ) 527 { 528 $Settings = $SliceColors[$SliceID]; 529 if ( $Border ) 530 { $Settings["R"]+= 30; $Settings["G"]+= 30; $Settings["B"]+= 30; } 531 532 if ( isset($SliceAngle[$SliceID][1]) ) /* Empty error handling */ 533 { 534 $Angle = $SliceAngle[$SliceID][1]; 535 if ( $Angle < 270 && $Angle > 90 ) 536 { 537 $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; 538 $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; 539 $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); 540 } 541 } 542 543 $Angle = $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1]; 544 if ( $Angle < 270 && $Angle > 90 ) 545 { 546 $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; 547 $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y; 548 $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); 549 } 550 551 if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 270 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 270 ) 552 { 553 $Xc = cos((270-90)*PI/180) * $Radius + $X; 554 $Yc = sin((270-90)*PI/180) * $Radius*$SkewFactor + $Y; 555 $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); 556 } 557 558 if ( isset($SliceAngle[$SliceID][1]) && $SliceAngle[$SliceID][1] > 90 && $SliceAngle[$SliceID][count($SliceAngle[$SliceID])-1] < 90 ) 559 { 560 $Xc = cos((0)*PI/180) * $Radius + $X; 561 $Yc = sin((0)*PI/180) * $Radius*$SkewFactor + $Y; 562 $this->pChartObject->drawLine($Xc,$Yc,$Xc,$Yc-$SliceHeight,$Settings); 563 } 564 565 } 566 } 567 568 /* Draw the top splice */ 569 foreach($Slices as $SliceID => $Plots) 570 { 571 $Settings = $SliceColors[$SliceID]; 572 $Settings["R"]+= 20; $Settings["G"]+= 20; $Settings["B"]+= 20; 573 574 $Top = ""; 575 for($j=0;$j<count($Plots);$j=$j+2) { $Top[] = $Plots[$j]; $Top[] = $Plots[$j+1]- $SliceHeight; } 576 $this->pChartObject->drawPolygon($Top,$Settings); 577 578 if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Top),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][count($Slices)-$SliceID-1],$Values[$SliceID]); } 579 } 580 581 582 /* Second pass to smooth the angles */ 583 if ( $SecondPass ) 584 { 585 $Step = 360 / (2 * PI * $Radius); 586 $Offset = 360; $ID = count($Values)-1; 587 foreach($Values as $Key => $Value) 588 { 589 $FirstPoint = TRUE; 590 if ( $Shadow ) 591 $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); 592 else 593 { 594 if ( $Border ) 595 { $Settings = array("R"=>$Palette[$ID]["R"]+30,"G"=>$Palette[$ID]["G"]+30,"B"=>$Palette[$ID]["B"]+30,"Alpha"=>$Palette[$ID]["Alpha"]); } 596 else 597 $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); 598 } 599 600 $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } 601 602 if ($DataGapAngle == 0) 603 { $X0 = $X; $Y0 = $Y- $SliceHeight; } 604 else 605 { 606 $Angle = ($EndAngle - $Offset)/2 + $Offset; 607 $X0 = cos(($Angle-90)*PI/180) * $DataGapRadius + $X; 608 $Y0 = sin(($Angle-90)*PI/180) * $DataGapRadius*$SkewFactor + $Y - $SliceHeight; 609 } 610 $Plots[] = $X0; $Plots[] = $Y0; 611 612 for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) 613 { 614 $Xc = cos(($i-90)*PI/180) * $Radius + $X; 615 $Yc = sin(($i-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight; 616 617 if ( $FirstPoint ) { $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); } { $FirstPoint = FALSE; } 618 619 $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); 620 if ($i < 270 && $i > 90 ) { $this->pChartObject->drawAntialiasPixel($Xc,$Yc+$SliceHeight,$Settings); } 621 } 622 $this->pChartObject->drawLine($Xc,$Yc,$X0,$Y0,$Settings); 623 624 $Offset = $i - $DataGapAngle; $ID--; 625 } 626 } 627 628 if ( $WriteValues != NULL ) 629 { 630 $Step = 360 / (2 * PI * $Radius); 631 $Offset = 360; $ID = count($Values)-1; 632 $Settings = array("Align"=>TEXT_ALIGN_MIDDLEMIDDLE,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB,"Alpha"=>$ValueAlpha); 633 foreach($Values as $Key => $Value) 634 { 635 $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } 636 637 $Angle = ($EndAngle - $Offset)/2 + $Offset; 638 639 if ( $ValuePosition == PIE_VALUE_OUTSIDE ) 640 { 641 $Xc = cos(($Angle-90)*PI/180) * ($Radius+$ValuePadding) + $X; 642 $Yc = sin(($Angle-90)*PI/180) * (($Radius*$SkewFactor)+$ValuePadding) + $Y - $SliceHeight; 643 } 644 else 645 { 646 $Xc = cos(($Angle-90)*PI/180) * ($Radius)/2 + $X; 647 $Yc = sin(($Angle-90)*PI/180) * ($Radius*$SkewFactor)/2 + $Y - $SliceHeight; 648 } 649 650 if ( $WriteValues == PIE_VALUE_PERCENTAGE ) 651 $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; 652 elseif ( $WriteValues == PIE_VALUE_NATURAL ) 653 $Display = $Value.$ValueSuffix; 654 655 $this->pChartObject->drawText($Xc,$Yc,$Display,$Settings); 656 657 $Offset = $EndAngle - $DataGapAngle; $ID--; 658 } 659 } 660 661 if ( $DrawLabels ) 662 { 663 $Step = 360 / (2 * PI * $Radius); 664 $Offset = 360; $ID = count($Values)-1; 665 foreach($Values as $Key => $Value) 666 { 667 if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) 668 { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} 669 else 670 { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } 671 672 $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } 673 674 $Angle = ($EndAngle - $Offset)/2 + $Offset; 675 $Xc = cos(($Angle-90)*PI/180) * $Radius + $X; 676 $Yc = sin(($Angle-90)*PI/180) * $Radius*$SkewFactor + $Y - $SliceHeight; 677 678 if ( isset($Data["Series"][$Data["Abscissa"]]["Data"][$ID]) ) 679 { 680 $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$ID]; 681 682 if ( $LabelStacked ) 683 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$Radius,TRUE); 684 else 685 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); 686 } 687 688 $Offset = $EndAngle - $DataGapAngle; $ID--; 689 } 690 } 691 692 if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } 693 694 $this->pChartObject->Shadow = $RestoreShadow; 695 696 return(PIE_RENDERED); 697 } 698 699 /* Draw the legend of pie chart */ 700 function drawPieLegend($X,$Y,$Format="") 701 { 702 $FontName = isset($Format["FontName"]) ? $Format["FontName"] : $this->pChartObject->FontName; 703 $FontSize = isset($Format["FontSize"]) ? $Format["FontSize"] : $this->pChartObject->FontSize; 704 $FontR = isset($Format["FontR"]) ? $Format["FontR"] : $this->pChartObject->FontColorR; 705 $FontG = isset($Format["FontG"]) ? $Format["FontG"] : $this->pChartObject->FontColorG; 706 $FontB = isset($Format["FontB"]) ? $Format["FontB"] : $this->pChartObject->FontColorB; 707 $BoxSize = isset($Format["BoxSize"]) ? $Format["BoxSize"] : 5; 708 $Margin = isset($Format["Margin"]) ? $Format["Margin"] : 5; 709 $R = isset($Format["R"]) ? $Format["R"] : 200; 710 $G = isset($Format["G"]) ? $Format["G"] : 200; 711 $B = isset($Format["B"]) ? $Format["B"] : 200; 712 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 713 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; 714 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; 715 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; 716 $Surrounding = isset($Format["Surrounding"]) ? $Format["Surrounding"] : NULL; 717 $Style = isset($Format["Style"]) ? $Format["Style"] : LEGEND_ROUND; 718 $Mode = isset($Format["Mode"]) ? $Format["Mode"] : LEGEND_VERTICAL; 719 720 if ( $Surrounding != NULL ) { $BorderR = $R + $Surrounding; $BorderG = $G + $Surrounding; $BorderB = $B + $Surrounding; } 721 722 $YStep = max($this->pChartObject->FontSize,$BoxSize) + 5; 723 $XStep = $BoxSize + 5; 724 725 /* Data Processing */ 726 $Data = $this->pDataObject->getData(); 727 $Palette = $this->pDataObject->getPalette(); 728 729 /* Do we have an abscissa serie defined? */ 730 if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } 731 732 $Boundaries = ""; $Boundaries["L"] = $X; $Boundaries["T"] = $Y; $Boundaries["R"] = 0; $Boundaries["B"] = 0; $vY = $Y; $vX = $X; 733 foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value) 734 { 735 $BoxArray = $this->pChartObject->getTextBox($vX+$BoxSize+4,$vY+$BoxSize/2,$FontName,$FontSize,0,$Value); 736 737 if ( $Mode == LEGEND_VERTICAL ) 738 { 739 if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; } 740 if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } 741 if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; } 742 $vY=$vY+$YStep; 743 } 744 elseif ( $Mode == LEGEND_HORIZONTAL ) 745 { 746 if ( $Boundaries["T"] > $BoxArray[2]["Y"]+$BoxSize/2 ) { $Boundaries["T"] = $BoxArray[2]["Y"]+$BoxSize/2; } 747 if ( $Boundaries["R"] < $BoxArray[1]["X"]+2 ) { $Boundaries["R"] = $BoxArray[1]["X"]+2; } 748 if ( $Boundaries["B"] < $BoxArray[1]["Y"]+2+$BoxSize/2 ) { $Boundaries["B"] = $BoxArray[1]["Y"]+2+$BoxSize/2; } 749 $vX=$Boundaries["R"]+$XStep; 750 } 751 } 752 $vY=$vY-$YStep; $vX=$vX-$XStep; 753 754 $TopOffset = $Y - $Boundaries["T"]; 755 if ( $Boundaries["B"]-($vY+$BoxSize) < $TopOffset ) { $Boundaries["B"] = $vY+$BoxSize+$TopOffset; } 756 757 if ( $Style == LEGEND_ROUND ) 758 $this->pChartObject->drawRoundedFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); 759 elseif ( $Style == LEGEND_BOX ) 760 $this->pChartObject->drawFilledRectangle($Boundaries["L"]-$Margin,$Boundaries["T"]-$Margin,$Boundaries["R"]+$Margin,$Boundaries["B"]+$Margin,array("R"=>$R,"G"=>$G,"B"=>$B,"Alpha"=>$Alpha,"BorderR"=>$BorderR,"BorderG"=>$BorderG,"BorderB"=>$BorderB)); 761 762 $RestoreShadow = $this->pChartObject->Shadow; $this->pChartObject->Shadow = FALSE; 763 foreach($Data["Series"][$Data["Abscissa"]]["Data"] as $Key => $Value) 764 { 765 $R = $Palette[$Key]["R"]; $G = $Palette[$Key]["G"]; $B = $Palette[$Key]["B"]; 766 767 $this->pChartObject->drawFilledRectangle($X+1,$Y+1,$X+$BoxSize+1,$Y+$BoxSize+1,array("R"=>0,"G"=>0,"B"=>0,"Alpha"=>20)); 768 $this->pChartObject->drawFilledRectangle($X,$Y,$X+$BoxSize,$Y+$BoxSize,array("R"=>$R,"G"=>$G,"B"=>$B,"Surrounding"=>20)); 769 if ( $Mode == LEGEND_VERTICAL ) 770 { 771 $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize)); 772 $Y=$Y+$YStep; 773 } 774 elseif ( $Mode == LEGEND_HORIZONTAL ) 775 { 776 $BoxArray = $this->pChartObject->drawText($X+$BoxSize+4,$Y+$BoxSize/2,$Value,array("R"=>$FontR,"G"=>$FontG,"B"=>$FontB,"Align"=>TEXT_ALIGN_MIDDLELEFT,"FontName"=>$FontName,"FontSize"=>$FontSize)); 777 $X=$BoxArray[1]["X"]+2+$XStep; 778 } 779 } 780 781 $this->Shadow = $RestoreShadow; 782 } 783 784 /* Set the color of the specified slice */ 785 function setSliceColor($SliceID,$Format="") 786 { 787 $R = isset($Format["R"]) ? $Format["R"] : 0; 788 $G = isset($Format["G"]) ? $Format["G"] : 0; 789 $B = isset($Format["B"]) ? $Format["B"] : 0; 790 $Alpha = isset($Format["Alpha"]) ? $Format["Alpha"] : 100; 791 792 $this->pDataObject->Palette[$SliceID]["R"] = $R; 793 $this->pDataObject->Palette[$SliceID]["G"] = $G; 794 $this->pDataObject->Palette[$SliceID]["B"] = $B; 795 $this->pDataObject->Palette[$SliceID]["Alpha"] = $Alpha; 796 } 797 798 /* Internally used compute the label positions */ 799 function writePieLabel($X,$Y,$Label,$Angle,$Settings,$Stacked,$Xc=0,$Yc=0,$Radius=0,$Reversed=FALSE) 800 { 801 $LabelOffset = 30; 802 $FontName = $this->pChartObject->FontName; 803 $FontSize = $this->pChartObject->FontSize; 804 805 if ( !$Stacked ) 806 { 807 $Settings["Angle"] = 360-$Angle; 808 $Settings["Length"] = 25; 809 $Settings["Size"] = 8; 810 811 $this->pChartObject->drawArrowLabel($X,$Y," ".$Label." ",$Settings); 812 } 813 else 814 { 815 $X2 = cos(deg2rad($Angle-90))*20+$X; 816 $Y2 = sin(deg2rad($Angle-90))*20+$Y; 817 818 $TxtPos = $this->pChartObject->getTextBox($X,$Y,$FontName,$FontSize,0,$Label); 819 $Height = $TxtPos[0]["Y"] - $TxtPos[2]["Y"]; 820 $YTop = $Y2 - $Height/2 - 2; 821 $YBottom = $Y2 + $Height/2 + 2; 822 823 if ( $this->LabelPos != "" ) 824 { 825 $Done = FALSE; 826 foreach($this->LabelPos as $Key => $Settings) 827 { 828 if ( !$Done ) 829 { 830 if ( $Angle <= 90 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) 831 { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; } 832 if ( $Angle > 90 && $Angle <= 180 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) 833 { $this->shift(0,180,-($Height+2),$Reversed); $Done = TRUE; } 834 if ( $Angle > 180 && $Angle <= 270 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) 835 { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; } 836 if ( $Angle > 270 && $Angle <= 360 && (($YTop >= $Settings["YTop"] && $YTop <= $Settings["YBottom"]) || ($YBottom >= $Settings["YTop"] && $YBottom <= $Settings["YBottom"]))) 837 { $this->shift(180,360,($Height+2),$Reversed); $Done = TRUE; } 838 } 839 } 840 } 841 842 $LabelSettings = array("YTop"=>$YTop,"YBottom"=>$YBottom,"Label"=>$Label,"Angle"=>$Angle,"X1"=>$X,"Y1"=>$Y,"X2"=>$X2,"Y2"=>$Y2); 843 if ( $Angle <= 180 ) { $LabelSettings["X3"] = $Xc+$Radius+$LabelOffset; } 844 if ( $Angle > 180 ) { $LabelSettings["X3"] = $Xc-$Radius-$LabelOffset; } 845 $this->LabelPos[] = $LabelSettings; 846 } 847 } 848 849 /* Internally used to shift label positions */ 850 function shift($StartAngle,$EndAngle,$Offset,$Reversed) 851 { 852 if ( $Reversed ) { $Offset = -$Offset; } 853 foreach($this->LabelPos as $Key => $Settings) 854 { 855 if ( $Settings["Angle"] > $StartAngle && $Settings["Angle"] <= $EndAngle ) { $this->LabelPos[$Key]["YTop"] = $Settings["YTop"] + $Offset; $this->LabelPos[$Key]["YBottom"] = $Settings["YBottom"] + $Offset; $this->LabelPos[$Key]["Y2"] = $Settings["Y2"] + $Offset; } 856 } 857 } 858 859 /* Internally used to write the re-computed labels */ 860 function writeShiftedLabels() 861 { 862 if ( $this->LabelPos == "" ) { return(0); } 863 foreach($this->LabelPos as $Key => $Settings) 864 { 865 $X1 = $Settings["X1"]; $Y1 = $Settings["Y1"]; 866 $X2 = $Settings["X2"]; $Y2 = $Settings["Y2"]; 867 $X3 = $Settings["X3"]; 868 $Angle = $Settings["Angle"]; 869 $Label = $Settings["Label"]; 870 871 $this->pChartObject->drawArrow($X2,$Y2,$X1,$Y1,array("Size"=>8)); 872 if ( $Angle <= 180 ) 873 { 874 $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2); 875 $this->pChartObject->drawText($X3+2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLELEFT)); 876 } 877 else 878 { 879 $this->pChartObject->drawLine($X2,$Y2,$X3,$Y2); 880 $this->pChartObject->drawText($X3-2,$Y2,$Label,array("Align"=>TEXT_ALIGN_MIDDLERIGHT)); 881 } 882 } 883 } 884 885 /* Draw a ring chart */ 886 function draw2DRing($X,$Y,$Format="") 887 { 888 $OuterRadius = isset($Format["Radius"]) ? $Format["Radius"] : 60; 889 $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; 890 $InnerRadius = isset($Format["Radius"]) ? $Format["Radius"] : 30; 891 $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; 892 $BorderR = isset($Format["BorderR"]) ? $Format["BorderR"] : 255; 893 $BorderG = isset($Format["BorderG"]) ? $Format["BorderG"] : 255; 894 $BorderB = isset($Format["BorderB"]) ? $Format["BorderB"] : 255; 895 $BorderAlpha = isset($Format["BorderAlpha"]) ? $Format["BorderAlpha"] : 100; 896 $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; 897 $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; 898 $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; 899 $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; 900 $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; 901 $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; 902 $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; 903 $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; 904 $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : NULL; //PIE_VALUE_PERCENTAGE 905 $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : 5; 906 $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; 907 $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; 908 $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; 909 $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; 910 $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; 911 $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; 912 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; 913 914 /* Data Processing */ 915 $Data = $this->pDataObject->getData(); 916 $Palette = $this->pDataObject->getPalette(); 917 918 /* Do we have an abscissa serie defined? */ 919 if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } 920 921 /* Try to find the data serie */ 922 $DataSerie = ""; 923 foreach ($Data["Series"] as $SerieName => $SerieData) 924 { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } 925 926 /* Do we have data to compute? */ 927 if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } 928 929 /* Remove unused data */ 930 list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); 931 932 /* Compute the pie sum */ 933 $SerieSum = $this->pDataObject->getSum($DataSerie); 934 935 /* Do we have data to draw? */ 936 if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } 937 938 /* Dump the real number of data to draw */ 939 $Values = ""; 940 foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) 941 { if ($Value != 0) { $Values[] = $Value; } } 942 943 /* Compute the wasted angular space between series */ 944 if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = 0; } // count($Values) 945 946 /* Compute the scale */ 947 $ScaleFactor = (360 - $WastedAngular) / $SerieSum; 948 949 $RestoreShadow = $this->pChartObject->Shadow; 950 if ( $this->pChartObject->Shadow ) 951 { 952 $this->pChartObject->Shadow = FALSE; 953 954 $ShadowFormat = $Format; $ShadowFormat["Shadow"] = TRUE; 955 $this->draw2DRing($X+$this->pChartObject->ShadowX,$Y+$this->pChartObject->ShadowY,$ShadowFormat); 956 } 957 958 /* Draw the polygon pie elements */ 959 $Step = 360 / (2 * PI * $OuterRadius); 960 $Offset = 0; $ID = 0; 961 foreach($Values as $Key => $Value) 962 { 963 if ( $Shadow ) 964 { 965 $Settings = array("R"=>$this->pChartObject->ShadowR,"G"=>$this->pChartObject->ShadowG,"B"=>$this->pChartObject->ShadowB,"Alpha"=>$this->pChartObject->Shadowa); 966 $BorderColor = $Settings; 967 } 968 else 969 { 970 if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } 971 $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); 972 973 if ( $Border ) 974 $BorderColor = array("R"=>$BorderR,"G"=>$BorderG,"B"=>$BorderB,"Alpha"=>$BorderAlpha); 975 else 976 $BorderColor = $Settings; 977 } 978 979 $Plots = ""; $Boundaries = ""; $AAPixels = ""; 980 $EndAngle = $Offset+($Value*$ScaleFactor); if ( $EndAngle > 360 ) { $EndAngle = 360; } 981 for($i=$Offset;$i<=$EndAngle;$i=$i+$Step) 982 { 983 $Xc = cos(($i-90)*PI/180) * $OuterRadius + $X; 984 $Yc = sin(($i-90)*PI/180) * $OuterRadius + $Y; 985 986 if ( !isset($Boundaries[0]["X1"]) ) { $Boundaries[0]["X1"] = $Xc; $Boundaries[0]["Y1"] = $Yc; } 987 $AAPixels[] = array($Xc,$Yc); 988 989 if ( $i<90 ) { $Yc++; } 990 if ( $i>180 && $i<270 ) { $Xc++; } 991 if ( $i>=270 ) { $Xc++; $Yc++; } 992 993 $Plots[] = $Xc; $Plots[] = $Yc; 994 } 995 $Boundaries[1]["X1"] = $Xc; $Boundaries[1]["Y1"] = $Yc; 996 $Lasti = $EndAngle; 997 998 for($i=$EndAngle;$i>=$Offset;$i=$i-$Step) 999 { 1000 $Xc = cos(($i-90)*PI/180) * ($InnerRadius-1) + $X; 1001 $Yc = sin(($i-90)*PI/180) * ($InnerRadius-1) + $Y; 1002 1003 if ( !isset($Boundaries[1]["X2"]) ) { $Boundaries[1]["X2"] = $Xc; $Boundaries[1]["Y2"] = $Yc; } 1004 $AAPixels[] = array($Xc,$Yc); 1005 1006 $Xc = cos(($i-90)*PI/180) * $InnerRadius + $X; 1007 $Yc = sin(($i-90)*PI/180) * $InnerRadius + $Y; 1008 1009 if ( $i<90 ) { $Yc++; } 1010 if ( $i>180 && $i<270 ) { $Xc++; } 1011 if ( $i>=270 ) { $Xc++; $Yc++; } 1012 1013 $Plots[] = $Xc; $Plots[] = $Yc; 1014 } 1015 $Boundaries[0]["X2"] = $Xc; $Boundaries[0]["Y2"] = $Yc; 1016 1017 /* Draw the polygon */ 1018 $this->pChartObject->drawPolygon($Plots,$Settings); 1019 if ( $RecordImageMap && !$Shadow ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots),$this->pChartObject->toHTMLColor($Palette[$ID]["R"],$Palette[$ID]["G"],$Palette[$ID]["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$Key],$Value); } 1020 1021 /* Smooth the edges using AA */ 1022 foreach($AAPixels as $iKey => $Pos ) { $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$BorderColor); } 1023 $this->pChartObject->drawLine($Boundaries[0]["X1"],$Boundaries[0]["Y1"],$Boundaries[0]["X2"],$Boundaries[0]["Y2"],$BorderColor); 1024 $this->pChartObject->drawLine($Boundaries[1]["X1"],$Boundaries[1]["Y1"],$Boundaries[1]["X2"],$Boundaries[1]["Y2"],$BorderColor); 1025 1026 if ( $DrawLabels && !$Shadow ) 1027 { 1028 if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) 1029 { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} 1030 else 1031 { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } 1032 1033 $Angle = ($EndAngle - $Offset)/2 + $Offset; 1034 $Xc = cos(($Angle-90)*PI/180) * $OuterRadius + $X; 1035 $Yc = sin(($Angle-90)*PI/180) * $OuterRadius + $Y; 1036 1037 $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; 1038 1039 if ( $LabelStacked ) 1040 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius); 1041 else 1042 $this->writePieLabel($Xc,$Yc,$Label,$Angle,$Settings,FALSE); 1043 } 1044 1045 $Offset = $Lasti; $ID++; 1046 } 1047 1048 if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } 1049 1050 if ( $WriteValues && !$Shadow ) 1051 { 1052 $Step = 360 / (2 * PI * $OuterRadius); 1053 $Offset = 0; 1054 foreach($Values as $Key => $Value) 1055 { 1056 $EndAngle = $Offset+($Value*$ScaleFactor); 1057 if ( $EndAngle > 360 ) { $EndAngle = 360; } 1058 1059 $Angle = $Offset+($Value*$ScaleFactor)/2; 1060 if ( $ValuePosition == PIE_VALUE_OUTSIDE ) 1061 { 1062 $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $X; 1063 $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$ValuePadding) + $Y; 1064 if ( $Angle >=0 && $Angle <= 90 ) { $Align = TEXT_ALIGN_BOTTOMLEFT; } 1065 if ( $Angle > 90 && $Angle <= 180 ) { $Align = TEXT_ALIGN_TOPLEFT; } 1066 if ( $Angle > 180 && $Angle <= 270 ) { $Align = TEXT_ALIGN_TOPRIGHT; } 1067 if ( $Angle > 270 ) { $Align = TEXT_ALIGN_BOTTOMRIGHT; } 1068 } 1069 else 1070 { 1071 $Xc = cos(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $X; 1072 $Yc = sin(($Angle-90)*PI/180) * (($OuterRadius-$InnerRadius)/2+$InnerRadius) + $Y; 1073 $Align = TEXT_ALIGN_MIDDLEMIDDLE; 1074 } 1075 1076 if ( $WriteValues == PIE_VALUE_PERCENTAGE ) 1077 $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; 1078 elseif ( $WriteValues == PIE_VALUE_NATURAL ) 1079 $Display = $Value.$ValueSuffix; 1080 else 1081 $Label = ""; 1082 1083 $this->pChartObject->drawText($Xc,$Yc,$Display,array("Align"=>$Align,"R"=>$ValueR,"G"=>$ValueG,"B"=>$ValueB)); 1084 $Offset = $EndAngle; 1085 } 1086 } 1087 1088 $this->pChartObject->Shadow = $RestoreShadow; 1089 1090 return(PIE_RENDERED); 1091 } 1092 1093 /* Draw a 3D ring chart */ 1094 function draw3DRing($X,$Y,$Format="") 1095 { 1096 $OuterRadius = isset($Format["OuterRadius"]) ? $Format["OuterRadius"] : 100; 1097 $Precision = isset($Format["Precision"]) ? $Format["Precision"] : 0; 1098 $InnerRadius = isset($Format["InnerRadius"]) ? $Format["InnerRadius"] : 30; 1099 $SkewFactor = isset($Format["SkewFactor"]) ? $Format["SkewFactor"] : .6; 1100 $SliceHeight = isset($Format["SliceHeight"]) ? $Format["SliceHeight"] : 10; 1101 $DataGapAngle = isset($Format["DataGapAngle"]) ? $Format["DataGapAngle"] : 10; 1102 $DataGapRadius = isset($Format["DataGapRadius"]) ? $Format["DataGapRadius"] : 10; 1103 $Border = isset($Format["Border"]) ? $Format["Border"] : FALSE; 1104 $Shadow = isset($Format["Shadow"]) ? $Format["Shadow"] : FALSE; 1105 $DrawLabels = isset($Format["DrawLabels"]) ? $Format["DrawLabels"] : FALSE; 1106 $LabelStacked = isset($Format["LabelStacked"]) ? $Format["LabelStacked"] : FALSE; 1107 $LabelColor = isset($Format["LabelColor"]) ? $Format["LabelColor"] : PIE_LABEL_COLOR_MANUAL; 1108 $LabelR = isset($Format["LabelR"]) ? $Format["LabelR"] : 0; 1109 $LabelG = isset($Format["LabelG"]) ? $Format["LabelG"] : 0; 1110 $LabelB = isset($Format["LabelB"]) ? $Format["LabelB"] : 0; 1111 $LabelAlpha = isset($Format["LabelAlpha"]) ? $Format["LabelAlpha"] : 100; 1112 $Cf = isset($Format["Cf"]) ? $Format["Cf"] : 20; 1113 $WriteValues = isset($Format["WriteValues"]) ? $Format["WriteValues"] : PIE_VALUE_NATURAL; 1114 $ValuePadding = isset($Format["ValuePadding"]) ? $Format["ValuePadding"] : $SliceHeight + 15; 1115 $ValuePosition = isset($Format["ValuePosition"]) ? $Format["ValuePosition"] : PIE_VALUE_OUTSIDE; 1116 $ValueSuffix = isset($Format["ValueSuffix"]) ? $Format["ValueSuffix"] : ""; 1117 $ValueR = isset($Format["ValueR"]) ? $Format["ValueR"] : 255; 1118 $ValueG = isset($Format["ValueG"]) ? $Format["ValueG"] : 255; 1119 $ValueB = isset($Format["ValueB"]) ? $Format["ValueB"] : 255; 1120 $ValueAlpha = isset($Format["ValueAlpha"]) ? $Format["ValueAlpha"] : 100; 1121 $RecordImageMap = isset($Format["RecordImageMap"]) ? $Format["RecordImageMap"] : FALSE; 1122 1123 /* Error correction for overlaying rounded corners */ 1124 if ( $SkewFactor < .5 ) { $SkewFactor = .5; } 1125 1126 /* Data Processing */ 1127 $Data = $this->pDataObject->getData(); 1128 $Palette = $this->pDataObject->getPalette(); 1129 1130 /* Do we have an abscissa serie defined? */ 1131 if ( $Data["Abscissa"] == "" ) { return(PIE_NO_ABSCISSA); } 1132 1133 /* Try to find the data serie */ 1134 $DataSerie = ""; 1135 foreach ($Data["Series"] as $SerieName => $SerieData) 1136 { if ( $SerieName != $Data["Abscissa"]) { $DataSerie = $SerieName; } } 1137 1138 /* Do we have data to compute? */ 1139 if ( $DataSerie == "" ) { return(PIE_NO_DATASERIE); } 1140 1141 /* Remove unused data */ 1142 list($Data,$Palette) = $this->clean0Values($Data,$Palette,$DataSerie,$Data["Abscissa"]); 1143 1144 /* Compute the pie sum */ 1145 $SerieSum = $this->pDataObject->getSum($DataSerie); 1146 1147 /* Do we have data to draw? */ 1148 if ( $SerieSum == 0 ) { return(PIE_SUMISNULL); } 1149 1150 /* Dump the real number of data to draw */ 1151 $Values = ""; 1152 foreach ($Data["Series"][$DataSerie]["Data"] as $Key => $Value) 1153 { if ($Value != 0) { $Values[] = $Value; } } 1154 1155 /* Compute the wasted angular space between series */ 1156 if (count($Values)==1) { $WastedAngular = 0; } else { $WastedAngular = count($Values) * $DataGapAngle; } 1157 1158 /* Compute the scale */ 1159 $ScaleFactor = (360 - $WastedAngular) / $SerieSum; 1160 1161 $RestoreShadow = $this->pChartObject->Shadow; 1162 if ( $this->pChartObject->Shadow ) { $this->pChartObject->Shadow = FALSE; } 1163 1164 /* Draw the polygon ring elements */ 1165 $Offset = 360; $ID = count($Values)-1; 1166 $Values = array_reverse($Values); 1167 $Slice = 0; $Slices = ""; $SliceColors = ""; $Visible = ""; $SliceAngle = ""; 1168 foreach($Values as $Key => $Value) 1169 { 1170 if ( !isset($Palette[$ID]["R"]) ) { $Color = $this->pChartObject->getRandomColor(); $Palette[$ID] = $Color; $this->pDataObject->savePalette($ID,$Color); } 1171 $Settings = array("R"=>$Palette[$ID]["R"],"G"=>$Palette[$ID]["G"],"B"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]); 1172 1173 $SliceColors[$Slice] = $Settings; 1174 1175 $StartAngle = $Offset; 1176 $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } 1177 1178 if ( $StartAngle > 180 ) { $Visible[$Slice]["Start"] = TRUE; } else { $Visible[$Slice]["Start"] = TRUE; } 1179 if ( $EndAngle < 180 ) { $Visible[$Slice]["End"] = FALSE; } else { $Visible[$Slice]["End"] = TRUE; } 1180 1181 $Step = (360 / (2 * PI * $OuterRadius))/2; 1182 $OutX1 = VOID; $OutY1 = VOID; 1183 for($i=$Offset;$i>=$EndAngle;$i=$i-$Step) 1184 { 1185 $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2) + $X; 1186 $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-2)*$SkewFactor + $Y; 1187 $Slices[$Slice]["AA"][] = array($Xc,$Yc); 1188 1189 $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1) + $X; 1190 $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius-1)*$SkewFactor + $Y; 1191 $Slices[$Slice]["AA"][] = array($Xc,$Yc); 1192 1193 $Xc = cos(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X; 1194 $Yc = sin(($i-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y; 1195 $this->pChartObject->drawAntialiasPixel($Xc,$Yc,$Settings); 1196 1197 if ( $OutX1 == VOID ) { $OutX1 = $Xc; $OutY1 = $Yc; } 1198 1199 if ( $i<90 ) { $Yc++; } 1200 if ( $i>90 && $i<180 ) { $Xc++; } 1201 if ( $i>180 && $i<270 ) { $Xc++; } 1202 if ( $i>=270 ) { $Xc++; $Yc++; } 1203 1204 $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc); 1205 $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight; 1206 $Slices[$Slice]["Angle"][] = $i; 1207 } 1208 $OutX2 = $Xc; $OutY2 = $Yc; 1209 1210 $Slices[$Slice]["Angle"][] = VOID; 1211 $Lasti = $i; 1212 1213 $Step = (360 / (2 * PI * $InnerRadius))/2; 1214 $InX1 = VOID; $InY1 = VOID; 1215 for($i=$EndAngle;$i<=$Offset;$i=$i+$Step) 1216 { 1217 $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1) + $X; 1218 $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius-1)*$SkewFactor + $Y; 1219 $Slices[$Slice]["AA"][] = array($Xc,$Yc); 1220 1221 $Xc = cos(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius) + $X; 1222 $Yc = sin(($i-90)*PI/180) * ($InnerRadius+$DataGapRadius)*$SkewFactor + $Y; 1223 $Slices[$Slice]["AA"][] = array($Xc,$Yc); 1224 1225 if ( $InX1 == VOID ) { $InX1 = $Xc; $InY1 = $Yc; } 1226 1227 if ( $i<90 ) { $Yc++; } 1228 if ( $i>90 && $i<180 ) { $Xc++; } 1229 if ( $i>180 && $i<270 ) { $Xc++; } 1230 if ( $i>=270 ) { $Xc++; $Yc++; } 1231 1232 $Slices[$Slice]["BottomPoly"][] = floor($Xc); $Slices[$Slice]["BottomPoly"][] = floor($Yc); 1233 $Slices[$Slice]["TopPoly"][] = floor($Xc); $Slices[$Slice]["TopPoly"][] = floor($Yc)-$SliceHeight; 1234 $Slices[$Slice]["Angle"][] = $i; 1235 } 1236 $InX2 = $Xc; $InY2 = $Yc; 1237 1238 $Slices[$Slice]["InX1"] = $InX1; $Slices[$Slice]["InY1"] = $InY1; 1239 $Slices[$Slice]["InX2"] = $InX2; $Slices[$Slice]["InY2"] = $InY2; 1240 $Slices[$Slice]["OutX1"] = $OutX1; $Slices[$Slice]["OutY1"] = $OutY1; 1241 $Slices[$Slice]["OutX2"] = $OutX2; $Slices[$Slice]["OutY2"] = $OutY2; 1242 1243 $Offset = $Lasti - $DataGapAngle; $ID--; $Slice++; 1244 } 1245 1246 /* Draw the bottom pie splice */ 1247 foreach($Slices as $SliceID => $Plots) 1248 { 1249 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 1250 $this->pChartObject->drawPolygon($Plots["BottomPoly"],$Settings); 1251 1252 foreach($Plots["AA"] as $Key => $Pos) 1253 $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1],$Settings); 1254 1255 $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["OutX2"],$Plots["OutY2"],$Settings); 1256 $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["OutX1"],$Plots["OutY1"],$Settings); 1257 } 1258 1259 $Slices = array_reverse($Slices); 1260 $SliceColors = array_reverse($SliceColors); 1261 1262 /* Draw the vertical edges (semi-visible) */ 1263 foreach($Slices as $SliceID => $Plots) 1264 { 1265 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 1266 $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; 1267 1268 $StartAngle = $Plots["Angle"][0]; 1269 foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } 1270 1271 if ( $StartAngle >= 270 || $StartAngle <= 90 ) 1272 $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); 1273 if ( $StartAngle >= 270 || $StartAngle <= 90 ) 1274 $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); 1275 1276 $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"],$Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Settings); 1277 $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"],$Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Settings); 1278 } 1279 1280 /* Draw the inner vertical slices */ 1281 foreach($Slices as $SliceID => $Plots) 1282 { 1283 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 1284 $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; 1285 1286 $Outer = TRUE; $Inner = FALSE; 1287 $InnerPlotsA = ""; $InnerPlotsB = ""; 1288 foreach($Plots["Angle"] as $ID => $Angle) 1289 { 1290 if ( $Angle == VOID ) 1291 { $Outer = FALSE; $Inner = TRUE; } 1292 elseif( $Inner ) 1293 { 1294 if (( $Angle < 90 || $Angle > 270 ) && isset($Plots["BottomPoly"][$ID*2]) ) 1295 { 1296 $Xo = $Plots["BottomPoly"][$ID*2]; 1297 $Yo = $Plots["BottomPoly"][$ID*2+1]; 1298 1299 $InnerPlotsA[] = $Xo; $InnerPlotsA[] = $Yo; 1300 $InnerPlotsB[] = $Xo; $InnerPlotsB[] = $Yo-$SliceHeight; 1301 } 1302 } 1303 } 1304 1305 if ( $InnerPlotsA != "" ) 1306 { $InnerPlots = array_merge($InnerPlotsA,$this->arrayReverse($InnerPlotsB)); $this->pChartObject->drawPolygon($InnerPlots,$Settings); } 1307 } 1308 1309 /* Draw the splice top and left poly */ 1310 foreach($Slices as $SliceID => $Plots) 1311 { 1312 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 1313 $Settings["R"] = $Settings["R"]+$Cf*1.5; $Settings["G"] = $Settings["G"]+$Cf*1.5; $Settings["B"] = $Settings["B"]+$Cf*1.5; 1314 1315 $StartAngle = $Plots["Angle"][0]; 1316 foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } 1317 1318 if ( $StartAngle < 180 ) 1319 { 1320 $Points = ""; 1321 $Points[] = $Plots["InX2"]; 1322 $Points[] = $Plots["InY2"]; 1323 $Points[] = $Plots["InX2"]; 1324 $Points[] = $Plots["InY2"]-$SliceHeight; 1325 $Points[] = $Plots["OutX1"]; 1326 $Points[] = $Plots["OutY1"]-$SliceHeight; 1327 $Points[] = $Plots["OutX1"]; 1328 $Points[] = $Plots["OutY1"]; 1329 1330 $this->pChartObject->drawPolygon($Points,$Settings); 1331 } 1332 1333 if ( $EndAngle > 180 ) 1334 { 1335 $Points = ""; 1336 $Points[] = $Plots["InX1"]; 1337 $Points[] = $Plots["InY1"]; 1338 $Points[] = $Plots["InX1"]; 1339 $Points[] = $Plots["InY1"]-$SliceHeight; 1340 $Points[] = $Plots["OutX2"]; 1341 $Points[] = $Plots["OutY2"]-$SliceHeight; 1342 $Points[] = $Plots["OutX2"]; 1343 $Points[] = $Plots["OutY2"]; 1344 1345 $this->pChartObject->drawPolygon($Points,$Settings); 1346 } 1347 } 1348 1349 1350 /* Draw the vertical edges (visible) */ 1351 foreach($Slices as $SliceID => $Plots) 1352 { 1353 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 1354 $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; 1355 1356 $StartAngle = $Plots["Angle"][0]; 1357 foreach($Plots["Angle"] as $Key =>$Angle) { if ($Angle == VOID) { $EndAngle = $Plots["Angle"][$Key-1]; } } 1358 1359 if ( $StartAngle <= 270 && $StartAngle >= 90 ) 1360 $this->pChartObject->drawLine($Plots["OutX1"],$Plots["OutY1"],$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); 1361 if ( $EndAngle <= 270 && $EndAngle >= 90 ) 1362 $this->pChartObject->drawLine($Plots["OutX2"],$Plots["OutY2"],$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); 1363 } 1364 1365 1366 /* Draw the outer vertical slices */ 1367 foreach($Slices as $SliceID => $Plots) 1368 { 1369 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 1370 $Settings["R"] = $Settings["R"]+$Cf; $Settings["G"] = $Settings["G"]+$Cf; $Settings["B"] = $Settings["B"]+$Cf; 1371 1372 $Outer = TRUE; $Inner = FALSE; 1373 $OuterPlotsA = ""; $OuterPlotsB = ""; $InnerPlotsA = ""; $InnerPlotsB = ""; 1374 foreach($Plots["Angle"] as $ID => $Angle) 1375 { 1376 if ( $Angle == VOID ) 1377 { $Outer = FALSE; $Inner = TRUE; } 1378 elseif( $Outer ) 1379 { 1380 if ( ( $Angle > 90 && $Angle < 270 ) && isset($Plots["BottomPoly"][$ID*2]) ) 1381 { 1382 $Xo = $Plots["BottomPoly"][$ID*2]; 1383 $Yo = $Plots["BottomPoly"][$ID*2+1]; 1384 1385 $OuterPlotsA[] = $Xo; $OuterPlotsA[] = $Yo; 1386 $OuterPlotsB[] = $Xo; $OuterPlotsB[] = $Yo-$SliceHeight; 1387 } 1388 } 1389 } 1390 if ( $OuterPlotsA != "" ) 1391 { $OuterPlots = array_merge($OuterPlotsA,$this->arrayReverse($OuterPlotsB)); $this->pChartObject->drawPolygon($OuterPlots,$Settings); } 1392 } 1393 1394 $Slices = array_reverse($Slices); 1395 $SliceColors = array_reverse($SliceColors); 1396 1397 1398 /* Draw the top pie splice */ 1399 foreach($Slices as $SliceID => $Plots) 1400 { 1401 $Settings = $SliceColors[$SliceID]; $Settings["NoBorder"] = TRUE; 1402 $Settings["R"] = $Settings["R"]+$Cf*2; $Settings["G"] = $Settings["G"]+$Cf*2; $Settings["B"] = $Settings["B"]+$Cf*2; 1403 1404 $this->pChartObject->drawPolygon($Plots["TopPoly"],$Settings); 1405 1406 if ( $RecordImageMap ) { $this->pChartObject->addToImageMap("POLY",$this->arraySerialize($Plots["TopPoly"]),$this->pChartObject->toHTMLColor($Settings["R"],$Settings["G"],$Settings["B"]),$Data["Series"][$Data["Abscissa"]]["Data"][$SliceID],$Data["Series"][$DataSerie]["Data"][count($Slices)-$SliceID-1]); } 1407 1408 foreach($Plots["AA"] as $Key => $Pos) 1409 $this->pChartObject->drawAntialiasPixel($Pos[0],$Pos[1]-$SliceHeight,$Settings); 1410 1411 $this->pChartObject->drawLine($Plots["InX1"],$Plots["InY1"]-$SliceHeight,$Plots["OutX2"],$Plots["OutY2"]-$SliceHeight,$Settings); 1412 $this->pChartObject->drawLine($Plots["InX2"],$Plots["InY2"]-$SliceHeight,$Plots["OutX1"],$Plots["OutY1"]-$SliceHeight,$Settings); 1413 } 1414 1415 if ( $DrawLabels ) 1416 { 1417 $Offset = 360; 1418 foreach($Values as $Key => $Value) 1419 { 1420 $StartAngle = $Offset; 1421 $EndAngle = $Offset-($Value*$ScaleFactor); if ( $EndAngle < 0 ) { $EndAngle = 0; } 1422 1423 if ( $LabelColor == PIE_LABEL_COLOR_AUTO ) 1424 { $Settings = array("FillR"=>$Palette[$ID]["R"],"FillG"=>$Palette[$ID]["G"],"FillB"=>$Palette[$ID]["B"],"Alpha"=>$Palette[$ID]["Alpha"]);} 1425 else 1426 { $Settings = array("FillR"=>$LabelR,"FillG"=>$LabelG,"FillB"=>$LabelB,"Alpha"=>$LabelAlpha); } 1427 1428 $Angle = ($EndAngle - $Offset)/2 + $Offset; 1429 $Xc = cos(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius) + $X; 1430 $Yc = sin(($Angle-90)*PI/180) * ($OuterRadius+$DataGapRadius)*$SkewFactor + $Y; 1431 1432 if ( $WriteValues == PIE_VALUE_PERCENTAGE ) 1433 $Label = $Display = round(( 100 / $SerieSum ) * $Value,$Precision)."%"; 1434 elseif ( $WriteValues == PIE_VALUE_NATURAL ) 1435 $Label = $Data["Series"][$Data["Abscissa"]]["Data"][$Key]; 1436 else 1437 $Label = ""; 1438 1439 if ( $LabelStacked ) 1440 $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,TRUE,$X,$Y,$OuterRadius); 1441 else 1442 $this->writePieLabel($Xc,$Yc-$SliceHeight,$Label,$Angle,$Settings,FALSE); 1443 1444 $Offset = $EndAngle - $DataGapAngle; $ID--; $Slice++; 1445 } 1446 } 1447 if ( $DrawLabels && $LabelStacked ) { $this->writeShiftedLabels(); } 1448 1449 $this->pChartObject->Shadow = $RestoreShadow; 1450 1451 return(PIE_RENDERED); 1452 } 1453 1454 /* Serialize an array */ 1455 function arraySerialize($Data) 1456 { 1457 $Result = ""; 1458 foreach($Data as $Key => $Value) 1459 { if ($Result == "") { $Result = floor($Value); } else { $Result = $Result.",".floor($Value); } } 1460 1461 return($Result); 1462 } 1463 1464 /* Reverse an array */ 1465 function arrayReverse($Plots) 1466 { 1467 $Result = ""; 1468 1469 for($i=count($Plots)-1;$i>=0;$i=$i-2) 1470 { $Result[] = $Plots[$i-1]; $Result[] = $Plots[$i]; } 1471 1472 return($Result); 1473 } 1474 1475 /* Remove unused series & values */ 1476 function clean0Values($Data,$Palette,$DataSerie,$AbscissaSerie) 1477 { 1478 $NewPalette = ""; $NewData = ""; $NewAbscissa = ""; 1479 1480 /* Remove unused series */ 1481 foreach($Data["Series"] as $SerieName => $SerieSettings) 1482 { if ( $SerieName != $DataSerie && $SerieName != $AbscissaSerie ) { unset($Data["Series"][$SerieName]); } } 1483 1484 /* Remove NULL values */ 1485 foreach($Data["Series"][$DataSerie]["Data"] as $Key => $Value) 1486 { 1487 if ($Value != 0 ) 1488 { 1489 $NewData[] = $Value; 1490 $NewAbscissa[] = $Data["Series"][$AbscissaSerie]["Data"][$Key]; 1491 if ( isset($Palette[$Key]) ) { $NewPalette[] = $Palette[$Key]; } 1492 } 1493 } 1494 $Data["Series"][$DataSerie]["Data"] = $NewData; 1495 $Data["Series"][$AbscissaSerie]["Data"] = $NewAbscissa; 1496 1497 return(array($Data,$NewPalette)); 1498 } 1499 } 1500?>