@emasoft/svg-matrix 1.0.27 → 1.0.29
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.
- package/README.md +325 -0
- package/bin/svg-matrix.js +994 -378
- package/bin/svglinter.cjs +4172 -433
- package/bin/svgm.js +744 -184
- package/package.json +16 -4
- package/src/animation-references.js +71 -52
- package/src/arc-length.js +160 -96
- package/src/bezier-analysis.js +257 -117
- package/src/bezier-intersections.js +411 -148
- package/src/browser-verify.js +240 -100
- package/src/clip-path-resolver.js +350 -142
- package/src/convert-path-data.js +279 -134
- package/src/css-specificity.js +78 -70
- package/src/flatten-pipeline.js +751 -263
- package/src/geometry-to-path.js +511 -182
- package/src/index.js +191 -46
- package/src/inkscape-support.js +404 -0
- package/src/marker-resolver.js +278 -164
- package/src/mask-resolver.js +209 -98
- package/src/matrix.js +147 -67
- package/src/mesh-gradient.js +187 -96
- package/src/off-canvas-detection.js +201 -104
- package/src/path-analysis.js +187 -107
- package/src/path-data-plugins.js +628 -167
- package/src/path-simplification.js +0 -1
- package/src/pattern-resolver.js +125 -88
- package/src/polygon-clip.js +111 -66
- package/src/svg-boolean-ops.js +194 -118
- package/src/svg-collections.js +48 -19
- package/src/svg-flatten.js +282 -164
- package/src/svg-parser.js +427 -200
- package/src/svg-rendering-context.js +147 -104
- package/src/svg-toolbox.js +16411 -3298
- package/src/svg2-polyfills.js +114 -245
- package/src/transform-decomposition.js +46 -41
- package/src/transform-optimization.js +89 -68
- package/src/transforms2d.js +49 -16
- package/src/transforms3d.js +58 -22
- package/src/use-symbol-resolver.js +150 -110
- package/src/vector.js +67 -15
- package/src/vendor/README.md +110 -0
- package/src/vendor/inkscape-hatch-polyfill.js +401 -0
- package/src/vendor/inkscape-hatch-polyfill.min.js +8 -0
- package/src/vendor/inkscape-mesh-polyfill.js +843 -0
- package/src/vendor/inkscape-mesh-polyfill.min.js +8 -0
- package/src/verification.js +288 -124
|
@@ -0,0 +1,843 @@
|
|
|
1
|
+
|
|
2
|
+
// Use Canvas to render a mesh gradient, passing the rendering to an image via a data stream.
|
|
3
|
+
// Copyright: Tavmjong Bah 2017
|
|
4
|
+
// Distributed under GNU General Public License version 3 or later. See <http://fsf.org/>.
|
|
5
|
+
|
|
6
|
+
(function() {
|
|
7
|
+
var counter = 0; // Temp, number of calls to Canvas
|
|
8
|
+
|
|
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";
|
|
13
|
+
|
|
14
|
+
// Test if mesh gradients are supported.
|
|
15
|
+
var m = document.createElementNS( svgNS, "meshgradient" );
|
|
16
|
+
|
|
17
|
+
if (m.x) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Point class -----------------------------------
|
|
22
|
+
function Point(x, y) {
|
|
23
|
+
this.x = x || 0;
|
|
24
|
+
this.y = y || 0;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Point.prototype.x = null;
|
|
28
|
+
Point.prototype.y = null;
|
|
29
|
+
|
|
30
|
+
Point.prototype.get_x = function() {
|
|
31
|
+
return this.x;
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
Point.prototype.get_y = function() {
|
|
35
|
+
return this.y;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
Point.prototype.clone = function() {
|
|
39
|
+
return new Point(this.x, this.y);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
Point.prototype.add = function(v) {
|
|
43
|
+
return new Point(this.x + v.x, this.y + v.y);
|
|
44
|
+
};
|
|
45
|
+
|
|
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
|
+
}
|
|
92
|
+
}
|
|
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;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function colorToString(c) {
|
|
237
|
+
return ("rgb(" + Math.round(c[0]) + "," + Math.round(c[1]) + "," +Math.round(c[2]) + ")");
|
|
238
|
+
}
|
|
239
|
+
|
|
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]]);
|
|
257
|
+
}
|
|
258
|
+
|
|
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;
|
|
270
|
+
}
|
|
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)
|
|
276
|
+
}
|
|
277
|
+
|
|
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)
|
|
317
|
+
}
|
|
318
|
+
|
|
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
|
+
};
|
|
338
|
+
|
|
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
|
+
};
|
|
345
|
+
|
|
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
|
+
};
|
|
352
|
+
|
|
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 = [];
|
|
398
|
+
|
|
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
|
+
}
|
|
403
|
+
|
|
404
|
+
var max = Math.max.apply(null,tmp);
|
|
405
|
+
|
|
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);
|
|
413
|
+
}
|
|
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
|
+
|
|
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));
|
|
439
|
+
|
|
440
|
+
return p;
|
|
441
|
+
}
|
|
442
|
+
|
|
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;
|
|
682
|
+
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
return {
|
|
687
|
+
nodes: nodes,
|
|
688
|
+
colors: colors
|
|
689
|
+
};
|
|
690
|
+
};
|
|
691
|
+
|
|
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) {
|
|
696
|
+
|
|
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));
|
|
700
|
+
}
|
|
701
|
+
|
|
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));
|
|
705
|
+
|
|
706
|
+
var patch = new Patch(slice_nodes, slice_colors);
|
|
707
|
+
patch.paint(v, w);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
|
|
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);
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
}
|
|
730
|
+
};
|
|
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
|
+
}
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
|
|
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
|
+
}
|
|
750
|
+
|
|
751
|
+
return points;
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
// Start of document processing ---------------------
|
|
755
|
+
var shapes = document.querySelectorAll('rect,circle,ellipse,path,text');
|
|
756
|
+
|
|
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");
|
|
761
|
+
|
|
762
|
+
if (!shape_id) {
|
|
763
|
+
shape_id = "patchjs_shape" + i;
|
|
764
|
+
shape.setAttribute("id", shape_id);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
var fill = shape.style.fill,
|
|
768
|
+
url_value = fill.match(/^url\(\s*\"?\s*#([^\s\"]+)\"?\s*\)/);
|
|
769
|
+
|
|
770
|
+
if (url_value && url_value[1]) {
|
|
771
|
+
var mesh = document.getElementById(url_value[1]);
|
|
772
|
+
|
|
773
|
+
if (mesh.nodeName === "meshgradient" ) {
|
|
774
|
+
var bbox = shape.getBBox();
|
|
775
|
+
|
|
776
|
+
// Create temporary canvas
|
|
777
|
+
var my_canvas = document.createElementNS( xhtmlNS, "canvas" );
|
|
778
|
+
my_canvas.width = bbox.width;
|
|
779
|
+
my_canvas.height = bbox.height;
|
|
780
|
+
|
|
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;
|
|
784
|
+
|
|
785
|
+
// Draw a mesh
|
|
786
|
+
var my_mesh = new Mesh( url_value[1] );
|
|
787
|
+
|
|
788
|
+
// Adjust for bounding box if necessary.
|
|
789
|
+
if (mesh.getAttribute( "gradientUnits" ) === "objectBoundingBox") {
|
|
790
|
+
my_mesh.scale( new Point( bbox.width, bbox.height ) );
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Apply gradient transform.
|
|
794
|
+
var gradientTransform = mesh.getAttribute("gradientTransform");
|
|
795
|
+
|
|
796
|
+
if (gradientTransform !== null) {
|
|
797
|
+
var affine = parseTransform(gradientTransform);
|
|
798
|
+
my_mesh.transform(affine);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// Position to Canvas coordinate.
|
|
802
|
+
var t = new Point(-bbox.x, -bbox.y);
|
|
803
|
+
|
|
804
|
+
if (mesh.getAttribute( "gradientUnits" ) === "userSpaceOnUse") {
|
|
805
|
+
my_mesh.transform(t);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
// Paint
|
|
809
|
+
my_mesh.paint(my_data, my_canvas.width);
|
|
810
|
+
|
|
811
|
+
my_context.putImageData(my_canvas_image, 0, 0);
|
|
812
|
+
|
|
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);
|
|
819
|
+
|
|
820
|
+
// Set image to data url
|
|
821
|
+
var my_png = my_canvas.toDataURL();
|
|
822
|
+
my_image.setAttributeNS(xlinkNS, "xlink:href", my_png);
|
|
823
|
+
|
|
824
|
+
// Insert image into document
|
|
825
|
+
shape.parentNode.insertBefore(my_image, shape);
|
|
826
|
+
shape.style.fill = "none";
|
|
827
|
+
|
|
828
|
+
// Create clip referencing shape and insert into document
|
|
829
|
+
var clip = document.createElementNS(svgNS, "clipPath"),
|
|
830
|
+
clip_id = "patchjs_clip" + i;
|
|
831
|
+
|
|
832
|
+
clip.setAttribute("id", clip_id);
|
|
833
|
+
|
|
834
|
+
var use = document.createElementNS(svgNS, "use");
|
|
835
|
+
|
|
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
|
+
}
|
|
842
|
+
}
|
|
843
|
+
})();
|