Source for file jpgraph_pie.php

Documentation is available at jpgraph_pie.php

  1. <?php
  2. /**
  3. * File: JPGRAPH_PIE.PHP
  4. * Description: Pie plot extension for JpGraph
  5. * Created: 2001-02-14
  6. * Author: Johan Persson (johanp@aditus.nu)
  7. * Ver: $Id: jpgraph_pie.php,v 1.24 2002/05/13 20:38:19 aditus Exp $
  8. *
  9. * License: This code is released under QPL
  10. * Copyright (C) 2001,2002 Johan Persson
  11. * @package JPGraph
  12. ***/
  13.  
  14.  
  15. // Defines for PiePlot::SetLabelType()
  16. DEFINE("PIE_VALUE_ABS",1);
  17. DEFINE("PIE_VALUE_PER",0);
  18. DEFINE("PIE_VALUE_PERCENTAGE",0);
  19.  
  20. /**
  21. * CLASS PiePlot
  22. * Description: Draws a
  23. **/
  24.  
  25. class PiePlot {
  26. var $posx=0.5,$posy=0.5;
  27. var $radius=0.3;
  28. var $explode_radius=array(),$explode_all=false,$explode_r=20;
  29. var $labels, $legends=null;
  30. var $csimtargets=null; // Array of targets for CSIM
  31. var $csimareas=''; // Generated CSIM text
  32. var $csimalts=null; // ALT tags for corresponding target
  33. var $data=null;
  34. var $title;
  35. var $startangle=0;
  36. var $weight=1, $color="black";
  37. var $font_family=FF_FONT1,$font_style=FS_NORMAL,$font_size=12,$font_color="black";
  38. var $legend_margin=6,$show_labels=true;
  39. var $themearr = array(
  40. "earth" => array(10,34,40,45,46,62,63,134,74,77,120,136,141,168,180,209,218,346,395,89,430),
  41. "pastel" => array(27,38,42,59,66,79,105,110,128,147,152,230,236,240,331,337,405,415),
  42. "water" => array(8,370,10,40,335,56,213,237,268,14,326,387,24,388),
  43. "sand" => array(27,168,34,170,19,50,65,72,131,209,46,393));
  44. var $theme="earth";
  45. var $setslicecolors=array();
  46. var $labelformat="%01.0f"; // Default format for labels
  47. var $labeltype=0; // Default to percentage
  48. var $pie_border=true,$pie_interior_border=true;
  49. var $value;
  50. //---------------
  51. // CONSTRUCTOR
  52. function PiePlot(&$data) {
  53. $this->data = $data;
  54. $this->title = new Text("");
  55. $this->title->SetFont(FF_FONT1,FS_BOLD);
  56. $this->value = new DisplayValue();
  57. }
  58.  
  59. //---------------
  60. // PUBLIC METHODS
  61. function SetCenter($x,$y=0.5) {
  62. $this->posx = $x;
  63. $this->posy = $y;
  64. }
  65.  
  66. function SetColor($aColor) {
  67. $this->color = $aColor;
  68. }
  69.  
  70. function SetCSIMTargets(&$targets,$alts=null) {
  71. $this->csimtargets=$targets;
  72. $this->csimalts=$alts;
  73. }
  74. function GetCSIMareas() {
  75. return $this->csimareas;
  76. }
  77.  
  78. function AddSliceToCSIM($i,$xc,$yc,$radius,$sa,$ea) { //Slice number, ellipse centre (x,y), height, width, start angle, end angle
  79. while( $sa > 2*M_PI ) $sa = $sa - 2*M_PI;
  80. while( $ea > 2*M_PI ) $ea = $ea - 2*M_PI;
  81.  
  82. $sa = 2*M_PI - $sa;
  83. $ea = 2*M_PI - $ea;
  84.  
  85. $gsa = round(180/M_PI*$sa);
  86. $gea = round(180/M_PI*$ea);
  87.  
  88. //echo "sa=$gsa, ea=$gea<br>";
  89.  
  90. //add coordinates of the centre to the map
  91. $coords = "$xc, $yc";
  92.  
  93. //add coordinates of the first point on the arc to the map
  94. $xp = floor(($radius*cos($ea))+$xc);
  95. $yp = floor($yc-$radius*sin($ea));
  96. $coords.= ", $xp, $yp";
  97. //add coordinates every 0.2 radians
  98. $a=$ea+0.2;
  99. while ($a<$sa) {
  100. $xp = floor($radius*cos($a)+$xc);
  101. $yp = floor($yc-$radius*sin($a));
  102. $coords.= ", $xp, $yp";
  103. $a += 0.2;
  104. }
  105. //Add the last point on the arc
  106. $xp = floor($radius*cos($sa)+$xc);
  107. $yp = floor($yc-$radius*sin($sa));
  108. $coords.= ", $xp, $yp";
  109. if( !empty($this->csimtargets[$i]) )
  110. $this->csimareas .= "<area shape=\"poly\" coords=\"$coords\" href=\"".$this->csimtargets[$i]."\"";
  111. if( !empty($this->csimalts[$i]) ) {
  112. $tmp=sprintf($this->csimalts[$i],$this->data[$i]);
  113. $this->csimareas .= " alt=\"$tmp\" title=\"$tmp\"";
  114. }
  115. $this->csimareas .= ">\r\n";
  116. }
  117.  
  118. function SetTheme($t) {
  119. if( in_array($t,array_keys($this->themearr)) )
  120. $this->theme = $t;
  121. else
  122. JpGraphError::Raise("PiePLot::SetTheme() Unknown theme: $t");
  123. }
  124. function ExplodeSlice($e,$radius=20) {
  125. $this->explode_radius[$e]=$radius;
  126. }
  127.  
  128. function ExplodeAll($radius=-1) {
  129. $this->explode_all=true;
  130. if( $radius==-1 )
  131. $this->explode_r = 20;
  132. else
  133. $this->explode_r = $radius;
  134. }
  135.  
  136. function Explode($radarr) {
  137. if( !is_array($radarr) ) {
  138. JpGraphError::Raise("Argument to PiePlot::Explode() must be an array.");
  139. }
  140. $this->explode_radius = $radarr;
  141. }
  142. function SetSliceColors($c) {
  143. $this->setslicecolors = $c;
  144. }
  145. function SetStartAngle($a) {
  146. $this->startangle = $a;
  147. }
  148. function SetFont($family,$style=FS_NORMAL,$size=10) {
  149. $this->font_family=$family;
  150. $this->font_style=$style;
  151. $this->font_size=$size;
  152. }
  153. // Size in percentage
  154. function SetSize($size) {
  155. if( ($size>0 && $size<=0.5) || ($size>10 && $size<1000) )
  156. $this->radius = $size;
  157. else
  158. JpGraphError::Raise("PiePlot::SetSize() Radius for pie must either be specified as a fraction
  159. [0, 0.5] of the size of the image or as an absolute size in pixels
  160. in the range [10, 1000]");
  161. }
  162. function SetFontColor($color) {
  163. $this->font_color = $color;
  164. }
  165. // Set label arrays
  166. function SetLegends($l) {
  167. $this->legends = $l;
  168. }
  169. // Should we display actual value or percentage?
  170. function SetLabelType($t) {
  171. if( $t<0 || $t>1 )
  172. JpGraphError::Raise("PiePlot::SetLabelType() Type for pie plots must be 0 or 1 (not $t).");
  173. $this->labeltype=$t;
  174. }
  175.  
  176. function SetValueType($t) {
  177. $this->SetLabelType($t);
  178. }
  179.  
  180.  
  181. // Should the circle around a pie plot be displayed
  182. function ShowBorder($exterior=true,$interior=true) {
  183. $this->pie_border = $exterior;
  184. $this->pie_interior_border = $interior;
  185. }
  186. // Setup the legends
  187. function Legend(&$graph) {
  188. $colors = array_keys($graph->img->rgb->rgb_table);
  189. sort($colors);
  190. $ta=$this->themearr[$this->theme];
  191. if( $this->setslicecolors==null )
  192. $numcolors=count($ta);
  193. else
  194. $numcolors=count($this->setslicecolors);
  195. $sum=0;
  196. for($i=0; $i<count($this->data); ++$i)
  197. $sum += $this->data[$i];
  198.  
  199. // Bail out with error if the sum is 0
  200. if( $sum==0 )
  201. JpGraphError::Raise("Illegal pie plot. Sum of all data is zero for Pie!");
  202.  
  203. $i=0;
  204. if( count($this->legends)>0 ) {
  205. foreach( $this->legends as $l ) {
  206. // Replace possible format with actual values
  207. if( $this->labeltype==0 )
  208. $l = sprintf($l,100*$this->data[$i]/$sum);
  209. else
  210. $l = sprintf($l,$this->data[$i]);
  211. if( $this->setslicecolors==null )
  212. $graph->legend->Add($l,$colors[$ta[$i%$numcolors]]);
  213. else
  214. $graph->legend->Add($l,$this->setslicecolors[$i%$numcolors]);
  215. ++$i;
  216. // Breakout if there are more legends then values
  217. if( $i==count($this->data) ) return;
  218. }
  219. }
  220. }
  221. // Specify precision for labels. This is a deprecated function
  222. // nowadays since the introduction of value->Property()
  223. function SetPrecision($p,$psign=true) {
  224. JpGraphError::Raise("PiePlot::SetPrecision() is deprecated. Use $plot->value->SetFormat() instead.");
  225. }
  226. function Stroke(&$img) {
  227. $colors = array_keys($img->rgb->rgb_table);
  228. sort($colors);
  229. $ta=$this->themearr[$this->theme];
  230. if( $this->setslicecolors==null )
  231. $numcolors=count($ta);
  232. else
  233. $numcolors=count($this->setslicecolors);
  234. // Draw the slices
  235. $sum=0;
  236. for($i=0; $i<count($this->data); ++$i)
  237. $sum += $this->data[$i];
  238. // Bail out with error if the sum is 0
  239. if( $sum==0 )
  240. JpGraphError::Raise("Sum of all data is 0 for Pie.");
  241. // Format the titles for each slice
  242. for( $i=0; $i<count($this->data); ++$i) {
  243. if( $this->labeltype==0 )
  244. if( $sum != 0 )
  245. $l = 100*$this->data[$i]/$sum;
  246. else
  247. $l = 0;
  248. else
  249. $l = $this->data[$i];
  250. $l = sprintf($this->labelformat,$l);
  251. $this->labels[$i]=$l;
  252. }
  253. // Set up the pic-circle
  254. if( $this->radius < 1 )
  255. $radius = floor($this->radius*min($img->width,$img->height));
  256. else
  257. $radius = $this->radius;
  258. $xc = $this->posx*$img->width;
  259. $yc = $this->posy*$img->height;
  260. $accsum=0;
  261. $angle2 = $this->startangle*M_PI/180;
  262. $img->SetColor($this->color);
  263.  
  264. if( $this->explode_all )
  265. for($i=0;$i<count($this->data);++$i)
  266. $this->explode_radius[$i]=$this->explode_r;
  267.  
  268. for($i=0; $sum>0 && $i<count($this->data); ++$i) {
  269. $d = $this->data[$i];
  270. $angle1 = $angle2;
  271. $accsum += $d;
  272. $angle2 = $this->startangle*M_PI/180+2*M_PI*$accsum/$sum;
  273. if( $this->setslicecolors==null )
  274. $slicecolor=$colors[$ta[$i%$numcolors]];
  275. else
  276. $slicecolor=$this->setslicecolors[$i%$numcolors];
  277.  
  278. if( $this->pie_interior_border )
  279. $img->SetColor($this->color);
  280. else
  281. $img->SetColor($slicecolor);
  282.  
  283. $arccolor = $this->pie_border ? $this->color : "";
  284.  
  285. $la = 2*M_PI - (abs($angle2-$angle1)/2.0+$angle1);
  286.  
  287. if( empty($this->explode_radius[$i]) )
  288. $this->explode_radius[$i]=0;
  289.  
  290. $xcm = $xc + $this->explode_radius[$i]*cos($la);
  291. $ycm = $yc - $this->explode_radius[$i]*sin($la);
  292. $img->CakeSlice($xcm,$ycm,$radius-1,$radius-1,$angle1*180/M_PI,$angle2*180/M_PI,$slicecolor,$arccolor);
  293.  
  294. if( $this->value->show )
  295. $this->StrokeLabels($this->labels[$i],$img,$xc,$yc,$la,$radius+$this->explode_radius[$i]);
  296.  
  297. if ($this->csimtargets)
  298. $this->AddSliceToCSIM($i,$xcm,$ycm,$radius,$angle1,$angle2);
  299.  
  300. }
  301. // Adjust title position
  302. $this->title->Pos($xc,$yc-$img->GetFontHeight()-$radius,"center","bottom");
  303. $this->title->Stroke($img);
  304. }
  305.  
  306. //---------------
  307. // PRIVATE METHODS
  308. // Position the labels of each slice
  309. function StrokeLabels($label,$img,$xc,$yc,$a,$r) {
  310. $this->value->halign = "left";
  311. $this->value->valign = "top";
  312. $this->value->margin = 0;
  313.  
  314. $r += $img->GetFontHeight()/2;
  315. $xt=round($r*cos($a)+$xc);
  316. $yt=round($yc-$r*sin($a));
  317.  
  318. // Position the axis title.
  319. // dx, dy is the offset from the top left corner of the bounding box that sorrounds the text
  320. // that intersects with the extension of the corresponding axis. The code looks a little
  321. // bit messy but this is really the only way of having a reasonable position of the
  322. // axis titles.
  323. $img->SetFont($this->value->ff,$this->value->fs,$this->value->fsize);
  324. $h=$img->GetTextHeight($label);
  325. $w=$img->GetTextWidth(sprintf($this->value->format,$label));
  326. while( $a > 2*M_PI ) $a -= 2*M_PI;
  327. if( $a>=7*M_PI/4 || $a <= M_PI/4 ) $dx=0;
  328. if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dx=($a-M_PI/4)*2/M_PI;
  329. if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dx=1;
  330. if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dx=(1-($a-M_PI*5/4)*2/M_PI);
  331. if( $a>=7*M_PI/4 ) $dy=(($a-M_PI)-3*M_PI/4)*2/M_PI;
  332. if( $a<=M_PI/4 ) $dy=(1-$a*2/M_PI);
  333. if( $a>=M_PI/4 && $a <= 3*M_PI/4 ) $dy=1;
  334. if( $a>=3*M_PI/4 && $a <= 5*M_PI/4 ) $dy=(1-($a-3*M_PI/4)*2/M_PI);
  335. if( $a>=5*M_PI/4 && $a <= 7*M_PI/4 ) $dy=0;
  336. $this->value->Stroke($img,$label,$xt-$dx*$w,$yt-$dy*$h);
  337. }
  338. } // Class
  339. /*
  340. * CLASS PieGraph
  341. **/
  342. class PieGraph extends Graph {
  343. var $posx, $posy, $radius;
  344. var $legends=array();
  345. var $plots=array();
  346. //---------------
  347. // CONSTRUCTOR
  348. function PieGraph($width=300,$height=200,$cachedName="",$timeout=0,$inline=1) {
  349. $this->Graph($width,$height,$cachedName,$timeout,$inline);
  350. $this->posx=$width/2;
  351. $this->posy=$height/2;
  352. $this->SetColor(array(255,255,255));
  353. }
  354.  
  355. //---------------
  356. // PUBLIC METHODS
  357. function Add(&$pie) {
  358. $this->plots[] = $pie;
  359. }
  360. function SetColor($c) {
  361. $this->SetMarginColor($c);
  362. }
  363.  
  364.  
  365. function DisplayCSIMAreas() {
  366. $csim="";
  367. foreach($this->plots as $p ) {
  368. $csim .= $p->GetCSIMareas();
  369. }
  370. //$csim.= $this->legend->GetCSIMareas();
  371. if (preg_match_all("/area shape=\"(\w+)\" coords=\"([0-9\, ]+)\"/", $csim, $coords)) {
  372. $this->img->SetColor($this->csimcolor);
  373. for ($i=0; $i<count($coords[0]); $i++) {
  374. if ($coords[1][$i]=="poly") {
  375. preg_match_all('/\s*([0-9]+)\s*,\s*([0-9]+)\s*,*/',$coords[2][$i],$pts);
  376. $this->img->SetStartPoint($pts[1][count($pts[0])-1],$pts[2][count($pts[0])-1]);
  377. for ($j=0; $j<count($pts[0]); $j++) {
  378. $this->img->LineTo($pts[1][$j],$pts[2][$j]);
  379. }
  380. } else if ($coords[1][$i]=="rect") {
  381. $pts = preg_split('/,/', $coords[2][$i]);
  382. $this->img->SetStartPoint($pts[0],$pts[1]);
  383. $this->img->LineTo($pts[2],$pts[1]);
  384. $this->img->LineTo($pts[2],$pts[3]);
  385. $this->img->LineTo($pts[0],$pts[3]);
  386. $this->img->LineTo($pts[0],$pts[1]);
  387. }
  388. }
  389. }
  390. }
  391.  
  392. // Method description
  393. function Stroke($aStrokeFileName="") {
  394. $this->StrokeFrame();
  395. for($i=0; $i<count($this->plots); ++$i)
  396. $this->plots[$i]->Stroke($this->img);
  397. foreach( $this->plots as $p)
  398. $p->Legend($this);
  399. $this->legend->Stroke($this->img);
  400. $this->StrokeTitles();
  401.  
  402. // Stroke texts
  403. if( $this->texts != null )
  404. foreach( $this->texts as $t)
  405. $t->Stroke($this->img);
  406. if( JPG_DEBUG ) {
  407. $this->DisplayCSIMAreas();
  408. }
  409. // Finally output the image
  410. $this->cache->PutAndStream($this->img,$this->cache_name,$this->inline,$aStrokeFileName);
  411. }
  412. } // Class
  413. /* EOF */
  414. ?>

Documentation generated on Sun, 13 Mar 2005 14:25:22 +0100 by phpDocumentor 1.3.0RC3