@emasoft/svg-matrix 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/bin/svg-matrix.js +7 -6
  2. package/bin/svgm.js +109 -40
  3. package/dist/svg-matrix.min.js +7 -7
  4. package/dist/svg-toolbox.min.js +148 -228
  5. package/dist/svgm.min.js +152 -232
  6. package/dist/version.json +5 -5
  7. package/package.json +1 -1
  8. package/scripts/postinstall.js +72 -41
  9. package/scripts/test-postinstall.js +18 -16
  10. package/scripts/version-sync.js +78 -60
  11. package/src/animation-optimization.js +190 -98
  12. package/src/animation-references.js +11 -3
  13. package/src/arc-length.js +23 -20
  14. package/src/bezier-analysis.js +9 -13
  15. package/src/bezier-intersections.js +18 -4
  16. package/src/browser-verify.js +35 -8
  17. package/src/clip-path-resolver.js +285 -114
  18. package/src/convert-path-data.js +20 -8
  19. package/src/css-specificity.js +33 -9
  20. package/src/douglas-peucker.js +272 -141
  21. package/src/geometry-to-path.js +79 -22
  22. package/src/gjk-collision.js +287 -126
  23. package/src/index.js +56 -21
  24. package/src/inkscape-support.js +122 -101
  25. package/src/logger.js +43 -27
  26. package/src/marker-resolver.js +201 -121
  27. package/src/mask-resolver.js +231 -98
  28. package/src/matrix.js +9 -5
  29. package/src/mesh-gradient.js +22 -14
  30. package/src/off-canvas-detection.js +53 -17
  31. package/src/path-optimization.js +356 -171
  32. package/src/path-simplification.js +671 -256
  33. package/src/pattern-resolver.js +1 -3
  34. package/src/polygon-clip.js +396 -78
  35. package/src/svg-boolean-ops.js +90 -23
  36. package/src/svg-collections.js +1546 -667
  37. package/src/svg-flatten.js +152 -38
  38. package/src/svg-matrix-lib.js +2 -2
  39. package/src/svg-parser.js +5 -1
  40. package/src/svg-rendering-context.js +3 -1
  41. package/src/svg-toolbox-lib.js +2 -2
  42. package/src/svg-toolbox.js +99 -457
  43. package/src/svg-validation-data.js +513 -345
  44. package/src/svg2-polyfills.js +156 -93
  45. package/src/svgm-lib.js +8 -4
  46. package/src/transform-optimization.js +168 -51
  47. package/src/transforms2d.js +73 -40
  48. package/src/transforms3d.js +34 -27
  49. package/src/use-symbol-resolver.js +175 -76
  50. package/src/vector.js +80 -44
  51. package/src/vendor/inkscape-hatch-polyfill.js +143 -108
  52. package/src/vendor/inkscape-hatch-polyfill.min.js +291 -1
  53. package/src/vendor/inkscape-mesh-polyfill.js +953 -766
  54. package/src/vendor/inkscape-mesh-polyfill.min.js +896 -1
  55. package/src/verification.js +3 -4
@@ -1,843 +1,1030 @@
1
-
2
1
  // Use Canvas to render a mesh gradient, passing the rendering to an image via a data stream.
3
2
  // Copyright: Tavmjong Bah 2017
4
3
  // Distributed under GNU General Public License version 3 or later. See <http://fsf.org/>.
5
4
 
