pPie.class.php

Constants

NameDescription
PIE_LABEL_COLOR_AUTO
PIE_LABEL_COLOR_MANUAL
PIE_NO_ABSCISSA
PIE_NO_DATASERIE
PIE_RENDERED
PIE_SUMISNULL
PIE_VALUE_INSIDE
PIE_VALUE_NATURAL
PIE_VALUE_OUTSIDE
PIE_VALUE_PERCENTAGE

Classes

NameDescription
pPie

File

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