MyHorBar.class.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. <?php
  2. /*
  3. pChart - a PHP class to build charts!
  4. Copyright (C) 2008 Jean-Damien POGOLOTTI
  5. Version 1.27d last updated on 09/30/08
  6. Extension by Gabriele FERRI
  7. http://www.gabrieleferri.it
  8. MyHorBar.class is writen to extend pChart.class to write a horizontal bar charts
  9. Copyright (C) 2009 Gabriele FERRI
  10. version 1.0beta 08/05/2009
  11. Contact me with bug reports and comments: info@gabrieleferri.it
  12. http://pchart.sourceforge.net
  13. This program is free software: you can redistribute it and/or modify
  14. it under the terms of the GNU General Public License as published by
  15. the Free Software Foundation, either version 1,2,3 of the License, or
  16. (at your option) any later version.
  17. This program is distributed in the hope that it will be useful,
  18. but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. GNU General Public License for more details.
  21. You should have received a copy of the GNU General Public License
  22. along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. Draw methods :
  24. drawHorBarGraph($Data,$DataDescription,$Shadow=TRUE,$Alpha=100)
  25. drawHorScale($Data,$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1,$RightScale=FALSE)
  26. drawHorGrid($LineWidth,$Mosaic,$R=220,$G=220,$B=220,$Alpha=100)
  27. drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnBottom=FALSE,$TickWidth=4,$FreeText=NULL,$Angle=0)
  28. */
  29. class MyHorBar extends pChart
  30. {
  31. /* This function draw a bar graph */
  32. function drawHorBarGraph($Data,$DataDescription,$Shadow=TRUE,$Alpha=100)
  33. {
  34. /* Validate the Data and DataDescription array */
  35. $this->validateDataDescription("drawBarGraph",$DataDescription);
  36. $this->validateData("drawBarGraph",$Data);
  37. $GraphID = 0;
  38. $Series = count($DataDescription["Values"]);
  39. $SeriesWidth = $this->DivisionWidth / ($Series+1);
  40. $SerieYOffset = $this->DivisionWidth / 2 - $SeriesWidth * $Series / 2;
  41. $XZero = $this->GArea_X1 + ((0-$this->VMin) * $this->DivisionRatio);
  42. if ( $XZero < $this->GArea_X1 ) { $XZero = $this->GArea_X1; }
  43. $SerieID = 0;
  44. foreach ( $DataDescription["Values"] as $Key2 => $ColName )
  45. {
  46. $ID = 0;
  47. foreach ( $DataDescription["Description"] as $keyI => $ValueI )
  48. { if ( $keyI == $ColName ) { $ColorID = $ID; }; $ID++; }
  49. $YPos = $this->GArea_Y1 + $this->GAreaXOffset + $SerieYOffset + $SeriesWidth * $SerieID;
  50. $XLast = -1;
  51. foreach ( $Data as $Key => $Values )
  52. {
  53. if ( isset($Data[$Key][$ColName]))
  54. {
  55. if ( is_numeric($Data[$Key][$ColName]) )
  56. {
  57. $Value = $Data[$Key][$ColName];
  58. $XPos = $this->GArea_X1 + (($Value-$this->VMin) * $this->DivisionRatio);
  59. /* Save point into the image map if option activated */
  60. if ( $this->BuildMap )
  61. {
  62. $this->addToImageMap(min($XZero,$XPos),$YPos+1,max($XZero,$XPos), $YPos+$SeriesWidth-1,$DataDescription["Description"][$ColName],$Data[$Key][$ColName].$DataDescription["Unit"]["Y"],"Bar");
  63. }
  64. if ( $Shadow && $Alpha == 100 )
  65. $this->drawRectangle($XZero,$YPos+1,$XPos,$YPos+$SeriesWidth-1,25,25,25,TRUE,$Alpha);
  66. $this->drawFilledRectangle($XZero,$YPos+1,$XPos,$YPos+$SeriesWidth-1,$this->Palette[$ColorID]["R"],$this->Palette[$ColorID]["G"],$this->Palette[$ColorID]["B"],TRUE,$Alpha);
  67. }
  68. }
  69. $YPos = $YPos + $this->DivisionWidth;
  70. }
  71. $SerieID++;
  72. }
  73. }
  74. /* Compute and draw the scale */
  75. function drawHorScale($Data,$DataDescription,$ScaleMode,$R,$G,$B,$DrawTicks=TRUE,$Angle=0,$Decimals=1,$WithMargin=FALSE,$SkipLabels=1,$RightScale=FALSE)
  76. {
  77. /* Validate the Data and DataDescription array */
  78. $this->validateData("drawScale",$Data);
  79. $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B);
  80. $this->drawLine($this->GArea_X1,$this->GArea_Y1,$this->GArea_X2,$this->GArea_Y1,$R,$G,$B);
  81. $this->drawLine($this->GArea_X1,$this->GArea_Y1,$this->GArea_X1,$this->GArea_Y2,$R,$G,$B);
  82. if ( $this->VMin == NULL && $this->VMax == NULL)
  83. {
  84. if (isset($DataDescription["Values"][0]))
  85. {
  86. $this->VMin = $Data[0][$DataDescription["Values"][0]];
  87. $this->VMax = $Data[0][$DataDescription["Values"][0]];
  88. }
  89. else { $this->VMin = 2147483647; $this->VMax = -2147483647; }
  90. /* Compute Min and Max values */
  91. if ( $ScaleMode == SCALE_NORMAL || $ScaleMode == SCALE_START0 )
  92. {
  93. if ( $ScaleMode == SCALE_START0 ) { $this->VMin = 0; }
  94. foreach ( $Data as $Key => $Values )
  95. {
  96. foreach ( $DataDescription["Values"] as $Key2 => $ColName )
  97. {
  98. if (isset($Data[$Key][$ColName]))
  99. {
  100. $Value = $Data[$Key][$ColName];
  101. if ( is_numeric($Value) )
  102. {
  103. if ( $this->VMax < $Value) { $this->VMax = $Value; }
  104. if ( $this->VMin > $Value) { $this->VMin = $Value; }
  105. }
  106. }
  107. }
  108. }
  109. }
  110. elseif ( $ScaleMode == SCALE_ADDALL || $ScaleMode == SCALE_ADDALLSTART0 ) /* Experimental */
  111. {
  112. if ( $ScaleMode == SCALE_ADDALLSTART0 ) { $this->VMin = 0; }
  113. foreach ( $Data as $Key => $Values )
  114. {
  115. $Sum = 0;
  116. foreach ( $DataDescription["Values"] as $Key2 => $ColName )
  117. {
  118. if (isset($Data[$Key][$ColName]))
  119. {
  120. $Value = $Data[$Key][$ColName];
  121. if ( is_numeric($Value) )
  122. $Sum += $Value;
  123. }
  124. }
  125. if ( $this->VMax < $Sum) { $this->VMax = $Sum; }
  126. if ( $this->VMin > $Sum) { $this->VMin = $Sum; }
  127. }
  128. }
  129. if ( $this->VMax > preg_replace('/\.[0-9]+/','',$this->VMax) )
  130. $this->VMax = preg_replace('/\.[0-9]+/','',$this->VMax)+1;
  131. /* If all values are the same */
  132. if ( $this->VMax == $this->VMin )
  133. {
  134. if ( $this->VMax >= 0 ) { $this->VMax++; }
  135. else { $this->VMin--; }
  136. }
  137. $DataRange = $this->VMax - $this->VMin;
  138. if ( $DataRange == 0 ) { $DataRange = .1; }
  139. /* Compute automatic scaling */
  140. $ScaleOk = FALSE; $Factor = 1;
  141. $MinDivHeight = 25;
  142. $MaxDivs = ($this->GArea_X2 - $this->GArea_X1) / $MinDivHeight;
  143. if ( $this->VMin == 0 && $this->VMax == 0 )
  144. { $this->VMin = 0; $this->VMax = 2; $Scale = 1; $Divisions = 2;}
  145. elseif ($MaxDivs > 1)
  146. {
  147. while(!$ScaleOk)
  148. {
  149. $Scale1 = ( $this->VMax - $this->VMin ) / $Factor;
  150. $Scale2 = ( $this->VMax - $this->VMin ) / $Factor / 2;
  151. $Scale4 = ( $this->VMax - $this->VMin ) / $Factor / 4;
  152. if ( $Scale1 > 1 && $Scale1 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale1); $Scale = 1;}
  153. if ( $Scale2 > 1 && $Scale2 <= $MaxDivs && !$ScaleOk) { $ScaleOk = TRUE; $Divisions = floor($Scale2); $Scale = 2;}
  154. if (!$ScaleOk)
  155. {
  156. if ( $Scale2 > 1 ) { $Factor = $Factor * 10; }
  157. if ( $Scale2 < 1 ) { $Factor = $Factor / 10; }
  158. }
  159. }
  160. if ( floor($this->VMax / $Scale / $Factor) != $this->VMax / $Scale / $Factor)
  161. {
  162. $GridID = floor ( $this->VMax / $Scale / $Factor) + 1;
  163. $this->VMax = $GridID * $Scale * $Factor;
  164. $Divisions++;
  165. }
  166. if ( floor($this->VMin / $Scale / $Factor) != $this->VMin / $Scale / $Factor)
  167. {
  168. $GridID = floor( $this->VMin / $Scale / $Factor);
  169. $this->VMin = $GridID * $Scale * $Factor;
  170. $Divisions++;
  171. }
  172. }
  173. else /* Can occurs for small graphs */
  174. $Scale = 1;
  175. if ( !isset($Divisions) )
  176. $Divisions = 2;
  177. if ($Scale == 1 && $Divisions%2 == 1)
  178. $Divisions--;
  179. }
  180. else
  181. $Divisions = $this->Divisions;
  182. $this->DivisionCount = $Divisions;
  183. $DataRange = $this->VMax - $this->VMin;
  184. if ( $DataRange == 0 ) { $DataRange = .1; }
  185. $this->DivisionHeight = ( $this->GArea_X2 - $this->GArea_X1 ) / $Divisions;
  186. $this->DivisionRatio = ( $this->GArea_X2 - $this->GArea_X1 ) / $DataRange;
  187. $this->GAreaYOffset = 0;
  188. if ( count($Data) > 1 )
  189. {
  190. if ( $WithMargin == FALSE )
  191. $this->DivisionWidth = ( $this->GArea_Y2 - $this->GArea_Y1 ) / (count($Data)-1);
  192. else
  193. {
  194. $this->DivisionWidth = ( $this->GArea_Y2 - $this->GArea_Y1 ) / (count($Data));
  195. $this->GAreaYOffset = $this->DivisionWidth / 2;
  196. }
  197. }
  198. else
  199. {
  200. $this->DivisionWidth = $this->GArea_Y2 - $this->GArea_Y1;
  201. $this->GAreaYOffset = $this->DivisionWidth / 2;
  202. }
  203. $this->DataCount = count($Data);
  204. if ( $DrawTicks == FALSE )
  205. return(0);
  206. $XPos = $this->GArea_X1;
  207. $YMin = NULL;
  208. for($i=1;$i<=$Divisions+1;$i++)
  209. {
  210. $this->drawLine($XPos,$this->GArea_Y1,$XPos,$this->GArea_Y1-5,$R,$G,$B);
  211. $Value = $this->VMin + ($i-1) * (( $this->VMax - $this->VMin ) / $Divisions);
  212. $Value = round($Value * pow(10,$Decimals)) / pow(10,$Decimals);
  213. if ( $DataDescription["Format"]["Y"] == "number" )
  214. $Value = $Value.$DataDescription["Unit"]["Y"];
  215. if ( $DataDescription["Format"]["Y"] == "time" )
  216. $Value = $this->ToTime($Value);
  217. if ( $DataDescription["Format"]["Y"] == "date" )
  218. $Value = $this->ToDate($Value);
  219. if ( $DataDescription["Format"]["Y"] == "metric" )
  220. $Value = $this->ToMetric($Value);
  221. if ( $DataDescription["Format"]["Y"] == "currency" )
  222. $Value = $this->ToCurrency($Value);
  223. $Position = imageftbbox($this->FontSize,0,$this->FontName,$Value);
  224. $TextWidth = $Position[2]-$Position[0];
  225. imagettftext($this->Picture,$this->FontSize,0,$XPos-($this->FontSize/2),$this->GArea_Y1-10,$C_TextColor,$this->FontName,$Value);
  226. if ( $YMin > $this->GArea_Y1-10-$TextWidth || $YMin == NULL ) { $YMin = $this->GArea_Y1-10-$TextWidth; }
  227. $XPos = $XPos + $this->DivisionHeight;
  228. }
  229. /* Write the Y Axis caption if set */
  230. if ( isset($DataDescription["Axis"]["Y"]) )
  231. {
  232. $Position = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["Y"]);
  233. $TextHeight = abs($Position[1])+abs($Position[3]);
  234. $TextTop = (($this->GArea_X2 - $this->GArea_X1) / 2) + $this->GArea_X1 + ($TextHeight/2);
  235. imagettftext($this->Picture,$this->FontSize,90,$YMin-$this->FontSize,$TextTop,$C_TextColor,$this->FontName,$DataDescription["Axis"]["Y"]);
  236. }
  237. /* Horizontal Axis */
  238. $YPos = $this->GArea_Y1 + $this->GAreaYOffset;
  239. $ID = 1;
  240. $XMax = NULL;
  241. foreach ( $Data as $Key => $Values )
  242. {
  243. if ( $ID % $SkipLabels == 0 )
  244. {
  245. $this->drawLine($this->GArea_X1,floor($YPos),$this->GArea_X1-5,floor($YPos),$R,$G,$B);
  246. $Value = $Data[$Key][$DataDescription["Position"]];
  247. if ( $DataDescription["Format"]["X"] == "number" )
  248. $Value = $Value.$DataDescription["Unit"]["X"];
  249. if ( $DataDescription["Format"]["X"] == "time" )
  250. $Value = $this->ToTime($Value);
  251. if ( $DataDescription["Format"]["X"] == "date" )
  252. $Value = $this->ToDate($Value);
  253. if ( $DataDescription["Format"]["X"] == "metric" )
  254. $Value = $this->ToMetric($Value);
  255. if ( $DataDescription["Format"]["X"] == "currency" )
  256. $Value = $this->ToCurrency($Value);
  257. $Position = imageftbbox($this->FontSize,$Angle,$this->FontName,$Value);
  258. $TextWidth = abs($Position[2])+abs($Position[0]);
  259. $TextHeight = abs($Position[1])+abs($Position[3]);
  260. if ( $Angle == 0 )
  261. {
  262. $XPos = $this->GArea_Y2+18; imagettftext($this->Picture,$this->FontSize,$Angle,$this->GArea_X1-10-floor($TextWidth),floor($YPos)+5-floor($TextHeight/2),$C_TextColor,$this->FontName,$Value);
  263. }
  264. else
  265. {
  266. $XPos = $this->GArea_Y2+10+$TextHeight;
  267. if ( $Angle <= 90 )
  268. imagettftext($this->Picture,$this->FontSize,$Angle,$XPos,floor($YPos)-$TextWidth+5,$C_TextColor,$this->FontName,$Value);
  269. else
  270. imagettftext($this->Picture,$this->FontSize,$Angle,$XPos,floor($YPos)+$TextWidth+5,$C_TextColor,$this->FontName,$Value);
  271. }
  272. if ( $XMax < $XPos || $XMax == NULL ) { $XMax = $XPos; }
  273. }
  274. $YPos = $YPos + $this->DivisionWidth;
  275. $ID++;
  276. }
  277. /* Write the X Axis caption if set */
  278. if ( isset($DataDescription["Axis"]["Y"]) )
  279. {
  280. $Position = imageftbbox($this->FontSize,90,$this->FontName,$DataDescription["Axis"]["Y"]);
  281. $TextWidth = abs($Position[2])+abs($Position[0]);
  282. $TextLeft = (($this->GArea_Y2 - $this->GArea_Y1) / 2) + $this->GArea_Y1 + ($TextWidth/2);
  283. imagettftext($this->Picture,$this->FontSize,0,$TextLeft,$XMax+$this->FontSize+5,$C_TextColor,$this->FontName,$DataDescription["Axis"]["Y"]);
  284. }
  285. }
  286. /* Compute and draw the scale */
  287. function drawHorGrid($LineWidth,$Mosaic=TRUE,$R=220,$G=220,$B=220,$Alpha=100)
  288. {
  289. /* Draw mosaic */
  290. if ( $Mosaic )
  291. {
  292. $LayerWidth = $this->GArea_Y2-$this->GArea_Y1;
  293. $LayerHeight = $this->GArea_X2-$this->GArea_X1;
  294. $this->Layers[0] = imagecreatetruecolor($LayerWidth,$LayerHeight);
  295. $C_White =$this->AllocateColor($this->Layers[0],255,255,255);
  296. imagefilledrectangle($this->Layers[0],0,0,$LayerWidth,$LayerHeight,$C_White);
  297. imagecolortransparent($this->Layers[0],$C_White);
  298. $C_Rectangle =$this->AllocateColor($this->Layers[0],250,250,250);
  299. $XPos = $LayerHeight;
  300. $LastX = $XPos;
  301. for($i=0;$i<=$this->DivisionCount;$i++)
  302. {
  303. $LastX = $XPos;
  304. $XPos = $XPos - $this->DivisionHeight;
  305. if ( $XPos <= 0 ) { $XPos = 1; }
  306. if ( $i % 2 == 0 )
  307. {
  308. imagefilledrectangle($this->Layers[0],$XPos,1,$LastX,$LayerWidth-1,$C_Rectangle);
  309. }
  310. }
  311. imagecopymerge($this->Picture,$this->Layers[0],$this->GArea_X1,$this->GArea_Y1,0,0,$LayerWidth,$LayerHeight,$Alpha);
  312. imagedestroy($this->Layers[0]);
  313. }
  314. /* Vertical lines */
  315. $XPos = $this->GArea_X2 - $this->DivisionHeight;
  316. for($i=1;$i<=$this->DivisionCount;$i++)
  317. {
  318. if ( $XPos > $this->GArea_X1 && $XPos < $this->GArea_X2 )
  319. $this->drawDottedLine($XPos,$this->GArea_Y1,$XPos,$this->GArea_Y2,$LineWidth,$R,$G,$B);
  320. $XPos = $XPos - $this->DivisionHeight;
  321. }
  322. /* Horizontal lines */
  323. if ( $this->GAreaYOffset == 0 )
  324. { $YPos = $this->GArea_Y1 + $this->DivisionWidth + $this->GAreaYOffset;
  325. $ColCount = $this->DataCount-2; }
  326. else
  327. { $YPos = $this->GArea_Y1 + $this->GAreaYOffset;
  328. //$ColCount = floor( ($this->GArea_X2 - $this->GArea_X1) / $this->DivisionWidth );
  329. $ColCount = $this->DataCount;
  330. }
  331. for($i=1;$i<=$ColCount;$i++)
  332. {
  333. if ( $YPos > $this->GArea_Y1 && $YPos < $this->GArea_Y2 )
  334. $this->drawDottedLine($this->GArea_X1,floor($YPos),$this->GArea_X2,floor($YPos),$LineWidth,$R,$G,$B);
  335. $YPos = $YPos + $this->DivisionWidth;
  336. }
  337. }
  338. /* Compute and draw the scale */
  339. function drawTreshold($Value,$R,$G,$B,$ShowLabel=FALSE,$ShowOnBottom=FALSE,$TickWidth=4,$FreeText=NULL,$Angle=0)
  340. {
  341. if ( $R < 0 ) { $R = 0; } if ( $R > 255 ) { $R = 255; }
  342. if ( $G < 0 ) { $G = 0; } if ( $G > 255 ) { $G = 255; }
  343. if ( $B < 0 ) { $B = 0; } if ( $B > 255 ) { $B = 255; }
  344. $C_TextColor =$this->AllocateColor($this->Picture,$R,$G,$B);
  345. $X = $this->GArea_X1 + ($Value - $this->VMin) * $this->DivisionRatio;
  346. if ( $X <= $this->GArea_X1 || $X >= $this->GArea_X2 )
  347. return(-1);
  348. if ( $TickWidth == 0 )
  349. $this->drawLine($X,$this->GArea_Y1,$X,$this->GArea_Y2,$R,$G,$B);
  350. else
  351. $this->drawDottedLine($X,$this->GArea_Y1,$X,$this->GArea_Y2,$TickWidth,$R,$G,$B);
  352. if ( $ShowLabel )
  353. {
  354. if ( $FreeText == NULL )
  355. { $Label = $Value; } else { $Label = $FreeText; }
  356. $Position = imageftbbox($this->FontSize,$Angle,$this->FontName,$Label);
  357. $TextWidth = abs($Position[2])-abs($Position[0]);
  358. $TextLeft = abs($Position[3])-abs($Position[1]);
  359. if ( $ShowOnBottom )
  360. imagettftext($this->Picture,$this->FontSize,$Angle,$X+9,$this->GArea_Y2,$C_TextColor,$this->FontName,$Label);
  361. else
  362. imagettftext($this->Picture,$this->FontSize,$Angle,$X+9,$this->GArea_Y1+$TextLeft,$C_TextColor,$this->FontName,$Label);
  363. }
  364. }
  365. }
  366. ?>