PageRenderTime 79ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/protected/components/pPie.php

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