]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/src/fx/DrawPath.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / src / fx / DrawPath.js
CommitLineData
6527f429
DM
1/**\r
2 * @class Ext.fx.DrawPath\r
3 * Provides SVG Paths handling functions. Copied from Ext.draw.Draw in ExtJs 4.2 in order\r
4 * to break the dependencies on parsePathString() and interpolatePaths() in PropertyHandler.js\r
5 * @private\r
6 */\r
7Ext.define('Ext.fx.DrawPath', {\r
8 /* Begin Definitions */\r
9\r
10 singleton: true,\r
11\r
12 /* End Definitions */\r
13\r
14 pathToStringRE: /,?([achlmqrstvxz]),?/gi,\r
15 pathCommandRE: /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,\r
16 pathValuesRE: /(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig,\r
17 stopsRE: /^(\d+%?)$/,\r
18 radian: Math.PI / 180,\r
19\r
20 is: function(o, type) {\r
21 type = String(type).toLowerCase();\r
22 return (type == "object" && o === Object(o)) ||\r
23 (type == "undefined" && typeof o == type) ||\r
24 (type == "null" && o === null) ||\r
25 (type == "array" && Array.isArray && Array.isArray(o)) ||\r
26 (Object.prototype.toString.call(o).toLowerCase().slice(8, -1)) == type;\r
27 },\r
28\r
29 // To be deprecated, converts itself (an arrayPath) to a proper SVG path string\r
30 path2string: function () {\r
31 return this.join(",").replace(Ext.fx.DrawPath.pathToStringRE, "$1");\r
32 },\r
33\r
34 // Convert the passed arrayPath to a proper SVG path string (d attribute)\r
35 pathToString: function(arrayPath) {\r
36 return arrayPath.join(",").replace(Ext.fx.DrawPath.pathToStringRE, "$1");\r
37 },\r
38\r
39 parsePathString: function (pathString) {\r
40 if (!pathString) {\r
41 return null;\r
42 }\r
43 var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0},\r
44 data = [],\r
45 me = this;\r
46 if (me.is(pathString, "array") && me.is(pathString[0], "array")) { // rough assumption\r
47 data = me.pathClone(pathString);\r
48 }\r
49 if (!data.length) {\r
50 String(pathString).replace(me.pathCommandRE, function (a, b, c) {\r
51 var params = [],\r
52 name = b.toLowerCase();\r
53 c.replace(me.pathValuesRE, function (a, b) {\r
54 if (b) {\r
55 params.push(+b);\r
56 }\r
57 });\r
58 if (name == "m" && params.length > 2) {\r
59 data.push([b].concat(Ext.Array.splice(params, 0, 2)));\r
60 name = "l";\r
61 b = (b == "m") ? "l" : "L";\r
62 }\r
63 while (params.length >= paramCounts[name]) {\r
64 data.push([b].concat(Ext.Array.splice(params, 0, paramCounts[name])));\r
65 if (!paramCounts[name]) {\r
66 break;\r
67 }\r
68 }\r
69 });\r
70 }\r
71 data.toString = me.path2string;\r
72 return data;\r
73 },\r
74\r
75 pathClone: function(pathArray) {\r
76 var res = [],\r
77 j, jj, i, ii;\r
78 if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { // rough assumption\r
79 pathArray = this.parsePathString(pathArray);\r
80 }\r
81 for (i = 0, ii = pathArray.length; i < ii; i++) {\r
82 res[i] = [];\r
83 for (j = 0, jj = pathArray[i].length; j < jj; j++) {\r
84 res[i][j] = pathArray[i][j];\r
85 }\r
86 }\r
87 res.toString = this.path2string;\r
88 return res;\r
89 },\r
90\r
91 pathToAbsolute: function (pathArray) {\r
92 if (!this.is(pathArray, "array") || !this.is(pathArray && pathArray[0], "array")) { // rough assumption\r
93 pathArray = this.parsePathString(pathArray);\r
94 }\r
95 var res = [],\r
96 x = 0,\r
97 y = 0,\r
98 mx = 0,\r
99 my = 0,\r
100 i = 0,\r
101 ln = pathArray.length,\r
102 r, pathSegment, j, ln2;\r
103 // MoveTo initial x/y position\r
104 if (ln && pathArray[0][0] == "M") {\r
105 x = +pathArray[0][1];\r
106 y = +pathArray[0][2];\r
107 mx = x;\r
108 my = y;\r
109 i++;\r
110 res[0] = ["M", x, y];\r
111 }\r
112 for (; i < ln; i++) {\r
113 r = res[i] = [];\r
114 pathSegment = pathArray[i];\r
115 if (pathSegment[0] != pathSegment[0].toUpperCase()) {\r
116 r[0] = pathSegment[0].toUpperCase();\r
117 switch (r[0]) {\r
118 // Elliptical Arc\r
119 case "A":\r
120 r[1] = pathSegment[1];\r
121 r[2] = pathSegment[2];\r
122 r[3] = pathSegment[3];\r
123 r[4] = pathSegment[4];\r
124 r[5] = pathSegment[5];\r
125 r[6] = +(pathSegment[6] + x);\r
126 r[7] = +(pathSegment[7] + y);\r
127 break;\r
128 // Vertical LineTo\r
129 case "V":\r
130 r[1] = +pathSegment[1] + y;\r
131 break;\r
132 // Horizontal LineTo\r
133 case "H":\r
134 r[1] = +pathSegment[1] + x;\r
135 break;\r
136 case "M":\r
137 // MoveTo\r
138 mx = +pathSegment[1] + x;\r
139 my = +pathSegment[2] + y;\r
140 // fall;\r
141 default:\r
142 j = 1;\r
143 ln2 = pathSegment.length;\r
144 for (; j < ln2; j++) {\r
145 r[j] = +pathSegment[j] + ((j % 2) ? x : y);\r
146 }\r
147 }\r
148 }\r
149 else {\r
150 j = 0;\r
151 ln2 = pathSegment.length;\r
152 for (; j < ln2; j++) {\r
153 res[i][j] = pathSegment[j];\r
154 }\r
155 }\r
156 switch (r[0]) {\r
157 // ClosePath\r
158 case "Z":\r
159 x = mx;\r
160 y = my;\r
161 break;\r
162 // Horizontal LineTo\r
163 case "H":\r
164 x = r[1];\r
165 break;\r
166 // Vertical LineTo\r
167 case "V":\r
168 y = r[1];\r
169 break;\r
170 // MoveTo\r
171 case "M":\r
172 pathSegment = res[i];\r
173 ln2 = pathSegment.length;\r
174 mx = pathSegment[ln2 - 2];\r
175 my = pathSegment[ln2 - 1];\r
176 // fall;\r
177 default:\r
178 pathSegment = res[i];\r
179 ln2 = pathSegment.length;\r
180 x = pathSegment[ln2 - 2];\r
181 y = pathSegment[ln2 - 1];\r
182 }\r
183 }\r
184 res.toString = this.path2string;\r
185 return res;\r
186 },\r
187\r
188 interpolatePaths: function (path, path2) {\r
189 var me = this,\r
190 p = me.pathToAbsolute(path),\r
191 p2 = me.pathToAbsolute(path2),\r
192 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},\r
193 attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},\r
194 fixArc = function (pp, i) {\r
195 if (pp[i].length > 7) {\r
196 pp[i].shift();\r
197 var pi = pp[i];\r
198 while (pi.length) {\r
199 Ext.Array.splice(pp, i++, 0, ["C"].concat(Ext.Array.splice(pi, 0, 6)));\r
200 }\r
201 Ext.Array.erase(pp, i, 1);\r
202 ii = Math.max(p.length, p2.length || 0);\r
203 }\r
204 },\r
205 fixM = function (path1, path2, a1, a2, i) {\r
206 if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {\r
207 Ext.Array.splice(path2, i, 0, ["M", a2.x, a2.y]);\r
208 a1.bx = 0;\r
209 a1.by = 0;\r
210 a1.x = path1[i][1];\r
211 a1.y = path1[i][2];\r
212 ii = Math.max(p.length, p2.length || 0);\r
213 }\r
214 },\r
215 i, ii,\r
216 seg, seg2, seglen, seg2len;\r
217 for (i = 0, ii = Math.max(p.length, p2.length || 0); i < ii; i++) {\r
218 p[i] = me.command2curve(p[i], attrs);\r
219 fixArc(p, i);\r
220 (p2[i] = me.command2curve(p2[i], attrs2));\r
221 fixArc(p2, i);\r
222 fixM(p, p2, attrs, attrs2, i);\r
223 fixM(p2, p, attrs2, attrs, i);\r
224 seg = p[i];\r
225 seg2 = p2[i];\r
226 seglen = seg.length;\r
227 seg2len = seg2.length;\r
228 attrs.x = seg[seglen - 2];\r
229 attrs.y = seg[seglen - 1];\r
230 attrs.bx = parseFloat(seg[seglen - 4]) || attrs.x;\r
231 attrs.by = parseFloat(seg[seglen - 3]) || attrs.y;\r
232 attrs2.bx = (parseFloat(seg2[seg2len - 4]) || attrs2.x);\r
233 attrs2.by = (parseFloat(seg2[seg2len - 3]) || attrs2.y);\r
234 attrs2.x = seg2[seg2len - 2];\r
235 attrs2.y = seg2[seg2len - 1];\r
236 }\r
237 return [p, p2];\r
238 },\r
239 \r
240 //Returns any path command as a curveto command based on the attrs passed\r
241 command2curve: function (pathCommand, d) {\r
242 var me = this;\r
243 if (!pathCommand) {\r
244 return ["C", d.x, d.y, d.x, d.y, d.x, d.y];\r
245 }\r
246 if (pathCommand[0] != "T" && pathCommand[0] != "Q") {\r
247 d.qx = d.qy = null;\r
248 }\r
249 switch (pathCommand[0]) {\r
250 case "M":\r
251 d.X = pathCommand[1];\r
252 d.Y = pathCommand[2];\r
253 break;\r
254 case "A":\r
255 pathCommand = ["C"].concat(me.arc2curve.apply(me, [d.x, d.y].concat(pathCommand.slice(1))));\r
256 break;\r
257 case "S":\r
258 pathCommand = ["C", d.x + (d.x - (d.bx || d.x)), d.y + (d.y - (d.by || d.y))].concat(pathCommand.slice(1));\r
259 break;\r
260 case "T":\r
261 d.qx = d.x + (d.x - (d.qx || d.x));\r
262 d.qy = d.y + (d.y - (d.qy || d.y));\r
263 pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, d.qx, d.qy, pathCommand[1], pathCommand[2]));\r
264 break;\r
265 case "Q":\r
266 d.qx = pathCommand[1];\r
267 d.qy = pathCommand[2];\r
268 pathCommand = ["C"].concat(me.quadratic2curve(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[3], pathCommand[4]));\r
269 break;\r
270 case "L":\r
271 pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], pathCommand[2], pathCommand[1], pathCommand[2]);\r
272 break;\r
273 case "H":\r
274 pathCommand = ["C"].concat(d.x, d.y, pathCommand[1], d.y, pathCommand[1], d.y);\r
275 break;\r
276 case "V":\r
277 pathCommand = ["C"].concat(d.x, d.y, d.x, pathCommand[1], d.x, pathCommand[1]);\r
278 break;\r
279 case "Z":\r
280 pathCommand = ["C"].concat(d.x, d.y, d.X, d.Y, d.X, d.Y);\r
281 break;\r
282 }\r
283 return pathCommand;\r
284 },\r
285\r
286 quadratic2curve: function (x1, y1, ax, ay, x2, y2) {\r
287 var _13 = 1 / 3,\r
288 _23 = 2 / 3;\r
289 return [\r
290 _13 * x1 + _23 * ax,\r
291 _13 * y1 + _23 * ay,\r
292 _13 * x2 + _23 * ax,\r
293 _13 * y2 + _23 * ay,\r
294 x2,\r
295 y2\r
296 ];\r
297 },\r
298 \r
299 rotate: function (x, y, rad) {\r
300 var cos = Math.cos(rad),\r
301 sin = Math.sin(rad),\r
302 X = x * cos - y * sin,\r
303 Y = x * sin + y * cos;\r
304 return {x: X, y: Y};\r
305 },\r
306\r
307 arc2curve: function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {\r
308 // for more information of where this Math came from visit:\r
309 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes\r
310 var me = this,\r
311 PI = Math.PI,\r
312 radian = me.radian,\r
313 _120 = PI * 120 / 180,\r
314 rad = radian * (+angle || 0),\r
315 res = [],\r
316 math = Math,\r
317 mcos = math.cos,\r
318 msin = math.sin,\r
319 msqrt = math.sqrt,\r
320 mabs = math.abs,\r
321 masin = math.asin,\r
322 xy, x, y, h, rx2, ry2, k, cx, cy, f1, f2, df, c1, s1, c2, s2,\r
323 t, hx, hy, m1, m2, m3, m4, newres, i, ln, f2old, x2old, y2old;\r
324 if (!recursive) {\r
325 xy = me.rotate(x1, y1, -rad);\r
326 x1 = xy.x;\r
327 y1 = xy.y;\r
328 xy = me.rotate(x2, y2, -rad);\r
329 x2 = xy.x;\r
330 y2 = xy.y;\r
331 x = (x1 - x2) / 2;\r
332 y = (y1 - y2) / 2;\r
333 h = (x * x) / (rx * rx) + (y * y) / (ry * ry);\r
334 if (h > 1) {\r
335 h = msqrt(h);\r
336 rx = h * rx;\r
337 ry = h * ry;\r
338 }\r
339 rx2 = rx * rx;\r
340 ry2 = ry * ry;\r
341 k = (large_arc_flag == sweep_flag ? -1 : 1) *\r
342 msqrt(mabs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x)));\r
343 cx = k * rx * y / ry + (x1 + x2) / 2;\r
344 cy = k * -ry * x / rx + (y1 + y2) / 2;\r
345 f1 = masin(((y1 - cy) / ry).toFixed(7));\r
346 f2 = masin(((y2 - cy) / ry).toFixed(7));\r
347\r
348 f1 = x1 < cx ? PI - f1 : f1;\r
349 f2 = x2 < cx ? PI - f2 : f2;\r
350 if (f1 < 0) {\r
351 f1 = PI * 2 + f1;\r
352 }\r
353 if (f2 < 0) {\r
354 f2 = PI * 2 + f2;\r
355 }\r
356 if (sweep_flag && f1 > f2) {\r
357 f1 = f1 - PI * 2;\r
358 }\r
359 if (!sweep_flag && f2 > f1) {\r
360 f2 = f2 - PI * 2;\r
361 }\r
362 }\r
363 else {\r
364 f1 = recursive[0];\r
365 f2 = recursive[1];\r
366 cx = recursive[2];\r
367 cy = recursive[3];\r
368 }\r
369 df = f2 - f1;\r
370 if (mabs(df) > _120) {\r
371 f2old = f2;\r
372 x2old = x2;\r
373 y2old = y2;\r
374 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);\r
375 x2 = cx + rx * mcos(f2);\r
376 y2 = cy + ry * msin(f2);\r
377 res = me.arc2curve(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);\r
378 }\r
379 df = f2 - f1;\r
380 c1 = mcos(f1);\r
381 s1 = msin(f1);\r
382 c2 = mcos(f2);\r
383 s2 = msin(f2);\r
384 t = math.tan(df / 4);\r
385 hx = 4 / 3 * rx * t;\r
386 hy = 4 / 3 * ry * t;\r
387 m1 = [x1, y1];\r
388 m2 = [x1 + hx * s1, y1 - hy * c1];\r
389 m3 = [x2 + hx * s2, y2 - hy * c2];\r
390 m4 = [x2, y2];\r
391 m2[0] = 2 * m1[0] - m2[0];\r
392 m2[1] = 2 * m1[1] - m2[1];\r
393 if (recursive) {\r
394 return [m2, m3, m4].concat(res);\r
395 }\r
396 else {\r
397 res = [m2, m3, m4].concat(res).join().split(",");\r
398 newres = [];\r
399 ln = res.length;\r
400 for (i = 0; i < ln; i++) {\r
401 newres[i] = i % 2 ? me.rotate(res[i - 1], res[i], rad).y : me.rotate(res[i], res[i + 1], rad).x;\r
402 }\r
403 return newres;\r
404 }\r
405 }\r
406\r
407});\r