Skip to content

Commit fd494ad

Browse files
committed
v.1.2.2
* Transform.transform() method * Export Matrix, Transform, * update examples
1 parent fe9dbc3 commit fd494ad

File tree

5 files changed

+119
-34
lines changed

5 files changed

+119
-34
lines changed

README.md

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Class to create **linear, radial, conic and elliptic gradients** and **image patterns** as bitmaps without canvas
44

5-
**version 1.2.1** (13 kB minified)
5+
**version 1.2.2** (13 kB minified)
66

77
**API:**
88

@@ -23,6 +23,7 @@ grad.transform.reflectX();
2323
grad.transform.reflectY();
2424
grad.transform.skewX(s);
2525
grad.transform.skewY(s);
26+
grad.transform.transform(a, b, c, d, e, f);
2627
grad.transform.reset();
2728
grad.transform.save();
2829
grad.transform.restore();
@@ -41,6 +42,7 @@ pat.transform.reflectX();
4142
pat.transform.reflectY();
4243
pat.transform.skewX(s);
4344
pat.transform.skewY(s);
45+
pat.transform.transform(a, b, c, d, e, f);
4446
pat.transform.reset();
4547
pat.transform.save();
4648
pat.transform.restore();
@@ -53,6 +55,7 @@ pat.getBitmap(width, height);
5355