6
- (function() {
7
- var counter = 0; // Temp, number of calls to Canvas
5
+ (function () {
6
+ var counter = 0; // Temp, number of calls to Canvas
8
7
 
9
- // Name spaces -----------------------------------
10
- var svgNS = "http://www.w3.org/2000/svg",
11
- xlinkNS = "http://www.w3.org/1999/xlink",
12
- xhtmlNS = "http://www.w3.org/1999/xhtml";
8
+ // Name spaces -----------------------------------
9
+ var svgNS = "http://www.w3.org/2000/svg",
10
+ xlinkNS = "http://www.w3.org/1999/xlink",
11
+ xhtmlNS = "http://www.w3.org/1999/xhtml";
13
12
 
14
- // Test if mesh gradients are supported.
15
- var m = document.createElementNS( svgNS, "meshgradient" );
13
+ // Test if mesh gradients are supported.
14
+ var m = document.createElementNS(svgNS, "meshgradient");
16
15
 
17
- if (m.x) {
18
- return;
19
- }
16
+ if (m.x) {
17
+ return;
18
+ }
20
19
 
21
- // Point class -----------------------------------
22
- function Point(x, y) {
23
- this.x = x || 0;
24
- this.y = y || 0;
25
- }
20
+ // Point class -----------------------------------
21
+ function Point(x, y) {
22
+ this.x = x || 0;
23
+ this.y = y || 0;
24
+ }
26
25
 
27
- Point.prototype.x = null;
28
- Point.prototype.y = null;
26
+ Point.prototype.x = null;
27
+ Point.prototype.y = null;
29
28
 
30
- Point.prototype.get_x = function() {
31
- return this.x;
32
- };
29
+ Point.prototype.get_x = function () {
30
+ return this.x;
31
+ };
33
32
 
34
- Point.prototype.get_y = function() {
35
- return this.y;
36
- };
33
+ Point.prototype.get_y = function () {
34
+ return this.y;
35
+ };
37
36
 
38
- Point.prototype.clone = function() {
39
- return new Point(this.x, this.y);
40
- };
37
+ Point.prototype.clone = function () {
38
+ return new Point(this.x, this.y);
39
+ };
41
40
 
42
- Point.prototype.add = function(v) {
43
- return new Point(this.x + v.x, this.y + v.y);
44
- };
41
+ Point.prototype.add = function (v) {
42
+ return new Point(this.x + v.x, this.y + v.y);
43
+ };
45
44
 
46
- Point.prototype.scale = function(v) {
47
- if(v instanceof Point) {
48
- return new Point(this.x * v.x, this.y * v.y);
49
- }
50
- return new Point(this.x * v, this.y * v);
51
- };
52
-
53
- // Transform by affine
54
- Point.prototype.transform = function(a) {
55
- var x = this.x * a.a + this.y * a.c + a.e,
56
- y = this.x * a.b + this.y * a.d + a.f;
57
- return new Point(x, y);
58
- };
59
-
60
- Point.prototype.dist_sq = function(v) {
61
- var x = this.x - v.x,
62
- y = this.y - v.y;
63
- return (x*x + y*y);
64
- };
65
-
66
- Point.prototype.toString = function() {
67
- return "(x=" + this.x + ", y=" + this.y + ")";
68
- };
69
-
70
- // Affine class -----------------------------------
71
-
72
- // As defined in the SVG spec
73
- // | a c e |
74
- // | b d f |
75
- // | 0 0 1 |
76
- function Affine(a, b, c, d, e, f) {
77
- if (a === undefined) {
78
- this.a = 1;
79
- this.b = 0;
80
- this.c = 0;
81
- this.d = 1;
82
- this.e = 0;
83
- this.f = 0;
84
- } else {
85
- this.a = a;
86
- this.b = b;
87
- this.c = c;
88
- this.d = d;
89
- this.e = e;
90
- this.f = f;
91
- }
45
+ Point.prototype.scale = function (v) {
46
+ if (v instanceof Point) {
47
+ return new Point(this.x * v.x, this.y * v.y);
92
48
  }
93
-
94
- Affine.prototype.a = null;
95
- Affine.prototype.b = null;
96
- Affine.prototype.c = null;
97
- Affine.prototype.d = null;
98
- Affine.prototype.e = null;
99
- Affine.prototype.f = null;
100
-
101
- Affine.prototype.append = function(v) {
102
- if (!(v instanceof Affine)) {
103
- console.log ( "mesh.js: argument to Affine.append is not affine!");
104
- }
105
-
106
- var a = this.a * v.a + this.c * v.b,
107
- b = this.b * v.a + this.d * v.b,
108
- c = this.a * v.c + this.c * v.d,
109
- d = this.b * v.c + this.d * v.d,
110
- e = this.a * v.e + this.c * v.f + this.e,
111
- f = this.b * v.e + this.d * v.f + this.f;
112
-
113
- return new Affine(a, b, c, d, e, f);
114
- };
115
-
116
- Affine.prototype.toString = function() {
117
- return ("affine: " + this.a + " " + this.c + " " + this.e +
118
- "\n " + this.b + " " + this.d + " " + this.f);
119
- };
120
-
121
- // Utility functions ---------------------------------
122
-
123
- // Browsers return a string rather than a transform list for gradientTransform!
124
- function parseTransform(t) {
125
- var affine = new Affine(),
126
- radian,
127
- tan,
128
- cos;
129
-
130
- for (var i in t = t.match(/(\w+\(\s*(\-?\d+\.?\d*e?\-?\d*\s*,?\s*)+\))+/g)) {
131
- var c = t[i].match(/[\w\.\-]+/g),
132
- type = c.shift();
133
-
134
- switch (type) {
135
- case "translate":
136
- var trans;
137
- if (c.length == 2) {
138
- trans = new Affine( 1, 0, 0, 1, c[0], c[1] );
139
- } else {
140
- console.log( "mesh.js: translate does not have 2 arguments!" );
141
- trans = new Affine( 1, 0, 0, 1, 0, 0 );
142
- }
143
- affine = affine.append( trans );
144
- break;
145
-
146
- case "scale":
147
- var scale;
148
-
149
- if (c.length == 1) {
150
- scale = new Affine( c[0], 0, 0, c[0], 0, 0 );
151
- } else if (c.length == 2) {
152
- scale = new Affine( c[0], 0, 0, c[1], 0, 0 );
153
- } else {
154
- console.log( "mesh.js: scale does not have 1 or 2 arguments!" );
155
- scale = new Affine( 1, 0, 0, 1, 0, 0 );
156
- }
157
-
158
- affine = affine.append(scale);
159
-
160
- break;
161
-
162
- case "rotate":
163
- if (c.length == 3 ) {
164
- trans = new Affine( 1, 0, 0, 1, c[1], c[2]);
165
- affine = affine.append(trans);
166
- }
167
-
168
- if (c[0]) {
169
- radian = c[0] * Math.PI/180.0;
170
- cos = Math.cos(radian);
171
- sin = Math.sin(radian);
172
-
173
- if (Math.abs(cos) < 1e-16) { // I hate rounding errors...
174
- cos = 0;
175
- }
176
- if (Math.abs(sin) < 1e-16) { // I hate rounding errors...
177
- sin = 0;
178
- }
179
- var rotate = new Affine(cos, sin, -sin, cos, 0, 0);
180
- affine = affine.append(rotate);
181
- } else {
182
- console.log( "math.js: No argument to rotate transform!" );
183
- }
184
-
185
- if (c.length == 3) {
186
- trans = new Affine(1, 0, 0, 1, -c[1], -c[2]);
187
- affine = affine.append(trans);
188
- }
189
-
190
- break;
191
-
192
- case "skewX":
193
- if (c[0]) {
194
- radian = c[0] * Math.PI/180.0;
195
- tan = Math.tan(radian);
196
- skewx = new Affine( 1, 0, tan, 1, 0, 0 );
197
- affine = affine.append(skewx);
198
- } else {
199
- console.log("math.js: No argument to skewX transform!");
200
- }
201
-
202
- break;
203
-
204
- case "skewY":
205
- if (c[0]) {
206
- radian = c[0] * Math.PI/180.0;
207
- tan = Math.tan(radian);
208
- skewy = new Affine( 1, tan, 0, 1, 0, 0 );
209
- affine = affine.append(skewy);
210
- } else {
211
- console.log("math.js: No argument to skewY transform!");
212
- }
213
-
214
- break;
215
-
216
- case "matrix":
217
- if (c.length == 6) {
218
- var matrix = new Affine( c[0], c[1], c[2], c[3], c[4], c[5] );
219
- affine = affine.append(matrix);
220
- } else {
221
- console.log("math.js: Incorrect number of arguments for matrix!");
222
- }
223
-
224
- break;
225
-
226
- default:
227
- console.log("mesh.js: Unhandled transform type: " + type);
228
-
229
- break;
230
- }
231
- }
232
-
233
- return affine;
49
+ return new Point(this.x * v, this.y * v);
50
+ };
51
+
52
+ // Transform by affine
53
+ Point.prototype.transform = function (a) {
54
+ var x = this.x * a.a + this.y * a.c + a.e,
55
+ y = this.x * a.b + this.y * a.d + a.f;
56
+ return new Point(x, y);
57
+ };
58
+
59
+ Point.prototype.dist_sq = function (v) {
60
+ var x = this.x - v.x,
61
+ y = this.y - v.y;
62
+ return x * x + y * y;
63
+ };
64
+
65
+ Point.prototype.toString = function () {
66
+ return "(x=" + this.x + ", y=" + this.y + ")";
67
+ };
68
+
69
+ // Affine class -----------------------------------
70
+
71
+ // As defined in the SVG spec
72
+ // | a c e |
73
+ // | b d f |
74
+ // | 0 0 1 |
75
+ function Affine(a, b, c, d, e, f) {
76
+ if (a === undefined) {
77
+ this.a = 1;
78
+ this.b = 0;
79
+ this.c = 0;
80
+ this.d = 1;
81
+ this.e = 0;
82
+ this.f = 0;
83
+ } else {
84
+ this.a = a;
85
+ this.b = b;
86
+ this.c = c;
87
+ this.d = d;
88
+ this.e = e;
89
+ this.f = f;
234
90
  }
235
-
236
- function colorToString(c) {
237
- return ("rgb(" + Math.round(c[0]) + "," + Math.round(c[1]) + "," +Math.round(c[2]) + ")");
91
+ }
92
+
93
+ Affine.prototype.a = null;
94
+ Affine.prototype.b = null;
95
+ Affine.prototype.c = null;
96
+ Affine.prototype.d = null;
97
+ Affine.prototype.e = null;
98
+ Affine.prototype.f = null;
99
+
100
+ Affine.prototype.append = function (v) {
101
+ if (!(v instanceof Affine)) {
102
+ console.log("mesh.js: argument to Affine.append is not affine!");
238
103
  }
239
104
 
240
- // Split Bezier using de Casteljau's method... faster version
241
- function split_bezier(p0, p1, p2, p3) {
242
- var p00 = p0.clone(),
243
- p13 = p3.clone(),
244
-
245
- tmp = new Point((p1.x + p2.x)*0.5, (p1.y + p2.y)*0.5),
246
- p01 = new Point((p0.x + p1.x)*0.5, (p0.y + p1.y)*0.5),
247
- p12 = new Point((p2.x + p3.x)*0.5, (p2.y + p3.y)*0.5),
248
-
249
- p02 = new Point((tmp.x + p01.x)*0.5, (tmp.y + p01.y)*0.5),
250
- p11 = new Point((tmp.x + p12.x)*0.5, (tmp.y + p12.y)*0.5),
251
-
252
- p03 = new Point((p02.x + p11.x)*0.5, (p02.y + p11.y)*0.5),
253
- p10 = p03.clone();
254
-
255
- return ([[p00, p01, p02, p03],
256
- [p10, p11, p12, p13]]);
105
+ var a = this.a * v.a + this.c * v.b,
106
+ b = this.b * v.a + this.d * v.b,
107
+ c = this.a * v.c + this.c * v.d,
108
+ d = this.b * v.c + this.d * v.d,
109
+ e = this.a * v.e + this.c * v.f + this.e,
110
+ f = this.b * v.e + this.d * v.f + this.f;
111
+
112
+ return new Affine(a, b, c, d, e, f);
113
+ };
114
+
115
+ Affine.prototype.toString = function () {
116
+ return (
117
+ "affine: " +
118
+ this.a +
119
+ " " +
120
+ this.c +
121
+ " " +
122
+ this.e +
123
+ "\n " +
124
+ this.b +
125
+ " " +
126
+ this.d +
127
+ " " +
128
+ this.f
129
+ );
130
+ };
131
+
132
+ // Utility functions ---------------------------------
133
+
134
+ // Browsers return a string rather than a transform list for gradientTransform!
135
+ function parseTransform(t) {
136
+ var affine = new Affine(),
137
+ radian,
138
+ tan,
139
+ cos;
140
+
141
+ for (var i in (t = t.match(
142
+ /(\w+\(\s*(\-?\d+\.?\d*e?\-?\d*\s*,?\s*)+\))+/g,
143
+ ))) {
144
+ var c = t[i].match(/[\w\.\-]+/g),
145
+ type = c.shift();
146
+
147
+ switch (type) {
148
+ case "translate":
149
+ var trans;
150
+ if (c.length == 2) {
151
+ trans = new Affine(1, 0, 0, 1, c[0], c[1]);
152
+ } else {
153
+ console.log("mesh.js: translate does not have 2 arguments!");
154
+ trans = new Affine(1, 0, 0, 1, 0, 0);
155
+ }
156
+ affine = affine.append(trans);
157
+ break;
158
+
159
+ case "scale":
160
+ var scale;
161
+
162
+ if (c.length == 1) {
163
+ scale = new Affine(c[0], 0, 0, c[0], 0, 0);
164
+ } else if (c.length == 2) {
165
+ scale = new Affine(c[0], 0, 0, c[1], 0, 0);
166
+ } else {
167
+ console.log("mesh.js: scale does not have 1 or 2 arguments!");
168
+ scale = new Affine(1, 0, 0, 1, 0, 0);
169
+ }
170
+
171
+ affine = affine.append(scale);
172
+
173
+ break;
174
+
175
+ case "rotate":
176
+ if (c.length == 3) {
177
+ trans = new Affine(1, 0, 0, 1, c[1], c[2]);
178
+ affine = affine.append(trans);
179
+ }
180
+
181
+ if (c[0]) {
182
+ radian = (c[0] * Math.PI) / 180.0;
183
+ cos = Math.cos(radian);
184
+ sin = Math.sin(radian);
185
+
186
+ if (Math.abs(cos) < 1e-16) {
187
+ // I hate rounding errors...
188
+ cos = 0;
189
+ }
190
+ if (Math.abs(sin) < 1e-16) {
191
+ // I hate rounding errors...
192
+ sin = 0;
193
+ }
194
+ var rotate = new Affine(cos, sin, -sin, cos, 0, 0);
195
+ affine = affine.append(rotate);
196
+ } else {
197
+ console.log("math.js: No argument to rotate transform!");
198
+ }
199
+
200
+ if (c.length == 3) {
201
+ trans = new Affine(1, 0, 0, 1, -c[1], -c[2]);
202
+ affine = affine.append(trans);
203
+ }
204
+
205
+ break;
206
+
207
+ case "skewX":
208
+ if (c[0]) {
209
+ radian = (c[0] * Math.PI) / 180.0;
210
+ tan = Math.tan(radian);
211
+ skewx = new Affine(1, 0, tan, 1, 0, 0);
212
+ affine = affine.append(skewx);
213
+ } else {
214
+ console.log("math.js: No argument to skewX transform!");
215
+ }
216
+
217
+ break;
218
+
219
+ case "skewY":
220
+ if (c[0]) {
221
+ radian = (c[0] * Math.PI) / 180.0;
222
+ tan = Math.tan(radian);
223
+ skewy = new Affine(1, tan, 0, 1, 0, 0);
224
+ affine = affine.append(skewy);
225
+ } else {
226
+ console.log("math.js: No argument to skewY transform!");
227
+ }
228
+
229
+ break;
230
+
231
+ case "matrix":
232
+ if (c.length == 6) {
233
+ var matrix = new Affine(c[0], c[1], c[2], c[3], c[4], c[5]);
234
+ affine = affine.append(matrix);
235
+ } else {
236
+ console.log("math.js: Incorrect number of arguments for matrix!");
237
+ }
238
+
239
+ break;
240
+
241
+ default:
242
+ console.log("mesh.js: Unhandled transform type: " + type);
243
+
244
+ break;
245
+ }
257
246
  }
258
247
 
259
- // See Cairo: cairo-mesh-pattern-rasterizer.c
260
- function bezier_steps_sq(points) {
261
- var tmp0 = points[0].dist_sq(points[1]),
262
- tmp1 = points[2].dist_sq(points[3]),
263
- tmp2 = points[0].dist_sq(points[2]) * 0.25,
264
- tmp3 = points[1].dist_sq(points[3]) * 0.25,
265
- max1 = (tmp0>tmp1?tmp0:tmp1),
266
- max2 = (tmp2>tmp3?tmp2:tmp3),
267
- max = (max1>max2?max1:max2);
268
-
269
- return max*18;
248
+ return affine;
249
+ }
250
+
251
+ function colorToString(c) {
252
+ return (
253
+ "rgb(" +
254
+ Math.round(c[0]) +
255
+ "," +
256
+ Math.round(c[1]) +
257
+ "," +
258
+ Math.round(c[2]) +
259
+ ")"
260
+ );
261
+ }
262
+
263
+ // Split Bezier using de Casteljau's method... faster version
264
+ function split_bezier(p0, p1, p2, p3) {
265
+ var p00 = p0.clone(),
266
+ p13 = p3.clone(),
267
+ tmp = new Point((p1.x + p2.x) * 0.5, (p1.y + p2.y) * 0.5),
268
+ p01 = new Point((p0.x + p1.x) * 0.5, (p0.y + p1.y) * 0.5),
269
+ p12 = new Point((p2.x + p3.x) * 0.5, (p2.y + p3.y) * 0.5),
270
+ p02 = new Point((tmp.x + p01.x) * 0.5, (tmp.y + p01.y) * 0.5),
271
+ p11 = new Point((tmp.x + p12.x) * 0.5, (tmp.y + p12.y) * 0.5),
272
+ p03 = new Point((p02.x + p11.x) * 0.5, (p02.y + p11.y) * 0.5),
273
+ p10 = p03.clone();
274
+
275
+ return [
276
+ [p00, p01, p02, p03],
277
+ [p10, p11, p12, p13],
278
+ ];
279
+ }
280
+
281
+ // See Cairo: cairo-mesh-pattern-rasterizer.c
282
+ function bezier_steps_sq(points) {
283
+ var tmp0 = points[0].dist_sq(points[1]),
284
+ tmp1 = points[2].dist_sq(points[3]),
285
+ tmp2 = points[0].dist_sq(points[2]) * 0.25,
286
+ tmp3 = points[1].dist_sq(points[3]) * 0.25,
287
+ max1 = tmp0 > tmp1 ? tmp0 : tmp1,
288
+ max2 = tmp2 > tmp3 ? tmp2 : tmp3,
289
+ max = max1 > max2 ? max1 : max2;
290
+
291
+ return max * 18;
292
+ }
293
+
294
+ // Curve class --------------------------------------
295
+ function Curve(nodes, colors) {
296
+ this.nodes = nodes; // 4 Bezier points
297
+ this.colors = colors; // 2 x 4 colors (two ends x R+G+B+A)
298
+ }
299
+
300
+ // Paint a Bezier curve. w is width of Canvas window.
301
+ Curve.prototype.paint_curve = function (v, w) {
302
+ // If inside, see if we need to split
303
+ var max = bezier_steps_sq(this.nodes);
304
+
305
+ if (max > 2.0) {
306
+ // Larger values leave holes, smaller take longer to render.
307
+ var beziers = split_bezier(
308
+ this.nodes[0],
309
+ this.nodes[1],
310
+ this.nodes[2],
311
+ this.nodes[3],
312
+ ),
313
+ colors0 = [[], []], // ([start][end])
314
+ colors1 = [[], []];
315
+ for (var i = 0; i < 4; ++i) {
316
+ colors0[0][i] = this.colors[0][i];
317
+ colors0[1][i] = (this.colors[0][i] + this.colors[1][i]) / 2;
318
+ colors1[0][i] = (this.colors[0][i] + this.colors[1][i]) / 2;
319
+ colors1[1][i] = this.colors[1][i];
320
+ }
321
+ var curve0 = new Curve(beziers[0], colors0),
322
+ curve1 = new Curve(beziers[1], colors1);
323
+ curve0.paint_curve(v, w);
324
+ curve1.paint_curve(v, w);
325
+ } else {
326
+ counter++;
327
+
328
+ // Directly write data
329
+ var x = Math.round(this.nodes[0].x),
330
+ y = Math.round(this.nodes[0].y);
331
+ if (x >= 0 && x < w) {
332
+ var index = (y * w + x) * 4;
333
+ v[index] = Math.round(this.colors[0][0]);
334
+ v[index + 1] = Math.round(this.colors[0][1]);
335
+ v[index + 2] = Math.round(this.colors[0][2]);
336
+ v[index + 3] = Math.round(this.colors[0][3]); // Alpha
337
+ }
270
338
  }
271
-
272
- // Curve class --------------------------------------
273
- function Curve(nodes, colors) {
274
- this.nodes = nodes; // 4 Bezier points
275
- this.colors = colors; // 2 x 4 colors (two ends x R+G+B+A)
339
+ };
340
+
341
+ // Patch class -------------------------------------
342
+ function Patch(nodes, colors) {
343
+ this.nodes = nodes; // 4x4 array of points
344
+ this.colors = colors; // 2x2x4 colors (four corners x R+G+B+A)
345
+ }
346
+
347
+ // Set path for future stroking or filling... useful for debugging.
348
+ Patch.prototype.setOutline = function (v) {
349
+ // Draw patch outline
350
+ v.beginPath();
351
+ v.moveTo(this.nodes[0][0].x, this.nodes[0][0].y);
352
+ v.bezierCurveTo(
353
+ this.nodes[0][1].x,
354
+ this.nodes[0][1].y,
355
+ this.nodes[0][2].x,
356
+ this.nodes[0][2].y,
357
+ this.nodes[0][3].x,
358
+ this.nodes[0][3].y,
359
+ );
360
+ v.bezierCurveTo(
361
+ this.nodes[1][3].x,
362
+ this.nodes[1][3].y,
363
+ this.nodes[2][3].x,
364
+ this.nodes[2][3].y,
365
+ this.nodes[3][3].x,
366
+ this.nodes[3][3].y,
367
+ );
368
+ v.bezierCurveTo(
369
+ this.nodes[3][2].x,
370
+ this.nodes[3][2].y,
371
+ this.nodes[3][1].x,
372
+ this.nodes[3][1].y,
373
+ this.nodes[3][0].x,
374
+ this.nodes[3][0].y,
375
+ );
376
+ v.bezierCurveTo(
377
+ this.nodes[2][0].x,
378
+ this.nodes[2][0].y,
379
+ this.nodes[1][0].x,
380
+ this.nodes[1][0].y,
381
+ this.nodes[0][0].x,
382
+ this.nodes[0][0].y,
383
+ );
384
+ v.closePath();
385
+ };
386
+
387
+ // Draw stroke patch... useful if debugging.
388
+ Patch.prototype.drawOutline = function (v) {
389
+ this.setOutline(v);
390
+ v.strokeStyle = "black";
391
+ v.stroke();
392
+ };
393
+
394
+ // Fill patch... useful if debugging.
395
+ Patch.prototype.fillOutline = function (v) {
396
+ this.setOutline(v);
397
+ v.fillStyle = colorToString(this.colors[0]);
398
+ v.fill();
399
+ };
400
+
401
+ // Split patch horizontally into two patches.
402
+ Patch.prototype.split = function () {
403
+ var nodes0 = [[], [], [], []],
404
+ nodes1 = [[], [], [], []],
405
+ colors0 = [
406
+ [[], []],
407
+ [[], []],
408
+ ],
409
+ colors1 = [
410
+ [[], []],
411
+ [[], []],
412
+ ];
413
+
414
+ for (var i = 0; i < 4; ++i) {
415
+ var beziers = split_bezier(
416
+ this.nodes[0][i],
417
+ this.nodes[1][i],
418
+ this.nodes[2][i],
419
+ this.nodes[3][i],
420
+ );
421
+
422
+ for (var j = 0; j < 4; ++j) {
423
+ nodes0[0][i] = beziers[0][0];
424
+ nodes0[1][i] = beziers[0][1];
425
+ nodes0[2][i] = beziers[0][2];
426
+ nodes0[3][i] = beziers[0][3];
427
+ nodes1[0][i] = beziers[1][0];
428
+ nodes1[1][i] = beziers[1][1];
429
+ nodes1[2][i] = beziers[1][2];
430
+ nodes1[3][i] = beziers[1][3];
431
+ }
276
432
  }
277
433
 
278
- // Paint a Bezier curve. w is width of Canvas window.
279
- Curve.prototype.paint_curve = function(v, w) {
280
- // If inside, see if we need to split
281
- var max = bezier_steps_sq(this.nodes);
282
-
283
- if (max > 2.0) { // Larger values leave holes, smaller take longer to render.
284
- var beziers = split_bezier(this.nodes[0],this.nodes[1],this.nodes[2],this.nodes[3]),
285
- colors0 = [[],[]], // ([start][end])
286
- colors1 = [[],[]];
287
- for (var i = 0; i < 4; ++ i) {
288
- colors0[0][i] = this.colors[0][i];
289
- colors0[1][i] = (this.colors[0][i] + this.colors[1][i])/2;
290
- colors1[0][i] = (this.colors[0][i] + this.colors[1][i])/2;
291
- colors1[1][i] = this.colors[1][i];
292
- }
293
- var curve0 = new Curve(beziers[0], colors0),
294
- curve1 = new Curve(beziers[1], colors1);
295
- curve0.paint_curve(v, w);
296
- curve1.paint_curve(v, w);
297
- } else {
298
- counter++;
299
-
300
- // Directly write data
301
- var x = Math.round(this.nodes[0].x),
302
- y = Math.round(this.nodes[0].y);
303
- if (x >= 0 && x < w) {
304
- var index = (y * w + x) * 4;
305
- v[index ] = Math.round(this.colors[0][0]);
306
- v[index + 1] = Math.round(this.colors[0][1]);
307
- v[index + 2] = Math.round(this.colors[0][2]);
308
- v[index + 3] = Math.round(this.colors[0][3]); // Alpha
309
- }
310
- }
311
- };
312
-
313
- // Patch class -------------------------------------
314
- function Patch(nodes, colors) {
315
- this.nodes = nodes; // 4x4 array of points
316
- this.colors = colors; // 2x2x4 colors (four corners x R+G+B+A)
434
+ for (i = 0; i < 4; ++i) {
435
+ colors0[0][0][i] = this.colors[0][0][i];
436
+ colors0[0][1][i] = this.colors[0][1][i];
437
+ colors0[1][0][i] = (this.colors[0][0][i] + this.colors[1][0][i]) / 2;
438
+ colors0[1][1][i] = (this.colors[0][1][i] + this.colors[1][1][i]) / 2;
439
+ colors1[0][0][i] = (this.colors[0][0][i] + this.colors[1][0][i]) / 2;
440
+ colors1[0][1][i] = (this.colors[0][1][i] + this.colors[1][1][i]) / 2;
441
+ colors1[1][0][i] = this.colors[1][0][i];
442
+ colors1[1][1][i] = this.colors[1][1][i];
317
443
  }
318
444
 
319
- // Set path for future stroking or filling... useful for debugging.
320
- Patch.prototype.setOutline = function(v) {
321
- // Draw patch outline
322
- v.beginPath();
323
- v.moveTo( this.nodes[0][0].x, this.nodes[0][0].y );
324
- v.bezierCurveTo( this.nodes[0][1].x, this.nodes[0][1].y,
325
- this.nodes[0][2].x, this.nodes[0][2].y,
326
- this.nodes[0][3].x, this.nodes[0][3].y );
327
- v.bezierCurveTo( this.nodes[1][3].x, this.nodes[1][3].y,
328
- this.nodes[2][3].x, this.nodes[2][3].y,
329
- this.nodes[3][3].x, this.nodes[3][3].y );
330
- v.bezierCurveTo( this.nodes[3][2].x, this.nodes[3][2].y,
331
- this.nodes[3][1].x, this.nodes[3][1].y,
332
- this.nodes[3][0].x, this.nodes[3][0].y );
333
- v.bezierCurveTo( this.nodes[2][0].x, this.nodes[2][0].y,
334
- this.nodes[1][0].x, this.nodes[1][0].y,
335
- this.nodes[0][0].x, this.nodes[0][0].y );
336
- v.closePath();
337
- };
445
+ var patch0 = new Patch(nodes0, colors0),
446
+ patch1 = new Patch(nodes1, colors1);
338
447
 
339
- // Draw stroke patch... useful if debugging.
340
- Patch.prototype.drawOutline = function(v) {
341
- this.setOutline(v);
342
- v.strokeStyle = "black";
343
- v.stroke();
344
- };
448
+ return [patch0, patch1];
449
+ };
345
450
 
346
- // Fill patch... useful if debugging.
347
- Patch.prototype.fillOutline = function(v) {
348
- this.setOutline(v);
349
- v.fillStyle = colorToString( this.colors[0] );
350
- v.fill();
351
- };
451
+ Patch.prototype.paint = function (v, w) {
452
+ // Check if patch is inside canvas (need canvas dimensions)
453
+ // To be done.....
352
454
 
353
- // Split patch horizontally into two patches.
354
- Patch.prototype.split = function() {
355
- var nodes0 = [[],[],[],[]],
356
- nodes1 = [[],[],[],[]],
357
- colors0 = [[[],[]],[[],[]]],
358
- colors1 = [[[],[]],[[],[]]];
359
-
360
- for (var i = 0; i < 4; ++i) {
361
- var beziers = split_bezier(this.nodes[0][i], this.nodes[1][i], this.nodes[2][i], this.nodes[3][i]);
362
-
363
- for (var j = 0; j < 4; ++j) {
364
- nodes0[0][i] = beziers[0][0];
365
- nodes0[1][i] = beziers[0][1];
366
- nodes0[2][i] = beziers[0][2];
367
- nodes0[3][i] = beziers[0][3];
368
- nodes1[0][i] = beziers[1][0];
369
- nodes1[1][i] = beziers[1][1];
370
- nodes1[2][i] = beziers[1][2];
371
- nodes1[3][i] = beziers[1][3];
372
- }
373
- }
374
-
375
- for (i = 0; i < 4; ++ i) {
376
- colors0[0][0][i] = this.colors[0][0][i];
377
- colors0[0][1][i] = this.colors[0][1][i];
378
- colors0[1][0][i] = (this.colors[0][0][i] + this.colors[1][0][i])/2;
379
- colors0[1][1][i] = (this.colors[0][1][i] + this.colors[1][1][i])/2;
380
- colors1[0][0][i] = (this.colors[0][0][i] + this.colors[1][0][i])/2;
381
- colors1[0][1][i] = (this.colors[0][1][i] + this.colors[1][1][i])/2;
382
- colors1[1][0][i] = this.colors[1][0][i];
383
- colors1[1][1][i] = this.colors[1][1][i];
384
- }
385
-
386
- var patch0 = new Patch(nodes0, colors0),
387
- patch1 = new Patch(nodes1, colors1);
388
-
389
- return ([patch0, patch1]);
390
- };
391
-
392
- Patch.prototype.paint = function(v, w) {
393
- // Check if patch is inside canvas (need canvas dimensions)
394
- // To be done.....
395
-
396
- // If inside, see if we need to split
397
- var tmp = [];
455
+ // If inside, see if we need to split
456
+ var tmp = [];
398
457
 
399
- for (var i = 0; i < 4; ++i) {
400
- tmp[i] = bezier_steps_sq([this.nodes[0][i],this.nodes[1][i],
401
- this.nodes[2][i],this.nodes[3][i]]);
402
- }
458
+ for (var i = 0; i < 4; ++i) {
459
+ tmp[i] = bezier_steps_sq([
460
+ this.nodes[0][i],
461
+ this.nodes[1][i],
462
+ this.nodes[2][i],
463
+ this.nodes[3][i],
464
+ ]);
465
+ }
403
466
 
404
- var max = Math.max.apply(null,tmp);
467
+ var max = Math.max.apply(null, tmp);
405
468
 
406
- if (max > 2.0) { // Larger values leave holes, smaller take longer to render.
407
- var patches = this.split();
408
- patches[0].paint(v, w);
409
- patches[1].paint(v, w);
410
- } else {
411
- //this.fillOutline(v);
412
- this.paint_curve(v, w);
469
+ if (max > 2.0) {
470
+ // Larger values leave holes, smaller take longer to render.
471
+ var patches = this.split();
472
+ patches[0].paint(v, w);
473
+ patches[1].paint(v, w);
474
+ } else {
475
+ //this.fillOutline(v);
476
+ this.paint_curve(v, w);
477
+ }
478
+ };
479
+
480
+ Patch.prototype.paint_curve = function (v, w) {
481
+ // Paint a Bezier curve using just the top of the patch. If
482
+ // the patch is thin enough this should work. We leave this
483
+ // function here in case we want to do something more fancy.
484
+ var curve = new Curve(
485
+ [this.nodes[0][0], this.nodes[0][1], this.nodes[0][2], this.nodes[0][3]],
486
+ [this.colors[0][0], this.colors[0][1]],
487
+ );
488
+
489
+ curve.paint_curve(v, w);
490
+ };
491
+
492
+ // Mesh class ---------------------------------------
493
+ function Mesh(id) {
494
+ this.id = id;
495
+ var raw = this.readMesh(id);
496
+ this.nodes = raw.nodes; // (m*3+1) x (n*3+1) points
497
+ this.colors = raw.colors; // (m+1) x (n+1) x 4 colors (R+G+B+A)
498
+ }
499
+
500
+ // Weighted average to find Bezier points for linear sides.
501
+ function w_ave(p0, p1) {
502
+ var p = p0.scale(2.0 / 3.0).add(p1.scale(1.0 / 3.0));
503
+
504
+ return p;
505
+ }
506
+
507
+ // Function to parse an SVG mesh and return an array of nodes (points) and an array of colors.
508
+ Mesh.prototype.readMesh = function (id) {
509
+ var nodes = [],
510
+ colors = [],
511
+ i,
512
+ j;
513
+
514
+ // First, find the mesh
515
+ var theMesh = document.getElementById(id);
516
+
517
+ if (theMesh === null) {
518
+ console.log("mesh.js: Could not find mesh: " + id);
519
+ } else {
520
+ nodes[0] = []; // Top row
521
+ colors[0] = []; // Top row
522
+
523
+ var x = Number(theMesh.getAttribute("x")),
524
+ y = Number(theMesh.getAttribute("y"));
525
+
526
+ nodes[0][0] = new Point(x, y);
527
+
528
+ var rows = theMesh.children;
529
+
530
+ for (i = 0; i < rows.length; ++i) {
531
+ // Need to validate if meshrow...
532
+ nodes[3 * i + 1] = []; // Need three extra rows for each meshrow.
533
+ nodes[3 * i + 2] = [];
534
+ nodes[3 * i + 3] = [];
535
+ colors[i + 1] = []; // Need one more row than number of meshrows.
536
+
537
+ var patches = rows[i].children;
538
+
539
+ for (j = 0; j < patches.length; ++j) {
540
+ var stops = patches[j].children;
541
+
542
+ for (var k = 0; k < stops.length; ++k) {
543
+ var l = k,
544
+ parts;
545
+
546
+ if (i !== 0) {
547
+ ++l; // There is no top if row isn't first row.
413
548
  }
414
- };
415
-
416
- Patch.prototype.paint_curve = function(v, w) {
417
- // Paint a Bezier curve using just the top of the patch. If
418
- // the patch is thin enough this should work. We leave this
419
- // function here in case we want to do something more fancy.
420
- var curve = new Curve(
421
- [this.nodes[0][0],this.nodes[0][1],this.nodes[0][2],this.nodes[0][3]],
422
- [this.colors[0][0],this.colors[0][1]]);
423
-
424
- curve.paint_curve(v, w);
425
- };
426
-
427
-
428
- // Mesh class ---------------------------------------
429
- function Mesh(id) {
430
- this.id = id;
431
- var raw = this.readMesh(id);
432
- this.nodes = raw.nodes; // (m*3+1) x (n*3+1) points
433
- this.colors = raw.colors; // (m+1) x (n+1) x 4 colors (R+G+B+A)
434
- }
435
549
 
436
- // Weighted average to find Bezier points for linear sides.
437
- function w_ave(p0, p1) {
438
- var p = p0.scale(2.0/3.0).add(p1.scale(1.0/3.0));
550
+ var path = stops[k].getAttribute("path"),
551
+ type = "l"; // We need to still find mid-points even if no path.
439
552
 
440
- return p;
441
- }
553
+ if (path !== null) {
554
+ parts = path.match(/\s*([lLcC])\s*(.*)/);
555
+ type = parts[1];
556
+ }
557
+ var stop_nodes = parse_points(parts[2]);
442
558
 
443
- // Function to parse an SVG mesh and return an array of nodes (points) and an array of colors.
444
- Mesh.prototype.readMesh = function(id) {
445
- var nodes = [],
446
- colors = [],
447
- i,
448
- j;
449
-
450
- // First, find the mesh
451
- var theMesh = document.getElementById(id);
452
-
453
- if (theMesh === null) {
454
- console.log( "mesh.js: Could not find mesh: " + id);
455
- } else {
456
- nodes[0] = []; // Top row
457
- colors[0] = []; // Top row
458
-
459
- var x = Number(theMesh.getAttribute("x")),
460
- y = Number(theMesh.getAttribute("y"));
461
-
462
- nodes[0][0] = new Point(x, y);
463
-
464
- var rows = theMesh.children;
465
-
466
- for (i = 0; i < rows.length; ++i) {
467
- // Need to validate if meshrow...
468
- nodes[3*i+1] = []; // Need three extra rows for each meshrow.
469
- nodes[3*i+2] = [];
470
- nodes[3*i+3] = [];
471
- colors[i+1] = []; // Need one more row than number of meshrows.
472
-
473
- var patches = rows[i].children;
474
-
475
- for (j = 0; j < patches.length; ++j) {
476
- var stops = patches[j].children;
477
-
478
- for (var k = 0; k < stops.length; ++k) {
479
- var l = k,
480
- parts;
481
-
482
- if (i !== 0) {
483
- ++l; // There is no top if row isn't first row.
484
- }
485
-
486
- var path = stops[k].getAttribute("path"),
487
- type = "l"; // We need to still find mid-points even if no path.
488
-
489
- if (path !== null) {
490
- parts = path.match(/\s*([lLcC])\s*(.*)/);
491
- type = parts[1];
492
- }
493
- var stop_nodes = parse_points( parts[2] );
494
-
495
- switch (type) {
496
- case "l":
497
- if (l === 0) { // Top
498
- nodes[3*i][3*j+3] = stop_nodes[0].add(nodes[3*i][3*j]);
499
- nodes[3*i][3*j+1] = w_ave( nodes[3*i][3*j], nodes[3*i][3*j+3] );
500
- nodes[3*i][3*j+2] = w_ave( nodes[3*i][3*j+3], nodes[3*i][3*j] );
501
- } else if (l == 1) { // Right
502
- nodes[3*i+3][3*j+3] = stop_nodes[0].add(nodes[3*i][3*j+3]);
503
- nodes[3*i+1][3*j+3] = w_ave( nodes[3*i][3*j+3], nodes[3*i+3][3*j+3] );
504
- nodes[3*i+2][3*j+3] = w_ave( nodes[3*i+3][3*j+3], nodes[3*i][3*j+3] );
505
- } else if (l == 2) { // Bottom
506
- if(j===0) {
507
- nodes[3*i+3][3*j+0] = stop_nodes[0].add(nodes[3*i+3][3*j+3]);
508
- }
509
- nodes[3*i+3][3*j+1] = w_ave( nodes[3*i+3][3*j], nodes[3*i+3][3*j+3] );
510
- nodes[3*i+3][3*j+2] = w_ave( nodes[3*i+3][3*j+3], nodes[3*i+3][3*j] );
511
- } else { // Left
512
- nodes[3*i+1][3*j] = w_ave( nodes[3*i][3*j], nodes[3*i+3][3*j] );
513
- nodes[3*i+2][3*j] = w_ave( nodes[3*i+3][3*j], nodes[3*i][3*j] );
514
- }
515
-
516
- break;
517
-
518
- case "L":
519
- if (l === 0) { // Top
520
- nodes[3*i][3*j+3] = stop_nodes[0];
521
- nodes[3*i][3*j+1] = w_ave( nodes[3*i][3*j], nodes[3*i][3*j+3] );
522
- nodes[3*i][3*j+2] = w_ave( nodes[3*i][3*j+3], nodes[3*i][3*j] );
523
- } else if (l === 1) { // Right
524
- nodes[3*i+3][3*j+3] = stop_nodes[0];
525
- nodes[3*i+1][3*j+3] = w_ave( nodes[3*i][3*j+3], nodes[3*i+3][3*j+3] );
526
- nodes[3*i+2][3*j+3] = w_ave( nodes[3*i+3][3*j+3], nodes[3*i][3*j+3] );
527
- } else if (l === 2) { // Bottom
528
- if(j === 0) {
529
- nodes[3*i+3][3*j+0] = stop_nodes[0];
530
- }
531
- nodes[3*i+3][3*j+1] = w_ave( nodes[3*i+3][3*j], nodes[3*i+3][3*j+3] );
532
- nodes[3*i+3][3*j+2] = w_ave( nodes[3*i+3][3*j+3], nodes[3*i+3][3*j] );
533
- } else { // Left
534
- nodes[3*i+1][3*j] = w_ave( nodes[3*i][3*j], nodes[3*i+3][3*j] );
535
- nodes[3*i+2][3*j] = w_ave( nodes[3*i+3][3*j], nodes[3*i][3*j] );
536
- }
537
-
538
- break;
539
-
540
- case "c":
541
- if (l === 0) { // Top
542
- nodes[3*i][3*j+1] = stop_nodes[0].add(nodes[3*i][3*j]);
543
- nodes[3*i][3*j+2] = stop_nodes[1].add(nodes[3*i][3*j]);
544
- nodes[3*i][3*j+3] = stop_nodes[2].add(nodes[3*i][3*j]);
545
- } else if (l === 1) { // Right
546
- nodes[3*i+1][3*j+3] = stop_nodes[0].add(nodes[3*i][3*j+3]);
547
- nodes[3*i+2][3*j+3] = stop_nodes[1].add(nodes[3*i][3*j+3]);
548
- nodes[3*i+3][3*j+3] = stop_nodes[2].add(nodes[3*i][3*j+3]);
549
- } else if (l === 2) { // Bottom
550
- nodes[3*i+3][3*j+2] = stop_nodes[0].add(nodes[3*i+3][3*j+3]);
551
- nodes[3*i+3][3*j+1] = stop_nodes[1].add(nodes[3*i+3][3*j+3]);
552
- if(j === 0) {
553
- nodes[3*i+3][3*j+0] = stop_nodes[2].add(nodes[3*i+3][3*j+3]);
554
- }
555
- } else { // Left
556
- nodes[3*i+2][3*j] = stop_nodes[0].add(nodes[3*i+3][3*j]);
557
- nodes[3*i+1][3*j] = stop_nodes[1].add(nodes[3*i+3][3*j]);
558
- }
559
-
560
- break;
561
-
562
- case "C":
563
- if (l === 0) { // Top
564
- nodes[3*i][3*j+1] = stop_nodes[0];
565
- nodes[3*i][3*j+2] = stop_nodes[1];
566
- nodes[3*i][3*j+3] = stop_nodes[2];
567
- } else if (l == 1) { // Right
568
- nodes[3*i+1][3*j+3] = stop_nodes[0];
569
- nodes[3*i+2][3*j+3] = stop_nodes[1];
570
- nodes[3*i+3][3*j+3] = stop_nodes[2];
571
- } else if (l == 2) { // Bottom
572
- nodes[3*i+3][3*j+2] = stop_nodes[0];
573
- nodes[3*i+3][3*j+1] = stop_nodes[1];
574
- if(j === 0) {
575
- nodes[3*i+3][3*j+0] = stop_nodes[2];
576
- }
577
- } else { // Left
578
- nodes[3*i+2][3*j] = stop_nodes[0];
579
- nodes[3*i+1][3*j] = stop_nodes[1];
580
- }
581
-
582
- break;
583
-
584
- default:
585
- console.log("mesh.js: " + type + " invalid path type.");
586
- }
587
-
588
- if ((i === 0 && j === 0) || k > 0) {
589
- var color_raw = getComputedStyle(stops[k]).stopColor.match(/^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i),
590
- alpha_raw = getComputedStyle(stops[k]).stopOpacity,
591
- alpha = 255;
592
-
593
- if (alpha_raw) {
594
- alpha = parseInt(alpha_raw * 255);
595
- }
596
-
597
- if (color_raw) {
598
- if (l === 0) { // upper left corner
599
- colors[i][j] = [];
600
- colors[i][j][0] = parseInt(color_raw[1]);
601
- colors[i][j][1] = parseInt(color_raw[2]);
602
- colors[i][j][2] = parseInt(color_raw[3]);
603
- colors[i][j][3] = alpha; // Alpha
604
- } else if (l === 1) { // upper right corner
605
- colors[i][j+1] = [];
606
- colors[i][j+1][0] = parseInt(color_raw[1]);
607
- colors[i][j+1][1] = parseInt(color_raw[2]);
608
- colors[i][j+1][2] = parseInt(color_raw[3]);
609
- colors[i][j+1][3] = alpha; // Alpha
610
- } else if (l === 2) { // lower right corner
611
- colors[i+1][j+1] = [];
612
- colors[i+1][j+1][0] = parseInt(color_raw[1]);
613
- colors[i+1][j+1][1] = parseInt(color_raw[2]);
614
- colors[i+1][j+1][2] = parseInt(color_raw[3]);
615
- colors[i+1][j+1][3] = alpha; // Alpha
616
- } else if (l === 3) { // lower left corner
617
- colors[i+1][j] = [];
618
- colors[i+1][j][0] = parseInt(color_raw[1]);
619
- colors[i+1][j][1] = parseInt(color_raw[2]);
620
- colors[i+1][j][2] = parseInt(color_raw[3]);
621
- colors[i+1][j][3] = alpha; // Alpha
622
- }
623
- }
624
- }
625
- }
626
-
627
- // SVG doesn't use tensor points but we need them for rendering.
628
- nodes[3*i+1][3*j+1] = new Point();
629
- nodes[3*i+1][3*j+2] = new Point();
630
- nodes[3*i+2][3*j+1] = new Point();
631
- nodes[3*i+2][3*j+2] = new Point();
632
-
633
- nodes[3*i+1][3*j+1].x =
634
- ( -4.0 * nodes[3*i ][3*j ].x +
635
- 6.0 * (nodes[3*i ][3*j+1].x + nodes[3*i+1][3*j ].x) +
636
- -2.0 * (nodes[3*i ][3*j+3].x + nodes[3*i+3][3*j ].x) +
637
- 3.0 * (nodes[3*i+3][3*j+1].x + nodes[3*i+1][3*j+3].x) +
638
- -1.0 * nodes[3*i+3][3*j+3].x ) / 9.0;
639
- nodes[3*i+1][3*j+2].x =
640
- ( -4.0 * nodes[3*i ][3*j+3].x +
641
- 6.0 * (nodes[3*i ][3*j+2].x + nodes[3*i+1][3*j+3].x) +
642
- -2.0 * (nodes[3*i ][3*j ].x + nodes[3*i+3][3*j+3].x) +
643
- 3.0 * (nodes[3*i+3][3*j+2].x + nodes[3*i+1][3*j ].x) +
644
- -1.0 * nodes[3*i+3][3*j ].x ) / 9.0;
645
- nodes[3*i+2][3*j+1].x =
646
- ( -4.0 * nodes[3*i+3][3*j ].x +
647
- 6.0 * (nodes[3*i+3][3*j+1].x + nodes[3*i+2][3*j ].x) +
648
- -2.0 * (nodes[3*i+3][3*j+3].x + nodes[3*i ][3*j ].x) +
649
- 3.0 * (nodes[3*i ][3*j+1].x + nodes[3*i+2][3*j+3].x) +
650
- -1.0 * nodes[3*i ][3*j+3].x ) / 9.0;
651
- nodes[3*i+2][3*j+2].x =
652
- ( -4.0 * nodes[3*i+3][3*j+3].x +
653
- 6.0 * (nodes[3*i+3][3*j+2].x + nodes[3*i+2][3*j+3].x) +
654
- -2.0 * (nodes[3*i+3][3*j ].x + nodes[3*i ][3*j+3].x) +
655
- 3.0 * (nodes[3*i ][3*j+2].x + nodes[3*i+2][3*j ].x) +
656
- -1.0 * nodes[3*i ][3*j ].x ) / 9.0;
657
-
658
- nodes[3*i+1][3*j+1].y =
659
- ( -4.0 * nodes[3*i ][3*j ].y +
660
- 6.0 * (nodes[3*i ][3*j+1].y + nodes[3*i+1][3*j ].y) +
661
- -2.0 * (nodes[3*i ][3*j+3].y + nodes[3*i+3][3*j ].y) +
662
- 3.0 * (nodes[3*i+3][3*j+1].y + nodes[3*i+1][3*j+3].y) +
663
- -1.0 * nodes[3*i+3][3*j+3].y ) / 9.0;
664
- nodes[3*i+1][3*j+2].y =
665
- ( -4.0 * nodes[3*i ][3*j+3].y +
666
- 6.0 * (nodes[3*i ][3*j+2].y + nodes[3*i+1][3*j+3].y) +
667
- -2.0 * (nodes[3*i ][3*j ].y + nodes[3*i+3][3*j+3].y) +
668
- 3.0 * (nodes[3*i+3][3*j+2].y + nodes[3*i+1][3*j ].y) +
669
- -1.0 * nodes[3*i+3][3*j ].y ) / 9.0;
670
- nodes[3*i+2][3*j+1].y =
671
- ( -4.0 * nodes[3*i+3][3*j ].y +
672
- 6.0 * (nodes[3*i+3][3*j+1].y + nodes[3*i+2][3*j ].y) +
673
- -2.0 * (nodes[3*i+3][3*j+3].y + nodes[3*i ][3*j ].y) +
674
- 3.0 * (nodes[3*i ][3*j+1].y + nodes[3*i+2][3*j+3].y) +
675
- -1.0 * nodes[3*i ][3*j+3].y ) / 9.0;
676
- nodes[3*i+2][3*j+2].y =
677
- ( -4.0 * nodes[3*i+3][3*j+3].y +
678
- 6.0 * (nodes[3*i+3][3*j+2].y + nodes[3*i+2][3*j+3].y) +
679
- -2.0 * (nodes[3*i+3][3*j ].y + nodes[3*i ][3*j+3].y) +
680
- 3.0 * (nodes[3*i ][3*j+2].y + nodes[3*i+2][3*j ].y) +
681
- -1.0 * nodes[3*i ][3*j ].y ) / 9.0;
559
+ switch (type) {
560
+ case "l":
561
+ if (l === 0) {
562
+ // Top
563
+ nodes[3 * i][3 * j + 3] = stop_nodes[0].add(
564
+ nodes[3 * i][3 * j],
565
+ );
566
+ nodes[3 * i][3 * j + 1] = w_ave(
567
+ nodes[3 * i][3 * j],
568
+ nodes[3 * i][3 * j + 3],
569
+ );
570
+ nodes[3 * i][3 * j + 2] = w_ave(
571
+ nodes[3 * i][3 * j + 3],
572
+ nodes[3 * i][3 * j],
573
+ );
574
+ } else if (l == 1) {
575
+ // Right
576
+ nodes[3 * i + 3][3 * j + 3] = stop_nodes[0].add(
577
+ nodes[3 * i][3 * j + 3],
578
+ );
579
+ nodes[3 * i + 1][3 * j + 3] = w_ave(
580
+ nodes[3 * i][3 * j + 3],
581
+ nodes[3 * i + 3][3 * j + 3],
582
+ );
583
+ nodes[3 * i + 2][3 * j + 3] = w_ave(
584
+ nodes[3 * i + 3][3 * j + 3],
585
+ nodes[3 * i][3 * j + 3],
586
+ );
587
+ } else if (l == 2) {
588
+ // Bottom
589
+ if (j === 0) {
590
+ nodes[3 * i + 3][3 * j + 0] = stop_nodes[0].add(
591
+ nodes[3 * i + 3][3 * j + 3],
592
+ );
593
+ }
594
+ nodes[3 * i + 3][3 * j + 1] = w_ave(
595
+ nodes[3 * i + 3][3 * j],
596
+ nodes[3 * i + 3][3 * j + 3],
597
+ );
598
+ nodes[3 * i + 3][3 * j + 2] = w_ave(
599
+ nodes[3 * i + 3][3 * j + 3],
600
+ nodes[3 * i + 3][3 * j],
601
+ );
602
+ } else {
603
+ // Left
604
+ nodes[3 * i + 1][3 * j] = w_ave(
605
+ nodes[3 * i][3 * j],
606
+ nodes[3 * i + 3][3 * j],
607
+ );
608
+ nodes[3 * i + 2][3 * j] = w_ave(
609
+ nodes[3 * i + 3][3 * j],
610
+ nodes[3 * i][3 * j],
611
+ );
612
+ }
682
613
 
614
+ break;
615
+
616
+ case "L":
617
+ if (l === 0) {
618
+ // Top
619
+ nodes[3 * i][3 * j + 3] = stop_nodes[0];
620
+ nodes[3 * i][3 * j + 1] = w_ave(
621
+ nodes[3 * i][3 * j],
622
+ nodes[3 * i][3 * j + 3],
623
+ );
624
+ nodes[3 * i][3 * j + 2] = w_ave(
625
+ nodes[3 * i][3 * j + 3],
626
+ nodes[3 * i][3 * j],
627
+ );
628
+ } else if (l === 1) {
629
+ // Right
630
+ nodes[3 * i + 3][3 * j + 3] = stop_nodes[0];
631
+ nodes[3 * i + 1][3 * j + 3] = w_ave(
632
+ nodes[3 * i][3 * j + 3],
633
+ nodes[3 * i + 3][3 * j + 3],
634
+ );
635
+ nodes[3 * i + 2][3 * j + 3] = w_ave(
636
+ nodes[3 * i + 3][3 * j + 3],
637
+ nodes[3 * i][3 * j + 3],
638
+ );
639
+ } else if (l === 2) {
640
+ // Bottom
641
+ if (j === 0) {
642
+ nodes[3 * i + 3][3 * j + 0] = stop_nodes[0];
643
+ }
644
+ nodes[3 * i + 3][3 * j + 1] = w_ave(
645
+ nodes[3 * i + 3][3 * j],
646
+ nodes[3 * i + 3][3 * j + 3],
647
+ );
648
+ nodes[3 * i + 3][3 * j + 2] = w_ave(
649
+ nodes[3 * i + 3][3 * j + 3],
650
+ nodes[3 * i + 3][3 * j],
651
+ );
652
+ } else {
653
+ // Left
654
+ nodes[3 * i + 1][3 * j] = w_ave(
655
+ nodes[3 * i][3 * j],
656
+ nodes[3 * i + 3][3 * j],
657
+ );
658
+ nodes[3 * i + 2][3 * j] = w_ave(
659
+ nodes[3 * i + 3][3 * j],
660
+ nodes[3 * i][3 * j],
661
+ );
683
662
  }
684
- }
685
- }
686
- return {
687
- nodes: nodes,
688
- colors: colors
689
- };
690
- };
691
663
 
692
- // Extracts out each patch and then paints it
693
- Mesh.prototype.paint = function(v, w) {
694
- for (var i = 0; i < (this.nodes.length-1)/3; ++i) {
695
- for (var j = 0; j < (this.nodes[0].length-1)/3; ++j) {
664
+ break;
665
+
666
+ case "c":
667
+ if (l === 0) {
668
+ // Top
669
+ nodes[3 * i][3 * j + 1] = stop_nodes[0].add(
670
+ nodes[3 * i][3 * j],
671
+ );
672
+ nodes[3 * i][3 * j + 2] = stop_nodes[1].add(
673
+ nodes[3 * i][3 * j],
674
+ );
675
+ nodes[3 * i][3 * j + 3] = stop_nodes[2].add(
676
+ nodes[3 * i][3 * j],
677
+ );
678
+ } else if (l === 1) {
679
+ // Right
680
+ nodes[3 * i + 1][3 * j + 3] = stop_nodes[0].add(
681
+ nodes[3 * i][3 * j + 3],
682
+ );
683
+ nodes[3 * i + 2][3 * j + 3] = stop_nodes[1].add(
684
+ nodes[3 * i][3 * j + 3],
685
+ );
686
+ nodes[3 * i + 3][3 * j + 3] = stop_nodes[2].add(
687
+ nodes[3 * i][3 * j + 3],
688
+ );
689
+ } else if (l === 2) {
690
+ // Bottom
691
+ nodes[3 * i + 3][3 * j + 2] = stop_nodes[0].add(
692
+ nodes[3 * i + 3][3 * j + 3],
693
+ );
694
+ nodes[3 * i + 3][3 * j + 1] = stop_nodes[1].add(
695
+ nodes[3 * i + 3][3 * j + 3],
696
+ );
697
+ if (j === 0) {
698
+ nodes[3 * i + 3][3 * j + 0] = stop_nodes[2].add(
699
+ nodes[3 * i + 3][3 * j + 3],
700
+ );
701
+ }
702
+ } else {
703
+ // Left
704
+ nodes[3 * i + 2][3 * j] = stop_nodes[0].add(
705
+ nodes[3 * i + 3][3 * j],
706
+ );
707
+ nodes[3 * i + 1][3 * j] = stop_nodes[1].add(
708
+ nodes[3 * i + 3][3 * j],
709
+ );
710
+ }
696
711
 
697
- var slice_nodes = [];
698
- for (var k = i*3; k < (i*3)+4; ++k) {
699
- slice_nodes.push(this.nodes[k].slice(j*3,(j*3)+4));
712
+ break;
713
+
714
+ case "C":
715
+ if (l === 0) {
716
+ // Top
717
+ nodes[3 * i][3 * j + 1] = stop_nodes[0];
718
+ nodes[3 * i][3 * j + 2] = stop_nodes[1];
719
+ nodes[3 * i][3 * j + 3] = stop_nodes[2];
720
+ } else if (l == 1) {
721
+ // Right
722
+ nodes[3 * i + 1][3 * j + 3] = stop_nodes[0];
723
+ nodes[3 * i + 2][3 * j + 3] = stop_nodes[1];
724
+ nodes[3 * i + 3][3 * j + 3] = stop_nodes[2];
725
+ } else if (l == 2) {
726
+ // Bottom
727
+ nodes[3 * i + 3][3 * j + 2] = stop_nodes[0];
728
+ nodes[3 * i + 3][3 * j + 1] = stop_nodes[1];
729
+ if (j === 0) {
730
+ nodes[3 * i + 3][3 * j + 0] = stop_nodes[2];
731
+ }
732
+ } else {
733
+ // Left
734
+ nodes[3 * i + 2][3 * j] = stop_nodes[0];
735
+ nodes[3 * i + 1][3 * j] = stop_nodes[1];
700
736
  }
701
737
 
702
- var slice_colors = [];
703
- slice_colors.push(this.colors[i ].slice(j,j+2));
704
- slice_colors.push(this.colors[i+1].slice(j,j+2));
738
+ break;
705
739
 
706
- var patch = new Patch(slice_nodes, slice_colors);
707
- patch.paint(v, w);
740
+ default:
741
+ console.log("mesh.js: " + type + " invalid path type.");
708
742
  }
709
- }
710
- };
711
743
 
712
- // Transforms mesh into coordinate space of canvas (t is either Point or Affine).
713
- Mesh.prototype.transform = function(t) {
714
- var i,
715
- j;
716
- if (t instanceof Point) {
717
- for (i = 0; i < this.nodes.length; ++i) {
718
- for (j = 0; j < this.nodes[0].length; ++j) {
719
- this.nodes[i][j] = this.nodes[i][j].add(t);
720
- }
721
- }
722
- }
723
- if (t instanceof Affine) {
724
- for (i = 0; i < this.nodes.length; ++i) {
725
- for (j = 0; j < this.nodes[0].length; ++j) {
726
- this.nodes[i][j] = this.nodes[i][j].transform(t);
744
+ if ((i === 0 && j === 0) || k > 0) {
745
+ var color_raw = getComputedStyle(stops[k]).stopColor.match(
746
+ /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i,
747
+ ),
748
+ alpha_raw = getComputedStyle(stops[k]).stopOpacity,
749
+ alpha = 255;
750
+
751
+ if (alpha_raw) {
752
+ alpha = parseInt(alpha_raw * 255);
753
+ }
754
+
755
+ if (color_raw) {
756
+ if (l === 0) {
757
+ // upper left corner
758
+ colors[i][j] = [];
759
+ colors[i][j][0] = parseInt(color_raw[1]);
760
+ colors[i][j][1] = parseInt(color_raw[2]);
761
+ colors[i][j][2] = parseInt(color_raw[3]);
762
+ colors[i][j][3] = alpha; // Alpha
763
+ } else if (l === 1) {
764
+ // upper right corner
765
+ colors[i][j + 1] = [];
766
+ colors[i][j + 1][0] = parseInt(color_raw[1]);
767
+ colors[i][j + 1][1] = parseInt(color_raw[2]);
768
+ colors[i][j + 1][2] = parseInt(color_raw[3]);
769
+ colors[i][j + 1][3] = alpha; // Alpha
770
+ } else if (l === 2) {
771
+ // lower right corner
772
+ colors[i + 1][j + 1] = [];
773
+ colors[i + 1][j + 1][0] = parseInt(color_raw[1]);
774
+ colors[i + 1][j + 1][1] = parseInt(color_raw[2]);
775
+ colors[i + 1][j + 1][2] = parseInt(color_raw[3]);
776
+ colors[i + 1][j + 1][3] = alpha; // Alpha
777
+ } else if (l === 3) {
778
+ // lower left corner
779
+ colors[i + 1][j] = [];
780
+ colors[i + 1][j][0] = parseInt(color_raw[1]);
781
+ colors[i + 1][j][1] = parseInt(color_raw[2]);
782
+ colors[i + 1][j][2] = parseInt(color_raw[3]);
783
+ colors[i + 1][j][3] = alpha; // Alpha
727
784
  }
785
+ }
728
786
  }
787
+ }
788
+
789
+ // SVG doesn't use tensor points but we need them for rendering.
790
+ nodes[3 * i + 1][3 * j + 1] = new Point();
791
+ nodes[3 * i + 1][3 * j + 2] = new Point();
792
+ nodes[3 * i + 2][3 * j + 1] = new Point();
793
+ nodes[3 * i + 2][3 * j + 2] = new Point();
794
+
795
+ nodes[3 * i + 1][3 * j + 1].x =
796
+ (-4.0 * nodes[3 * i][3 * j].x +
797
+ 6.0 * (nodes[3 * i][3 * j + 1].x + nodes[3 * i + 1][3 * j].x) +
798
+ -2.0 * (nodes[3 * i][3 * j + 3].x + nodes[3 * i + 3][3 * j].x) +
799
+ 3.0 *
800
+ (nodes[3 * i + 3][3 * j + 1].x +
801
+ nodes[3 * i + 1][3 * j + 3].x) +
802
+ -1.0 * nodes[3 * i + 3][3 * j + 3].x) /
803
+ 9.0;
804
+ nodes[3 * i + 1][3 * j + 2].x =
805
+ (-4.0 * nodes[3 * i][3 * j + 3].x +
806
+ 6.0 *
807
+ (nodes[3 * i][3 * j + 2].x + nodes[3 * i + 1][3 * j + 3].x) +
808
+ -2.0 * (nodes[3 * i][3 * j].x + nodes[3 * i + 3][3 * j + 3].x) +
809
+ 3.0 *
810
+ (nodes[3 * i + 3][3 * j + 2].x + nodes[3 * i + 1][3 * j].x) +
811
+ -1.0 * nodes[3 * i + 3][3 * j].x) /
812
+ 9.0;
813
+ nodes[3 * i + 2][3 * j + 1].x =
814
+ (-4.0 * nodes[3 * i + 3][3 * j].x +
815
+ 6.0 *
816
+ (nodes[3 * i + 3][3 * j + 1].x + nodes[3 * i + 2][3 * j].x) +
817
+ -2.0 * (nodes[3 * i + 3][3 * j + 3].x + nodes[3 * i][3 * j].x) +
818
+ 3.0 *
819
+ (nodes[3 * i][3 * j + 1].x + nodes[3 * i + 2][3 * j + 3].x) +
820
+ -1.0 * nodes[3 * i][3 * j + 3].x) /
821
+ 9.0;
822
+ nodes[3 * i + 2][3 * j + 2].x =
823
+ (-4.0 * nodes[3 * i + 3][3 * j + 3].x +
824
+ 6.0 *
825
+ (nodes[3 * i + 3][3 * j + 2].x +
826
+ nodes[3 * i + 2][3 * j + 3].x) +
827
+ -2.0 * (nodes[3 * i + 3][3 * j].x + nodes[3 * i][3 * j + 3].x) +
828
+ 3.0 * (nodes[3 * i][3 * j + 2].x + nodes[3 * i + 2][3 * j].x) +
829
+ -1.0 * nodes[3 * i][3 * j].x) /
830
+ 9.0;
831
+
832
+ nodes[3 * i + 1][3 * j + 1].y =
833
+ (-4.0 * nodes[3 * i][3 * j].y +
834
+ 6.0 * (nodes[3 * i][3 * j + 1].y + nodes[3 * i + 1][3 * j].y) +
835
+ -2.0 * (nodes[3 * i][3 * j + 3].y + nodes[3 * i + 3][3 * j].y) +
836
+ 3.0 *
837
+ (nodes[3 * i + 3][3 * j + 1].y +
838
+ nodes[3 * i + 1][3 * j + 3].y) +
839
+ -1.0 * nodes[3 * i + 3][3 * j + 3].y) /
840
+ 9.0;
841
+ nodes[3 * i + 1][3 * j + 2].y =
842
+ (-4.0 * nodes[3 * i][3 * j + 3].y +
843
+ 6.0 *
844
+ (nodes[3 * i][3 * j + 2].y + nodes[3 * i + 1][3 * j + 3].y) +
845
+ -2.0 * (nodes[3 * i][3 * j].y + nodes[3 * i + 3][3 * j + 3].y) +
846
+ 3.0 *
847
+ (nodes[3 * i + 3][3 * j + 2].y + nodes[3 * i + 1][3 * j].y) +
848
+ -1.0 * nodes[3 * i + 3][3 * j].y) /
849
+ 9.0;
850
+ nodes[3 * i + 2][3 * j + 1].y =
851
+ (-4.0 * nodes[3 * i + 3][3 * j].y +
852
+ 6.0 *
853
+ (nodes[3 * i + 3][3 * j + 1].y + nodes[3 * i + 2][3 * j].y) +
854
+ -2.0 * (nodes[3 * i + 3][3 * j + 3].y + nodes[3 * i][3 * j].y) +
855
+ 3.0 *
856
+ (nodes[3 * i][3 * j + 1].y + nodes[3 * i + 2][3 * j + 3].y) +
857
+ -1.0 * nodes[3 * i][3 * j + 3].y) /
858
+ 9.0;
859
+ nodes[3 * i + 2][3 * j + 2].y =
860
+ (-4.0 * nodes[3 * i + 3][3 * j + 3].y +
861
+ 6.0 *
862
+ (nodes[3 * i + 3][3 * j + 2].y +
863
+ nodes[3 * i + 2][3 * j + 3].y) +
864
+ -2.0 * (nodes[3 * i + 3][3 * j].y + nodes[3 * i][3 * j + 3].y) +
865
+ 3.0 * (nodes[3 * i][3 * j + 2].y + nodes[3 * i + 2][3 * j].y) +
866
+ -1.0 * nodes[3 * i][3 * j].y) /
867
+ 9.0;
729
868
  }
869
+ }
870
+ }
871
+ return {
872
+ nodes: nodes,
873
+ colors: colors,
730
874
  };
731
-
732
- // Scale mesh into coordinate space of canvas (t is a Point).
733
- Mesh.prototype.scale = function(t) {
734
- var i,
735
- j;
736
- for (i = 0; i < this.nodes.length; ++i) {
737
- for (j = 0; j < this.nodes[0].length; ++j) {
738
- this.nodes[i][j] = this.nodes[i][j].scale(t);
739
- }
875
+ };
876
+
877
+ // Extracts out each patch and then paints it
878
+ Mesh.prototype.paint = function (v, w) {
879
+ for (var i = 0; i < (this.nodes.length - 1) / 3; ++i) {
880
+ for (var j = 0; j < (this.nodes[0].length - 1) / 3; ++j) {
881
+ var slice_nodes = [];
882
+ for (var k = i * 3; k < i * 3 + 4; ++k) {
883
+ slice_nodes.push(this.nodes[k].slice(j * 3, j * 3 + 4));
740
884
  }
741
- };
742
885
 
743
- function parse_points(s) {
744
- var points = [],
745
- values = s.split(/[ ,]+/),
746
- i;
747
- for (i = 0; i < values.length-1; i += 2) {
748
- points.push( new Point( parseFloat( values[i]), parseFloat( values[i+1] )));
749
- }
886
+ var slice_colors = [];
887
+ slice_colors.push(this.colors[i].slice(j, j + 2));
888
+ slice_colors.push(this.colors[i + 1].slice(j, j + 2));
750
889
 
751
- return points;
890
+ var patch = new Patch(slice_nodes, slice_colors);
891
+ patch.paint(v, w);
892
+ }
893
+ }
894
+ };
895
+
896
+ // Transforms mesh into coordinate space of canvas (t is either Point or Affine).
897
+ Mesh.prototype.transform = function (t) {
898
+ var i, j;
899
+ if (t instanceof Point) {
900
+ for (i = 0; i < this.nodes.length; ++i) {
901
+ for (j = 0; j < this.nodes[0].length; ++j) {
902
+ this.nodes[i][j] = this.nodes[i][j].add(t);
903
+ }
904
+ }
905
+ }
906
+ if (t instanceof Affine) {
907
+ for (i = 0; i < this.nodes.length; ++i) {
908
+ for (j = 0; j < this.nodes[0].length; ++j) {
909
+ this.nodes[i][j] = this.nodes[i][j].transform(t);
910
+ }
911
+ }
912
+ }
913
+ };
914
+
915
+ // Scale mesh into coordinate space of canvas (t is a Point).
916
+ Mesh.prototype.scale = function (t) {
917
+ var i, j;
918
+ for (i = 0; i < this.nodes.length; ++i) {
919
+ for (j = 0; j < this.nodes[0].length; ++j) {
920
+ this.nodes[i][j] = this.nodes[i][j].scale(t);
921
+ }
922
+ }
923
+ };
924
+
925
+ function parse_points(s) {
926
+ var points = [],
927
+ values = s.split(/[ ,]+/),
928
+ i;
929
+ for (i = 0; i < values.length - 1; i += 2) {
930
+ points.push(new Point(parseFloat(values[i]), parseFloat(values[i + 1])));
752
931
  }
753
932
 
754
- // Start of document processing ---------------------
755
- var shapes = document.querySelectorAll('rect,circle,ellipse,path,text');
933
+ return points;
934
+ }
756
935
 
757
- for (i = 0; i < shapes.length; ++i) {
758
- var shape = shapes[i];
759
- // Get id. If no id, create one.
760
- var shape_id = shape.getAttribute("id");
936
+ // Start of document processing ---------------------
937
+ var shapes = document.querySelectorAll("rect,circle,ellipse,path,text");
761
938
 
762
- if (!shape_id) {
763
- shape_id = "patchjs_shape" + i;
764
- shape.setAttribute("id", shape_id);
765
- }
939
+ for (i = 0; i < shapes.length; ++i) {
940
+ var shape = shapes[i];
941
+ // Get id. If no id, create one.
942
+ var shape_id = shape.getAttribute("id");
766
943
 
767
- var fill = shape.style.fill,
768
- url_value = fill.match(/^url\(\s*\"?\s*#([^\s\"]+)\"?\s*\)/);
944
+ if (!shape_id) {
945
+ shape_id = "patchjs_shape" + i;
946
+ shape.setAttribute("id", shape_id);
947
+ }
769
948
 
770
- if (url_value && url_value[1]) {
771
- var mesh = document.getElementById(url_value[1]);
949
+ var fill = shape.style.fill,
950
+ url_value = fill.match(/^url\(\s*\"?\s*#([^\s\"]+)\"?\s*\)/);
772
951
 
773
- if (mesh.nodeName === "meshgradient" ) {
774
- var bbox = shape.getBBox();
952
+ if (url_value && url_value[1]) {
953
+ var mesh = document.getElementById(url_value[1]);
775
954
 
776
- // Create temporary canvas
777
- var my_canvas = document.createElementNS( xhtmlNS, "canvas" );
778
- my_canvas.width = bbox.width;
779
- my_canvas.height = bbox.height;
955
+ if (mesh.nodeName === "meshgradient") {
956
+ var bbox = shape.getBBox();
780
957
 
781
- var my_context = my_canvas.getContext("2d"),
782
- my_canvas_image = my_context.getImageData( 0, 0, my_canvas.width, my_canvas.height),
783
- my_data = my_canvas_image.data;
958
+ // Create temporary canvas
959
+ var my_canvas = document.createElementNS(xhtmlNS, "canvas");
960
+ my_canvas.width = bbox.width;
961
+ my_canvas.height = bbox.height;
784
962
 
785
- // Draw a mesh
786
- var my_mesh = new Mesh( url_value[1] );
963
+ var my_context = my_canvas.getContext("2d"),
964
+ my_canvas_image = my_context.getImageData(
965
+ 0,
966
+ 0,
967
+ my_canvas.width,
968
+ my_canvas.height,
969
+ ),
970
+ my_data = my_canvas_image.data;
787
971
 
788
- // Adjust for bounding box if necessary.
789
- if (mesh.getAttribute( "gradientUnits" ) === "objectBoundingBox") {
790
- my_mesh.scale( new Point( bbox.width, bbox.height ) );
791
- }
972
+ // Draw a mesh
973
+ var my_mesh = new Mesh(url_value[1]);
792
974
 
793
- // Apply gradient transform.
794
- var gradientTransform = mesh.getAttribute("gradientTransform");
975
+ // Adjust for bounding box if necessary.
976
+ if (mesh.getAttribute("gradientUnits") === "objectBoundingBox") {
977
+ my_mesh.scale(new Point(bbox.width, bbox.height));
978
+ }
795
979
 
796
- if (gradientTransform !== null) {
797
- var affine = parseTransform(gradientTransform);
798
- my_mesh.transform(affine);
799
- }
980
+ // Apply gradient transform.
981
+ var gradientTransform = mesh.getAttribute("gradientTransform");
800
982
 
801
- // Position to Canvas coordinate.
802
- var t = new Point(-bbox.x, -bbox.y);
983
+ if (gradientTransform !== null) {
984
+ var affine = parseTransform(gradientTransform);
985
+ my_mesh.transform(affine);
986
+ }
803
987
 
804
- if (mesh.getAttribute( "gradientUnits" ) === "userSpaceOnUse") {
805
- my_mesh.transform(t);
806
- }
988
+ // Position to Canvas coordinate.
989
+ var t = new Point(-bbox.x, -bbox.y);
990
+
991
+ if (mesh.getAttribute("gradientUnits") === "userSpaceOnUse") {
992
+ my_mesh.transform(t);
993
+ }
807
994
 
808
- // Paint
809
- my_mesh.paint(my_data, my_canvas.width);
995
+ // Paint
996
+ my_mesh.paint(my_data, my_canvas.width);
810
997
 
811
- my_context.putImageData(my_canvas_image, 0, 0);
998
+ my_context.putImageData(my_canvas_image, 0, 0);
812
999
 
813
- // Create image element of correct size
814
- var my_image = document.createElementNS( svgNS, "image" );
815
- my_image.setAttribute("width", my_canvas.width);
816
- my_image.setAttribute("height",my_canvas.height);
817
- my_image.setAttribute("x", bbox.x);
818
- my_image.setAttribute("y", bbox.y);
1000
+ // Create image element of correct size
1001
+ var my_image = document.createElementNS(svgNS, "image");
1002
+ my_image.setAttribute("width", my_canvas.width);
1003
+ my_image.setAttribute("height", my_canvas.height);
1004
+ my_image.setAttribute("x", bbox.x);
1005
+ my_image.setAttribute("y", bbox.y);
819
1006
 
820
- // Set image to data url
821
- var my_png = my_canvas.toDataURL();
822
- my_image.setAttributeNS(xlinkNS, "xlink:href", my_png);
1007
+ // Set image to data url
1008
+ var my_png = my_canvas.toDataURL();
1009
+ my_image.setAttributeNS(xlinkNS, "xlink:href", my_png);
823
1010
 
824
- // Insert image into document
825
- shape.parentNode.insertBefore(my_image, shape);
826
- shape.style.fill = "none";
1011
+ // Insert image into document
1012
+ shape.parentNode.insertBefore(my_image, shape);
1013
+ shape.style.fill = "none";
827
1014
 
828
- // Create clip referencing shape and insert into document
829
- var clip = document.createElementNS(svgNS, "clipPath"),
830
- clip_id = "patchjs_clip" + i;
1015
+ // Create clip referencing shape and insert into document
1016
+ var clip = document.createElementNS(svgNS, "clipPath"),
1017
+ clip_id = "patchjs_clip" + i;
831
1018
 
832
- clip.setAttribute("id", clip_id);
1019
+ clip.setAttribute("id", clip_id);
833
1020
 
834
- var use = document.createElementNS(svgNS, "use");
1021
+ var use = document.createElementNS(svgNS, "use");
835
1022
 
836
- use.setAttributeNS(xlinkNS, "xlink:href", "#" + shape_id);
837
- clip.appendChild(use);
838
- shape.parentElement.insertBefore(clip, shape);
839
- my_image.setAttribute("clip-path", "url(#" + clip_id + ")");
840
- }
841
- }
1023
+ use.setAttributeNS(xlinkNS, "xlink:href", "#" + shape_id);
1024
+ clip.appendChild(use);
1025
+ shape.parentElement.insertBefore(clip, shape);
1026
+ my_image.setAttribute("clip-path", "url(#" + clip_id + ")");
1027
+ }
842
1028
  }
1029
+ }
843
1030
  })();