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