2
2
* Gradient
3
3
* class to create linear/radial/elliptical/conic gradients as bitmaps even without canvas
4
4
*
5
- * @version 1.0 .0
5
+ * @version 1.1 .0
6
6
* https://github.com/foo123/Gradient
7
7
*
8
8
**/
@@ -27,15 +27,42 @@ function Gradient(gradColorGetter)
27
27
{
28
28
var self = this ;
29
29
self . _colorAt = gradColorGetter || null ;
30
+ self . resetTransform ( ) ;
30
31
self . addColorStop ( 0 , 'transparent' ) ;
31
32
self . addColorStop ( 1 , 'transparent' ) ;
32
33
}
33
- Gradient . VERSION = "1.0 .0" ;
34
+ Gradient . VERSION = "1.1 .0" ;
34
35
Gradient . prototype = {
35
36
constructor : Gradient ,
36
37
stops : null ,
37
38
_stops : null ,
38
39
_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
+ } ,
39
66
addColorStop : function ( offset , color ) {
40
67
var self = this ;
41
68
if ( null == self . stops ) self . stops = { } ;
@@ -45,29 +72,27 @@ Gradient.prototype = {
45
72
self . _stops = o . map ( function ( o ) { return self . stops [ o ] ; } ) ;
46
73
} ,
47
74
getColorAt : function ( x , y ) {
48
- var self = this , stops ;
75
+ var self = this , p ;
49
76
if ( self . _colorAt )
50
77
{
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 ) ;
52
80
}
53
81
} ,
54
82
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 ;
57
85
if ( color_at )
58
86
{
59
- size = ( w * h ) << 2 ;
87
+ size = ( w * h ) << 2 ;
60
88
bmp = new ImArray ( size ) ;
61
89
c = new ImArray ( 4 ) ;
62
90
stops = self . _stops ;
63
91
for ( x = 0 , y = 0 , i = 0 ; i < size ; i += 4 , ++ x )
64
92
{
65
93
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 ) ;
71
96
}
72
97
return bmp ;
73
98
}
@@ -82,7 +107,7 @@ Gradient.createLinearGradient = function(x1, y1, x2, y2) {
82
107
vert = is_strictly_equal ( dx , 0 ) ,
83
108
hor = is_strictly_equal ( dy , 0 ) ,
84
109
f = 2 * dx * dy ;
85
- return new Gradient ( function ( x , y , stops , pixel ) {
110
+ return new Gradient ( function ( x , y , stops , pixel , i ) {
86
111
var t , px , py , stop1 , stop2 , sl = stops . length ;
87
112
px = x - x1 ; py = y - y1 ;
88
113
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) {
102
127
stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
103
128
}
104
129
return interpolatePixel (
105
- pixel , 0 ,
130
+ pixel , i || 0 ,
106
131
stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
107
132
// warp the value if needed, between stop ranges
108
133
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) {
125
150
var a = r0 * r0 - 2 * r0 * r1 + r1 * r1 - x0 * x0 + 2 * x0 * x1 - x1 * x1 - y0 * y0 + 2 * y0 * y1 - y1 * y1 ,
126
151
b = - 2 * r0 * r0 + 2 * r0 * r1 + 2 * x0 * x0 - 2 * x0 * x1 + 2 * y0 * y0 - 2 * y0 * y1 ,
127
152
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 ) {
129
154
var t , px , py , pr , s , stop1 , stop2 , sl = stops . length ;
130
155
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 ) ;
131
156
if ( ! s )
@@ -165,7 +190,7 @@ Gradient.createRadialGradient = function(x0, y0, r0, x1, y1, r1) {
165
190
stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
166
191
}
167
192
return interpolatePixel (
168
- pixel , 0 ,
193
+ pixel , i || 0 ,
169
194
stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
170
195
// warp the value if needed, between stop ranges
171
196
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) {
176
201
angle = angle || 0 ;
177
202
cx = cx || 0 ;
178
203
cy = cy || 0 ;
179
- return new Gradient ( function ( x , y , stops , pixel ) {
204
+ return new Gradient ( function ( x , y , stops , pixel , i ) {
180
205
var t , stop1 , stop2 , sl = stops . length ;
181
206
t = stdMath . atan2 ( y - cy , x - cx ) + HALF_PI - angle ;
182
207
if ( 0 > t ) t += TWO_PI ;
@@ -185,7 +210,7 @@ Gradient.createConicGradient = function(angle, cx, cy) {
185
210
stop2 = binary_search ( t , stops , sl ) ;
186
211
stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
187
212
return interpolatePixel (
188
- pixel , 0 ,
213
+ pixel , i || 0 ,
189
214
stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
190
215
// warp the value if needed, between stop ranges
191
216
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) {
199
224
ry = ry || 0 ;
200
225
angle = angle || 0 ;
201
226
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 ) {
203
228
var t , px , py , stop1 , stop2 , sl = stops . length ;
204
229
px = ( cos * ( x - cx ) - sin * ( y - cy ) ) / rx ;
205
230
py = ( sin * ( x - cx ) + cos * ( y - cy ) ) / ry ;
@@ -215,14 +240,114 @@ Gradient.createEllipticGradient = function(cx, cy, rx, ry, angle) {
215
240
stop1 = 0 === stop2 ? 0 : ( stop2 - 1 ) ;
216
241
}
217
242
return interpolatePixel (
218
- pixel , 0 ,
243
+ pixel , i || 0 ,
219
244
stops [ stop1 ] [ 1 ] , stops [ stop2 ] [ 1 ] ,
220
245
// warp the value if needed, between stop ranges
221
246
stops [ stop2 ] [ 0 ] > stops [ stop1 ] [ 0 ] ? ( t - stops [ stop1 ] [ 0 ] ) / ( stops [ stop2 ] [ 0 ] - stops [ stop1 ] [ 0 ] ) : t
222
247
) ;
223
248
} ) ;
224
249
} ;
225
250
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
+
226
351
// utils
227
352
function is_strictly_equal ( a , b )
228
353
{
0 commit comments