PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/jpgraph/src/jpgraph_gradient.php

https://code.google.com/
PHP | 434 lines | 349 code | 39 blank | 46 comment | 56 complexity | 3b261197cef5b3539328a8f90cefc3c3 MD5 | raw file
Possible License(s): GPL-3.0, BSD-3-Clause, LGPL-2.0, LGPL-2.1, LGPL-3.0
  1. <?php
  2. /*=======================================================================
  3. // File: JPGRAPH_GRADIENT.PHP
  4. // Description: Create a color gradient
  5. // Created: 2003-02-01
  6. // Ver: $Id: jpgraph_gradient.php 1301 2009-06-15 07:03:27Z ljp $
  7. //
  8. // Copyright (c) Aditus Consulting. All rights reserved.
  9. //========================================================================
  10. */
  11. // Styles for gradient color fill
  12. define("GRAD_VER",1);
  13. define("GRAD_VERT",1);
  14. define("GRAD_HOR",2);
  15. define("GRAD_MIDHOR",3);
  16. define("GRAD_MIDVER",4);
  17. define("GRAD_CENTER",5);
  18. define("GRAD_WIDE_MIDVER",6);
  19. define("GRAD_WIDE_MIDHOR",7);
  20. define("GRAD_LEFT_REFLECTION",8);
  21. define("GRAD_RIGHT_REFLECTION",9);
  22. define("GRAD_RAISED_PANEL",10);
  23. define("GRAD_DIAGONAL",11);
  24. //===================================================
  25. // CLASS Gradient
  26. // Description: Handles gradient fills. This is to be
  27. // considered a "friend" class of Class Image.
  28. //===================================================
  29. class Gradient {
  30. private $img=null, $numcolors=100;
  31. //---------------
  32. // CONSTRUCTOR
  33. function __construct(&$img) {
  34. $this->img = $img;
  35. }
  36. function SetNumColors($aNum) {
  37. $this->numcolors=$aNum;
  38. }
  39. //---------------
  40. // PUBLIC METHODS
  41. // Produce a gradient filled rectangle with a smooth transition between
  42. // two colors.
  43. // ($xl,$yt) Top left corner
  44. // ($xr,$yb) Bottom right
  45. // $from_color Starting color in gradient
  46. // $to_color End color in the gradient
  47. // $style Which way is the gradient oriented?
  48. function FilledRectangle($xl,$yt,$xr,$yb,$from_color,$to_color,$style=1) {
  49. switch( $style ) {
  50. case GRAD_VER:
  51. $steps = ceil(abs($xr-$xl)+1);
  52. $delta = $xr>=$xl ? 1 : -1;
  53. $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);
  54. for( $i=0, $x=$xl; $i < $steps; ++$i ) {
  55. $this->img->current_color = $colors[$i];
  56. $this->img->Line($x,$yt,$x,$yb);
  57. $x += $delta;
  58. }
  59. break;
  60. case GRAD_HOR:
  61. $steps = ceil(abs($yb-$yt)+1);
  62. $delta = $yb>=$yt ? 1 : -1;
  63. $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);
  64. for($i=0,$y=$yt; $i < $steps; ++$i) {
  65. $this->img->current_color = $colors[$i];
  66. $this->img->Line($xl,$y,$xr,$y);
  67. $y += $delta;
  68. }
  69. break;
  70. case GRAD_MIDHOR:
  71. $steps = ceil(abs($yb-$yt)/2);
  72. $delta = $yb >= $yt ? 1 : -1;
  73. $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);
  74. for($y=$yt, $i=0; $i < $steps; ++$i) {
  75. $this->img->current_color = $colors[$i];
  76. $this->img->Line($xl,$y,$xr,$y);
  77. $y += $delta;
  78. }
  79. --$i;
  80. if( abs($yb-$yt) % 2 == 1 ) {
  81. --$steps;
  82. }
  83. for($j=0; $j < $steps; ++$j, --$i) {
  84. $this->img->current_color = $colors[$i];
  85. $this->img->Line($xl,$y,$xr,$y);
  86. $y += $delta;
  87. }
  88. $this->img->Line($xl,$y,$xr,$y);
  89. break;
  90. case GRAD_MIDVER:
  91. $steps = ceil(abs($xr-$xl)/2);
  92. $delta = $xr>=$xl ? 1 : -1;
  93. $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);
  94. for($x=$xl, $i=0; $i < $steps; ++$i) {
  95. $this->img->current_color = $colors[$i];
  96. $this->img->Line($x,$yb,$x,$yt);
  97. $x += $delta;
  98. }
  99. --$i;
  100. if( abs($xr-$xl) % 2 == 1 ) {
  101. --$steps;
  102. }
  103. for($j=0; $j < $steps; ++$j, --$i) {
  104. $this->img->current_color = $colors[$i];
  105. $this->img->Line($x,$yb,$x,$yt);
  106. $x += $delta;
  107. }
  108. $this->img->Line($x,$yb,$x,$yt);
  109. break;
  110. case GRAD_WIDE_MIDVER:
  111. $diff = ceil(abs($xr-$xl));
  112. $steps = floor(abs($diff)/3);
  113. $firststep = $diff - 2*$steps ;
  114. $delta = $xr >= $xl ? 1 : -1;
  115. $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors);
  116. for($x=$xl, $i=0; $i < $firststep; ++$i) {
  117. $this->img->current_color = $colors[$i];
  118. $this->img->Line($x,$yb,$x,$yt);
  119. $x += $delta;
  120. }
  121. --$i;
  122. $this->img->current_color = $colors[$i];
  123. for($j=0; $j< $steps; ++$j) {
  124. $this->img->Line($x,$yb,$x,$yt);
  125. $x += $delta;
  126. }
  127. for($j=0; $j < $steps; ++$j, --$i) {
  128. $this->img->current_color = $colors[$i];
  129. $this->img->Line($x,$yb,$x,$yt);
  130. $x += $delta;
  131. }
  132. break;
  133. case GRAD_WIDE_MIDHOR:
  134. $diff = ceil(abs($yb-$yt));
  135. $steps = floor(abs($diff)/3);
  136. $firststep = $diff - 2*$steps ;
  137. $delta = $yb >= $yt? 1 : -1;
  138. $this->GetColArray($from_color,$to_color,$firststep,$colors,$this->numcolors);
  139. for($y=$yt, $i=0; $i < $firststep; ++$i) {
  140. $this->img->current_color = $colors[$i];
  141. $this->img->Line($xl,$y,$xr,$y);
  142. $y += $delta;
  143. }
  144. --$i;
  145. $this->img->current_color = $colors[$i];
  146. for($j=0; $j < $steps; ++$j) {
  147. $this->img->Line($xl,$y,$xr,$y);
  148. $y += $delta;
  149. }
  150. for($j=0; $j < $steps; ++$j, --$i) {
  151. $this->img->current_color = $colors[$i];
  152. $this->img->Line($xl,$y,$xr,$y);
  153. $y += $delta;
  154. }
  155. break;
  156. case GRAD_LEFT_REFLECTION:
  157. $steps1 = ceil(0.3*abs($xr-$xl));
  158. $delta = $xr>=$xl ? 1 : -1;
  159. $from_color = $this->img->rgb->Color($from_color);
  160. $adj = 1.4;
  161. $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2]))));
  162. $from_color2 = array(min(255,$from_color[0]+$m),
  163. min(255,$from_color[1]+$m), min(255,$from_color[2]+$m));
  164. $this->GetColArray($from_color2,$to_color,$steps1,$colors,$this->numcolors);
  165. $n = count($colors);
  166. for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) {
  167. $this->img->current_color = $colors[$i];
  168. $this->img->Line($x,$yb,$x,$yt);
  169. $x += $delta;
  170. }
  171. $steps2 = max(1,ceil(0.08*abs($xr-$xl)));
  172. $this->img->SetColor($to_color);
  173. for($j=0; $j< $steps2; ++$j) {
  174. $this->img->Line($x,$yb,$x,$yt);
  175. $x += $delta;
  176. }
  177. $steps = abs($xr-$xl)-$steps1-$steps2;
  178. $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors);
  179. $n = count($colors);
  180. for($i=0; $i < $steps && $i < $n; ++$i) {
  181. $this->img->current_color = $colors[$i];
  182. $this->img->Line($x,$yb,$x,$yt);
  183. $x += $delta;
  184. }
  185. break;
  186. case GRAD_RIGHT_REFLECTION:
  187. $steps1 = ceil(0.7*abs($xr-$xl));
  188. $delta = $xr>=$xl ? 1 : -1;
  189. $this->GetColArray($from_color,$to_color,$steps1,$colors,$this->numcolors);
  190. $n = count($colors);
  191. for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) {
  192. $this->img->current_color = $colors[$i];
  193. $this->img->Line($x,$yb,$x,$yt);
  194. $x += $delta;
  195. }
  196. $steps2 = max(1,ceil(0.08*abs($xr-$xl)));
  197. $this->img->SetColor($to_color);
  198. for($j=0; $j< $steps2; ++$j) {
  199. $this->img->Line($x,$yb,$x,$yt);
  200. $x += $delta;
  201. }
  202. $from_color = $this->img->rgb->Color($from_color);
  203. $adj = 1.4;
  204. $m = ($adj-1.0)*(255-min(255,min($from_color[0],min($from_color[1],$from_color[2]))));
  205. $from_color = array(min(255,$from_color[0]+$m),
  206. min(255,$from_color[1]+$m), min(255,$from_color[2]+$m));
  207. $steps = abs($xr-$xl)-$steps1-$steps2;
  208. $this->GetColArray($to_color,$from_color,$steps,$colors,$this->numcolors);
  209. $n = count($colors);
  210. for($i=0; $i < $steps && $i < $n; ++$i) {
  211. $this->img->current_color = $colors[$i];
  212. $this->img->Line($x,$yb,$x,$yt);
  213. $x += $delta;
  214. }
  215. break;
  216. case GRAD_CENTER:
  217. $steps = ceil(min(($yb-$yt)+1,($xr-$xl)+1)/2);
  218. $this->GetColArray($from_color,$to_color,$steps,$colors,$this->numcolors);
  219. $dx = ($xr-$xl)/2;
  220. $dy = ($yb-$yt)/2;
  221. $x=$xl;$y=$yt;$x2=$xr;$y2=$yb;
  222. $n = count($colors);
  223. for($x=$xl, $i=0; $x < $xl+$dx && $y < $yt+$dy && $i < $n; ++$x, ++$y, --$x2, --$y2, ++$i) {
  224. $this->img->current_color = $colors[$i];
  225. $this->img->Rectangle($x,$y,$x2,$y2);
  226. }
  227. $this->img->Line($x,$y,$x2,$y2);
  228. break;
  229. case GRAD_RAISED_PANEL:
  230. // right to left
  231. $steps1 = $xr-$xl;
  232. $delta = $xr>=$xl ? 1 : -1;
  233. $this->GetColArray($to_color,$from_color,$steps1,$colors,$this->numcolors);
  234. $n = count($colors);
  235. for($x=$xl, $i=0; $i < $steps1 && $i < $n; ++$i) {
  236. $this->img->current_color = $colors[$i];
  237. $this->img->Line($x,$yb,$x,$yt);
  238. $x += $delta;
  239. }
  240. // left to right
  241. $xr -= 3;
  242. $xl += 3;
  243. $yb -= 3;
  244. $yt += 3;
  245. $steps2 = $xr-$xl;
  246. $delta = $xr>=$xl ? 1 : -1;
  247. for($x=$xl, $j=$steps2; $j >= 0; --$j) {
  248. $this->img->current_color = $colors[$j];
  249. $this->img->Line($x,$yb,$x,$yt);
  250. $x += $delta;
  251. }
  252. break;
  253. case GRAD_DIAGONAL:
  254. // use the longer dimension to determine the required number of steps.
  255. // first loop draws from one corner to the mid-diagonal and the second
  256. // loop draws from the mid-diagonal to the opposing corner.
  257. if($xr-$xl > $yb - $yt) {
  258. // width is greater than height -> use x-dimension for steps
  259. $steps = $xr-$xl;
  260. $delta = $xr>=$xl ? 1 : -1;
  261. $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors);
  262. $n = count($colors);
  263. for($x=$xl, $i=0; $i < $steps && $i < $n; ++$i) {
  264. $this->img->current_color = $colors[$i];
  265. $y = $yt+($i/$steps)*($yb-$yt)*$delta;
  266. $this->img->Line($x,$yt,$xl,$y);
  267. $x += $delta;
  268. }
  269. for($x=$xl, $i = 0; $i < $steps && $i < $n; ++$i) {
  270. $this->img->current_color = $colors[$steps+$i];
  271. $y = $yt+($i/$steps)*($yb-$yt)*$delta;
  272. $this->img->Line($x,$yb,$xr,$y);
  273. $x += $delta;
  274. }
  275. } else {
  276. // height is greater than width -> use y-dimension for steps
  277. $steps = $yb-$yt;
  278. $delta = $yb>=$yt ? 1 : -1;
  279. $this->GetColArray($from_color,$to_color,$steps*2,$colors,$this->numcolors);
  280. $n = count($colors);
  281. for($y=$yt, $i=0; $i < $steps && $i < $n; ++$i) {
  282. $this->img->current_color = $colors[$i];
  283. $x = $xl+($i/$steps)*($xr-$xl)*$delta;
  284. $this->img->Line($x,$yt,$xl,$y);
  285. $y += $delta;
  286. }
  287. for($y=$yt, $i = 0; $i < $steps && $i < $n; ++$i) {
  288. $this->img->current_color = $colors[$steps+$i];
  289. $x = $xl+($i/$steps)*($xr-$xl)*$delta;
  290. $this->img->Line($x,$yb,$xr,$y);
  291. $x += $delta;
  292. }
  293. }
  294. break;
  295. default:
  296. JpGraphError::RaiseL(7001,$style);
  297. //("Unknown gradient style (=$style).");
  298. break;
  299. }
  300. }
  301. // Fill a special case of a polygon with a flat bottom
  302. // with a gradient. Can be used for filled line plots.
  303. // Please note that this is NOT a generic gradient polygon fill
  304. // routine. It assumes that the bottom is flat (like a drawing
  305. // of a mountain)
  306. function FilledFlatPolygon($pts,$from_color,$to_color) {
  307. if( count($pts) == 0 ) return;
  308. $maxy=$pts[1];
  309. $miny=$pts[1];
  310. $n = count($pts) ;
  311. for( $i=0, $idx=0; $i < $n; $i += 2) {
  312. $x = round($pts[$i]);
  313. $y = round($pts[$i+1]);
  314. $miny = min($miny,$y);
  315. $maxy = max($maxy,$y);
  316. }
  317. $colors = array();
  318. $this->GetColArray($from_color,$to_color,abs($maxy-$miny)+1,$colors,$this->numcolors);
  319. for($i=$miny, $idx=0; $i <= $maxy; ++$i ) {
  320. $colmap[$i] = $colors[$idx++];
  321. }
  322. $n = count($pts)/2 ;
  323. $idx = 0 ;
  324. while( $idx < $n-1 ) {
  325. $p1 = array(round($pts[$idx*2]),round($pts[$idx*2+1]));
  326. $p2 = array(round($pts[++$idx*2]),round($pts[$idx*2+1]));
  327. // Find the largest rectangle we can fill
  328. $y = max($p1[1],$p2[1]) ;
  329. for($yy=$maxy; $yy > $y; --$yy) {
  330. $this->img->current_color = $colmap[$yy];
  331. $this->img->Line($p1[0],$yy,$p2[0]-1,$yy);
  332. }
  333. if( $p1[1] == $p2[1] ) {
  334. continue;
  335. }
  336. // Fill the rest using lines (slow...)
  337. $slope = ($p2[0]-$p1[0])/($p1[1]-$p2[1]);
  338. $x1 = $p1[0];
  339. $x2 = $p2[0]-1;
  340. $start = $y;
  341. if( $p1[1] > $p2[1] ) {
  342. while( $y >= $p2[1] ) {
  343. $x1=$slope*($start-$y)+$p1[0];
  344. $this->img->current_color = $colmap[$y];
  345. $this->img->Line($x1,$y,$x2,$y);
  346. --$y;
  347. }
  348. }
  349. else {
  350. while( $y >= $p1[1] ) {
  351. $x2=$p2[0]+$slope*($start-$y);
  352. $this->img->current_color = $colmap[$y];
  353. $this->img->Line($x1,$y,$x2,$y);
  354. --$y;
  355. }
  356. }
  357. }
  358. }
  359. //---------------
  360. // PRIVATE METHODS
  361. // Add to the image color map the necessary colors to do the transition
  362. // between the two colors using $numcolors intermediate colors
  363. function GetColArray($from_color,$to_color,$arr_size,&$colors,$numcols=100) {
  364. if( $arr_size==0 ) {
  365. return;
  366. }
  367. // If color is given as text get it's corresponding r,g,b values
  368. $from_color = $this->img->rgb->Color($from_color);
  369. $to_color = $this->img->rgb->Color($to_color);
  370. $rdelta=($to_color[0]-$from_color[0])/$numcols;
  371. $gdelta=($to_color[1]-$from_color[1])/$numcols;
  372. $bdelta=($to_color[2]-$from_color[2])/$numcols;
  373. $colorsperstep = $numcols/$arr_size;
  374. $prevcolnum = -1;
  375. $from_alpha = $from_color[3];
  376. $to_alpha = $to_color[3];
  377. $adelta = ( $to_alpha - $from_alpha ) / $numcols ;
  378. for ($i=0; $i < $arr_size; ++$i) {
  379. $colnum = floor($colorsperstep*$i);
  380. if ( $colnum == $prevcolnum ) {
  381. $colors[$i] = $colidx;
  382. }
  383. else {
  384. $r = floor($from_color[0] + $colnum*$rdelta);
  385. $g = floor($from_color[1] + $colnum*$gdelta);
  386. $b = floor($from_color[2] + $colnum*$bdelta);
  387. $alpha = $from_alpha + $colnum*$adelta;
  388. $colidx = $this->img->rgb->Allocate(sprintf("#%02x%02x%02x",$r,$g,$b),$alpha);
  389. $colors[$i] = $colidx;
  390. }
  391. $prevcolnum = $colnum;
  392. }
  393. }
  394. } // Class
  395. ?>