22* Gradient
33* class to create linear/radial/elliptical/conic gradients as bitmaps even without canvas
44*
5- * @version 1.0 .0
5+ * @version 1.1 .0
66* https://github.com/foo123/Gradient
77*
88**/
@@ -27,15 +27,42 @@ function Gradient(gradColorGetter)
2727{
2828 var self = this ;
2929 self . _colorAt = gradColorGetter || null ;
30+ self . resetTransform ( ) ;
3031 self . addColorStop ( 0 , 'transparent' ) ;
3132 self . addColorStop ( 1 , 'transparent' ) ;
3233}
33- Gradient . VERSION = "1.0 .0" ;
34+ Gradient . VERSION = "1.1 .0" ;
3435Gradient . prototype = {
3536 constructor : Gradient ,
3637 stops : null ,
3738 _stops : null ,
3839 _colorAt : null ,
40+ matrix : null ,
41+ imatrix : null ,
42+ resetTransform : function ( ) {
43+ this . matrix = new Matrix ( ) ;
44+ this . imatrix = new Matrix ( ) ;
45+ } ,
46+ scale : function ( sx , sy , ox , oy ) {
47+ this . matrix = Matrix . scale ( sx , sy , ox , oy ) . mul ( this . matrix ) ;
48+ this . imatrix = this . matrix . inv ( ) ;
49+ } ,
50+ rotate : function ( theta , ox , oy ) {
51+ this . matrix = Matrix . rotate ( theta , ox , oy ) . mul ( this . matrix ) ;
52+ this . imatrix = this . matrix . inv ( ) ;
53+ } ,
54+ translate : function ( tx , ty ) {
55+ this . matrix = Matrix . translate ( tx , ty ) . mul ( this . matrix ) ;
56+ this . imatrix = this . matrix . inv ( ) ;
57+ } ,
58+ skewX : function ( s ) {
59+ this . matrix = Matrix . skewX ( s ) . mul ( this . matrix ) ;
60+ this . imatrix = this . matrix . inv ( ) ;
61+ } ,
62+ skewY : function ( s ) {
63+ this . matrix = Matrix . skewY ( s ) . mul ( this . matrix ) ;
64+ this . imatrix = this . matrix . inv ( ) ;
65+ } ,
3966 addColorStop : function ( offset , color ) {
4067 var self = this ;
4168 if ( null == self . stops ) self . stops = { } ;
@@ -45,29 +72,27 @@ Gradient.prototype = {
4572 self . _stops = o . map ( function ( o ) { return self . stops [ o ] ; } ) ;
4673 } ,
4774 getColorAt : function ( x , y ) {
48- var self = this , stops ;
75+ var self = this , p ;
4976 if ( self . _colorAt )
5077 {
51- return self . _colorAt ( x , y , self . _stops , new ImArray ( 4 ) ) ;
78+ p = self . imatrix . transform ( x , y )
79+ return self . _colorAt ( p . x , p . y , self . _stops , new ImArray ( 4 ) , 0 ) ;
5280 }
5381 } ,
5482 getBitmap : function ( w , h ) {
55- var self = this , color_at = self . _colorAt ,
56- stops , i , x , y , size , bmp , c ;
83+ var self = this , m = self . imatrix , color_at = self . _colorAt ,
84+ stops , i , x , y , p , size , bmp , c ;
5785 if ( color_at )
5886 {
59- size = ( w * h ) << 2 ;
87+ size = ( w * h ) << 2 ;
6088 bmp = new ImArray ( size ) ;
6189 c = new ImArray ( 4 ) ;
6290 stops = self . _stops ;
6391 for ( x = 0 , y = 0 , i = 0 ; i < size ; i += 4 , ++ x )
6492 {
6593 if ( x >= w ) { x = 0 ; ++ y ; }
66- color_at ( x , y , stops , c ) ;
67- bmp [ i + 0 ] = c [ 0 ] ;
68- bmp [ i + 1 ] = c [ 1 ] ;
69- bmp [ i + 2 ] = c [ 2 ] ;
70- bmp [ i + 3 ] = c [ 3 ] ;
94+ p = m . transform ( x , y )
95+ color_at ( p . x , p . y , stops , bmp , i ) ;
7196 }
7297 return bmp ;
7398 }
@@ -82,7 +107,7 @@ Gradient.createLinearGradient = function(x1, y1, x2, y2) {
82107 vert = is_strictly_equal ( dx , 0 ) ,
83108 hor = is_strictly_equal ( dy , 0 ) ,
84109 f = 2 * dx * dy ;
85- return new Gradient ( function ( x , y , stops , pixel ) {
110+ return new Gradient ( function ( x , y , stops , pixel , i ) {
86111 var t , px , py , stop1 , stop2 , sl = stops . length ;
87112 px = x - x1 ; py = y - y1 ;
88113 t = hor && vert ? 0 : ( vert ? py / dy : ( hor ? px / dx : ( px * dy + py * dx ) / f ) ) ;
@@ -102,7 +127,7 @@ Gradient.createLinearGradient = function(x1, y1, x2, y2) {
102127 stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
103128 }
104129 return interpolatePixel (
105- pixel , 0 ,
130+ pixel , i || 0 ,
106131 stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
107132 // warp the value if needed, between stop ranges
108133 stops [ stop2 ] [ 0 ] > stops [ stop1 ] [ 0 ] ? ( t - stops [ stop1 ] [ 0 ] ) / ( stops [ stop2 ] [ 0 ] - stops [ stop1 ] [ 0 ] ) : t
@@ -125,7 +150,7 @@ Gradient.createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
125150 var a = r0 * r0 - 2 * r0 * r1 + r1 * r1 - x0 * x0 + 2 * x0 * x1 - x1 * x1 - y0 * y0 + 2 * y0 * y1 - y1 * y1 ,
126151 b = - 2 * r0 * r0 + 2 * r0 * r1 + 2 * x0 * x0 - 2 * x0 * x1 + 2 * y0 * y0 - 2 * y0 * y1 ,
127152 c = - x0 * x0 - y0 * y0 + r0 * r0 ;
128- return new Gradient ( function ( x , y , stops , pixel ) {
153+ return new Gradient ( function ( x , y , stops , pixel , i ) {
129154 var t , px , py , pr , s , stop1 , stop2 , sl = stops . length ;
130155 s = quadratic_roots ( a , b - 2 * x * x0 + 2 * x * x1 - 2 * y * y0 + 2 * y * y1 , c - x * x + 2 * x * x0 - y * y + 2 * y * y0 ) ;
131156 if ( ! s )
@@ -165,7 +190,7 @@ Gradient.createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
165190 stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
166191 }
167192 return interpolatePixel (
168- pixel , 0 ,
193+ pixel , i || 0 ,
169194 stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
170195 // warp the value if needed, between stop ranges
171196 stops [ stop2 ] [ 0 ] > stops [ stop1 ] [ 0 ] ? ( t - stops [ stop1 ] [ 0 ] ) / ( stops [ stop2 ] [ 0 ] - stops [ stop1 ] [ 0 ] ) : t
@@ -176,7 +201,7 @@ Gradient.createConicGradient = function(angle, cx, cy) {
176201 angle = angle || 0 ;
177202 cx = cx || 0 ;
178203 cy = cy || 0 ;
179- return new Gradient ( function ( x , y , stops , pixel ) {
204+ return new Gradient ( function ( x , y , stops , pixel , i ) {
180205 var t , stop1 , stop2 , sl = stops . length ;
181206 t = stdMath . atan2 ( y - cy , x - cx ) + HALF_PI - angle ;
182207 if ( 0 > t ) t += TWO_PI ;
@@ -185,7 +210,7 @@ Gradient.createConicGradient = function(angle, cx, cy) {
185210 stop2 = binary_search ( t , stops , sl ) ;
186211 stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
187212 return interpolatePixel (
188- pixel , 0 ,
213+ pixel , i || 0 ,
189214 stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
190215 // warp the value if needed, between stop ranges
191216 stops [ stop2 ] [ 0 ] > stops [ stop1 ] [ 0 ] ? ( t - stops [ stop1 ] [ 0 ] ) / ( stops [ stop2 ] [ 0 ] - stops [ stop1 ] [ 0 ] ) : t
@@ -199,7 +224,7 @@ Gradient.createEllipticGradient = function(cx, cy, rx, ry, angle) {
199224 ry = ry || 0 ;
200225 angle = angle || 0 ;
201226 var cos = stdMath . cos ( angle ) , sin = stdMath . sin ( angle ) ;
202- return new Gradient ( function ( x , y , stops , pixel ) {
227+ return new Gradient ( function ( x , y , stops , pixel , i ) {
203228 var t , px , py , stop1 , stop2 , sl = stops . length ;
204229 px = ( cos * ( x - cx ) - sin * ( y - cy ) ) / rx ;
205230 py = ( sin * ( x - cx ) + cos * ( y - cy ) ) / ry ;
@@ -215,14 +240,114 @@ Gradient.createEllipticGradient = function(cx, cy, rx, ry, angle) {
215240 stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
216241 }
217242 return interpolatePixel (
218- pixel , 0 ,
243+ pixel , i || 0 ,
219244 stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
220245 // warp the value if needed, between stop ranges
221246 stops [ stop2 ] [ 0 ] > stops [ stop1 ] [ 0 ] ? ( t - stops [ stop1 ] [ 0 ] ) / ( stops [ stop2 ] [ 0 ] - stops [ stop1 ] [ 0 ] ) : t
222247 ) ;
223248 } ) ;
224249} ;
225250
251+ function Matrix ( m00 , m01 , m02 , m10 , m11 , m12 )
252+ {
253+ var self = this ;
254+ if ( arguments . length )
255+ {
256+ self . m00 = m00 ;
257+ self . m01 = m01 ;
258+ self . m02 = m02 ;
259+ self . m10 = m10 ;
260+ self . m11 = m11 ;
261+ self . m12 = m12 ;
262+ }
263+ else
264+ {
265+ self . m00 = 1 ;
266+ self . m01 = 0 ;
267+ self . m02 = 0 ;
268+ self . m10 = 0 ;
269+ self . m11 = 1 ;
270+ self . m12 = 0 ;
271+ }
272+ }
273+ Matrix . prototype = {
274+ constructor : Matrix ,
275+ m00 : 1 ,
276+ m01 : 0 ,
277+ m02 : 0 ,
278+ m10 : 0 ,
279+ m11 : 1 ,
280+ m12 : 0 ,
281+ mul : function ( other ) {
282+ var self = this ;
283+ return new Matrix (
284+ self . m00 * other . m00 + self . m01 * other . m10 ,
285+ self . m00 * other . m01 + self . m01 * other . m11 ,
286+ self . m00 * other . m02 + self . m01 * other . m12 + self . m02 ,
287+ self . m10 * other . m00 + self . m11 * other . m10 ,
288+ self . m10 * other . m01 + self . m11 * other . m11 ,
289+ self . m10 * other . m02 + self . m11 * other . m12 + self . m12
290+ ) ;
291+ } ,
292+ inv : function ( ) {
293+ var self = this ,
294+ a00 = self . m00 , a01 = self . m01 , a02 = self . m02 ,
295+ a10 = self . m10 , a11 = self . m11 , a12 = self . m12 ,
296+ det2 = a00 * a11 - a01 * a10 ,
297+ i00 = 0 , i01 = 0 , i10 = 0 , i11 = 0 ;
298+
299+ if ( is_strictly_equal ( det2 , 0 ) ) return null ;
300+ i00 = a11 / det2 ; i01 = - a01 / det2 ;
301+ i10 = - a10 / det2 ; i11 = a00 / det2 ;
302+ return new Matrix (
303+ i00 , i01 , - i00 * a02 - i01 * a12 ,
304+ i10 , i11 , - i10 * a02 - i11 * a12
305+ ) ;
306+ } ,
307+ transform : function ( x , y ) {
308+ var self = this ;
309+ return {
310+ x : self . m00 * x + self . m01 * y + self . m02 ,
311+ y : self . m10 * x + self . m11 * y + self . m12
312+ } ;
313+ }
314+ } ;
315+ Matrix . translate = function ( tx , ty ) {
316+ return new Matrix (
317+ 1 , 0 , tx ,
318+ 0 , 1 , ty
319+ ) ;
320+ } ;
321+ Matrix . scale = function ( sx , sy , ox , oy ) {
322+ ox = ox || 0 ;
323+ oy = oy || 0 ;
324+ return new Matrix (
325+ sx , 0 , - sx * ox + ox ,
326+ 0 , sy , - sy * oy + oy
327+ ) ;
328+ } ;
329+ Matrix . rotate = function ( theta , ox , oy ) {
330+ ox = ox || 0 ;
331+ oy = oy || 0 ;
332+ var cos = stdMath . cos ( theta ) , sin = stdMath . sin ( theta ) ;
333+ return new Matrix (
334+ cos , - sin , ox - cos * ox + sin * oy ,
335+ sin , cos , oy - cos * oy - sin * ox
336+ ) ;
337+ } ;
338+ Matrix . skewX = function ( s ) {
339+ return new Matrix (
340+ 1 , s , 0 ,
341+ 0 , 1 , 0
342+ ) ;
343+ } ;
344+ Matrix . skewY = function ( s ) {
345+ return new Matrix (
346+ 1 , 0 , 0 ,
347+ s , 1 , 0
348+ ) ;
349+ } ;
350+
226351// utils
227352function is_strictly_equal ( a , b )
228353{
0 commit comments