5456
```javascript
5557
const w = 200, h = 200;
58+
const Matrix = Gradient.Matrix;
5659

5760
function addColorStops(gradient)
5861
{
@@ -63,6 +66,22 @@ function addColorStops(gradient)
6366
});
6467
return gradient;
6568
}
69+
function fill_transformed_rect(ctx, x, y, w, h)
70+
{
71+
const m = ctx.getTransform();
72+
const m2 = (new Matrix(m.a, m.c, m.e, m.b, m.d, m.f)).inv();
73+
const p1 = m2.transform(x, y),
74+
p2 = m2.transform(x+w, y),
75+
p3 = m2.transform(x+w, y+h),
76+
p4 = m2.transform(x, y+h);
77+
ctx.beginPath();
78+
ctx.moveTo(p1.x, p1.y);
79+
ctx.lineTo(p2.x, p2.y);
80+
ctx.lineTo(p3.x, p3.y);
81+
ctx.lineTo(p4.x, p4.y);
82+
ctx.closePath();
83+
ctx.fill();
84+
}
6685
function drawLinearGradient(x1, y1, x2, y2)
6786
{
6887
const canvas1 = document.getElementById('linear1');
@@ -107,26 +126,56 @@ function drawEllipticGradient(cx, cy, rx, ry, angle)
107126
{
108127
const canvas1 = document.getElementById('elliptic1');
109128
const canvas2 = document.getElementById('elliptic2');
129+
const canvas3 = document.getElementById('elliptic3');
130+
const canvas4 = document.getElementById('elliptic4');
110131
const ctx1 = canvas1.getContext("2d");
111132
const ctx2 = canvas2.getContext("2d");
133+
const ctx3 = canvas3.getContext("2d");
134+
const ctx4 = canvas4.getContext("2d");
112135

113136
const r = Math.max(rx, ry), sx = rx/r, sy = ry/r;
114137

115138
const gradient1 = ctx1.createRadialGradient(cx/sx, cy/sy, 0, cx/sx, cy/sy, r);
116-
const gradient2 = Gradient.createEllipticGradient(cx, cy, rx, ry, 0/*angle*/);
139+
const gradient2 = Gradient.createRadialGradient(cx/sx, cy/sy, 0, cx/sx, cy/sy, r);
140+
const gradient3 = ctx3.createRadialGradient(cx, cy, 0, cx, cy, r);
141+
const gradient4 = Gradient.createEllipticGradient(cx, cy, rx, ry, angle);
117142

118143
addColorStops(gradient1);
119144
addColorStops(gradient2);
145+
addColorStops(gradient3);
146+
addColorStops(gradient4);
120147

121-
// scale radial gradient1 to become an unrotated elliptic
148+
// transform radial gradient1 to become an unrotated elliptic
122149
ctx1.scale(sx, sy);
123150
ctx1.fillStyle = gradient1;
124-
ctx1.fillRect(0, 0, w/sx, h/sy);
125-
126-
// gradient2 is true elliptic gradient
151+
fill_transformed_rect(ctx1, 0, 0, w, h);
152+
153+
// create a pattern from the gradient, just for fun
154+
const pattern2 = Gradient.createPattern({
155+
data: gradient2.getBitmap(w/sx, h/sy),
156+
width: Math.round(w/sx),
157+
height: Math.round(h/sy)
158+
}, 'no-repeat');
159+
// gradient2/pattern2 is a transformed radial gradient
160+
//pattern2.transform.translate(-cx, -cy);
161+
pattern2.transform.scale(sx, sy);
162+
//pattern2.transform.rotate(-angle);
163+
//pattern2.transform.translate(cx, cy);
127164
const imData2 = ctx2.createImageData(w, h);
128-
imData2.data.set(gradient2.getBitmap(w, h));
165+
imData2.data.set(pattern2.getBitmap(w, h));
129166
ctx2.putImageData(imData2, 0, 0);
167+
168+
// transform radial gradient3 to become a rotated elliptic
169+
ctx3.translate(cx, cy);
170+
ctx3.rotate(-angle);
171+
ctx3.translate(-cx*sx, -cy*sy);
172+
ctx3.scale(sx, sy);
173+
ctx3.fillStyle = gradient3;
174+
fill_transformed_rect(ctx3, 0, 0, w, h);
175+
// gradient4 is elliptic gradient
176+
const imData4 = ctx4.createImageData(w, h);
177+
imData4.data.set(gradient4.getBitmap(w, h));
178+
ctx4.putImageData(imData4, 0, 0);
130179
}
131180
function drawConicGradient(angle, cx, cy)
132181
{

screenshot.png

-892 Bytes
Loading

src/Gradient.js

Lines changed: 36 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Gradient
33
* class to create linear/radial/elliptical/conic gradients as bitmaps even without canvas
44
*
5-
* @version 1.2.1
5+
* @version 1.2.2
66
* https://github.com/foo123/Gradient
77
*
88
**/
@@ -63,27 +63,32 @@ function Gradient(grad_color_at)
6363
stops[String(offset)] = [+offset, parseColor(color) || [0,0,0,0]];
6464
};
6565
self.getColorAt = function(x, y) {
66-
var p = transform.imatrix(true).transform(x, y);
67-
return grad_color_at(p.x, p.y, colorStops(), new ImArray(4), 0);
66+
var im = transform.imatrix(true),
67+
p = im ? im.transform(x, y) : null;
68+
return p ? grad_color_at(p.x, p.y, colorStops(), new ImArray(4), 0) : new ImArray(4);
6869
};
6970
self.getBitmap = function(width, height) {
7071
width = stdMath.round(width);
7172
height = stdMath.round(height);
7273
var imatrix = transform.imatrix(true),
73-
color_stops = colorStops(),
74+
color_stops,
7475
i, x, y, p,
7576
size = (width*height) << 2,
7677
bmp = new ImArray(size);
77-
for (x=0,y=0,i=0; i<size; i+=4,++x)
78+
if (imatrix)
7879
{
79-
if (x >= width) {x=0; ++y;}
80-
p = imatrix.transform(x, y);
81-
grad_color_at(p.x, p.y, color_stops, bmp, i);
80+
color_stops = colorStops();
81+
for (x=0,y=0,i=0; i<size; i+=4,++x)
82+
{
83+
if (x >= width) {x=0; ++y;}
84+
p = imatrix.transform(x, y);
85+
grad_color_at(p.x, p.y, color_stops, bmp, i);
86+
}
8287
}
8388
return bmp;
8489
};
8590
}
86-
Gradient.VERSION = "1.2.1";
91+
Gradient.VERSION = "1.2.2";
8792
Gradient.prototype = {
8893
constructor: Gradient,
8994
transform: null,
@@ -433,6 +438,13 @@ function Transform()
433438
imatrix = imatrix.mul(Matrix.skewY(s).inv());
434439
return self;
435440
};
441+
self.transform = function(a, b, c, d, e, f) {
442+
var m = new Matrix(a, c, e, b, d, f);
443+
matrix = m.mul(matrix);
444+
imatrix = imatrix.mul(m.inv());
445+
return self;
446+
};
447+
436448
}
437449
Transform.prototype = {
438450
constructor: Transform,
@@ -448,8 +460,10 @@ Transform.prototype = {
448460
reflectX: null,
449461
reflectY: null,
450462
skewX: null,
451-
skewY: null
463+
skewY: null,
464+
transform: null
452465
};
466+
Gradient.Transform = Transform;
453467

454468
// Homogeneous Transformation Matrix
455469
function Matrix(m00, m01, m02, m10, m11, m12)
@@ -482,14 +496,17 @@ Matrix.prototype = {
482496
},
483497
mul: function(other) {
484498
var self = this;
485-
return new Matrix(
486-
self.m00*other.m00 + self.m01*other.m10,
487-
self.m00*other.m01 + self.m01*other.m11,
488-
self.m00*other.m02 + self.m01*other.m12 + self.m02,
489-
self.m10*other.m00 + self.m11*other.m10,
490-
self.m10*other.m01 + self.m11*other.m11,
491-
self.m10*other.m02 + self.m11*other.m12 + self.m12
492-
);
499+
if (other instanceof Matrix)
500+
{
501+
return new Matrix(
502+
self.m00*other.m00 + self.m01*other.m10,
503+
self.m00*other.m01 + self.m01*other.m11,
504+
self.m00*other.m02 + self.m01*other.m12 + self.m02,
505+
self.m10*other.m00 + self.m11*other.m10,
506+
self.m10*other.m01 + self.m11*other.m11,
507+
self.m10*other.m02 + self.m11*other.m12 + self.m12
508+
);
509+
}
493510
},
494511
inv: function() {
495512
var self = this,
@@ -566,6 +583,7 @@ Matrix.skewY = function(s) {
566583
s || 0, 1, 0
567584
);
568585
};
586+
Gradient.Matrix = Matrix;
569587

570588
// utils
571589
function is_strictly_equal(a, b)

0 commit comments

Comments
 (0)