Mercurial > laserkard
comparison awesome_js/raphael.js @ 29:7742910e0479 laserkard
[svn r30] implemented drawing text on the picture dynamically. still need to center stuff
author | rlm |
---|---|
date | Sat, 16 Jan 2010 12:25:43 -0500 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
28:5b5c03a850b9 | 29:7742910e0479 |
---|---|
1 /*! | |
2 * Raphael 1.3.0 - JavaScript Vector Library | |
3 * | |
4 * Copyright (c) 2008 - 2009 Dmitry Baranovskiy (http://raphaeljs.com) | |
5 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. | |
6 */ | |
7 | |
8 | |
9 window.Raphael = (function () { | |
10 var separator = /[, ]+/, | |
11 elements = /^(circle|rect|path|ellipse|text|image)$/, | |
12 doc = document, | |
13 win = window, | |
14 oldRaphael = { | |
15 was: "Raphael" in win, | |
16 is: win.Raphael | |
17 }, | |
18 R = function () { | |
19 if (R.is(arguments[0], "array")) { | |
20 var a = arguments[0], | |
21 cnv = create[apply](R, a.splice(0, 3 + R.is(a[0], nu))), | |
22 res = cnv.set(); | |
23 for (var i = 0, ii = a[length]; i < ii; i++) { | |
24 var j = a[i] || {}; | |
25 elements.test(j.type) && res[push](cnv[j.type]().attr(j)); | |
26 } | |
27 return res; | |
28 } | |
29 return create[apply](R, arguments); | |
30 }, | |
31 Paper = function () {}, | |
32 appendChild = "appendChild", | |
33 apply = "apply", | |
34 concat = "concat", | |
35 E = "", | |
36 S = " ", | |
37 split = "split", | |
38 events = "click dblclick mousedown mousemove mouseout mouseover mouseup"[split](S), | |
39 has = "hasOwnProperty", | |
40 join = "join", | |
41 length = "length", | |
42 proto = "prototype", | |
43 lowerCase = String[proto].toLowerCase, | |
44 math = Math, | |
45 mmax = math.max, | |
46 mmin = math.min, | |
47 nu = "number", | |
48 toString = "toString", | |
49 objectToString = Object[proto][toString], | |
50 paper = {}, | |
51 pow = math.pow, | |
52 push = "push", | |
53 rg = /^(?=[\da-f]$)/, | |
54 ISURL = /^url\(['"]?([^\)]+)['"]?\)$/i, | |
55 colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgb\(\s*([\d\.]+\s*,\s*[\d\.]+\s*,\s*[\d\.]+)\s*\)|rgb\(\s*([\d\.]+%\s*,\s*[\d\.]+%\s*,\s*[\d\.]+%)\s*\)|hs[bl]\(\s*([\d\.]+\s*,\s*[\d\.]+\s*,\s*[\d\.]+)\s*\)|hs[bl]\(\s*([\d\.]+%\s*,\s*[\d\.]+%\s*,\s*[\d\.]+%)\s*\))\s*$/i, | |
56 round = math.round, | |
57 setAttribute = "setAttribute", | |
58 toFloat = parseFloat, | |
59 toInt = parseInt, | |
60 upperCase = String[proto].toUpperCase, | |
61 availableAttrs = {"clip-rect": "0 0 1e9 1e9", cursor: "default", cx: 0, cy: 0, fill: "#fff", "fill-opacity": 1, font: '10px "Arial"', "font-family": '"Arial"', "font-size": "10", "font-style": "normal", "font-weight": 400, gradient: 0, height: 0, href: "http://raphaeljs.com/", opacity: 1, path: "M0,0", r: 0, rotation: 0, rx: 0, ry: 0, scale: "1 1", src: "", stroke: "#000", "stroke-dasharray": "", "stroke-linecap": "butt", "stroke-linejoin": "butt", "stroke-miterlimit": 0, "stroke-opacity": 1, "stroke-width": 1, target: "_blank", "text-anchor": "middle", title: "Raphael", translation: "0 0", width: 0, x: 0, y: 0}, | |
62 availableAnimAttrs = {along: "along", "clip-rect": "csv", cx: nu, cy: nu, fill: "colour", "fill-opacity": nu, "font-size": nu, height: nu, opacity: nu, path: "path", r: nu, rotation: "csv", rx: nu, ry: nu, scale: "csv", stroke: "colour", "stroke-opacity": nu, "stroke-width": nu, translation: "csv", width: nu, x: nu, y: nu}, | |
63 rp = "replace"; | |
64 R.version = "1.3.0"; | |
65 R.type = (win.SVGAngle || doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); | |
66 if (R.type == "VML") { | |
67 var d = document.createElement("div"); | |
68 d.innerHTML = '<!--[if vml]><br><br><![endif]-->'; | |
69 if (d.childNodes[length] != 2) { | |
70 return null; | |
71 } | |
72 } | |
73 R.svg = !(R.vml = R.type == "VML"); | |
74 Paper[proto] = R[proto]; | |
75 R._id = 0; | |
76 R._oid = 0; | |
77 R.fn = {}; | |
78 R.is = function (o, type) { | |
79 type = lowerCase.call(type); | |
80 return ((type == "object" || type == "undefined") && typeof o == type) || (o == null && type == "null") || lowerCase.call(objectToString.call(o).slice(8, -1)) == type; | |
81 }; | |
82 R.setWindow = function (newwin) { | |
83 win = newwin; | |
84 doc = win.document; | |
85 }; | |
86 // colour utilities | |
87 var toHex = function (color) { | |
88 if (R.vml) { | |
89 // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ | |
90 var trim = /^\s+|\s+$/g; | |
91 toHex = cacher(function (color) { | |
92 var bod; | |
93 color = (color + E)[rp](trim, E); | |
94 try { | |
95 var docum = new ActiveXObject("htmlfile"); | |
96 docum.write("<body>"); | |
97 docum.close(); | |
98 bod = docum.body; | |
99 } catch(e) { | |
100 bod = createPopup().document.body; | |
101 } | |
102 var range = bod.createTextRange(); | |
103 try { | |
104 bod.style.color = color; | |
105 var value = range.queryCommandValue("ForeColor"); | |
106 value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); | |
107 return "#" + ("000000" + value[toString](16)).slice(-6); | |
108 } catch(e) { | |
109 return "none"; | |
110 } | |
111 }); | |
112 } else { | |
113 var i = doc.createElement("i"); | |
114 i.title = "Rapha\xebl Colour Picker"; | |
115 i.style.display = "none"; | |
116 doc.body[appendChild](i); | |
117 toHex = cacher(function (color) { | |
118 i.style.color = color; | |
119 return doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); | |
120 }); | |
121 } | |
122 return toHex(color); | |
123 }; | |
124 R.hsb2rgb = cacher(function (hue, saturation, brightness) { | |
125 if (R.is(hue, "object") && "h" in hue && "s" in hue && "b" in hue) { | |
126 brightness = hue.b; | |
127 saturation = hue.s; | |
128 hue = hue.h; | |
129 } | |
130 var red, | |
131 green, | |
132 blue; | |
133 if (brightness == 0) { | |
134 return {r: 0, g: 0, b: 0, hex: "#000"}; | |
135 } | |
136 if (hue > 1 || saturation > 1 || brightness > 1) { | |
137 hue /= 255; | |
138 saturation /= 255; | |
139 brightness /= 255; | |
140 } | |
141 var i = ~~(hue * 6), | |
142 f = (hue * 6) - i, | |
143 p = brightness * (1 - saturation), | |
144 q = brightness * (1 - (saturation * f)), | |
145 t = brightness * (1 - (saturation * (1 - f))); | |
146 red = [brightness, q, p, p, t, brightness, brightness][i]; | |
147 green = [t, brightness, brightness, q, p, p, t][i]; | |
148 blue = [p, p, t, brightness, brightness, q, p][i]; | |
149 red *= 255; | |
150 green *= 255; | |
151 blue *= 255; | |
152 var rgb = {r: red, g: green, b: blue}, | |
153 r = (~~red)[toString](16), | |
154 g = (~~green)[toString](16), | |
155 b = (~~blue)[toString](16); | |
156 r = r[rp](rg, "0"); | |
157 g = g[rp](rg, "0"); | |
158 b = b[rp](rg, "0"); | |
159 rgb.hex = "#" + r + g + b; | |
160 return rgb; | |
161 }, R); | |
162 R.rgb2hsb = cacher(function (red, green, blue) { | |
163 if (R.is(red, "object") && "r" in red && "g" in red && "b" in red) { | |
164 blue = red.b; | |
165 green = red.g; | |
166 red = red.r; | |
167 } | |
168 if (R.is(red, "string")) { | |
169 var clr = R.getRGB(red); | |
170 red = clr.r; | |
171 green = clr.g; | |
172 blue = clr.b; | |
173 } | |
174 if (red > 1 || green > 1 || blue > 1) { | |
175 red /= 255; | |
176 green /= 255; | |
177 blue /= 255; | |
178 } | |
179 var max = mmax(red, green, blue), | |
180 min = mmin(red, green, blue), | |
181 hue, | |
182 saturation, | |
183 brightness = max; | |
184 if (min == max) { | |
185 return {h: 0, s: 0, b: max}; | |
186 } else { | |
187 var delta = (max - min); | |
188 saturation = delta / max; | |
189 if (red == max) { | |
190 hue = (green - blue) / delta; | |
191 } else if (green == max) { | |
192 hue = 2 + ((blue - red) / delta); | |
193 } else { | |
194 hue = 4 + ((red - green) / delta); | |
195 } | |
196 hue /= 6; | |
197 hue < 0 && hue++; | |
198 hue > 1 && hue--; | |
199 } | |
200 return {h: hue, s: saturation, b: brightness}; | |
201 }, R); | |
202 var p2s = /,?([achlmqrstvxz]),?/gi; | |
203 R._path2string = function () { | |
204 return this.join(",")[rp](p2s, "$1"); | |
205 }; | |
206 function cacher(f, scope, postprocessor) { | |
207 function newf() { | |
208 var arg = Array[proto].slice.call(arguments, 0), | |
209 args = arg[join]("\u25ba"), | |
210 cache = newf.cache = newf.cache || {}, | |
211 count = newf.count = newf.count || []; | |
212 if (cache[has](args)) { | |
213 return postprocessor ? postprocessor(cache[args]) : cache[args]; | |
214 } | |
215 count[length] >= 1e3 && delete cache[count.shift()]; | |
216 count[push](args); | |
217 cache[args] = f[apply](scope, arg); | |
218 return postprocessor ? postprocessor(cache[args]) : cache[args]; | |
219 } | |
220 return newf; | |
221 } | |
222 | |
223 R.getRGB = cacher(function (colour) { | |
224 if (!colour || !!((colour = colour + E).indexOf("-") + 1)) { | |
225 return {r: -1, g: -1, b: -1, hex: "none", error: 1}; | |
226 } | |
227 if (colour == "none") { | |
228 return {r: -1, g: -1, b: -1, hex: "none"}; | |
229 } | |
230 !(({hs: 1, rg: 1})[has](colour.substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); | |
231 var res, | |
232 red, | |
233 green, | |
234 blue, | |
235 t, | |
236 rgb = colour.match(colourRegExp); | |
237 if (rgb) { | |
238 if (rgb[2]) { | |
239 blue = toInt(rgb[2].substring(5), 16); | |
240 green = toInt(rgb[2].substring(3, 5), 16); | |
241 red = toInt(rgb[2].substring(1, 3), 16); | |
242 } | |
243 if (rgb[3]) { | |
244 blue = toInt((t = rgb[3].charAt(3)) + t, 16); | |
245 green = toInt((t = rgb[3].charAt(2)) + t, 16); | |
246 red = toInt((t = rgb[3].charAt(1)) + t, 16); | |
247 } | |
248 if (rgb[4]) { | |
249 rgb = rgb[4][split](/\s*,\s*/); | |
250 red = toFloat(rgb[0]); | |
251 green = toFloat(rgb[1]); | |
252 blue = toFloat(rgb[2]); | |
253 } | |
254 if (rgb[5]) { | |
255 rgb = rgb[5][split](/\s*,\s*/); | |
256 red = toFloat(rgb[0]) * 2.55; | |
257 green = toFloat(rgb[1]) * 2.55; | |
258 blue = toFloat(rgb[2]) * 2.55; | |
259 } | |
260 if (rgb[6]) { | |
261 rgb = rgb[6][split](/\s*,\s*/); | |
262 red = toFloat(rgb[0]); | |
263 green = toFloat(rgb[1]); | |
264 blue = toFloat(rgb[2]); | |
265 return R.hsb2rgb(red, green, blue); | |
266 } | |
267 if (rgb[7]) { | |
268 rgb = rgb[7][split](/\s*,\s*/); | |
269 red = toFloat(rgb[0]) * 2.55; | |
270 green = toFloat(rgb[1]) * 2.55; | |
271 blue = toFloat(rgb[2]) * 2.55; | |
272 return R.hsb2rgb(red, green, blue); | |
273 } | |
274 rgb = {r: red, g: green, b: blue}; | |
275 var r = (~~red)[toString](16), | |
276 g = (~~green)[toString](16), | |
277 b = (~~blue)[toString](16); | |
278 r = r[rp](rg, "0"); | |
279 g = g[rp](rg, "0"); | |
280 b = b[rp](rg, "0"); | |
281 rgb.hex = "#" + r + g + b; | |
282 return rgb; | |
283 } | |
284 return {r: -1, g: -1, b: -1, hex: "none", error: 1}; | |
285 }, R); | |
286 R.getColor = function (value) { | |
287 var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, | |
288 rgb = this.hsb2rgb(start.h, start.s, start.b); | |
289 start.h += .075; | |
290 if (start.h > 1) { | |
291 start.h = 0; | |
292 start.s -= .2; | |
293 start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b}); | |
294 } | |
295 return rgb.hex; | |
296 }; | |
297 R.getColor.reset = function () { | |
298 delete this.start; | |
299 }; | |
300 // path utilities | |
301 R.parsePathString = cacher(function (pathString) { | |
302 if (!pathString) { | |
303 return null; | |
304 } | |
305 var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0}, | |
306 data = []; | |
307 if (R.is(pathString, "array") && R.is(pathString[0], "array")) { // rough assumption | |
308 data = pathClone(pathString); | |
309 } | |
310 if (!data[length]) { | |
311 (pathString + E)[rp](/([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig, function (a, b, c) { | |
312 var params = [], | |
313 name = lowerCase.call(b); | |
314 c[rp](/(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig, function (a, b) { | |
315 b && params[push](+b); | |
316 }); | |
317 while (params[length] >= paramCounts[name]) { | |
318 data[push]([b][concat](params.splice(0, paramCounts[name]))); | |
319 if (!paramCounts[name]) { | |
320 break; | |
321 }; | |
322 } | |
323 }); | |
324 } | |
325 data[toString] = R._path2string; | |
326 return data; | |
327 }); | |
328 R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { | |
329 var t1 = 1 - t, | |
330 x = pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, | |
331 y = pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y, | |
332 mx = p1x + 2 * t * (c1x - p1x) + t * t * (c2x - 2 * c1x + p1x), | |
333 my = p1y + 2 * t * (c1y - p1y) + t * t * (c2y - 2 * c1y + p1y), | |
334 nx = c1x + 2 * t * (c2x - c1x) + t * t * (p2x - 2 * c2x + c1x), | |
335 ny = c1y + 2 * t * (c2y - c1y) + t * t * (p2y - 2 * c2y + c1y), | |
336 ax = (1 - t) * p1x + t * c1x, | |
337 ay = (1 - t) * p1y + t * c1y, | |
338 cx = (1 - t) * c2x + t * p2x, | |
339 cy = (1 - t) * c2y + t * p2y, | |
340 alpha = (90 - math.atan((mx - nx) / (my - ny)) * 180 / math.PI); | |
341 (mx > nx || my < ny) && (alpha += 180); | |
342 return {x: x, y: y, m: {x: mx, y: my}, n: {x: nx, y: ny}, start: {x: ax, y: ay}, end: {x: cx, y: cy}, alpha: alpha}; | |
343 }; | |
344 var pathDimensions = cacher(function (path) { | |
345 if (!path) { | |
346 return {x: 0, y: 0, width: 0, height: 0}; | |
347 } | |
348 path = path2curve(path); | |
349 var x = 0, | |
350 y = 0, | |
351 X = [], | |
352 Y = [], | |
353 p; | |
354 for (var i = 0, ii = path[length]; i < ii; i++) { | |
355 p = path[i]; | |
356 if (p[0] == "M") { | |
357 x = p[1]; | |
358 y = p[2]; | |
359 X[push](x); | |
360 Y[push](y); | |
361 } else { | |
362 var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); | |
363 X = X[concat](dim.min.x, dim.max.x); | |
364 Y = Y[concat](dim.min.y, dim.max.y); | |
365 x = p[5]; | |
366 y = p[6]; | |
367 } | |
368 } | |
369 var xmin = mmin[apply](0, X), | |
370 ymin = mmin[apply](0, Y); | |
371 return { | |
372 x: xmin, | |
373 y: ymin, | |
374 width: mmax[apply](0, X) - xmin, | |
375 height: mmax[apply](0, Y) - ymin | |
376 }; | |
377 }), | |
378 pathClone = function (pathArray) { | |
379 var res = []; | |
380 if (!R.is(pathArray, "array") || !R.is(pathArray && pathArray[0], "array")) { // rough assumption | |
381 pathArray = R.parsePathString(pathArray); | |
382 } | |
383 for (var i = 0, ii = pathArray[length]; i < ii; i++) { | |
384 res[i] = []; | |
385 for (var j = 0, jj = pathArray[i][length]; j < jj; j++) { | |
386 res[i][j] = pathArray[i][j]; | |
387 } | |
388 } | |
389 res[toString] = R._path2string; | |
390 return res; | |
391 }, | |
392 pathToRelative = cacher(function (pathArray) { | |
393 if (!R.is(pathArray, "array") || !R.is(pathArray && pathArray[0], "array")) { // rough assumption | |
394 pathArray = R.parsePathString(pathArray); | |
395 } | |
396 var res = [], | |
397 x = 0, | |
398 y = 0, | |
399 mx = 0, | |
400 my = 0, | |
401 start = 0; | |
402 if (pathArray[0][0] == "M") { | |
403 x = pathArray[0][1]; | |
404 y = pathArray[0][2]; | |
405 mx = x; | |
406 my = y; | |
407 start++; | |
408 res[push](["M", x, y]); | |
409 } | |
410 for (var i = start, ii = pathArray[length]; i < ii; i++) { | |
411 var r = res[i] = [], | |
412 pa = pathArray[i]; | |
413 if (pa[0] != lowerCase.call(pa[0])) { | |
414 r[0] = lowerCase.call(pa[0]); | |
415 switch (r[0]) { | |
416 case "a": | |
417 r[1] = pa[1]; | |
418 r[2] = pa[2]; | |
419 r[3] = pa[3]; | |
420 r[4] = pa[4]; | |
421 r[5] = pa[5]; | |
422 r[6] = +(pa[6] - x).toFixed(3); | |
423 r[7] = +(pa[7] - y).toFixed(3); | |
424 break; | |
425 case "v": | |
426 r[1] = +(pa[1] - y).toFixed(3); | |
427 break; | |
428 case "m": | |
429 mx = pa[1]; | |
430 my = pa[2]; | |
431 default: | |
432 for (var j = 1, jj = pa[length]; j < jj; j++) { | |
433 r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); | |
434 } | |
435 } | |
436 } else { | |
437 r = res[i] = []; | |
438 if (pa[0] == "m") { | |
439 mx = pa[1] + x; | |
440 my = pa[2] + y; | |
441 } | |
442 for (var k = 0, kk = pa[length]; k < kk; k++) { | |
443 res[i][k] = pa[k]; | |
444 } | |
445 } | |
446 var len = res[i][length]; | |
447 switch (res[i][0]) { | |
448 case "z": | |
449 x = mx; | |
450 y = my; | |
451 break; | |
452 case "h": | |
453 x += +res[i][len - 1]; | |
454 break; | |
455 case "v": | |
456 y += +res[i][len - 1]; | |
457 break; | |
458 default: | |
459 x += +res[i][len - 2]; | |
460 y += +res[i][len - 1]; | |
461 } | |
462 } | |
463 res[toString] = R._path2string; | |
464 return res; | |
465 }, 0, pathClone), | |
466 pathToAbsolute = cacher(function (pathArray) { | |
467 if (!R.is(pathArray, "array") || !R.is(pathArray && pathArray[0], "array")) { // rough assumption | |
468 pathArray = R.parsePathString(pathArray); | |
469 } | |
470 var res = [], | |
471 x = 0, | |
472 y = 0, | |
473 mx = 0, | |
474 my = 0, | |
475 start = 0; | |
476 if (pathArray[0][0] == "M") { | |
477 x = +pathArray[0][1]; | |
478 y = +pathArray[0][2]; | |
479 mx = x; | |
480 my = y; | |
481 start++; | |
482 res[0] = ["M", x, y]; | |
483 } | |
484 for (var i = start, ii = pathArray[length]; i < ii; i++) { | |
485 var r = res[i] = [], | |
486 pa = pathArray[i]; | |
487 if (pa[0] != upperCase.call(pa[0])) { | |
488 r[0] = upperCase.call(pa[0]); | |
489 switch (r[0]) { | |
490 case "A": | |
491 r[1] = pa[1]; | |
492 r[2] = pa[2]; | |
493 r[3] = pa[3]; | |
494 r[4] = pa[4]; | |
495 r[5] = pa[5]; | |
496 r[6] = +(pa[6] + x); | |
497 r[7] = +(pa[7] + y); | |
498 break; | |
499 case "V": | |
500 r[1] = +pa[1] + y; | |
501 break; | |
502 case "H": | |
503 r[1] = +pa[1] + x; | |
504 break; | |
505 case "M": | |
506 mx = +pa[1] + x; | |
507 my = +pa[2] + y; | |
508 default: | |
509 for (var j = 1, jj = pa[length]; j < jj; j++) { | |
510 r[j] = +pa[j] + ((j % 2) ? x : y); | |
511 } | |
512 } | |
513 } else { | |
514 for (var k = 0, kk = pa[length]; k < kk; k++) { | |
515 res[i][k] = pa[k]; | |
516 } | |
517 } | |
518 switch (r[0]) { | |
519 case "Z": | |
520 x = mx; | |
521 y = my; | |
522 break; | |
523 case "H": | |
524 x = r[1]; | |
525 break; | |
526 case "V": | |
527 y = r[1]; | |
528 break; | |
529 default: | |
530 x = res[i][res[i][length] - 2]; | |
531 y = res[i][res[i][length] - 1]; | |
532 } | |
533 } | |
534 res[toString] = R._path2string; | |
535 return res; | |
536 }, null, pathClone), | |
537 l2c = function (x1, y1, x2, y2) { | |
538 return [x1, y1, x2, y2, x2, y2]; | |
539 }, | |
540 q2c = function (x1, y1, ax, ay, x2, y2) { | |
541 var _13 = 1 / 3, | |
542 _23 = 2 / 3; | |
543 return [ | |
544 _13 * x1 + _23 * ax, | |
545 _13 * y1 + _23 * ay, | |
546 _13 * x2 + _23 * ax, | |
547 _13 * y2 + _23 * ay, | |
548 x2, | |
549 y2 | |
550 ]; | |
551 }, | |
552 a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { | |
553 // for more information of where this math came from visit: | |
554 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes | |
555 var PI = math.PI, | |
556 _120 = PI * 120 / 180, | |
557 rad = PI / 180 * (+angle || 0), | |
558 res = [], | |
559 xy, | |
560 rotate = cacher(function (x, y, rad) { | |
561 var X = x * math.cos(rad) - y * math.sin(rad), | |
562 Y = x * math.sin(rad) + y * math.cos(rad); | |
563 return {x: X, y: Y}; | |
564 }); | |
565 if (!recursive) { | |
566 xy = rotate(x1, y1, -rad); | |
567 x1 = xy.x; | |
568 y1 = xy.y; | |
569 xy = rotate(x2, y2, -rad); | |
570 x2 = xy.x; | |
571 y2 = xy.y; | |
572 var cos = math.cos(PI / 180 * angle), | |
573 sin = math.sin(PI / 180 * angle), | |
574 x = (x1 - x2) / 2, | |
575 y = (y1 - y2) / 2; | |
576 rx = mmax(rx, math.abs(x)); | |
577 ry = mmax(ry, math.abs(y)); | |
578 var rx2 = rx * rx, | |
579 ry2 = ry * ry, | |
580 k = (large_arc_flag == sweep_flag ? -1 : 1) * | |
581 math.sqrt(math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), | |
582 cx = k * rx * y / ry + (x1 + x2) / 2, | |
583 cy = k * -ry * x / rx + (y1 + y2) / 2, | |
584 f1 = math.asin(((y1 - cy) / ry).toFixed(7)), | |
585 f2 = math.asin(((y2 - cy) / ry).toFixed(7)); | |
586 | |
587 f1 = x1 < cx ? PI - f1 : f1; | |
588 f2 = x2 < cx ? PI - f2 : f2; | |
589 f1 < 0 && (f1 = PI * 2 + f1); | |
590 f2 < 0 && (f2 = PI * 2 + f2); | |
591 if (sweep_flag && f1 > f2) { | |
592 f1 = f1 - PI * 2; | |
593 } | |
594 if (!sweep_flag && f2 > f1) { | |
595 f2 = f2 - PI * 2; | |
596 } | |
597 } else { | |
598 f1 = recursive[0]; | |
599 f2 = recursive[1]; | |
600 cx = recursive[2]; | |
601 cy = recursive[3]; | |
602 } | |
603 var df = f2 - f1; | |
604 if (math.abs(df) > _120) { | |
605 var f2old = f2, | |
606 x2old = x2, | |
607 y2old = y2; | |
608 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); | |
609 x2 = cx + rx * math.cos(f2); | |
610 y2 = cy + ry * math.sin(f2); | |
611 res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); | |
612 } | |
613 df = f2 - f1; | |
614 var c1 = math.cos(f1), | |
615 s1 = math.sin(f1), | |
616 c2 = math.cos(f2), | |
617 s2 = math.sin(f2), | |
618 t = math.tan(df / 4), | |
619 hx = 4 / 3 * rx * t, | |
620 hy = 4 / 3 * ry * t, | |
621 m1 = [x1, y1], | |
622 m2 = [x1 + hx * s1, y1 - hy * c1], | |
623 m3 = [x2 + hx * s2, y2 - hy * c2], | |
624 m4 = [x2, y2]; | |
625 m2[0] = 2 * m1[0] - m2[0]; | |
626 m2[1] = 2 * m1[1] - m2[1]; | |
627 if (recursive) { | |
628 return [m2, m3, m4][concat](res); | |
629 } else { | |
630 res = [m2, m3, m4][concat](res)[join]()[split](","); | |
631 var newres = []; | |
632 for (var i = 0, ii = res[length]; i < ii; i++) { | |
633 newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; | |
634 } | |
635 return newres; | |
636 } | |
637 }, | |
638 findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { | |
639 var t1 = 1 - t; | |
640 return { | |
641 x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, | |
642 y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y | |
643 }; | |
644 }, | |
645 curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { | |
646 var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), | |
647 b = 2 * (c1x - p1x) - 2 * (c2x - c1x), | |
648 c = p1x - c1x, | |
649 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a, | |
650 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a, | |
651 y = [p1y, p2y], | |
652 x = [p1x, p2x], | |
653 dot; | |
654 math.abs(t1) > 1e12 && (t1 = .5); | |
655 math.abs(t2) > 1e12 && (t2 = .5); | |
656 if (t1 > 0 && t1 < 1) { | |
657 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); | |
658 x[push](dot.x); | |
659 y[push](dot.y); | |
660 } | |
661 if (t2 > 0 && t2 < 1) { | |
662 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); | |
663 x[push](dot.x); | |
664 y[push](dot.y); | |
665 } | |
666 a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); | |
667 b = 2 * (c1y - p1y) - 2 * (c2y - c1y); | |
668 c = p1y - c1y; | |
669 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; | |
670 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; | |
671 math.abs(t1) > 1e12 && (t1 = .5); | |
672 math.abs(t2) > 1e12 && (t2 = .5); | |
673 if (t1 > 0 && t1 < 1) { | |
674 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); | |
675 x[push](dot.x); | |
676 y[push](dot.y); | |
677 } | |
678 if (t2 > 0 && t2 < 1) { | |
679 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); | |
680 x[push](dot.x); | |
681 y[push](dot.y); | |
682 } | |
683 return { | |
684 min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, | |
685 max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} | |
686 }; | |
687 }), | |
688 path2curve = cacher(function (path, path2) { | |
689 var p = pathToAbsolute(path), | |
690 p2 = path2 && pathToAbsolute(path2), | |
691 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, | |
692 attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, | |
693 processPath = function (path, d) { | |
694 var nx, ny; | |
695 if (!path) { | |
696 return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; | |
697 } | |
698 !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null); | |
699 switch (path[0]) { | |
700 case "M": | |
701 d.X = path[1]; | |
702 d.Y = path[2]; | |
703 break; | |
704 case "A": | |
705 path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1)))); | |
706 break; | |
707 case "S": | |
708 nx = d.x + (d.x - (d.bx || d.x)); | |
709 ny = d.y + (d.y - (d.by || d.y)); | |
710 path = ["C", nx, ny][concat](path.slice(1)); | |
711 break; | |
712 case "T": | |
713 d.qx = d.x + (d.x - (d.qx || d.x)); | |
714 d.qy = d.y + (d.y - (d.qy || d.y)); | |
715 path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); | |
716 break; | |
717 case "Q": | |
718 d.qx = path[1]; | |
719 d.qy = path[2]; | |
720 path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4])); | |
721 break; | |
722 case "L": | |
723 path = ["C"][concat](l2c(d.x, d.y, path[1], path[2])); | |
724 break; | |
725 case "H": | |
726 path = ["C"][concat](l2c(d.x, d.y, path[1], d.y)); | |
727 break; | |
728 case "V": | |
729 path = ["C"][concat](l2c(d.x, d.y, d.x, path[1])); | |
730 break; | |
731 case "Z": | |
732 path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y)); | |
733 break; | |
734 } | |
735 return path; | |
736 }, | |
737 fixArc = function (pp, i) { | |
738 if (pp[i][length] > 7) { | |
739 pp[i].shift(); | |
740 var pi = pp[i]; | |
741 while (pi[length]) { | |
742 pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); | |
743 } | |
744 pp.splice(i, 1); | |
745 ii = mmax(p[length], p2 && p2[length] || 0); | |
746 } | |
747 }, | |
748 fixM = function (path1, path2, a1, a2, i) { | |
749 if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { | |
750 path2.splice(i, 0, ["M", a2.x, a2.y]); | |
751 a1.bx = 0; | |
752 a1.by = 0; | |
753 a1.x = path1[i][1]; | |
754 a1.y = path1[i][2]; | |
755 ii = mmax(p[length], p2 && p2[length] || 0); | |
756 } | |
757 }; | |
758 for (var i = 0, ii = mmax(p[length], p2 && p2[length] || 0); i < ii; i++) { | |
759 p[i] = processPath(p[i], attrs); | |
760 fixArc(p, i); | |
761 p2 && (p2[i] = processPath(p2[i], attrs2)); | |
762 p2 && fixArc(p2, i); | |
763 fixM(p, p2, attrs, attrs2, i); | |
764 fixM(p2, p, attrs2, attrs, i); | |
765 var seg = p[i], | |
766 seg2 = p2 && p2[i], | |
767 seglen = seg[length], | |
768 seg2len = p2 && seg2[length]; | |
769 attrs.x = seg[seglen - 2]; | |
770 attrs.y = seg[seglen - 1]; | |
771 attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; | |
772 attrs.by = toFloat(seg[seglen - 3]) || attrs.y; | |
773 attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); | |
774 attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); | |
775 attrs2.x = p2 && seg2[seg2len - 2]; | |
776 attrs2.y = p2 && seg2[seg2len - 1]; | |
777 } | |
778 return p2 ? [p, p2] : p; | |
779 }, null, pathClone), | |
780 parseDots = cacher(function (gradient) { | |
781 var dots = []; | |
782 for (var i = 0, ii = gradient[length]; i < ii; i++) { | |
783 var dot = {}, | |
784 par = gradient[i].match(/^([^:]*):?([\d\.]*)/); | |
785 dot.color = R.getRGB(par[1]); | |
786 if (dot.color.error) { | |
787 return null; | |
788 } | |
789 dot.color = dot.color.hex; | |
790 par[2] && (dot.offset = par[2] + "%"); | |
791 dots[push](dot); | |
792 } | |
793 for (var i = 1, ii = dots[length] - 1; i < ii; i++) { | |
794 if (!dots[i].offset) { | |
795 var start = toFloat(dots[i - 1].offset || 0), | |
796 end = 0; | |
797 for (var j = i + 1; j < ii; j++) { | |
798 if (dots[j].offset) { | |
799 end = dots[j].offset; | |
800 break; | |
801 } | |
802 } | |
803 if (!end) { | |
804 end = 100; | |
805 j = ii; | |
806 } | |
807 end = toFloat(end); | |
808 var d = (end - start) / (j - i + 1); | |
809 for (; i < j; i++) { | |
810 start += d; | |
811 dots[i].offset = start + "%"; | |
812 } | |
813 } | |
814 } | |
815 return dots; | |
816 }), | |
817 getContainer = function () { | |
818 var container, | |
819 x, | |
820 y, | |
821 width, | |
822 height; | |
823 if (R.is(arguments[0], "string") || R.is(arguments[0], "object")) { | |
824 if (R.is(arguments[0], "string")) { | |
825 container = doc.getElementById(arguments[0]); | |
826 } else { | |
827 container = arguments[0]; | |
828 } | |
829 if (container.tagName) { | |
830 if (arguments[1] == null) { | |
831 return { | |
832 container: container, | |
833 width: container.style.pixelWidth || container.offsetWidth, | |
834 height: container.style.pixelHeight || container.offsetHeight | |
835 }; | |
836 } else { | |
837 return {container: container, width: arguments[1], height: arguments[2]}; | |
838 } | |
839 } | |
840 } else if (R.is(arguments[0], nu) && arguments[length] > 3) { | |
841 return {container: 1, x: arguments[0], y: arguments[1], width: arguments[2], height: arguments[3]}; | |
842 } | |
843 }, | |
844 plugins = function (con, add) { | |
845 var that = this; | |
846 for (var prop in add) if (add[has](prop) && !(prop in con)) { | |
847 switch (typeof add[prop]) { | |
848 case "function": | |
849 (function (f) { | |
850 con[prop] = con === that ? f : function () { return f[apply](that, arguments); }; | |
851 })(add[prop]); | |
852 break; | |
853 case "object": | |
854 con[prop] = con[prop] || {}; | |
855 plugins.call(this, con[prop], add[prop]); | |
856 break; | |
857 default: | |
858 con[prop] = add[prop]; | |
859 break; | |
860 } | |
861 } | |
862 }, | |
863 tear = function (el, paper) { | |
864 el == paper.top && (paper.top = el.prev); | |
865 el == paper.bottom && (paper.bottom = el.next); | |
866 el.next && (el.next.prev = el.prev); | |
867 el.prev && (el.prev.next = el.next); | |
868 }, | |
869 tofront = function (el, paper) { | |
870 if (paper.top === el) { | |
871 return; | |
872 } | |
873 tear(el, paper); | |
874 el.next = null; | |
875 el.prev = paper.top; | |
876 paper.top.next = el; | |
877 paper.top = el; | |
878 }, | |
879 toback = function (el, paper) { | |
880 if (paper.bottom === el) { | |
881 return; | |
882 } | |
883 tear(el, paper); | |
884 el.next = paper.bottom; | |
885 el.prev = null; | |
886 paper.bottom.prev = el; | |
887 paper.bottom = el; | |
888 }, | |
889 insertafter = function (el, el2, paper) { | |
890 tear(el, paper); | |
891 el2 == paper.top && (paper.top = el); | |
892 el2.next && (el2.next.prev = el); | |
893 el.next = el2.next; | |
894 el.prev = el2; | |
895 el2.next = el; | |
896 }, | |
897 insertbefore = function (el, el2, paper) { | |
898 tear(el, paper); | |
899 el2 == paper.bottom && (paper.bottom = el); | |
900 el2.prev && (el2.prev.next = el); | |
901 el.prev = el2.prev; | |
902 el2.prev = el; | |
903 el.next = el2; | |
904 }, | |
905 removed = function (methodname) { | |
906 return function () { | |
907 throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object"); | |
908 }; | |
909 }, | |
910 radial_gradient = /^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/; | |
911 | |
912 // SVG | |
913 if (R.svg) { | |
914 Paper[proto].svgns = "http://www.w3.org/2000/svg"; | |
915 Paper[proto].xlink = "http://www.w3.org/1999/xlink"; | |
916 var round = function (num) { | |
917 return +num + (~~num === num) * .5; | |
918 }, | |
919 roundPath = function (path) { | |
920 for (var i = 0, ii = path[length]; i < ii; i++) { | |
921 if (lowerCase.call(path[i][0]) != "a") { | |
922 for (var j = 1, jj = path[i][length]; j < jj; j++) { | |
923 path[i][j] = round(path[i][j]); | |
924 } | |
925 } else { | |
926 path[i][6] = round(path[i][6]); | |
927 path[i][7] = round(path[i][7]); | |
928 } | |
929 } | |
930 return path; | |
931 }, | |
932 $ = function (el, attr) { | |
933 if (attr) { | |
934 for (var key in attr) if (attr[has](key)) { | |
935 el[setAttribute](key, attr[key]); | |
936 } | |
937 } else { | |
938 return doc.createElementNS(Paper[proto].svgns, el); | |
939 } | |
940 }; | |
941 R[toString] = function () { | |
942 return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; | |
943 }; | |
944 var thePath = function (pathString, SVG) { | |
945 var el = $("path"); | |
946 SVG.canvas && SVG.canvas[appendChild](el); | |
947 var p = new Element(el, SVG); | |
948 p.type = "path"; | |
949 setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString}); | |
950 return p; | |
951 }; | |
952 var addGradientFill = function (o, gradient, SVG) { | |
953 var type = "linear", | |
954 fx = .5, fy = .5, | |
955 s = o.style; | |
956 gradient = (gradient + E)[rp](radial_gradient, function (all, _fx, _fy) { | |
957 type = "radial"; | |
958 if (_fx && _fy) { | |
959 fx = toFloat(_fx); | |
960 fy = toFloat(_fy); | |
961 var dir = ((fy > .5) * 2 - 1); | |
962 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && | |
963 (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && | |
964 fy != .5 && | |
965 (fy = fy.toFixed(5) - 1e-5 * dir); | |
966 } | |
967 return E; | |
968 }); | |
969 gradient = gradient[split](/\s*\-\s*/); | |
970 if (type == "linear") { | |
971 var angle = gradient.shift(); | |
972 angle = -toFloat(angle); | |
973 if (isNaN(angle)) { | |
974 return null; | |
975 } | |
976 var vector = [0, 0, math.cos(angle * math.PI / 180), math.sin(angle * math.PI / 180)], | |
977 max = 1 / (mmax(math.abs(vector[2]), math.abs(vector[3])) || 1); | |
978 vector[2] *= max; | |
979 vector[3] *= max; | |
980 if (vector[2] < 0) { | |
981 vector[0] = -vector[2]; | |
982 vector[2] = 0; | |
983 } | |
984 if (vector[3] < 0) { | |
985 vector[1] = -vector[3]; | |
986 vector[3] = 0; | |
987 } | |
988 } | |
989 var dots = parseDots(gradient); | |
990 if (!dots) { | |
991 return null; | |
992 } | |
993 var el = $(type + "Gradient"); | |
994 el.id = "r" + (R._id++)[toString](36); | |
995 $(el, type == "radial" ? {fx: fx, fy: fy} : {x1: vector[0], y1: vector[1], x2: vector[2], y2: vector[3]}); | |
996 SVG.defs[appendChild](el); | |
997 for (var i = 0, ii = dots[length]; i < ii; i++) { | |
998 var stop = $("stop"); | |
999 $(stop, { | |
1000 offset: dots[i].offset ? dots[i].offset : !i ? "0%" : "100%", | |
1001 "stop-color": dots[i].color || "#fff" | |
1002 }); | |
1003 el[appendChild](stop); | |
1004 }; | |
1005 $(o, { | |
1006 fill: "url(#" + el.id + ")", | |
1007 opacity: 1, | |
1008 "fill-opacity": 1 | |
1009 }); | |
1010 s.fill = E; | |
1011 s.opacity = 1; | |
1012 s.fillOpacity = 1; | |
1013 return 1; | |
1014 }; | |
1015 var updatePosition = function (o) { | |
1016 var bbox = o.getBBox(); | |
1017 $(o.pattern, {patternTransform: R.format("translate({0},{1})", bbox.x, bbox.y)}); | |
1018 }; | |
1019 var setFillAndStroke = function (o, params) { | |
1020 var dasharray = { | |
1021 "": [0], | |
1022 "none": [0], | |
1023 "-": [3, 1], | |
1024 ".": [1, 1], | |
1025 "-.": [3, 1, 1, 1], | |
1026 "-..": [3, 1, 1, 1, 1, 1], | |
1027 ". ": [1, 3], | |
1028 "- ": [4, 3], | |
1029 "--": [8, 3], | |
1030 "- .": [4, 3, 1, 3], | |
1031 "--.": [8, 3, 1, 3], | |
1032 "--..": [8, 3, 1, 3, 1, 3] | |
1033 }, | |
1034 node = o.node, | |
1035 attrs = o.attrs, | |
1036 rot = o.rotate(), | |
1037 addDashes = function (o, value) { | |
1038 value = dasharray[lowerCase.call(value)]; | |
1039 if (value) { | |
1040 var width = o.attrs["stroke-width"] || "1", | |
1041 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, | |
1042 dashes = []; | |
1043 var i = value[length]; | |
1044 while (i--) { | |
1045 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; | |
1046 } | |
1047 $(node, {"stroke-dasharray": dashes[join](",")}); | |
1048 } | |
1049 }; | |
1050 params[has]("rotation") && (rot = params.rotation); | |
1051 var rotxy = (rot + E)[split](separator); | |
1052 if (!(rotxy.length - 1)) { | |
1053 rotxy = null; | |
1054 } else { | |
1055 rotxy[1] = +rotxy[1]; | |
1056 rotxy[2] = +rotxy[2]; | |
1057 } | |
1058 toFloat(rot) && o.rotate(0, true); | |
1059 for (var att in params) if (params[has](att)) { | |
1060 if (!availableAttrs[has](att)) { | |
1061 continue; | |
1062 } | |
1063 var value = params[att]; | |
1064 attrs[att] = value; | |
1065 switch (att) { | |
1066 case "rotation": | |
1067 o.rotate(value, true); | |
1068 break; | |
1069 // Hyperlink | |
1070 case "href": | |
1071 case "title": | |
1072 case "target": | |
1073 var pn = node.parentNode; | |
1074 if (lowerCase.call(pn.tagName) != "a") { | |
1075 var hl = $("a"); | |
1076 pn.insertBefore(hl, node); | |
1077 hl[appendChild](node); | |
1078 pn = hl; | |
1079 } | |
1080 pn.setAttributeNS(o.Paper[proto].xlink, att, value); | |
1081 break; | |
1082 case "cursor": | |
1083 node.style.cursor = value; | |
1084 break; | |
1085 case "clip-rect": | |
1086 var rect = (value + E)[split](separator); | |
1087 if (rect[length] == 4) { | |
1088 o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); | |
1089 var el = $("clipPath"), | |
1090 rc = $("rect"); | |
1091 el.id = "r" + (R._id++)[toString](36); | |
1092 $(rc, { | |
1093 x: rect[0], | |
1094 y: rect[1], | |
1095 width: rect[2], | |
1096 height: rect[3] | |
1097 }); | |
1098 el[appendChild](rc); | |
1099 o.paper.defs[appendChild](el); | |
1100 $(node, {"clip-path": "url(#" + el.id + ")"}); | |
1101 o.clip = rc; | |
1102 } | |
1103 if (!value) { | |
1104 var clip = doc.getElementById(node.getAttribute("clip-path")[rp](/(^url\(#|\)$)/g, E)); | |
1105 clip && clip.parentNode.removeChild(clip); | |
1106 $(node, {"clip-path": E}); | |
1107 delete o.clip; | |
1108 } | |
1109 break; | |
1110 case "path": | |
1111 if (value && o.type == "path") { | |
1112 attrs.path = roundPath(pathToAbsolute(value)); | |
1113 $(node, {d: attrs.path}); | |
1114 } | |
1115 break; | |
1116 case "width": | |
1117 node[setAttribute](att, value); | |
1118 if (attrs.fx) { | |
1119 att = "x"; | |
1120 value = attrs.x; | |
1121 } else { | |
1122 break; | |
1123 } | |
1124 case "x": | |
1125 if (attrs.fx) { | |
1126 value = -attrs.x - (attrs.width || 0); | |
1127 } | |
1128 case "rx": | |
1129 if (att == "rx" && o.type == "rect") { | |
1130 break; | |
1131 } | |
1132 case "cx": | |
1133 rotxy && (att == "x" || att == "cx") && (rotxy[1] += value - attrs[att]); | |
1134 node[setAttribute](att, round(value)); | |
1135 o.pattern && updatePosition(o); | |
1136 break; | |
1137 case "height": | |
1138 node[setAttribute](att, value); | |
1139 if (attrs.fy) { | |
1140 att = "y"; | |
1141 value = attrs.y; | |
1142 } else { | |
1143 break; | |
1144 } | |
1145 case "y": | |
1146 if (attrs.fy) { | |
1147 value = -attrs.y - (attrs.height || 0); | |
1148 } | |
1149 case "ry": | |
1150 if (att == "ry" && o.type == "rect") { | |
1151 break; | |
1152 } | |
1153 case "cy": | |
1154 rotxy && (att == "y" || att == "cy") && (rotxy[2] += value - attrs[att]); | |
1155 node[setAttribute](att, round(value)); | |
1156 o.pattern && updatePosition(o); | |
1157 break; | |
1158 case "r": | |
1159 if (o.type == "rect") { | |
1160 $(node, {rx: value, ry: value}); | |
1161 } else { | |
1162 node[setAttribute](att, value); | |
1163 } | |
1164 break; | |
1165 case "src": | |
1166 if (o.type == "image") { | |
1167 node.setAttributeNS(o.paper.xlink, "href", value); | |
1168 } | |
1169 break; | |
1170 case "stroke-width": | |
1171 node.style.strokeWidth = value; | |
1172 // Need following line for Firefox | |
1173 node[setAttribute](att, value); | |
1174 if (attrs["stroke-dasharray"]) { | |
1175 addDashes(o, attrs["stroke-dasharray"]); | |
1176 } | |
1177 break; | |
1178 case "stroke-dasharray": | |
1179 addDashes(o, value); | |
1180 break; | |
1181 case "translation": | |
1182 var xy = (value + E)[split](separator); | |
1183 xy[0] = +xy[0] || 0; | |
1184 xy[1] = +xy[1] || 0; | |
1185 if (rotxy) { | |
1186 rotxy[1] += xy[0]; | |
1187 rotxy[2] += xy[1]; | |
1188 } | |
1189 translate.call(o, xy[0], xy[1]); | |
1190 break; | |
1191 case "scale": | |
1192 var xy = (value + E)[split](separator); | |
1193 o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, +xy[2] || null, +xy[3] || null); | |
1194 break; | |
1195 case "fill": | |
1196 var isURL = (value + E).match(ISURL); | |
1197 if (isURL) { | |
1198 var el = $("pattern"), | |
1199 ig = $("image"); | |
1200 el.id = "r" + (R._id++)[toString](36); | |
1201 $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); | |
1202 $(ig, {x: 0, y: 0}); | |
1203 ig.setAttributeNS(o.paper.xlink, "href", isURL[1]); | |
1204 el[appendChild](ig); | |
1205 | |
1206 var img = doc.createElement("img"); | |
1207 img.style.cssText = "position:absolute;left:-9999em;top-9999em"; | |
1208 img.onload = function () { | |
1209 $(el, {width: this.offsetWidth, height: this.offsetHeight}); | |
1210 $(ig, {width: this.offsetWidth, height: this.offsetHeight}); | |
1211 doc.body.removeChild(this); | |
1212 o.paper.safari(); | |
1213 }; | |
1214 doc.body[appendChild](img); | |
1215 img.src = isURL[1]; | |
1216 o.paper.defs[appendChild](el); | |
1217 node.style.fill = "url(#" + el.id + ")"; | |
1218 $(node, {fill: "url(#" + el.id + ")"}); | |
1219 o.pattern = el; | |
1220 o.pattern && updatePosition(o); | |
1221 break; | |
1222 } | |
1223 if (!R.getRGB(value).error) { | |
1224 delete params.gradient; | |
1225 delete attrs.gradient; | |
1226 !R.is(attrs.opacity, "undefined") && | |
1227 R.is(params.opacity, "undefined") && | |
1228 $(node, {opacity: attrs.opacity}); | |
1229 !R.is(attrs["fill-opacity"], "undefined") && | |
1230 R.is(params["fill-opacity"], "undefined") && | |
1231 $(node, {"fill-opacity": attrs["fill-opacity"]}); | |
1232 } else if ((({circle: 1, ellipse: 1})[has](o.type) || (value + E).charAt() != "r") && addGradientFill(node, value, o.paper)) { | |
1233 attrs.gradient = value; | |
1234 attrs.fill = "none"; | |
1235 break; | |
1236 } | |
1237 case "stroke": | |
1238 node[setAttribute](att, R.getRGB(value).hex); | |
1239 break; | |
1240 case "gradient": | |
1241 (({circle: 1, ellipse: 1})[has](o.type) || (value + E).charAt() != "r") && addGradientFill(node, value, o.paper); | |
1242 break; | |
1243 case "opacity": | |
1244 case "fill-opacity": | |
1245 if (attrs.gradient) { | |
1246 var gradient = doc.getElementById(node.getAttribute("fill")[rp](/^url\(#|\)$/g, E)); | |
1247 if (gradient) { | |
1248 var stops = gradient.getElementsByTagName("stop"); | |
1249 stops[stops[length] - 1][setAttribute]("stop-opacity", value); | |
1250 } | |
1251 break; | |
1252 } | |
1253 default: | |
1254 att == "font-size" && (value = toInt(value, 10) + "px"); | |
1255 var cssrule = att[rp](/(\-.)/g, function (w) { | |
1256 return upperCase.call(w.substring(1)); | |
1257 }); | |
1258 node.style[cssrule] = value; | |
1259 // Need following line for Firefox | |
1260 node[setAttribute](att, value); | |
1261 break; | |
1262 } | |
1263 } | |
1264 | |
1265 tuneText(o, params); | |
1266 if (rotxy) { | |
1267 o.rotate(rotxy.join(S)); | |
1268 } else { | |
1269 toFloat(rot) && o.rotate(rot, true); | |
1270 } | |
1271 }; | |
1272 var leading = 1.2; | |
1273 var tuneText = function (el, params) { | |
1274 if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { | |
1275 return; | |
1276 } | |
1277 var a = el.attrs, | |
1278 node = el.node, | |
1279 fontSize = node.firstChild ? toInt(doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; | |
1280 | |
1281 if (params[has]("text")) { | |
1282 a.text = params.text; | |
1283 while (node.firstChild) { | |
1284 node.removeChild(node.firstChild); | |
1285 } | |
1286 var texts = (params.text + E)[split]("\n"); | |
1287 for (var i = 0, ii = texts[length]; i < ii; i++) if (texts[i]) { | |
1288 var tspan = $("tspan"); | |
1289 i && $(tspan, {dy: fontSize * leading, x: a.x}); | |
1290 tspan[appendChild](doc.createTextNode(texts[i])); | |
1291 node[appendChild](tspan); | |
1292 } | |
1293 } else { | |
1294 var texts = node.getElementsByTagName("tspan"); | |
1295 for (var i = 0, ii = texts[length]; i < ii; i++) { | |
1296 i && $(texts[i], {dy: fontSize * leading, x: a.x}); | |
1297 } | |
1298 } | |
1299 $(node, {y: a.y}); | |
1300 var bb = el.getBBox(), | |
1301 dif = a.y - (bb.y + bb.height / 2); | |
1302 dif && isFinite(dif) && $(node, {y: a.y + dif}); | |
1303 }; | |
1304 var Element = function (node, svg) { | |
1305 var X = 0, | |
1306 Y = 0; | |
1307 this[0] = node; | |
1308 this.id = R._oid++; | |
1309 this.node = node; | |
1310 node.raphael = this; | |
1311 this.paper = svg; | |
1312 this.attrs = this.attrs || {}; | |
1313 this.transformations = []; // rotate, translate, scale | |
1314 this._ = { | |
1315 tx: 0, | |
1316 ty: 0, | |
1317 rt: {deg: 0, cx: 0, cy: 0}, | |
1318 sx: 1, | |
1319 sy: 1 | |
1320 }; | |
1321 !svg.bottom && (svg.bottom = this); | |
1322 this.prev = svg.top; | |
1323 svg.top && (svg.top.next = this); | |
1324 svg.top = this; | |
1325 this.next = null; | |
1326 }; | |
1327 Element[proto].rotate = function (deg, cx, cy) { | |
1328 if (this.removed) { | |
1329 return this; | |
1330 } | |
1331 if (deg == null) { | |
1332 if (this._.rt.cx) { | |
1333 return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S); | |
1334 } | |
1335 return this._.rt.deg; | |
1336 } | |
1337 var bbox = this.getBBox(); | |
1338 deg = (deg + E)[split](separator); | |
1339 if (deg[length] - 1) { | |
1340 cx = toFloat(deg[1]); | |
1341 cy = toFloat(deg[2]); | |
1342 } | |
1343 deg = toFloat(deg[0]); | |
1344 if (cx != null) { | |
1345 this._.rt.deg = deg; | |
1346 } else { | |
1347 this._.rt.deg += deg; | |
1348 } | |
1349 (cy == null) && (cx = null); | |
1350 this._.rt.cx = cx; | |
1351 this._.rt.cy = cy; | |
1352 cx = cx == null ? bbox.x + bbox.width / 2 : cx; | |
1353 cy = cy == null ? bbox.y + bbox.height / 2 : cy; | |
1354 if (this._.rt.deg) { | |
1355 this.transformations[0] = R.format("rotate({0} {1} {2})", this._.rt.deg, cx, cy); | |
1356 this.clip && $(this.clip, {transform: R.format("rotate({0} {1} {2})", -this._.rt.deg, cx, cy)}); | |
1357 } else { | |
1358 this.transformations[0] = E; | |
1359 this.clip && $(this.clip, {transform: E}); | |
1360 } | |
1361 $(this.node, {transform: this.transformations[join](S)}); | |
1362 return this; | |
1363 }; | |
1364 Element[proto].hide = function () { | |
1365 !this.removed && (this.node.style.display = "none"); | |
1366 return this; | |
1367 }; | |
1368 Element[proto].show = function () { | |
1369 !this.removed && (this.node.style.display = ""); | |
1370 return this; | |
1371 }; | |
1372 Element[proto].remove = function () { | |
1373 if (this.removed) { | |
1374 return; | |
1375 } | |
1376 tear(this, this.paper); | |
1377 this.node.parentNode.removeChild(this.node); | |
1378 for (var i in this) { | |
1379 delete this[i]; | |
1380 } | |
1381 this.removed = true; | |
1382 }; | |
1383 Element[proto].getBBox = function () { | |
1384 if (this.removed) { | |
1385 return this; | |
1386 } | |
1387 if (this.type == "path") { | |
1388 return pathDimensions(this.attrs.path); | |
1389 } | |
1390 if (this.node.style.display == "none") { | |
1391 this.show(); | |
1392 var hide = true; | |
1393 } | |
1394 var bbox = {}; | |
1395 try { | |
1396 bbox = this.node.getBBox(); | |
1397 } catch(e) { | |
1398 // Firefox 3.0.x plays badly here | |
1399 } finally { | |
1400 bbox = bbox || {}; | |
1401 } | |
1402 if (this.type == "text") { | |
1403 bbox = {x: bbox.x, y: Infinity, width: 0, height: 0}; | |
1404 for (var i = 0, ii = this.node.getNumberOfChars(); i < ii; i++) { | |
1405 var bb = this.node.getExtentOfChar(i); | |
1406 (bb.y < bbox.y) && (bbox.y = bb.y); | |
1407 (bb.y + bb.height - bbox.y > bbox.height) && (bbox.height = bb.y + bb.height - bbox.y); | |
1408 (bb.x + bb.width - bbox.x > bbox.width) && (bbox.width = bb.x + bb.width - bbox.x); | |
1409 } | |
1410 } | |
1411 hide && this.hide(); | |
1412 return bbox; | |
1413 }; | |
1414 Element[proto].attr = function () { | |
1415 if (this.removed) { | |
1416 return this; | |
1417 } | |
1418 if (arguments[length] == 0) { | |
1419 var res = {}; | |
1420 for (var i in this.attrs) if (this.attrs[has](i)) { | |
1421 res[i] = this.attrs[i]; | |
1422 } | |
1423 this._.rt.deg && (res.rotation = this.rotate()); | |
1424 (this._.sx != 1 || this._.sy != 1) && (res.scale = this.scale()); | |
1425 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; | |
1426 return res; | |
1427 } | |
1428 if (arguments[length] == 1 && R.is(arguments[0], "string")) { | |
1429 if (arguments[0] == "translation") { | |
1430 return translate.call(this); | |
1431 } | |
1432 if (arguments[0] == "rotation") { | |
1433 return this.rotate(); | |
1434 } | |
1435 if (arguments[0] == "scale") { | |
1436 return this.scale(); | |
1437 } | |
1438 if (arguments[0] == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { | |
1439 return this.attrs.gradient; | |
1440 } | |
1441 return this.attrs[arguments[0]]; | |
1442 } | |
1443 if (arguments[length] == 1 && R.is(arguments[0], "array")) { | |
1444 var values = {}; | |
1445 for (var j in arguments[0]) if (arguments[0][has](j)) { | |
1446 values[arguments[0][j]] = this.attrs[arguments[0][j]]; | |
1447 } | |
1448 return values; | |
1449 } | |
1450 if (arguments[length] == 2) { | |
1451 var params = {}; | |
1452 params[arguments[0]] = arguments[1]; | |
1453 setFillAndStroke(this, params); | |
1454 } else if (arguments[length] == 1 && R.is(arguments[0], "object")) { | |
1455 setFillAndStroke(this, arguments[0]); | |
1456 } | |
1457 return this; | |
1458 }; | |
1459 Element[proto].toFront = function () { | |
1460 if (this.removed) { | |
1461 return this; | |
1462 } | |
1463 this.node.parentNode[appendChild](this.node); | |
1464 var svg = this.paper; | |
1465 svg.top != this && tofront(this, svg); | |
1466 return this; | |
1467 }; | |
1468 Element[proto].toBack = function () { | |
1469 if (this.removed) { | |
1470 return this; | |
1471 } | |
1472 if (this.node.parentNode.firstChild != this.node) { | |
1473 this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); | |
1474 toback(this, this.paper); | |
1475 var svg = this.paper; | |
1476 } | |
1477 return this; | |
1478 }; | |
1479 Element[proto].insertAfter = function (element) { | |
1480 if (this.removed) { | |
1481 return this; | |
1482 } | |
1483 var node = element.node; | |
1484 if (node.nextSibling) { | |
1485 node.parentNode.insertBefore(this.node, node.nextSibling); | |
1486 } else { | |
1487 node.parentNode[appendChild](this.node); | |
1488 } | |
1489 insertafter(this, element, this.paper); | |
1490 return this; | |
1491 }; | |
1492 Element[proto].insertBefore = function (element) { | |
1493 if (this.removed) { | |
1494 return this; | |
1495 } | |
1496 var node = element.node; | |
1497 node.parentNode.insertBefore(this.node, node); | |
1498 insertbefore(this, element, this.paper); | |
1499 return this; | |
1500 }; | |
1501 var theCircle = function (svg, x, y, r) { | |
1502 x = round(x); | |
1503 y = round(y); | |
1504 var el = $("circle"); | |
1505 svg.canvas && svg.canvas[appendChild](el); | |
1506 var res = new Element(el, svg); | |
1507 res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; | |
1508 res.type = "circle"; | |
1509 $(el, res.attrs); | |
1510 return res; | |
1511 }; | |
1512 var theRect = function (svg, x, y, w, h, r) { | |
1513 x = round(x); | |
1514 y = round(y); | |
1515 var el = $("rect"); | |
1516 svg.canvas && svg.canvas[appendChild](el); | |
1517 var res = new Element(el, svg); | |
1518 res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; | |
1519 res.type = "rect"; | |
1520 $(el, res.attrs); | |
1521 return res; | |
1522 }; | |
1523 var theEllipse = function (svg, x, y, rx, ry) { | |
1524 x = round(x); | |
1525 y = round(y); | |
1526 var el = $("ellipse"); | |
1527 svg.canvas && svg.canvas[appendChild](el); | |
1528 var res = new Element(el, svg); | |
1529 res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; | |
1530 res.type = "ellipse"; | |
1531 $(el, res.attrs); | |
1532 return res; | |
1533 }; | |
1534 var theImage = function (svg, src, x, y, w, h) { | |
1535 var el = $("image"); | |
1536 $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); | |
1537 el.setAttributeNS(svg.xlink, "href", src); | |
1538 svg.canvas && svg.canvas[appendChild](el); | |
1539 var res = new Element(el, svg); | |
1540 res.attrs = {x: x, y: y, width: w, height: h, src: src}; | |
1541 res.type = "image"; | |
1542 return res; | |
1543 }; | |
1544 var theText = function (svg, x, y, text) { | |
1545 var el = $("text"); | |
1546 $(el, {x: x, y: y, "text-anchor": "middle"}); | |
1547 svg.canvas && svg.canvas[appendChild](el); | |
1548 var res = new Element(el, svg); | |
1549 res.attrs = {x: x, y: y, "text-anchor": "middle", text: text, font: availableAttrs.font, stroke: "none", fill: "#000"}; | |
1550 res.type = "text"; | |
1551 setFillAndStroke(res, res.attrs); | |
1552 return res; | |
1553 }; | |
1554 var setSize = function (width, height) { | |
1555 this.width = width || this.width; | |
1556 this.height = height || this.height; | |
1557 this.canvas[setAttribute]("width", this.width); | |
1558 this.canvas[setAttribute]("height", this.height); | |
1559 return this; | |
1560 }; | |
1561 var create = function () { | |
1562 var con = getContainer[apply](null, arguments), | |
1563 container = con && con.container, | |
1564 x = con.x, | |
1565 y = con.y, | |
1566 width = con.width, | |
1567 height = con.height; | |
1568 if (!container) { | |
1569 throw new Error("SVG container not found."); | |
1570 } | |
1571 var cnvs = $("svg"); | |
1572 width = width || 512; | |
1573 height = height || 342; | |
1574 $(cnvs, { | |
1575 xmlns: "http://www.w3.org/2000/svg", | |
1576 version: 1.1, | |
1577 width: width, | |
1578 height: height | |
1579 }); | |
1580 if (container == 1) { | |
1581 cnvs.style.cssText = "position:absolute;left:" + x + "px;top:" + y + "px"; | |
1582 doc.body[appendChild](cnvs); | |
1583 } else { | |
1584 if (container.firstChild) { | |
1585 container.insertBefore(cnvs, container.firstChild); | |
1586 } else { | |
1587 container[appendChild](cnvs); | |
1588 } | |
1589 } | |
1590 container = new Paper; | |
1591 container.width = width; | |
1592 container.height = height; | |
1593 container.canvas = cnvs; | |
1594 plugins.call(container, container, R.fn); | |
1595 container.clear(); | |
1596 return container; | |
1597 }; | |
1598 Paper[proto].clear = function () { | |
1599 var c = this.canvas; | |
1600 while (c.firstChild) { | |
1601 c.removeChild(c.firstChild); | |
1602 } | |
1603 this.bottom = this.top = null; | |
1604 (this.desc = $("desc"))[appendChild](doc.createTextNode("Created with Rapha\xebl")); | |
1605 c[appendChild](this.desc); | |
1606 c[appendChild](this.defs = $("defs")); | |
1607 }; | |
1608 Paper[proto].remove = function () { | |
1609 this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); | |
1610 for (var i in this) { | |
1611 this[i] = removed(i); | |
1612 } | |
1613 }; | |
1614 } | |
1615 | |
1616 // VML | |
1617 if (R.vml) { | |
1618 var path2vml = function (path) { | |
1619 var total = /[ahqstv]/ig, | |
1620 command = pathToAbsolute; | |
1621 (path + E).match(total) && (command = path2curve); | |
1622 total = /[clmz]/g; | |
1623 if (command == pathToAbsolute && !(path + E).match(total)) { | |
1624 var map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, | |
1625 bites = /([clmz]),?([^clmz]*)/gi, | |
1626 val = /-?[^,\s-]+/g; | |
1627 var res = (path + E)[rp](bites, function (all, command, args) { | |
1628 var vals = []; | |
1629 args[rp](val, function (value) { | |
1630 vals[push](round(value)); | |
1631 }); | |
1632 return map[command] + vals; | |
1633 }); | |
1634 return res; | |
1635 } | |
1636 var pa = command(path), p, res = [], r; | |
1637 for (var i = 0, ii = pa[length]; i < ii; i++) { | |
1638 p = pa[i]; | |
1639 r = lowerCase.call(pa[i][0]); | |
1640 r == "z" && (r = "x"); | |
1641 for (var j = 1, jj = p[length]; j < jj; j++) { | |
1642 r += round(p[j]) + (j != jj - 1 ? "," : E); | |
1643 } | |
1644 res[push](r); | |
1645 } | |
1646 return res[join](S); | |
1647 }; | |
1648 | |
1649 R[toString] = function () { | |
1650 return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; | |
1651 }; | |
1652 var thePath = function (pathString, VML) { | |
1653 var g = createNode("group"); | |
1654 g.style.cssText = "position:absolute;left:0;top:0;width:" + VML.width + "px;height:" + VML.height + "px"; | |
1655 g.coordsize = VML.coordsize; | |
1656 g.coordorigin = VML.coordorigin; | |
1657 var el = createNode("shape"), ol = el.style; | |
1658 ol.width = VML.width + "px"; | |
1659 ol.height = VML.height + "px"; | |
1660 el.coordsize = this.coordsize; | |
1661 el.coordorigin = this.coordorigin; | |
1662 g[appendChild](el); | |
1663 var p = new Element(el, g, VML); | |
1664 p.isAbsolute = true; | |
1665 p.type = "path"; | |
1666 p.path = []; | |
1667 p.Path = E; | |
1668 pathString && setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString}); | |
1669 VML.canvas[appendChild](g); | |
1670 return p; | |
1671 }; | |
1672 var setFillAndStroke = function (o, params) { | |
1673 o.attrs = o.attrs || {}; | |
1674 var node = o.node, | |
1675 a = o.attrs, | |
1676 s = node.style, | |
1677 xy, | |
1678 res = o; | |
1679 for (var par in params) if (params[has](par)) { | |
1680 a[par] = params[par]; | |
1681 } | |
1682 params.href && (node.href = params.href); | |
1683 params.title && (node.title = params.title); | |
1684 params.target && (node.target = params.target); | |
1685 params.cursor && (s.cursor = params.cursor); | |
1686 if (params.path && o.type == "path") { | |
1687 a.path = params.path; | |
1688 node.path = path2vml(a.path); | |
1689 } | |
1690 if (params.rotation != null) { | |
1691 o.rotate(params.rotation, true); | |
1692 } | |
1693 if (params.translation) { | |
1694 xy = (params.translation + E)[split](separator); | |
1695 translate.call(o, xy[0], xy[1]); | |
1696 if (o._.rt.cx != null) { | |
1697 o._.rt.cx +=+ xy[0]; | |
1698 o._.rt.cy +=+ xy[1]; | |
1699 o.setBox(o.attrs, xy[0], xy[1]); | |
1700 } | |
1701 } | |
1702 if (params.scale) { | |
1703 xy = (params.scale + E)[split](separator); | |
1704 o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, +xy[2] || null, +xy[3] || null); | |
1705 } | |
1706 if ("clip-rect" in params) { | |
1707 var rect = (params["clip-rect"] + E)[split](separator); | |
1708 if (rect[length] == 4) { | |
1709 rect[2] = +rect[2] + (+rect[0]); | |
1710 rect[3] = +rect[3] + (+rect[1]); | |
1711 var div = node.clipRect || doc.createElement("div"), | |
1712 dstyle = div.style, | |
1713 group = node.parentNode; | |
1714 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); | |
1715 if (!node.clipRect) { | |
1716 dstyle.position = "absolute"; | |
1717 dstyle.top = 0; | |
1718 dstyle.left = 0; | |
1719 dstyle.width = o.paper.width + "px"; | |
1720 dstyle.height = o.paper.height + "px"; | |
1721 group.parentNode.insertBefore(div, group); | |
1722 div[appendChild](group); | |
1723 node.clipRect = div; | |
1724 } | |
1725 } | |
1726 if (!params["clip-rect"]) { | |
1727 node.clipRect && (node.clipRect.style.clip = E); | |
1728 } | |
1729 } | |
1730 if (o.type == "image" && params.src) { | |
1731 node.src = params.src; | |
1732 } | |
1733 if (o.type == "image" && params.opacity) { | |
1734 node.filterOpacity = " progid:DXImageTransform.Microsoft.Alpha(opacity=" + (params.opacity * 100) + ")"; | |
1735 s.filter = (node.filterMatrix || E) + (node.filterOpacity || E); | |
1736 } | |
1737 params.font && (s.font = params.font); | |
1738 params["font-family"] && (s.fontFamily = '"' + params["font-family"][split](",")[0][rp](/^['"]+|['"]+$/g, E) + '"'); | |
1739 params["font-size"] && (s.fontSize = params["font-size"]); | |
1740 params["font-weight"] && (s.fontWeight = params["font-weight"]); | |
1741 params["font-style"] && (s.fontStyle = params["font-style"]); | |
1742 if (params.opacity != null || | |
1743 params["stroke-width"] != null || | |
1744 params.fill != null || | |
1745 params.stroke != null || | |
1746 params["stroke-width"] != null || | |
1747 params["stroke-opacity"] != null || | |
1748 params["fill-opacity"] != null || | |
1749 params["stroke-dasharray"] != null || | |
1750 params["stroke-miterlimit"] != null || | |
1751 params["stroke-linejoin"] != null || | |
1752 params["stroke-linecap"] != null) { | |
1753 node = o.shape || node; | |
1754 var fill = (node.getElementsByTagName("fill") && node.getElementsByTagName("fill")[0]), | |
1755 newfill = false; | |
1756 !fill && (newfill = fill = createNode("fill")); | |
1757 if ("fill-opacity" in params || "opacity" in params) { | |
1758 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1); | |
1759 opacity < 0 && (opacity = 0); | |
1760 opacity > 1 && (opacity = 1); | |
1761 fill.opacity = opacity; | |
1762 } | |
1763 params.fill && (fill.on = true); | |
1764 if (fill.on == null || params.fill == "none") { | |
1765 fill.on = false; | |
1766 } | |
1767 if (fill.on && params.fill) { | |
1768 var isURL = params.fill.match(ISURL); | |
1769 if (isURL) { | |
1770 fill.src = isURL[1]; | |
1771 fill.type = "tile"; | |
1772 } else { | |
1773 fill.color = R.getRGB(params.fill).hex; | |
1774 fill.src = E; | |
1775 fill.type = "solid"; | |
1776 if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || (params.fill + E).charAt() != "r") && addGradientFill(res, params.fill)) { | |
1777 a.fill = "none"; | |
1778 a.gradient = params.fill; | |
1779 } | |
1780 } | |
1781 } | |
1782 newfill && node[appendChild](fill); | |
1783 var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), | |
1784 newstroke = false; | |
1785 !stroke && (newstroke = stroke = createNode("stroke")); | |
1786 if ((params.stroke && params.stroke != "none") || | |
1787 params["stroke-width"] || | |
1788 params["stroke-opacity"] != null || | |
1789 params["stroke-dasharray"] || | |
1790 params["stroke-miterlimit"] || | |
1791 params["stroke-linejoin"] || | |
1792 params["stroke-linecap"]) { | |
1793 stroke.on = true; | |
1794 } | |
1795 (params.stroke == "none" || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); | |
1796 stroke.on && params.stroke && (stroke.color = R.getRGB(params.stroke).hex); | |
1797 var opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1), | |
1798 width = (toFloat(params["stroke-width"]) || 1) * .75; | |
1799 opacity < 0 && (opacity = 0); | |
1800 opacity > 1 && (opacity = 1); | |
1801 params["stroke-width"] == null && (width = a["stroke-width"]); | |
1802 params["stroke-width"] && (stroke.weight = width); | |
1803 width && width < 1 && (opacity *= width) && (stroke.weight = 1); | |
1804 stroke.opacity = opacity; | |
1805 | |
1806 params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); | |
1807 stroke.miterlimit = params["stroke-miterlimit"] || 8; | |
1808 params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); | |
1809 if (params["stroke-dasharray"]) { | |
1810 var dasharray = { | |
1811 "-": "shortdash", | |
1812 ".": "shortdot", | |
1813 "-.": "shortdashdot", | |
1814 "-..": "shortdashdotdot", | |
1815 ". ": "dot", | |
1816 "- ": "dash", | |
1817 "--": "longdash", | |
1818 "- .": "dashdot", | |
1819 "--.": "longdashdot", | |
1820 "--..": "longdashdotdot" | |
1821 }; | |
1822 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; | |
1823 } | |
1824 newstroke && node[appendChild](stroke); | |
1825 } | |
1826 if (res.type == "text") { | |
1827 var s = res.paper.span.style; | |
1828 a.font && (s.font = a.font); | |
1829 a["font-family"] && (s.fontFamily = a["font-family"]); | |
1830 a["font-size"] && (s.fontSize = a["font-size"]); | |
1831 a["font-weight"] && (s.fontWeight = a["font-weight"]); | |
1832 a["font-style"] && (s.fontStyle = a["font-style"]); | |
1833 res.node.string && (res.paper.span.innerHTML = (res.node.string + E)[rp](/</g, "<")[rp](/&/g, "&")[rp](/\n/g, "<br>")); | |
1834 res.W = a.w = res.paper.span.offsetWidth; | |
1835 res.H = a.h = res.paper.span.offsetHeight; | |
1836 res.X = a.x; | |
1837 res.Y = a.y + round(res.H / 2); | |
1838 | |
1839 // text-anchor emulationm | |
1840 switch (a["text-anchor"]) { | |
1841 case "start": | |
1842 res.node.style["v-text-align"] = "left"; | |
1843 res.bbx = round(res.W / 2); | |
1844 break; | |
1845 case "end": | |
1846 res.node.style["v-text-align"] = "right"; | |
1847 res.bbx = -round(res.W / 2); | |
1848 break; | |
1849 default: | |
1850 res.node.style["v-text-align"] = "center"; | |
1851 break; | |
1852 } | |
1853 } | |
1854 }; | |
1855 var addGradientFill = function (o, gradient) { | |
1856 o.attrs = o.attrs || {}; | |
1857 var attrs = o.attrs, | |
1858 fill = o.node.getElementsByTagName("fill"), | |
1859 type = "linear", | |
1860 fxfy = ".5 .5"; | |
1861 o.attrs.gradient = gradient; | |
1862 gradient = (gradient + E)[rp](radial_gradient, function (all, fx, fy) { | |
1863 type = "radial"; | |
1864 if (fx && fy) { | |
1865 fx = toFloat(fx); | |
1866 fy = toFloat(fy); | |
1867 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); | |
1868 fxfy = fx + S + fy; | |
1869 } | |
1870 return E; | |
1871 }); | |
1872 gradient = gradient[split](/\s*\-\s*/); | |
1873 if (type == "linear") { | |
1874 var angle = gradient.shift(); | |
1875 angle = -toFloat(angle); | |
1876 if (isNaN(angle)) { | |
1877 return null; | |
1878 } | |
1879 } | |
1880 var dots = parseDots(gradient); | |
1881 if (!dots) { | |
1882 return null; | |
1883 } | |
1884 o = o.shape || o.node; | |
1885 fill = fill[0] || createNode("fill"); | |
1886 if (dots[length]) { | |
1887 fill.on = true; | |
1888 fill.method = "none"; | |
1889 fill.type = (type == "radial") ? "gradientradial" : "gradient"; | |
1890 fill.color = dots[0].color; | |
1891 fill.color2 = dots[dots[length] - 1].color; | |
1892 var clrs = []; | |
1893 for (var i = 0, ii = dots[length]; i < ii; i++) { | |
1894 dots[i].offset && clrs[push](dots[i].offset + S + dots[i].color); | |
1895 } | |
1896 fill.colors && (fill.colors.value = clrs[length] ? clrs[join](",") : "0% " + fill.color); | |
1897 if (type == "radial") { | |
1898 fill.focus = "100%"; | |
1899 fill.focussize = fxfy; | |
1900 fill.focusposition = fxfy; | |
1901 } else { | |
1902 fill.angle = (270 - angle) % 360; | |
1903 } | |
1904 } | |
1905 return 1; | |
1906 }; | |
1907 var Element = function (node, group, vml) { | |
1908 var Rotation = 0, | |
1909 RotX = 0, | |
1910 RotY = 0, | |
1911 Scale = 1; | |
1912 this[0] = node; | |
1913 this.id = R._oid++; | |
1914 this.node = node; | |
1915 node.raphael = this; | |
1916 this.X = 0; | |
1917 this.Y = 0; | |
1918 this.attrs = {}; | |
1919 this.Group = group; | |
1920 this.paper = vml; | |
1921 this._ = { | |
1922 tx: 0, | |
1923 ty: 0, | |
1924 rt: {deg:0}, | |
1925 sx: 1, | |
1926 sy: 1 | |
1927 }; | |
1928 !vml.bottom && (vml.bottom = this); | |
1929 this.prev = vml.top; | |
1930 vml.top && (vml.top.next = this); | |
1931 vml.top = this; | |
1932 this.next = null; | |
1933 }; | |
1934 Element[proto].rotate = function (deg, cx, cy) { | |
1935 if (this.removed) { | |
1936 return this; | |
1937 } | |
1938 if (deg == null) { | |
1939 if (this._.rt.cx) { | |
1940 return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S); | |
1941 } | |
1942 return this._.rt.deg; | |
1943 } | |
1944 deg = (deg + E)[split](separator); | |
1945 if (deg[length] - 1) { | |
1946 cx = toFloat(deg[1]); | |
1947 cy = toFloat(deg[2]); | |
1948 } | |
1949 deg = toFloat(deg[0]); | |
1950 if (cx != null) { | |
1951 this._.rt.deg = deg; | |
1952 } else { | |
1953 this._.rt.deg += deg; | |
1954 } | |
1955 cy == null && (cx = null); | |
1956 this._.rt.cx = cx; | |
1957 this._.rt.cy = cy; | |
1958 this.setBox(this.attrs, cx, cy); | |
1959 this.Group.style.rotation = this._.rt.deg; | |
1960 // gradient fix for rotation. TODO | |
1961 // var fill = (this.shape || this.node).getElementsByTagName("fill"); | |
1962 // fill = fill[0] || {}; | |
1963 // var b = ((360 - this._.rt.deg) - 270) % 360; | |
1964 // !R.is(fill.angle, "undefined") && (fill.angle = b); | |
1965 return this; | |
1966 }; | |
1967 Element[proto].setBox = function (params, cx, cy) { | |
1968 if (this.removed) { | |
1969 return this; | |
1970 } | |
1971 var gs = this.Group.style, | |
1972 os = (this.shape && this.shape.style) || this.node.style; | |
1973 params = params || {}; | |
1974 for (var i in params) if (params[has](i)) { | |
1975 this.attrs[i] = params[i]; | |
1976 } | |
1977 cx = cx || this._.rt.cx; | |
1978 cy = cy || this._.rt.cy; | |
1979 var attr = this.attrs, | |
1980 x, | |
1981 y, | |
1982 w, | |
1983 h; | |
1984 switch (this.type) { | |
1985 case "circle": | |
1986 x = attr.cx - attr.r; | |
1987 y = attr.cy - attr.r; | |
1988 w = h = attr.r * 2; | |
1989 break; | |
1990 case "ellipse": | |
1991 x = attr.cx - attr.rx; | |
1992 y = attr.cy - attr.ry; | |
1993 w = attr.rx * 2; | |
1994 h = attr.ry * 2; | |
1995 break; | |
1996 case "rect": | |
1997 case "image": | |
1998 x = +attr.x; | |
1999 y = +attr.y; | |
2000 w = attr.width || 0; | |
2001 h = attr.height || 0; | |
2002 break; | |
2003 case "text": | |
2004 this.textpath.v = ["m", round(attr.x), ", ", round(attr.y - 2), "l", round(attr.x) + 1, ", ", round(attr.y - 2)][join](E); | |
2005 x = attr.x - round(this.W / 2); | |
2006 y = attr.y - this.H / 2; | |
2007 w = this.W; | |
2008 h = this.H; | |
2009 break; | |
2010 case "path": | |
2011 if (!this.attrs.path) { | |
2012 x = 0; | |
2013 y = 0; | |
2014 w = this.paper.width; | |
2015 h = this.paper.height; | |
2016 } else { | |
2017 var dim = pathDimensions(this.attrs.path); | |
2018 x = dim.x; | |
2019 y = dim.y; | |
2020 w = dim.width; | |
2021 h = dim.height; | |
2022 } | |
2023 break; | |
2024 default: | |
2025 x = 0; | |
2026 y = 0; | |
2027 w = this.paper.width; | |
2028 h = this.paper.height; | |
2029 break; | |
2030 } | |
2031 cx = (cx == null) ? x + w / 2 : cx; | |
2032 cy = (cy == null) ? y + h / 2 : cy; | |
2033 var left = cx - this.paper.width / 2, | |
2034 top = cy - this.paper.height / 2; | |
2035 if (this.type == "path" || this.type == "text") { | |
2036 (gs.left != left + "px") && (gs.left = left + "px"); | |
2037 (gs.top != top + "px") && (gs.top = top + "px"); | |
2038 this.X = this.type == "text" ? x : -left; | |
2039 this.Y = this.type == "text" ? y : -top; | |
2040 this.W = w; | |
2041 this.H = h; | |
2042 (os.left != -left + "px") && (os.left = -left + "px"); | |
2043 (os.top != -top + "px") && (os.top = -top + "px"); | |
2044 } else { | |
2045 (gs.left != left + "px") && (gs.left = left + "px"); | |
2046 (gs.top != top + "px") && (gs.top = top + "px"); | |
2047 this.X = x; | |
2048 this.Y = y; | |
2049 this.W = w; | |
2050 this.H = h; | |
2051 (gs.width != this.paper.width + "px") && (gs.width = this.paper.width + "px"); | |
2052 (gs.height != this.paper.height + "px") && (gs.height = this.paper.height + "px"); | |
2053 (os.left != x - left + "px") && (os.left = x - left + "px"); | |
2054 (os.top != y - top + "px") && (os.top = y - top + "px"); | |
2055 (os.width != w + "px") && (os.width = w + "px"); | |
2056 (os.height != h + "px") && (os.height = h + "px"); | |
2057 var arcsize = (+params.r || 0) / mmin(w, h); | |
2058 if (this.type == "rect" && this.arcsize.toFixed(4) != arcsize.toFixed(4) && (arcsize || this.arcsize)) { | |
2059 // We should replace element with the new one | |
2060 var o = createNode("roundrect"), | |
2061 a = {}, | |
2062 i = 0, | |
2063 ii = this.events && this.events[length]; | |
2064 o.arcsize = arcsize; | |
2065 o.raphael = this; | |
2066 this.Group[appendChild](o); | |
2067 this.Group.removeChild(this.node); | |
2068 this[0] = this.node = o; | |
2069 this.arcsize = arcsize; | |
2070 for (var i in attr) { | |
2071 a[i] = attr[i]; | |
2072 } | |
2073 delete a.scale; | |
2074 this.attr(a); | |
2075 if (this.events) for (; i < ii; i++) { | |
2076 this.events[i].unbind = addEvent(this.node, this.events[i].name, this.events[i].f, this); | |
2077 } | |
2078 } | |
2079 } | |
2080 }; | |
2081 Element[proto].hide = function () { | |
2082 !this.removed && (this.Group.style.display = "none"); | |
2083 return this; | |
2084 }; | |
2085 Element[proto].show = function () { | |
2086 !this.removed && (this.Group.style.display = "block"); | |
2087 return this; | |
2088 }; | |
2089 Element[proto].getBBox = function () { | |
2090 if (this.removed) { | |
2091 return this; | |
2092 } | |
2093 if (this.type == "path") { | |
2094 return pathDimensions(this.attrs.path); | |
2095 } | |
2096 return { | |
2097 x: this.X + (this.bbx || 0), | |
2098 y: this.Y, | |
2099 width: this.W, | |
2100 height: this.H | |
2101 }; | |
2102 }; | |
2103 Element[proto].remove = function () { | |
2104 if (this.removed) { | |
2105 return; | |
2106 } | |
2107 tear(this, this.paper); | |
2108 this.node.parentNode.removeChild(this.node); | |
2109 this.Group.parentNode.removeChild(this.Group); | |
2110 this.shape && this.shape.parentNode.removeChild(this.shape); | |
2111 for (var i in this) { | |
2112 delete this[i]; | |
2113 } | |
2114 this.removed = true; | |
2115 }; | |
2116 Element[proto].attr = function () { | |
2117 if (this.removed) { | |
2118 return this; | |
2119 } | |
2120 if (arguments[length] == 0) { | |
2121 var res = {}; | |
2122 for (var i in this.attrs) if (this.attrs[has](i)) { | |
2123 res[i] = this.attrs[i]; | |
2124 } | |
2125 this._.rt.deg && (res.rotation = this.rotate()); | |
2126 (this._.sx != 1 || this._.sy != 1) && (res.scale = this.scale()); | |
2127 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; | |
2128 return res; | |
2129 } | |
2130 if (arguments[length] == 1 && R.is(arguments[0], "string")) { | |
2131 if (arguments[0] == "translation") { | |
2132 return translate.call(this); | |
2133 } | |
2134 if (arguments[0] == "rotation") { | |
2135 return this.rotate(); | |
2136 } | |
2137 if (arguments[0] == "scale") { | |
2138 return this.scale(); | |
2139 } | |
2140 if (arguments[0] == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { | |
2141 return this.attrs.gradient; | |
2142 } | |
2143 return this.attrs[arguments[0]]; | |
2144 } | |
2145 if (this.attrs && arguments[length] == 1 && R.is(arguments[0], "array")) { | |
2146 var values = {}; | |
2147 for (var i = 0, ii = arguments[0][length]; i < ii; i++) { | |
2148 values[arguments[0][i]] = this.attrs[arguments[0][i]]; | |
2149 }; | |
2150 return values; | |
2151 } | |
2152 var params; | |
2153 if (arguments[length] == 2) { | |
2154 params = {}; | |
2155 params[arguments[0]] = arguments[1]; | |
2156 } | |
2157 arguments[length] == 1 && R.is(arguments[0], "object") && (params = arguments[0]); | |
2158 if (params) { | |
2159 if (params.text && this.type == "text") { | |
2160 this.node.string = params.text; | |
2161 } | |
2162 setFillAndStroke(this, params); | |
2163 if (params.gradient && (({circle: 1, ellipse: 1})[has](this.type) || (params.gradient + E).charAt() != "r")) { | |
2164 addGradientFill(this, params.gradient); | |
2165 } | |
2166 (this.type != "path" || this._.rt.deg) && this.setBox(this.attrs); | |
2167 } | |
2168 return this; | |
2169 }; | |
2170 Element[proto].toFront = function () { | |
2171 !this.removed && this.Group.parentNode[appendChild](this.Group); | |
2172 this.paper.top != this && tofront(this, this.paper); | |
2173 return this; | |
2174 }; | |
2175 Element[proto].toBack = function () { | |
2176 if (this.removed) { | |
2177 return this; | |
2178 } | |
2179 if (this.Group.parentNode.firstChild != this.Group) { | |
2180 this.Group.parentNode.insertBefore(this.Group, this.Group.parentNode.firstChild); | |
2181 toback(this, this.paper); | |
2182 } | |
2183 return this; | |
2184 }; | |
2185 Element[proto].insertAfter = function (element) { | |
2186 if (this.removed) { | |
2187 return this; | |
2188 } | |
2189 if (element.Group.nextSibling) { | |
2190 element.Group.parentNode.insertBefore(this.Group, element.Group.nextSibling); | |
2191 } else { | |
2192 element.Group.parentNode[appendChild](this.Group); | |
2193 } | |
2194 insertafter(this, element, this.paper); | |
2195 return this; | |
2196 }; | |
2197 Element[proto].insertBefore = function (element) { | |
2198 if (this.removed) { | |
2199 return this; | |
2200 } | |
2201 element.Group.parentNode.insertBefore(this.Group, element.Group); | |
2202 insertbefore(this, element, this.paper); | |
2203 return this; | |
2204 }; | |
2205 | |
2206 var theCircle = function (vml, x, y, r) { | |
2207 var g = createNode("group"), | |
2208 o = createNode("oval"), | |
2209 ol = o.style; | |
2210 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; | |
2211 g.coordsize = vml.coordsize; | |
2212 g.coordorigin = vml.coordorigin; | |
2213 g[appendChild](o); | |
2214 var res = new Element(o, g, vml); | |
2215 res.type = "circle"; | |
2216 setFillAndStroke(res, {stroke: "#000", fill: "none"}); | |
2217 res.attrs.cx = x; | |
2218 res.attrs.cy = y; | |
2219 res.attrs.r = r; | |
2220 res.setBox({x: x - r, y: y - r, width: r * 2, height: r * 2}); | |
2221 vml.canvas[appendChild](g); | |
2222 return res; | |
2223 }, | |
2224 theRect = function (vml, x, y, w, h, r) { | |
2225 var g = createNode("group"), | |
2226 o = createNode("roundrect"), | |
2227 arcsize = (+r || 0) / (mmin(w, h)); | |
2228 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; | |
2229 g.coordsize = vml.coordsize; | |
2230 g.coordorigin = vml.coordorigin; | |
2231 g[appendChild](o); | |
2232 o.arcsize = arcsize; | |
2233 var res = new Element(o, g, vml); | |
2234 res.type = "rect"; | |
2235 setFillAndStroke(res, {stroke: "#000"}); | |
2236 res.arcsize = arcsize; | |
2237 res.setBox({x: x, y: y, width: w, height: h, r: r}); | |
2238 vml.canvas[appendChild](g); | |
2239 return res; | |
2240 }, | |
2241 theEllipse = function (vml, x, y, rx, ry) { | |
2242 var g = createNode("group"), | |
2243 o = createNode("oval"), | |
2244 ol = o.style; | |
2245 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; | |
2246 g.coordsize = vml.coordsize; | |
2247 g.coordorigin = vml.coordorigin; | |
2248 g[appendChild](o); | |
2249 var res = new Element(o, g, vml); | |
2250 res.type = "ellipse"; | |
2251 setFillAndStroke(res, {stroke: "#000"}); | |
2252 res.attrs.cx = x; | |
2253 res.attrs.cy = y; | |
2254 res.attrs.rx = rx; | |
2255 res.attrs.ry = ry; | |
2256 res.setBox({x: x - rx, y: y - ry, width: rx * 2, height: ry * 2}); | |
2257 vml.canvas[appendChild](g); | |
2258 return res; | |
2259 }, | |
2260 theImage = function (vml, src, x, y, w, h) { | |
2261 var g = createNode("group"), | |
2262 o = createNode("image"), | |
2263 ol = o.style; | |
2264 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; | |
2265 g.coordsize = vml.coordsize; | |
2266 g.coordorigin = vml.coordorigin; | |
2267 o.src = src; | |
2268 g[appendChild](o); | |
2269 var res = new Element(o, g, vml); | |
2270 res.type = "image"; | |
2271 res.attrs.src = src; | |
2272 res.attrs.x = x; | |
2273 res.attrs.y = y; | |
2274 res.attrs.w = w; | |
2275 res.attrs.h = h; | |
2276 res.setBox({x: x, y: y, width: w, height: h}); | |
2277 vml.canvas[appendChild](g); | |
2278 return res; | |
2279 }, | |
2280 theText = function (vml, x, y, text) { | |
2281 var g = createNode("group"), | |
2282 el = createNode("shape"), | |
2283 ol = el.style, | |
2284 path = createNode("path"), | |
2285 ps = path.style, | |
2286 o = createNode("textpath"); | |
2287 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; | |
2288 g.coordsize = vml.coordsize; | |
2289 g.coordorigin = vml.coordorigin; | |
2290 path.v = R.format("m{0},{1}l{2},{1}", round(x), round(y), round(x) + 1); | |
2291 path.textpathok = true; | |
2292 ol.width = vml.width; | |
2293 ol.height = vml.height; | |
2294 o.string = text + E; | |
2295 o.on = true; | |
2296 el[appendChild](o); | |
2297 el[appendChild](path); | |
2298 g[appendChild](el); | |
2299 var res = new Element(o, g, vml); | |
2300 res.shape = el; | |
2301 res.textpath = path; | |
2302 res.type = "text"; | |
2303 res.attrs.text = text; | |
2304 res.attrs.x = x; | |
2305 res.attrs.y = y; | |
2306 res.attrs.w = 1; | |
2307 res.attrs.h = 1; | |
2308 setFillAndStroke(res, {font: availableAttrs.font, stroke: "none", fill: "#000"}); | |
2309 res.setBox(); | |
2310 vml.canvas[appendChild](g); | |
2311 return res; | |
2312 }, | |
2313 setSize = function (width, height) { | |
2314 var cs = this.canvas.style; | |
2315 width == +width && (width += "px"); | |
2316 height == +height && (height += "px"); | |
2317 cs.width = width; | |
2318 cs.height = height; | |
2319 cs.clip = "rect(0 " + width + " " + height + " 0)"; | |
2320 return this; | |
2321 }, | |
2322 createNode; | |
2323 doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); | |
2324 try { | |
2325 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); | |
2326 createNode = function (tagName) { | |
2327 return doc.createElement('<rvml:' + tagName + ' class="rvml">'); | |
2328 }; | |
2329 } catch (e) { | |
2330 createNode = function (tagName) { | |
2331 return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); | |
2332 }; | |
2333 } | |
2334 var create = function () { | |
2335 var con = getContainer[apply](null, arguments), | |
2336 container = con.container, | |
2337 height = con.height, | |
2338 s, | |
2339 width = con.width, | |
2340 x = con.x, | |
2341 y = con.y; | |
2342 if (!container) { | |
2343 throw new Error("VML container not found."); | |
2344 } | |
2345 var res = new Paper, | |
2346 c = res.canvas = doc.createElement("div"), | |
2347 cs = c.style; | |
2348 width = width || 512; | |
2349 height = height || 342; | |
2350 width == +width && (width += "px"); | |
2351 height == +height && (height += "px"); | |
2352 res.width = 1e3; | |
2353 res.height = 1e3; | |
2354 res.coordsize = "1000 1000"; | |
2355 res.coordorigin = "0 0"; | |
2356 res.span = doc.createElement("span"); | |
2357 res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; | |
2358 c[appendChild](res.span); | |
2359 cs.cssText = R.format("width:{0};height:{1};position:absolute;clip:rect(0 {0} {1} 0);overflow:hidden", width, height); | |
2360 if (container == 1) { | |
2361 doc.body[appendChild](c); | |
2362 cs.left = x + "px"; | |
2363 cs.top = y + "px"; | |
2364 } else { | |
2365 container.style.width = width; | |
2366 container.style.height = height; | |
2367 if (container.firstChild) { | |
2368 container.insertBefore(c, container.firstChild); | |
2369 } else { | |
2370 container[appendChild](c); | |
2371 } | |
2372 } | |
2373 plugins.call(res, res, R.fn); | |
2374 return res; | |
2375 }; | |
2376 Paper[proto].clear = function () { | |
2377 this.canvas.innerHTML = E; | |
2378 this.span = doc.createElement("span"); | |
2379 this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; | |
2380 this.canvas[appendChild](this.span); | |
2381 this.bottom = this.top = null; | |
2382 }; | |
2383 Paper[proto].remove = function () { | |
2384 this.canvas.parentNode.removeChild(this.canvas); | |
2385 for (var i in this) { | |
2386 this[i] = removed(i); | |
2387 } | |
2388 }; | |
2389 } | |
2390 | |
2391 // rest | |
2392 // Safari or Chrome (WebKit) rendering bug workaround method | |
2393 if ((/^Apple|^Google/).test(navigator.vendor) && !(navigator.userAgent.indexOf("Version/4.0") + 1)) { | |
2394 Paper[proto].safari = function () { | |
2395 var rect = this.rect(-99, -99, this.width + 99, this.height + 99); | |
2396 setTimeout(function () {rect.remove();}); | |
2397 }; | |
2398 } else { | |
2399 Paper[proto].safari = function () {}; | |
2400 } | |
2401 | |
2402 // Events | |
2403 var addEvent = (function () { | |
2404 if (doc.addEventListener) { | |
2405 return function (obj, type, fn, element) { | |
2406 var f = function (e) { | |
2407 return fn.call(element, e); | |
2408 }; | |
2409 obj.addEventListener(type, f, false); | |
2410 return function () { | |
2411 obj.removeEventListener(type, f, false); | |
2412 return true; | |
2413 }; | |
2414 }; | |
2415 } else if (doc.attachEvent) { | |
2416 return function (obj, type, fn, element) { | |
2417 var f = function (e) { | |
2418 return fn.call(element, e || win.event); | |
2419 }; | |
2420 obj.attachEvent("on" + type, f); | |
2421 var detacher = function () { | |
2422 obj.detachEvent("on" + type, f); | |
2423 return true; | |
2424 }; | |
2425 return detacher; | |
2426 }; | |
2427 } | |
2428 })(); | |
2429 for (var i = events[length]; i--;) { | |
2430 (function (eventName) { | |
2431 Element[proto][eventName] = function (fn) { | |
2432 if (R.is(fn, "function")) { | |
2433 this.events = this.events || []; | |
2434 this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node, eventName, fn, this)}); | |
2435 } | |
2436 return this; | |
2437 }; | |
2438 Element[proto]["un" + eventName] = function (fn) { | |
2439 var events = this.events, | |
2440 l = events[length]; | |
2441 while (l--) if (events[l].name == eventName && events[l].f == fn) { | |
2442 events[l].unbind(); | |
2443 events.splice(l, 1); | |
2444 !events.length && delete this.events; | |
2445 return this; | |
2446 } | |
2447 return this; | |
2448 }; | |
2449 })(events[i]); | |
2450 } | |
2451 Element[proto].hover = function (f_in, f_out) { | |
2452 return this.mouseover(f_in).mouseout(f_out); | |
2453 }; | |
2454 Element[proto].unhover = function (f_in, f_out) { | |
2455 return this.unmouseover(f_in).unmouseout(f_out); | |
2456 }; | |
2457 Paper[proto].circle = function (x, y, r) { | |
2458 return theCircle(this, x || 0, y || 0, r || 0); | |
2459 }; | |
2460 Paper[proto].rect = function (x, y, w, h, r) { | |
2461 return theRect(this, x || 0, y || 0, w || 0, h || 0, r || 0); | |
2462 }; | |
2463 Paper[proto].ellipse = function (x, y, rx, ry) { | |
2464 return theEllipse(this, x || 0, y || 0, rx || 0, ry || 0); | |
2465 }; | |
2466 Paper[proto].path = function (pathString) { | |
2467 pathString && !R.is(pathString, "string") && !R.is(pathString[0], "array") && (pathString += E); | |
2468 return thePath(R.format[apply](R, arguments), this); | |
2469 }; | |
2470 Paper[proto].image = function (src, x, y, w, h) { | |
2471 return theImage(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); | |
2472 }; | |
2473 Paper[proto].text = function (x, y, text) { | |
2474 return theText(this, x || 0, y || 0, text || E); | |
2475 }; | |
2476 Paper[proto].set = function (itemsArray) { | |
2477 arguments[length] > 1 && (itemsArray = Array[proto].splice.call(arguments, 0, arguments[length])); | |
2478 return new Set(itemsArray); | |
2479 }; | |
2480 Paper[proto].setSize = setSize; | |
2481 Paper[proto].top = Paper[proto].bottom = null; | |
2482 Paper[proto].raphael = R; | |
2483 function x_y() { | |
2484 return this.x + S + this.y; | |
2485 }; | |
2486 Element[proto].scale = function (x, y, cx, cy) { | |
2487 if (x == null && y == null) { | |
2488 return { | |
2489 x: this._.sx, | |
2490 y: this._.sy, | |
2491 toString: x_y | |
2492 }; | |
2493 } | |
2494 y = y || x; | |
2495 !+y && (y = x); | |
2496 var dx, | |
2497 dy, | |
2498 dcx, | |
2499 dcy, | |
2500 a = this.attrs; | |
2501 if (x != 0) { | |
2502 var bb = this.getBBox(), | |
2503 rcx = bb.x + bb.width / 2, | |
2504 rcy = bb.y + bb.height / 2, | |
2505 kx = x / this._.sx, | |
2506 ky = y / this._.sy; | |
2507 cx = (+cx || cx == 0) ? cx : rcx; | |
2508 cy = (+cy || cy == 0) ? cy : rcy; | |
2509 var dirx = ~~(x / math.abs(x)), | |
2510 diry = ~~(y / math.abs(y)), | |
2511 s = this.node.style, | |
2512 ncx = cx + (rcx - cx) * kx, | |
2513 ncy = cy + (rcy - cy) * ky; | |
2514 switch (this.type) { | |
2515 case "rect": | |
2516 case "image": | |
2517 var neww = a.width * dirx * kx, | |
2518 newh = a.height * diry * ky; | |
2519 this.attr({ | |
2520 height: newh, | |
2521 r: a.r * mmin(dirx * kx, diry * ky), | |
2522 width: neww, | |
2523 x: ncx - neww / 2, | |
2524 y: ncy - newh / 2 | |
2525 }); | |
2526 break; | |
2527 case "circle": | |
2528 case "ellipse": | |
2529 this.attr({ | |
2530 rx: a.rx * dirx * kx, | |
2531 ry: a.ry * diry * ky, | |
2532 r: a.r * mmin(dirx * kx, diry * ky), | |
2533 cx: ncx, | |
2534 cy: ncy | |
2535 }); | |
2536 break; | |
2537 case "path": | |
2538 var path = pathToRelative(a.path), | |
2539 skip = true; | |
2540 for (var i = 0, ii = path[length]; i < ii; i++) { | |
2541 var p = path[i], | |
2542 j, | |
2543 P0 = upperCase.call(p[0]); | |
2544 if (P0 == "M" && skip) { | |
2545 continue; | |
2546 } else { | |
2547 skip = false; | |
2548 } | |
2549 if (P0 == "A") { | |
2550 p[path[i][length] - 2] *= kx; | |
2551 p[path[i][length] - 1] *= ky; | |
2552 p[1] *= dirx * kx; | |
2553 p[2] *= diry * ky; | |
2554 p[5] = +(dirx + diry ? !!+p[5] : !+p[5]); | |
2555 } else if (P0 == "H") { | |
2556 for (j = 1, jj = p[length]; j < jj; j++) { | |
2557 p[j] *= kx; | |
2558 } | |
2559 } else if (P0 == "V") { | |
2560 for (j = 1, jj = p[length]; j < jj; j++) { | |
2561 p[j] *= ky; | |
2562 } | |
2563 } else { | |
2564 for (j = 1, jj = p[length]; j < jj; j++) { | |
2565 p[j] *= (j % 2) ? kx : ky; | |
2566 } | |
2567 } | |
2568 } | |
2569 var dim2 = pathDimensions(path), | |
2570 dx = ncx - dim2.x - dim2.width / 2, | |
2571 dy = ncy - dim2.y - dim2.height / 2; | |
2572 path[0][1] += dx; | |
2573 path[0][2] += dy; | |
2574 this.attr({path: path}); | |
2575 break; | |
2576 } | |
2577 if (this.type in {text: 1, image:1} && (dirx != 1 || diry != 1)) { | |
2578 if (this.transformations) { | |
2579 this.transformations[2] = "scale("[concat](dirx, ",", diry, ")"); | |
2580 this.node[setAttribute]("transform", this.transformations[join](S)); | |
2581 dx = (dirx == -1) ? -a.x - (neww || 0) : a.x; | |
2582 dy = (diry == -1) ? -a.y - (newh || 0) : a.y; | |
2583 this.attr({x: dx, y: dy}); | |
2584 a.fx = dirx - 1; | |
2585 a.fy = diry - 1; | |
2586 } else { | |
2587 this.node.filterMatrix = " progid:DXImageTransform.Microsoft.Matrix(M11="[concat](dirx, | |
2588 ", M12=0, M21=0, M22=", diry, | |
2589 ", Dx=0, Dy=0, sizingmethod='auto expand', filtertype='bilinear')"); | |
2590 s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E); | |
2591 } | |
2592 } else { | |
2593 if (this.transformations) { | |
2594 this.transformations[2] = E; | |
2595 this.node[setAttribute]("transform", this.transformations[join](S)); | |
2596 a.fx = 0; | |
2597 a.fy = 0; | |
2598 } else { | |
2599 this.node.filterMatrix = E; | |
2600 s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E); | |
2601 } | |
2602 } | |
2603 a.scale = [x, y, cx, cy][join](S); | |
2604 this._.sx = x; | |
2605 this._.sy = y; | |
2606 } | |
2607 return this; | |
2608 }; | |
2609 Element[proto].clone = function () { | |
2610 var attr = this.attr(); | |
2611 delete attr.scale; | |
2612 delete attr.translation; | |
2613 return this.paper[this.type]().attr(attr); | |
2614 }; | |
2615 var getLengthFactory = function (istotal, subpath) { | |
2616 return function (path, length, onlystart) { | |
2617 path = path2curve(path); | |
2618 var x, y, p, l, sp = "", subpaths = {}, point, | |
2619 len = 0; | |
2620 for (var i = 0, ii = path.length; i < ii; i++) { | |
2621 p = path[i]; | |
2622 if (p[0] == "M") { | |
2623 x = +p[1]; | |
2624 y = +p[2]; | |
2625 } else { | |
2626 l = segmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); | |
2627 if (len + l > length) { | |
2628 if (subpath && !subpaths.start) { | |
2629 point = R.findDotsAtSegment(x, y, p[1], p[2], p[3], p[4], p[5], p[6], (length - len) / l); | |
2630 sp += ["C", point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; | |
2631 if (onlystart) { | |
2632 return sp; | |
2633 } | |
2634 subpaths.start = sp; | |
2635 sp = ["M", point.x, point.y, "C", point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]][join](); | |
2636 len += l; | |
2637 x = +p[5]; | |
2638 y = +p[6]; | |
2639 continue; | |
2640 } | |
2641 if (!istotal && !subpath) { | |
2642 point = R.findDotsAtSegment(x, y, p[1], p[2], p[3], p[4], p[5], p[6], (length - len) / l); | |
2643 return {x: point.x, y: point.y, alpha: point.alpha}; | |
2644 } | |
2645 } | |
2646 len += l; | |
2647 x = +p[5]; | |
2648 y = +p[6]; | |
2649 } | |
2650 sp += p; | |
2651 } | |
2652 subpaths.end = sp; | |
2653 point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[1], p[2], p[3], p[4], p[5], p[6], 1); | |
2654 point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); | |
2655 return point; | |
2656 }; | |
2657 }, | |
2658 segmentLength = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { | |
2659 var old = {x: 0, y: 0}, | |
2660 len = 0; | |
2661 for (var i = 0; i < 1.01; i+=.01) { | |
2662 var dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i); | |
2663 i && (len += math.sqrt(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2))); | |
2664 old = dot; | |
2665 } | |
2666 return len; | |
2667 }); | |
2668 var getTotalLength = getLengthFactory(1), | |
2669 getPointAtLength = getLengthFactory(), | |
2670 getSubpathsAtLength = getLengthFactory(0, 1); | |
2671 Element[proto].getTotalLength = function () { | |
2672 if (this.type != "path") return; | |
2673 return getTotalLength(this.attrs.path); | |
2674 }; | |
2675 Element[proto].getPointAtLength = function (length) { | |
2676 if (this.type != "path") return; | |
2677 return getPointAtLength(this.attrs.path, length); | |
2678 }; | |
2679 Element[proto].getSubpath = function (from, to) { | |
2680 if (this.type != "path") return; | |
2681 var a = getSubpathsAtLength(this.attrs.path, to, 1); | |
2682 return from ? getSubpathsAtLength(a, from).end : a; | |
2683 }; | |
2684 | |
2685 // animation easing formulas | |
2686 R.easing_formulas = { | |
2687 linear: function (n) { | |
2688 return n; | |
2689 }, | |
2690 "<": function (n) { | |
2691 return pow(n, 3); | |
2692 }, | |
2693 ">": function (n) { | |
2694 return pow(n - 1, 3) + 1; | |
2695 }, | |
2696 "<>": function (n) { | |
2697 n = n * 2; | |
2698 if (n < 1) { | |
2699 return pow(n, 3) / 2; | |
2700 } | |
2701 n -= 2; | |
2702 return (pow(n, 3) + 2) / 2; | |
2703 }, | |
2704 backIn: function (n) { | |
2705 var s = 1.70158; | |
2706 return n * n * ((s + 1) * n - s); | |
2707 }, | |
2708 backOut: function (n) { | |
2709 n = n - 1; | |
2710 var s = 1.70158; | |
2711 return n * n * ((s + 1) * n + s) + 1; | |
2712 }, | |
2713 elastic: function (n) { | |
2714 if (n == 0 || n == 1) { | |
2715 return n; | |
2716 } | |
2717 var p = .3, | |
2718 s = p / 4; | |
2719 return pow(2, -10 * n) * math.sin((n - s) * (2 * math.PI) / p) + 1; | |
2720 }, | |
2721 bounce: function (n) { | |
2722 var s = 7.5625, | |
2723 p = 2.75, | |
2724 l; | |
2725 if (n < (1 / p)) { | |
2726 l = s * n * n; | |
2727 } else { | |
2728 if (n < (2 / p)) { | |
2729 n -= (1.5 / p); | |
2730 l = s * n * n + .75; | |
2731 } else { | |
2732 if (n < (2.5 / p)) { | |
2733 n -= (2.25 / p); | |
2734 l = s * n * n + .9375; | |
2735 } else { | |
2736 n -= (2.625 / p); | |
2737 l = s * n * n + .984375; | |
2738 } | |
2739 } | |
2740 } | |
2741 return l; | |
2742 } | |
2743 }; | |
2744 | |
2745 var animationElements = {length : 0}, | |
2746 animation = function () { | |
2747 var Now = +new Date; | |
2748 for (var l in animationElements) if (l != "length" && animationElements[has](l)) { | |
2749 var e = animationElements[l]; | |
2750 if (e.stop) { | |
2751 delete animationElements[l]; | |
2752 animationElements[length]--; | |
2753 continue; | |
2754 } | |
2755 var time = Now - e.start, | |
2756 ms = e.ms, | |
2757 easing = e.easing, | |
2758 from = e.from, | |
2759 diff = e.diff, | |
2760 to = e.to, | |
2761 t = e.t, | |
2762 prev = e.prev || 0, | |
2763 that = e.el, | |
2764 callback = e.callback, | |
2765 set = {}, | |
2766 now; | |
2767 if (time < ms) { | |
2768 var pos = R.easing_formulas[easing] ? R.easing_formulas[easing](time / ms) : time / ms; | |
2769 for (var attr in from) if (from[has](attr)) { | |
2770 switch (availableAnimAttrs[attr]) { | |
2771 case "along": | |
2772 now = pos * ms * diff[attr]; | |
2773 to.back && (now = to.len - now); | |
2774 var point = getPointAtLength(to[attr], now); | |
2775 that.translate(diff.sx - diff.x || 0, diff.sy - diff.y || 0); | |
2776 diff.x = point.x; | |
2777 diff.y = point.y; | |
2778 that.translate(point.x - diff.sx, point.y - diff.sy); | |
2779 to.rot && that.rotate(diff.r + point.alpha, point.x, point.y); | |
2780 break; | |
2781 case "number": | |
2782 now = +from[attr] + pos * ms * diff[attr]; | |
2783 break; | |
2784 case "colour": | |
2785 now = "rgb(" + [ | |
2786 upto255(round(from[attr].r + pos * ms * diff[attr].r)), | |
2787 upto255(round(from[attr].g + pos * ms * diff[attr].g)), | |
2788 upto255(round(from[attr].b + pos * ms * diff[attr].b)) | |
2789 ][join](",") + ")"; | |
2790 break; | |
2791 case "path": | |
2792 now = []; | |
2793 for (var i = 0, ii = from[attr][length]; i < ii; i++) { | |
2794 now[i] = [from[attr][i][0]]; | |
2795 for (var j = 1, jj = from[attr][i][length]; j < jj; j++) { | |
2796 now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; | |
2797 } | |
2798 now[i] = now[i][join](S); | |
2799 } | |
2800 now = now[join](S); | |
2801 break; | |
2802 case "csv": | |
2803 switch (attr) { | |
2804 case "translation": | |
2805 var x = diff[attr][0] * (time - prev), | |
2806 y = diff[attr][1] * (time - prev); | |
2807 t.x += x; | |
2808 t.y += y; | |
2809 now = x + S + y; | |
2810 break; | |
2811 case "rotation": | |
2812 now = +from[attr][0] + pos * ms * diff[attr][0]; | |
2813 from[attr][1] && (now += "," + from[attr][1] + "," + from[attr][2]); | |
2814 break; | |
2815 case "scale": | |
2816 now = [+from[attr][0] + pos * ms * diff[attr][0], +from[attr][1] + pos * ms * diff[attr][1], (2 in to[attr] ? to[attr][2] : E), (3 in to[attr] ? to[attr][3] : E)][join](S); | |
2817 break; | |
2818 case "clip-rect": | |
2819 now = []; | |
2820 var i = 4; | |
2821 while (i--) { | |
2822 now[i] = +from[attr][i] + pos * ms * diff[attr][i]; | |
2823 } | |
2824 break; | |
2825 } | |
2826 break; | |
2827 } | |
2828 set[attr] = now; | |
2829 } | |
2830 that.attr(set); | |
2831 that._run && that._run.call(that); | |
2832 } else { | |
2833 if (to.along) { | |
2834 var point = getPointAtLength(to.along, to.len * !to.back); | |
2835 that.translate(diff.sx - (diff.x || 0) + point.x - diff.sx, diff.sy - (diff.y || 0) + point.y - diff.sy); | |
2836 to.rot && that.rotate(diff.r + point.alpha, point.x, point.y); | |
2837 } | |
2838 (t.x || t.y) && that.translate(-t.x, -t.y); | |
2839 to.scale && (to.scale = to.scale + E); | |
2840 that.attr(to); | |
2841 delete animationElements[l]; | |
2842 animationElements[length]--; | |
2843 that.in_animation = null; | |
2844 R.is(callback, "function") && callback.call(that); | |
2845 } | |
2846 e.prev = time; | |
2847 } | |
2848 R.svg && that && that.paper.safari(); | |
2849 animationElements[length] && setTimeout(animation); | |
2850 }, | |
2851 upto255 = function (color) { | |
2852 return color > 255 ? 255 : (color < 0 ? 0 : color); | |
2853 }, | |
2854 translate = function (x, y) { | |
2855 if (x == null) { | |
2856 return {x: this._.tx, y: this._.ty, toString: x_y}; | |
2857 } | |
2858 this._.tx += +x; | |
2859 this._.ty += +y; | |
2860 switch (this.type) { | |
2861 case "circle": | |
2862 case "ellipse": | |
2863 this.attr({cx: +x + this.attrs.cx, cy: +y + this.attrs.cy}); | |
2864 break; | |
2865 case "rect": | |
2866 case "image": | |
2867 case "text": | |
2868 this.attr({x: +x + this.attrs.x, y: +y + this.attrs.y}); | |
2869 break; | |
2870 case "path": | |
2871 var path = pathToRelative(this.attrs.path); | |
2872 path[0][1] += +x; | |
2873 path[0][2] += +y; | |
2874 this.attr({path: path}); | |
2875 break; | |
2876 } | |
2877 return this; | |
2878 }; | |
2879 Element[proto].animateWith = function (element, params, ms, easing, callback) { | |
2880 animationElements[element.id] && (params.start = animationElements[element.id].start); | |
2881 return this.animate(params, ms, easing, callback); | |
2882 }; | |
2883 Element[proto].animateAlong = along(); | |
2884 Element[proto].animateAlongBack = along(1); | |
2885 function along(isBack) { | |
2886 return function (path, ms, rotate, callback) { | |
2887 var params = {back: isBack}; | |
2888 R.is(rotate, "function") ? (callback = rotate) : (params.rot = rotate); | |
2889 path && path.constructor == Element && (path = path.attrs.path); | |
2890 path && (params.along = path); | |
2891 return this.animate(params, ms, callback); | |
2892 }; | |
2893 } | |
2894 Element[proto].onAnimation = function (f) { | |
2895 this._run = f || 0; | |
2896 return this; | |
2897 }; | |
2898 Element[proto].animate = function (params, ms, easing, callback) { | |
2899 if (R.is(easing, "function") || !easing) { | |
2900 callback = easing || null; | |
2901 } | |
2902 var from = {}, | |
2903 to = {}, | |
2904 diff = {}; | |
2905 for (var attr in params) if (params[has](attr)) { | |
2906 if (availableAnimAttrs[has](attr)) { | |
2907 from[attr] = this.attr(attr); | |
2908 (from[attr] == null) && (from[attr] = availableAttrs[attr]); | |
2909 to[attr] = params[attr]; | |
2910 switch (availableAnimAttrs[attr]) { | |
2911 case "along": | |
2912 var len = getTotalLength(params[attr]), | |
2913 point = getPointAtLength(params[attr], len * !!params.back), | |
2914 bb = this.getBBox(); | |
2915 diff[attr] = len / ms; | |
2916 diff.tx = bb.x; | |
2917 diff.ty = bb.y; | |
2918 diff.sx = point.x; | |
2919 diff.sy = point.y; | |
2920 to.rot = params.rot; | |
2921 to.back = params.back; | |
2922 to.len = len; | |
2923 params.rot && (diff.r = toFloat(this.rotate()) || 0); | |
2924 break; | |
2925 case "number": | |
2926 diff[attr] = (to[attr] - from[attr]) / ms; | |
2927 break; | |
2928 case "colour": | |
2929 from[attr] = R.getRGB(from[attr]); | |
2930 var toColour = R.getRGB(to[attr]); | |
2931 diff[attr] = { | |
2932 r: (toColour.r - from[attr].r) / ms, | |
2933 g: (toColour.g - from[attr].g) / ms, | |
2934 b: (toColour.b - from[attr].b) / ms | |
2935 }; | |
2936 break; | |
2937 case "path": | |
2938 var pathes = path2curve(from[attr], to[attr]); | |
2939 from[attr] = pathes[0]; | |
2940 var toPath = pathes[1]; | |
2941 diff[attr] = []; | |
2942 for (var i = 0, ii = from[attr][length]; i < ii; i++) { | |
2943 diff[attr][i] = [0]; | |
2944 for (var j = 1, jj = from[attr][i][length]; j < jj; j++) { | |
2945 diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; | |
2946 } | |
2947 } | |
2948 break; | |
2949 case "csv": | |
2950 var values = (params[attr] + E)[split](separator), | |
2951 from2 = (from[attr] + E)[split](separator); | |
2952 switch (attr) { | |
2953 case "translation": | |
2954 from[attr] = [0, 0]; | |
2955 diff[attr] = [values[0] / ms, values[1] / ms]; | |
2956 break; | |
2957 case "rotation": | |
2958 from[attr] = (from2[1] == values[1] && from2[2] == values[2]) ? from2 : [0, values[1], values[2]]; | |
2959 diff[attr] = [(values[0] - from[attr][0]) / ms, 0, 0]; | |
2960 break; | |
2961 case "scale": | |
2962 params[attr] = values; | |
2963 from[attr] = (from[attr] + E)[split](separator); | |
2964 diff[attr] = [(values[0] - from[attr][0]) / ms, (values[1] - from[attr][1]) / ms, 0, 0]; | |
2965 break; | |
2966 case "clip-rect": | |
2967 from[attr] = (from[attr] + E)[split](separator); | |
2968 diff[attr] = []; | |
2969 var i = 4; | |
2970 while (i--) { | |
2971 diff[attr][i] = (values[i] - from[attr][i]) / ms; | |
2972 } | |
2973 break; | |
2974 } | |
2975 to[attr] = values; | |
2976 } | |
2977 } | |
2978 } | |
2979 this.stop(); | |
2980 this.in_animation = 1; | |
2981 animationElements[this.id] = { | |
2982 start: params.start || +new Date, | |
2983 ms: ms, | |
2984 easing: easing, | |
2985 from: from, | |
2986 diff: diff, | |
2987 to: to, | |
2988 el: this, | |
2989 callback: callback, | |
2990 t: {x: 0, y: 0} | |
2991 }; | |
2992 ++animationElements[length] == 1 && animation(); | |
2993 return this; | |
2994 }; | |
2995 Element[proto].stop = function () { | |
2996 animationElements[this.id] && animationElements[length]--; | |
2997 delete animationElements[this.id]; | |
2998 return this; | |
2999 }; | |
3000 Element[proto].translate = function (x, y) { | |
3001 return this.attr({translation: x + " " + y}); | |
3002 }; | |
3003 Element[proto][toString] = function () { | |
3004 return "Rapha\xebl\u2019s object"; | |
3005 }; | |
3006 R.ae = animationElements; | |
3007 | |
3008 // Set | |
3009 var Set = function (items) { | |
3010 this.items = []; | |
3011 this[length] = 0; | |
3012 if (items) { | |
3013 for (var i = 0, ii = items[length]; i < ii; i++) { | |
3014 if (items[i] && (items[i].constructor == Element || items[i].constructor == Set)) { | |
3015 this[this.items[length]] = this.items[this.items[length]] = items[i]; | |
3016 this[length]++; | |
3017 } | |
3018 } | |
3019 } | |
3020 }; | |
3021 Set[proto][push] = function () { | |
3022 var item, | |
3023 len; | |
3024 for (var i = 0, ii = arguments[length]; i < ii; i++) { | |
3025 item = arguments[i]; | |
3026 if (item && (item.constructor == Element || item.constructor == Set)) { | |
3027 len = this.items[length]; | |
3028 this[len] = this.items[len] = item; | |
3029 this[length]++; | |
3030 } | |
3031 } | |
3032 return this; | |
3033 }; | |
3034 Set[proto].pop = function () { | |
3035 delete this[this[length]--]; | |
3036 return this.items.pop(); | |
3037 }; | |
3038 for (var method in Element[proto]) if (Element[proto][has](method)) { | |
3039 Set[proto][method] = (function (methodname) { | |
3040 return function () { | |
3041 for (var i = 0, ii = this.items[length]; i < ii; i++) { | |
3042 this.items[i][methodname][apply](this.items[i], arguments); | |
3043 } | |
3044 return this; | |
3045 }; | |
3046 })(method); | |
3047 } | |
3048 Set[proto].attr = function (name, value) { | |
3049 if (name && R.is(name, "array") && R.is(name[0], "object")) { | |
3050 for (var j = 0, jj = name[length]; j < jj; j++) { | |
3051 this.items[j].attr(name[j]); | |
3052 } | |
3053 } else { | |
3054 for (var i = 0, ii = this.items[length]; i < ii; i++) { | |
3055 this.items[i].attr[apply](this.items[i], arguments); | |
3056 } | |
3057 } | |
3058 return this; | |
3059 }; | |
3060 Set[proto].animate = function (params, ms, easing, callback) { | |
3061 (R.is(easing, "function") || !easing) && (callback = easing || null); | |
3062 var len = this.items[length], | |
3063 i = len, | |
3064 set = this, | |
3065 collector; | |
3066 callback && (collector = function () { | |
3067 !--len && callback.call(set); | |
3068 }); | |
3069 this.items[--i].animate(params, ms, easing || collector, collector); | |
3070 while (i--) { | |
3071 this.items[i].animateWith(this.items[len - 1], params, ms, easing || collector, collector); | |
3072 } | |
3073 return this; | |
3074 }; | |
3075 Set[proto].insertAfter = function (el) { | |
3076 var i = this.items[length]; | |
3077 while (i--) { | |
3078 this.items[i].insertAfter(el); | |
3079 } | |
3080 return this; | |
3081 }; | |
3082 Set[proto].getBBox = function () { | |
3083 var x = [], | |
3084 y = [], | |
3085 w = [], | |
3086 h = []; | |
3087 for (var i = this.items[length]; i--;) { | |
3088 var box = this.items[i].getBBox(); | |
3089 x[push](box.x); | |
3090 y[push](box.y); | |
3091 w[push](box.x + box.width); | |
3092 h[push](box.y + box.height); | |
3093 } | |
3094 x = mmin[apply](0, x); | |
3095 y = mmin[apply](0, y); | |
3096 return { | |
3097 x: x, | |
3098 y: y, | |
3099 width: mmax[apply](0, w) - x, | |
3100 height: mmax[apply](0, h) - y | |
3101 }; | |
3102 }; | |
3103 | |
3104 R.registerFont = function (font) { | |
3105 if (!font.face) { | |
3106 return font; | |
3107 } | |
3108 this.fonts = this.fonts || {}; | |
3109 var fontcopy = { | |
3110 w: font.w, | |
3111 face: {}, | |
3112 glyphs: {} | |
3113 }, | |
3114 family = font.face["font-family"]; | |
3115 for (var prop in font.face) if (font.face[has](prop)) { | |
3116 fontcopy.face[prop] = font.face[prop]; | |
3117 } | |
3118 if (this.fonts[family]) { | |
3119 this.fonts[family][push](fontcopy); | |
3120 } else { | |
3121 this.fonts[family] = [fontcopy]; | |
3122 } | |
3123 if (!font.svg) { | |
3124 fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); | |
3125 for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { | |
3126 var path = font.glyphs[glyph]; | |
3127 fontcopy.glyphs[glyph] = { | |
3128 w: path.w, | |
3129 k: {}, | |
3130 d: path.d && "M" + path.d[rp](/[mlcxtrv]/g, function (command) { | |
3131 return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; | |
3132 }) + "z" | |
3133 }; | |
3134 if (path.k) { | |
3135 for (var k in path.k) if (path[has](k)) { | |
3136 fontcopy.glyphs[glyph].k[k] = path.k[k]; | |
3137 } | |
3138 } | |
3139 } | |
3140 } | |
3141 return font; | |
3142 }; | |
3143 Paper[proto].getFont = function (family, weight, style, stretch) { | |
3144 stretch = stretch || "normal"; | |
3145 style = style || "normal"; | |
3146 weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; | |
3147 var font = R.fonts[family]; | |
3148 if (!font) { | |
3149 var name = new RegExp("(^|\\s)" + family[rp](/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); | |
3150 for (var fontName in R.fonts) if (R.fonts[has](fontName)) { | |
3151 if (name.test(fontName)) { | |
3152 font = R.fonts[fontName]; | |
3153 break; | |
3154 } | |
3155 } | |
3156 } | |
3157 var thefont; | |
3158 if (font) { | |
3159 for (var i = 0, ii = font[length]; i < ii; i++) { | |
3160 thefont = font[i]; | |
3161 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { | |
3162 break; | |
3163 } | |
3164 } | |
3165 } | |
3166 return thefont; | |
3167 }; | |
3168 Paper[proto].print = function (x, y, string, font, size, origin) { | |
3169 origin = origin || "middle"; // baseline|middle | |
3170 var out = this.set(), | |
3171 letters = (string + E)[split](E), | |
3172 shift = 0, | |
3173 path = E, | |
3174 scale; | |
3175 R.is(font, "string") && (font = this.getFont(font)); | |
3176 if (font) { | |
3177 scale = (size || 16) / font.face["units-per-em"]; | |
3178 var bb = font.face.bbox.split(separator), | |
3179 top = +bb[0], | |
3180 height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2); | |
3181 for (var i = 0, ii = letters[length]; i < ii; i++) { | |
3182 var prev = i && font.glyphs[letters[i - 1]] || {}, | |
3183 curr = font.glyphs[letters[i]]; | |
3184 shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) : 0; | |
3185 curr && curr.d && out[push](this.path(curr.d).attr({fill: "#000", stroke: "none", translation: [shift, 0]})); | |
3186 } | |
3187 out.scale(scale, scale, top, height).translate(x - top, y - height); | |
3188 } | |
3189 return out; | |
3190 }; | |
3191 | |
3192 R.format = function (token) { | |
3193 var args = R.is(arguments[1], "array") ? [0][concat](arguments[1]) : arguments, | |
3194 rg = /\{(\d+)\}/g; | |
3195 token && R.is(token, "string") && args[length] - 1 && (token = token[rp](rg, function (str, i) { | |
3196 return args[++i] == null ? E : args[i]; | |
3197 })); | |
3198 return token || E; | |
3199 }; | |
3200 R.ninja = function () { | |
3201 var r = win.Raphael, u; | |
3202 if (oldRaphael.was) { | |
3203 win.Raphael = oldRaphael.is; | |
3204 } else { | |
3205 try { | |
3206 delete win.Raphael; | |
3207 } catch (e) { | |
3208 win.Raphael = u; | |
3209 } | |
3210 } | |
3211 return r; | |
3212 }; | |
3213 R.el = Element[proto]; | |
3214 return R; | |
3215 })(); |