1/* 2 * Raphaël 2.0.0 - JavaScript Vector Library 3 * 4 * Copyright (c) 2011 Dmitry Baranovskiy (http://raphaeljs.com) 5 * Copyright (c) 2011 Sencha Labs (http://sencha.com) 6 * Licensed under the MIT (http://raphaeljs.com/license.html) license. 7 */ 8(function () { 9 /*\ 10 * Raphael 11 [ method ] 12 ** 13 * Creates a canvas object on which to draw. 14 * You must do this first, as all future calls to drawing methods 15 * from this instance will be bound to this canvas. 16 > Parameters 17 ** 18 - container (HTMLElement|string) DOM element or it’s id which is going to be a parent for drawing surface 19 - width (number) 20 - height (number) 21 * or 22 - x (number) 23 - y (number) 24 - width (number) 25 - height (number) 26 * or 27 - all (array) (first 3 or 4 elements in the array are equal to [containerID, width, height] or [x, y, width, height]. The rest are element descriptions in format {type: type, <attributes>}) 28 * or 29 - onReadyCallback (function) function that is going to be called on DOM ready event. You can also subscribe to this event via Eve’s “DOMLoad” event. In this case method returns `undefined`. 30 = (object) @Paper 31 > Usage 32 | // Each of the following examples create a canvas that is 320px wide by 200px high 33 | // Canvas is created at the viewport’s 10,50 coordinate 34 | var paper = Raphael(10, 50, 320, 200); 35 | // Canvas is created at the top left corner of the #notepad element 36 | // (or its top right corner in dir="rtl" elements) 37 | var paper = Raphael(document.getElementById("notepad"), 320, 200); 38 | // Same as above 39 | var paper = Raphael("notepad", 320, 200); 40 | // Image dump 41 | var set = Raphael(["notepad", 320, 200, { 42 | type: "rect", 43 | x: 10, 44 | y: 10, 45 | width: 25, 46 | height: 25, 47 | stroke: "#f00" 48 | }, { 49 | type: "text", 50 | x: 30, 51 | y: 40, 52 | text: "Dump" 53 | }]); 54 \*/ 55 function R(first) { 56 if (R.is(first, "function")) { 57 return eve.on("DOMload", first); 58 } else if (R.is(first, array)) { 59 var a = first, 60 cnv = create[apply](R, a.splice(0, 3 + R.is(a[0], nu))), 61 res = cnv.set(), 62 i = 0, 63 ii = a.length, 64 j; 65 for (; i < ii; i++) { 66 j = a[i] || {}; 67 elements[has](j.type) && res.push(cnv[j.type]().attr(j)); 68 } 69 return res; 70 } 71 return create[apply](R, arguments); 72 } 73 R.version = "2.0.0"; 74 var separator = /[, ]+/, 75 elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1}, 76 formatrg = /\{(\d+)\}/g, 77 proto = "prototype", 78 has = "hasOwnProperty", 79 g = { 80 doc: document, 81 win: window 82 }, 83 oldRaphael = { 84 was: Object.prototype[has].call(g.win, "Raphael"), 85 is: g.win.Raphael 86 }, 87 Paper = function () {}, 88 paperproto, 89 appendChild = "appendChild", 90 apply = "apply", 91 concat = "concat", 92 supportsTouch = "createTouch" in g.doc, 93 E = "", 94 S = " ", 95 Str = String, 96 split = "split", 97 events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend orientationchange touchcancel gesturestart gesturechange gestureend".split(S), 98 touchMap = { 99 mousedown: "touchstart", 100 mousemove: "touchmove", 101 mouseup: "touchend" 102 }, 103 lowerCase = Str.prototype.toLowerCase, 104 math = Math, 105 mmax = math.max, 106 mmin = math.min, 107 abs = math.abs, 108 pow = math.pow, 109 PI = math.PI, 110 nu = "number", 111 string = "string", 112 array = "array", 113 toString = "toString", 114 fillString = "fill", 115 objectToString = Object.prototype.toString, 116 paper = {}, 117 push = "push", 118 ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, 119 colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i, 120 isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1}, 121 bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, 122 round = math.round, 123 setAttribute = "setAttribute", 124 toFloat = parseFloat, 125 toInt = parseInt, 126 ms = " progid:DXImageTransform.Microsoft", 127 upperCase = Str.prototype.toUpperCase, 128 availableAttrs = {"arrow-end": "none", "arrow-start": "none", blur: 0, "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, rx: 0, ry: 0, 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", transform: "", width: 0, x: 0, y: 0}, 129 availableAnimAttrs = {blur: nu, "clip-rect": "csv", cx: nu, cy: nu, fill: "colour", "fill-opacity": nu, "font-size": nu, height: nu, opacity: nu, path: "path", r: nu, rx: nu, ry: nu, stroke: "colour", "stroke-opacity": nu, "stroke-width": nu, transform: "transform", width: nu, x: nu, y: nu}, 130 commaSpaces = /\s*,\s*/, 131 hsrg = {hs: 1, rg: 1}, 132 p2s = /,?([achlmqrstvxz]),?/gi, 133 pathCommand = /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig, 134 tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig, 135 pathValues = /(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig, 136 radial_gradient = /^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/, 137 sortByKey = function (a, b) { 138 return a.key - b.key; 139 }, 140 sortByNumber = function (a, b) { 141 return a - b; 142 }, 143 fun = function () {}, 144 pipe = function (x) { 145 return x; 146 }, 147 rectPath = function (x, y, w, h, r) { 148 if (r) { 149 return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]]; 150 } 151 return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; 152 }, 153 ellipsePath = function (x, y, rx, ry) { 154 if (ry == null) { 155 ry = rx; 156 } 157 return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]]; 158 }, 159 getPath = { 160 path: function (el) { 161 return el.attr("path"); 162 }, 163 circle: function (el) { 164 var a = el.attrs; 165 return ellipsePath(a.cx, a.cy, a.r); 166 }, 167 ellipse: function (el) { 168 var a = el.attrs; 169 return ellipsePath(a.cx, a.cy, a.rx, a.ry); 170 }, 171 rect: function (el) { 172 var a = el.attrs; 173 return rectPath(a.x, a.y, a.width, a.height, a.r); 174 }, 175 image: function (el) { 176 var a = el.attrs; 177 return rectPath(a.x, a.y, a.width, a.height); 178 }, 179 text: function (el) { 180 var bbox = el._getBBox(); 181 return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); 182 } 183 }, 184 mapPath = function (path, matrix) { 185 if (!matrix) { 186 return path; 187 } 188 var x, y, i, j, pathi; 189 path = path2curve(path); 190 for (i = 0, ii = path.length; i < ii; i++) { 191 pathi = path[i]; 192 for (j = 1, jj = pathi.length; j < jj; j += 2) { 193 x = matrix.x(pathi[j], pathi[j + 1]); 194 y = matrix.y(pathi[j], pathi[j + 1]); 195 pathi[j] = x; 196 pathi[j + 1] = y; 197 } 198 } 199 return path; 200 }; 201 202 /*\ 203 * Raphael.type 204 [ property (string) ] 205 ** 206 * Can be “SVG”, “VML” or empty, depending on browser support. 207 \*/ 208 R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); 209 if (R.type == "VML") { 210 var d = g.doc.createElement("div"), 211 b; 212 d.innerHTML = '<v:shape adj="1"/>'; 213 b = d.firstChild; 214 b.style.behavior = "url(#default#VML)"; 215 if (!(b && typeof b.adj == "object")) { 216 return R.type = E; 217 } 218 d = null; 219 } 220 /*\ 221 * Raphael.svg 222 [ property (boolean) ] 223 ** 224 * `true` if browser supports SVG. 225 \*/ 226 /*\ 227 * Raphael.vml 228 [ property (boolean) ] 229 ** 230 * `true` if browser supports VML. 231 \*/ 232 R.svg = !(R.vml = R.type == "VML"); 233 paperproto = Paper.prototype = R.prototype; 234 /*\ 235 * Paper.customAttributes 236 [ property (object) ] 237 ** 238 * If you have a set of attributes that you would like to represent 239 * as a function of some number you can do it easily with custom attributes: 240 > Usage 241 | paper.customAttributes.hue = function (num) { 242 | num = num % 1; 243 | return {fill: "hsb(" + num + ", .75, 1)"}; 244 | }; 245 | // Custom attribute “hue” will change fill 246 | // to be given hue with fixed saturation and brightness. 247 | // Now you can use it like this: 248 | var c = paper.circle(10, 10, 10).attr({hue: .45}); 249 | // or even like this: 250 | c.animate({hue: 1}, 1e3); 251 | 252 | // You could also create custom attribute 253 | // with multiple parameters: 254 | paper.customAttributes.hsb = function (h, s, b) { 255 | return {fill: "hsb(" + [h, s, b].join(",") + ")"}; 256 | }; 257 | c.attr({hsb: ".5 .8 1"}); 258 | c.animate({hsb: "1 0 .5"}, 1e3); 259 \*/ 260 paperproto.customAttributes = {}; 261 R._id = 0; 262 R._oid = 0; 263 /*\ 264 * Raphael.fn 265 [ property (object) ] 266 ** 267 * You can add your own method to the canvas. For example if you want to draw pie chart, 268 * you can create your own pie chart function and ship it as a Raphaël plugin. To do this 269 * you need to extend `Raphael.fn` object. Please note that you can create your own namespaces 270 * inside `fn` object. Methods will be run in context of canvas anyway. You should alter `fn` 271 * object before Raphaël instance was created, otherwise it will take no effect. 272 > Usage 273 | Raphael.fn.arrow = function (x1, y1, x2, y2, size) { 274 | return this.path( ... ); 275 | }; 276 | // or create namespace 277 | Raphael.fn.mystuff = { 278 | arrow: function () {…}, 279 | star: function () {…}, 280 | // etc… 281 | }; 282 | var paper = Raphael(10, 10, 630, 480); 283 | // then use it 284 | paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"}); 285 | paper.mystuff.arrow(); 286 | paper.mystuff.star(); 287 \*/ 288 R.fn = {}; 289 /*\ 290 * Raphael.is 291 [ method ] 292 ** 293 * Handfull replacement for `typeof` operator. 294 > Parameters 295 - o (…) any object or primitive 296 - type (string) name of the type, i.e. “string”, “function”, “number”, etc. 297 = (boolean) is given value is of given type 298 \*/ 299 R.is = function (o, type) { 300 type = lowerCase.call(type); 301 if (type == "finite") { 302 return !isnan[has](+o); 303 } 304 return (type == "null" && o === null) || 305 (type == typeof o) || 306 (type == "object" && o === Object(o)) || 307 (type == "array" && Array.isArray && Array.isArray(o)) || 308 objectToString.call(o).slice(8, -1).toLowerCase() == type; 309 }; 310 /*\ 311 * Raphael.angle 312 [ method ] 313 ** 314 * Returns angle between two or three points 315 > Parameters 316 - x1 (number) x coord of first point 317 - y1 (number) y coord of first point 318 - x2 (number) x coord of second point 319 - y2 (number) y coord of second point 320 - x3 (number) #optional x coord of third point 321 - y3 (number) #optional y coord of third point 322 = (number) angle in degrees. 323 \*/ 324 R.angle = function (x1, y1, x2, y2, x3, y3) { 325 if (x3 == null) { 326 var x = x1 - x2, 327 y = y1 - y2; 328 if (!x && !y) { 329 return 0; 330 } 331 return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; 332 } else { 333 return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3); 334 } 335 }; 336 /*\ 337 * Raphael.rad 338 [ method ] 339 ** 340 * Transform angle to radians 341 > Parameters 342 - deg (number) angle in degrees 343 = (number) angle in radians. 344 \*/ 345 R.rad = function (deg) { 346 return deg % 360 * PI / 180; 347 }; 348 /*\ 349 * Raphael.deg 350 [ method ] 351 ** 352 * Transform angle to degrees 353 > Parameters 354 - deg (number) angle in radians 355 = (number) angle in degrees. 356 \*/ 357 R.deg = function (rad) { 358 return rad * 180 / PI % 360; 359 }; 360 /*\ 361 * Raphael.snapTo 362 [ method ] 363 ** 364 * Snaps given value to given grid. 365 > Parameters 366 - values (array|number) given array of values or step of the grid 367 - value (number) value to adjust 368 - tolerance (number) #optional tolerance for snapping. Default is `10`. 369 = (number) adjusted value. 370 \*/ 371 R.snapTo = function (values, value, tolerance) { 372 tolerance = R.is(tolerance, "finite") ? tolerance : 10; 373 if (R.is(values, array)) { 374 var i = values.length; 375 while (i--) if (abs(values[i] - value) <= tolerance) { 376 return values[i]; 377 } 378 } else { 379 values = +values; 380 var rem = value % values; 381 if (rem < tolerance) { 382 return value - rem; 383 } 384 if (rem > values - tolerance) { 385 return value - rem + values; 386 } 387 } 388 return value; 389 }; 390 391 var createUUID = (function (uuidRegEx, uuidReplacer) { 392 return function () { 393 return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); 394 }; 395 })(/[xy]/g, function (c) { 396 var r = math.random() * 16 | 0, 397 v = c == "x" ? r : (r & 3 | 8); 398 return v.toString(16); 399 }); 400 401 /*\ 402 * Raphael.setWindow 403 [ method ] 404 ** 405 * Used when you need to draw in `<iframe>`. Switched window to the iframe one. 406 > Parameters 407 - newwin (window) new window object 408 \*/ 409 R.setWindow = function (newwin) { 410 eve("setWindow", R, g.win, newwin); 411 g.win = newwin; 412 g.doc = g.win.document; 413 if (initWin) { 414 initWin(g.win); 415 } 416 }; 417 // colour utilities 418 var toHex = function (color) { 419 if (R.vml) { 420 // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ 421 var trim = /^\s+|\s+$/g; 422 var bod; 423 try { 424 var docum = new ActiveXObject("htmlfile"); 425 docum.write("<body>"); 426 docum.close(); 427 bod = docum.body; 428 } catch(e) { 429 bod = createPopup().document.body; 430 } 431 var range = bod.createTextRange(); 432 toHex = cacher(function (color) { 433 try { 434 bod.style.color = Str(color).replace(trim, E); 435 var value = range.queryCommandValue("ForeColor"); 436 value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); 437 return "#" + ("000000" + value.toString(16)).slice(-6); 438 } catch(e) { 439 return "none"; 440 } 441 }); 442 } else { 443 var i = g.doc.createElement("i"); 444 i.title = "Rapha\xebl Colour Picker"; 445 i.style.display = "none"; 446 g.doc.body.appendChild(i); 447 toHex = cacher(function (color) { 448 i.style.color = color; 449 return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); 450 }); 451 } 452 return toHex(color); 453 }, 454 hsbtoString = function () { 455 return "hsb(" + [this.h, this.s, this.b] + ")"; 456 }, 457 hsltoString = function () { 458 return "hsl(" + [this.h, this.s, this.l] + ")"; 459 }, 460 rgbtoString = function () { 461 return this.hex; 462 }, 463 prepareRGB = function (r, g, b) { 464 if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) { 465 b = r.b; 466 g = r.g; 467 r = r.r; 468 } 469 if (g == null && R.is(r, string)) { 470 var clr = R.getRGB(r); 471 r = clr.r; 472 g = clr.g; 473 b = clr.b; 474 } 475 if (r > 1 || g > 1 || b > 1) { 476 r /= 255; 477 g /= 255; 478 b /= 255; 479 } 480 481 return [r, g, b]; 482 }, 483 packageRGB = function (r, g, b, o) { 484 r *= 255; 485 g *= 255; 486 b *= 255; 487 var rgb = { 488 r: r, 489 g: g, 490 b: b, 491 hex: R.rgb(r, g, b), 492 toString: rgbtoString 493 }; 494 R.is(o, "finite") && (rgb.opacity = o); 495 return rgb; 496 }; 497 /*\ 498 * Raphael.hsb2rgb 499 [ method ] 500 ** 501 * Converts HSB values to RGB object. 502 > Parameters 503 - h (number) hue 504 - s (number) saturation 505 - v (number) value or brightness 506 = (object) RGB object in format: 507 o { 508 o r (number) red, 509 o g (number) green, 510 o b (number) blue, 511 o hex (string) color in HTML/CSS format: #•••••• 512 o } 513 \*/ 514 R.hsb2rgb = function (h, s, v, o) { 515 if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { 516 v = h.b; 517 s = h.s; 518 h = h.h; 519 o = h.o; 520 } 521 h *= 360; 522 var R, G, B, X, C; 523 h = (h % 360) / 60; 524 C = v * s; 525 X = C * (1 - abs(h % 2 - 1)); 526 R = G = B = v - C; 527 528 h = ~~h; 529 R += [C, X, 0, 0, X, C][h]; 530 G += [X, C, C, X, 0, 0][h]; 531 B += [0, 0, X, C, C, X][h]; 532 return packageRGB(R, G, B, o); 533 }; 534 /*\ 535 * Raphael.hsl2rgb 536 [ method ] 537 ** 538 * Converts HSL values to RGB object. 539 > Parameters 540 - h (number) hue 541 - s (number) saturation 542 - l (number) luminosity 543 = (object) RGB object in format: 544 o { 545 o r (number) red, 546 o g (number) green, 547 o b (number) blue, 548 o hex (string) color in HTML/CSS format: #•••••• 549 o } 550 \*/ 551 R.hsl2rgb = function (h, s, l, o) { 552 if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) { 553 l = h.l; 554 s = h.s; 555 h = h.h; 556 } 557 if (h > 1 || s > 1 || l > 1) { 558 h /= 360; 559 s /= 100; 560 l /= 100; 561 } 562 h *= 360; 563 var R, G, B, X, C; 564 h = (h % 360) / 60; 565 C = 2 * s * (l < .5 ? l : 1 - l); 566 X = C * (1 - abs(h % 2 - 1)); 567 R = G = B = l - C / 2; 568 569 h = ~~h; 570 R += [C, X, 0, 0, X, C][h]; 571 G += [X, C, C, X, 0, 0][h]; 572 B += [0, 0, X, C, C, X][h]; 573 return packageRGB(R, G, B, o); 574 }; 575 /*\ 576 * Raphael.rgb2hsb 577 [ method ] 578 ** 579 * Converts RGB values to HSB object. 580 > Parameters 581 - r (number) red 582 - g (number) green 583 - b (number) blue 584 = (object) HSB object in format: 585 o { 586 o h (number) hue 587 o s (number) saturation 588 o b (number) brightness 589 o } 590 \*/ 591 R.rgb2hsb = function (r, g, b) { 592 b = prepareRGB(r, g, b); 593 r = b[0]; 594 g = b[1]; 595 b = b[2]; 596 597 var H, S, V, C; 598 V = mmax(r, g, b); 599 C = V - mmin(r, g, b); 600 H = (C == 0 ? null : 601 V == r ? (g - b) / C : 602 V == g ? (b - r) / C + 2 : 603 (r - g) / C + 4); 604 H = (H % 6) * 60; 605 S = C == 0 ? 0 : C / V; 606 return {h: H, s: S, b: V, toString: hsbtoString}; 607 }; 608 /*\ 609 * Raphael.rgb2hsl 610 [ method ] 611 ** 612 * Converts RGB values to HSL object. 613 > Parameters 614 - r (number) red 615 - g (number) green 616 - b (number) blue 617 = (object) HSL object in format: 618 o { 619 o h (number) hue 620 o s (number) saturation 621 o l (number) luminosity 622 o } 623 \*/ 624 R.rgb2hsl = function (r, g, b) { 625 b = prepareRGB(r, g, b); 626 r = b[0]; 627 g = b[1]; 628 b = b[2]; 629 630 var H, S, L, M, m, C; 631 M = mmax(r, g, b); 632 m = mmin(r, g, b); 633 C = M - m; 634 H = (C == 0 ? null : 635 M == r ? (g - b) / C : 636 M == g ? (b - r) / C + 2 : 637 (r - g) / C + 4); 638 H = (H % 6) * 60; 639 L = (M + m) / 2; 640 S = (C == 0 ? 0 : 641 L < .5 ? C / (2 * L) : 642 C / (2 - 2 * L)); 643 return {h: H, s: S, l: L, toString: hsltoString}; 644 }; 645 R._path2string = function () { 646 return this.join(",").replace(p2s, "$1"); 647 }; 648 function cacher(f, scope, postprocessor) { 649 function newf() { 650 var arg = Array.prototype.slice.call(arguments, 0), 651 args = arg.join("\u2400"), 652 cache = newf.cache = newf.cache || {}, 653 count = newf.count = newf.count || []; 654 if (cache[has](args)) { 655 return postprocessor ? postprocessor(cache[args]) : cache[args]; 656 } 657 count.length >= 1e3 && delete cache[count.shift()]; 658 count.push(args); 659 cache[args] = f[apply](scope, arg); 660 return postprocessor ? postprocessor(cache[args]) : cache[args]; 661 } 662 return newf; 663 } 664 665 function preload(src, f) { 666 var img = g.doc.createElement("img"); 667 img.style.cssText = "position:absolute;left:-9999em;top-9999em"; 668 img.onload = function () { 669 f.call(this); 670 this.onload = null; 671 g.doc.body.removeChild(this); 672 }; 673 img.onerror = function () { 674 g.doc.body.removeChild(this); 675 }; 676 g.doc.body.appendChild(img); 677 img.src = src; 678 } 679 680 /*\ 681 * Raphael.getRGB 682 [ method ] 683 ** 684 * Parses colour string as RGB object 685 > Parameters 686 - colour (string) colour string in one of formats: 687 <ul> 688 <li>Colour name (“<samp>red</samp>”, “<samp>green</samp>”, “<samp>cornflowerblue</samp>”, etc)</li> 689 <li>#••• — shortened HTML colour: (“<samp>#000</samp>”, “<samp>#fc0</samp>”, etc)</li> 690 <li>#•••••• — full length HTML colour: (“<samp>#000000</samp>”, “<samp>#bd2300</samp>”)</li> 691 <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<samp>rgb(2001000)</samp>”)</li> 692 <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<samp>rgb(100%, 175%, 0%)</samp>”)</li> 693 <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<samp>hsb(0.50.251)</samp>”)</li> 694 <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> 695 <li>hsl(•••, •••, •••) — same as hsb</li> 696 <li>hsl(•••%, •••%, •••%) — same as hsb</li> 697 </ul> 698 = (object) RGB object in format: 699 o { 700 o r (number) red, 701 o g (number) green, 702 o b (number) blue 703 o hex (string) color in HTML/CSS format: #••••••, 704 o error (boolean) true if string can’t be parsed 705 o } 706 \*/ 707 R.getRGB = cacher(function (colour) { 708 if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { 709 return {r: -1, g: -1, b: -1, hex: "none", error: 1}; 710 } 711 if (colour == "none") { 712 return {r: -1, g: -1, b: -1, hex: "none"}; 713 } 714 !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); 715 var res, 716 red, 717 green, 718 blue, 719 opacity, 720 t, 721 values, 722 rgb = colour.match(colourRegExp); 723 if (rgb) { 724 if (rgb[2]) { 725 blue = toInt(rgb[2].substring(5), 16); 726 green = toInt(rgb[2].substring(3, 5), 16); 727 red = toInt(rgb[2].substring(1, 3), 16); 728 } 729 if (rgb[3]) { 730 blue = toInt((t = rgb[3].charAt(3)) + t, 16); 731 green = toInt((t = rgb[3].charAt(2)) + t, 16); 732 red = toInt((t = rgb[3].charAt(1)) + t, 16); 733 } 734 if (rgb[4]) { 735 values = rgb[4].split(commaSpaces); 736 red = toFloat(values[0]); 737 values[0].slice(-1) == "%" && (red *= 2.55); 738 green = toFloat(values[1]); 739 values[1].slice(-1) == "%" && (green *= 2.55); 740 blue = toFloat(values[2]); 741 values[2].slice(-1) == "%" && (blue *= 2.55); 742 rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); 743 values[3] && values[3].slice(-1) == "%" && (opacity /= 100); 744 } 745 if (rgb[5]) { 746 values = rgb[5].split(commaSpaces); 747 red = toFloat(values[0]); 748 values[0].slice(-1) == "%" && (red *= 2.55); 749 green = toFloat(values[1]); 750 values[1].slice(-1) == "%" && (green *= 2.55); 751 blue = toFloat(values[2]); 752 values[2].slice(-1) == "%" && (blue *= 2.55); 753 (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); 754 rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); 755 values[3] && values[3].slice(-1) == "%" && (opacity /= 100); 756 return R.hsb2rgb(red, green, blue, opacity); 757 } 758 if (rgb[6]) { 759 values = rgb[6].split(commaSpaces); 760 red = toFloat(values[0]); 761 values[0].slice(-1) == "%" && (red *= 2.55); 762 green = toFloat(values[1]); 763 values[1].slice(-1) == "%" && (green *= 2.55); 764 blue = toFloat(values[2]); 765 values[2].slice(-1) == "%" && (blue *= 2.55); 766 (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); 767 rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); 768 values[3] && values[3].slice(-1) == "%" && (opacity /= 100); 769 return R.hsl2rgb(red, green, blue, opacity); 770 } 771 rgb = {r: red, g: green, b: blue}; 772 rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); 773 R.is(opacity, "finite") && (rgb.opacity = opacity); 774 return rgb; 775 } 776 return {r: -1, g: -1, b: -1, hex: "none", error: 1}; 777 }, R); 778 /*\ 779 * Raphael.hsb 780 [ method ] 781 ** 782 * Converts HSB values to hex representation of the colour. 783 > Parameters 784 - h (number) hue 785 - s (number) saturation 786 - b (number) value or brightness 787 = (string) hex representation of the colour. 788 \*/ 789 R.hsb = cacher(function (h, s, b) { 790 return R.hsb2rgb(h, s, b).hex; 791 }); 792 /*\ 793 * Raphael.hsl 794 [ method ] 795 ** 796 * Converts HSL values to hex representation of the colour. 797 > Parameters 798 - h (number) hue 799 - s (number) saturation 800 - l (number) luminosity 801 = (string) hex representation of the colour. 802 \*/ 803 R.hsl = cacher(function (h, s, l) { 804 return R.hsl2rgb(h, s, l).hex; 805 }); 806 /*\ 807 * Raphael.rgb 808 [ method ] 809 ** 810 * Converts RGB values to hex representation of the colour. 811 > Parameters 812 - r (number) red 813 - g (number) green 814 - b (number) blue 815 = (string) hex representation of the colour. 816 \*/ 817 R.rgb = cacher(function (r, g, b) { 818 return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); 819 }); 820 /*\ 821 * Raphael.getColor 822 [ method ] 823 ** 824 * On each call returns next colour in the spectrum. To reset it back to red call @Raphael.getColor.reset 825 > Parameters 826 - value (number) #optional brightness, default is `0.75` 827 = (string) hex representation of the colour. 828 \*/ 829 R.getColor = function (value) { 830 var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, 831 rgb = this.hsb2rgb(start.h, start.s, start.b); 832 start.h += .075; 833 if (start.h > 1) { 834 start.h = 0; 835 start.s -= .2; 836 start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b}); 837 } 838 return rgb.hex; 839 }; 840 /*\ 841 * Raphael.getColor.reset 842 [ method ] 843 ** 844 * Resets spectrum position for @Raphael.getColor back to red. 845 \*/ 846 R.getColor.reset = function () { 847 delete this.start; 848 }; 849 850 /*\ 851 * Raphael.parsePathString 852 [ method ] 853 ** 854 * Utility method 855 ** 856 * Parses given path string into an array of arrays of path segments. 857 > Parameters 858 - pathString (string|array) path string or array of segments (in the last case it will be returned stright away) 859 = (array) array of segments. 860 \*/ 861 R.parsePathString = cacher(function (pathString) { 862 if (!pathString) { 863 return null; 864 } 865 var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0}, 866 data = []; 867 if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption 868 data = pathClone(pathString); 869 } 870 if (!data.length) { 871 Str(pathString).replace(pathCommand, function (a, b, c) { 872 var params = [], 873 name = lowerCase.call(b); 874 c.replace(pathValues, function (a, b) { 875 b && params.push(+b); 876 }); 877 if (name == "m" && params.length > 2) { 878 data.push([b][concat](params.splice(0, 2))); 879 name = "l"; 880 b = b == "m" ? "l" : "L"; 881 } 882 while (params.length >= paramCounts[name]) { 883 data.push([b][concat](params.splice(0, paramCounts[name]))); 884 if (!paramCounts[name]) { 885 break; 886 } 887 } 888 }); 889 } 890 data.toString = R._path2string; 891 return data; 892 }); 893 /*\ 894 * Raphael.parseTransformString 895 [ method ] 896 ** 897 * Utility method 898 ** 899 * Parses given path string into an array of transformations. 900 > Parameters 901 - TString (string|array) transform string or array of transformations (in the last case it will be returned stright away) 902 = (array) array of transformations. 903 \*/ 904 R.parseTransformString = cacher(function (TString) { 905 if (!TString) { 906 return null; 907 } 908 var paramCounts = {r: 3, s: 4, t: 2, m: 6}, 909 data = []; 910 if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption 911 data = pathClone(TString); 912 } 913 if (!data.length) { 914 Str(TString).replace(tCommand, function (a, b, c) { 915 var params = [], 916 name = lowerCase.call(b); 917 c.replace(pathValues, function (a, b) { 918 b && params.push(+b); 919 }); 920 data.push([name][concat](params)); 921 }); 922 } 923 data.toString = R._path2string; 924 return data; 925 }); 926 /*\ 927 * Raphael.findDotsAtSegment 928 [ method ] 929 ** 930 * Utility method 931 ** 932 * Find dot coordinates on the given cubic bezier curve at the given t. 933 > Parameters 934 - p1x (number) x of the first point of the curve 935 - p1y (number) y of the first point of the curve 936 - c1x (number) x of the first anchor of the curve 937 - c1y (number) y of the first anchor of the curve 938 - c2x (number) x of the second anchor of the curve 939 - c2y (number) y of the second anchor of the curve 940 - p2x (number) x of the second point of the curve 941 - p2y (number) y of the second point of the curve 942 - t (number) position on the curve (0..1) 943 = (object) point information in format: 944 o { 945 o x: (number) x coordinate of the point 946 o y: (number) y coordinate of the point 947 o m: { 948 o x: (number) x coordinate of the left anchor 949 o y: (number) y coordinate of the left anchor 950 o } 951 o n: { 952 o x: (number) x coordinate of the right anchor 953 o y: (number) y coordinate of the right anchor 954 o } 955 o start: { 956 o x: (number) x coordinate of the start of the curve 957 o y: (number) y coordinate of the start of the curve 958 o } 959 o end: { 960 o x: (number) x coordinate of the end of the curve 961 o y: (number) y coordinate of the end of the curve 962 o } 963 o alpha: (number) angle of the curve derivative at the point 964 o } 965 \*/ 966 R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { 967 var t1 = 1 - t, 968 x = pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, 969 y = pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y, 970 mx = p1x + 2 * t * (c1x - p1x) + t * t * (c2x - 2 * c1x + p1x), 971 my = p1y + 2 * t * (c1y - p1y) + t * t * (c2y - 2 * c1y + p1y), 972 nx = c1x + 2 * t * (c2x - c1x) + t * t * (p2x - 2 * c2x + c1x), 973 ny = c1y + 2 * t * (c2y - c1y) + t * t * (p2y - 2 * c2y + c1y), 974 ax = (1 - t) * p1x + t * c1x, 975 ay = (1 - t) * p1y + t * c1y, 976 cx = (1 - t) * c2x + t * p2x, 977 cy = (1 - t) * c2y + t * p2y, 978 alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); 979 (mx > nx || my < ny) && (alpha += 180); 980 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}; 981 }; 982 var pathDimensions = cacher(function (path) { 983 if (!path) { 984 return {x: 0, y: 0, width: 0, height: 0}; 985 } 986 path = path2curve(path); 987 var x = 0, 988 y = 0, 989 X = [], 990 Y = [], 991 p; 992 for (var i = 0, ii = path.length; i < ii; i++) { 993 p = path[i]; 994 if (p[0] == "M") { 995 x = p[1]; 996 y = p[2]; 997 X.push(x); 998 Y.push(y); 999 } else { 1000 var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); 1001 X = X[concat](dim.min.x, dim.max.x); 1002 Y = Y[concat](dim.min.y, dim.max.y); 1003 x = p[5]; 1004 y = p[6]; 1005 } 1006 } 1007 var xmin = mmin[apply](0, X), 1008 ymin = mmin[apply](0, Y); 1009 return { 1010 x: xmin, 1011 y: ymin, 1012 width: mmax[apply](0, X) - xmin, 1013 height: mmax[apply](0, Y) - ymin 1014 }; 1015 }), 1016 pathClone = function (pathArray) { 1017 var res = []; 1018 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption 1019 pathArray = R.parsePathString(pathArray); 1020 } 1021 for (var i = 0, ii = pathArray.length; i < ii; i++) { 1022 res[i] = []; 1023 for (var j = 0, jj = pathArray[i].length; j < jj; j++) { 1024 res[i][j] = pathArray[i][j]; 1025 } 1026 } 1027 res.toString = R._path2string; 1028 return res; 1029 }, 1030 pathToRelative = cacher(function (pathArray) { 1031 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption 1032 pathArray = R.parsePathString(pathArray); 1033 } 1034 var res = [], 1035 x = 0, 1036 y = 0, 1037 mx = 0, 1038 my = 0, 1039 start = 0; 1040 if (pathArray[0][0] == "M") { 1041 x = pathArray[0][1]; 1042 y = pathArray[0][2]; 1043 mx = x; 1044 my = y; 1045 start++; 1046 res.push(["M", x, y]); 1047 } 1048 for (var i = start, ii = pathArray.length; i < ii; i++) { 1049 var r = res[i] = [], 1050 pa = pathArray[i]; 1051 if (pa[0] != lowerCase.call(pa[0])) { 1052 r[0] = lowerCase.call(pa[0]); 1053 switch (r[0]) { 1054 case "a": 1055 r[1] = pa[1]; 1056 r[2] = pa[2]; 1057 r[3] = pa[3]; 1058 r[4] = pa[4]; 1059 r[5] = pa[5]; 1060 r[6] = +(pa[6] - x).toFixed(3); 1061 r[7] = +(pa[7] - y).toFixed(3); 1062 break; 1063 case "v": 1064 r[1] = +(pa[1] - y).toFixed(3); 1065 break; 1066 case "m": 1067 mx = pa[1]; 1068 my = pa[2]; 1069 default: 1070 for (var j = 1, jj = pa.length; j < jj; j++) { 1071 r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); 1072 } 1073 } 1074 } else { 1075 r = res[i] = []; 1076 if (pa[0] == "m") { 1077 mx = pa[1] + x; 1078 my = pa[2] + y; 1079 } 1080 for (var k = 0, kk = pa.length; k < kk; k++) { 1081 res[i][k] = pa[k]; 1082 } 1083 } 1084 var len = res[i].length; 1085 switch (res[i][0]) { 1086 case "z": 1087 x = mx; 1088 y = my; 1089 break; 1090 case "h": 1091 x += +res[i][len - 1]; 1092 break; 1093 case "v": 1094 y += +res[i][len - 1]; 1095 break; 1096 default: 1097 x += +res[i][len - 2]; 1098 y += +res[i][len - 1]; 1099 } 1100 } 1101 res.toString = R._path2string; 1102 return res; 1103 }, 0, pathClone), 1104 pathToAbsolute = cacher(function (pathArray) { 1105 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption 1106 pathArray = R.parsePathString(pathArray); 1107 } 1108 var res = [], 1109 x = 0, 1110 y = 0, 1111 mx = 0, 1112 my = 0, 1113 start = 0; 1114 if (pathArray[0][0] == "M") { 1115 x = +pathArray[0][1]; 1116 y = +pathArray[0][2]; 1117 mx = x; 1118 my = y; 1119 start++; 1120 res[0] = ["M", x, y]; 1121 } 1122 for (var i = start, ii = pathArray.length; i < ii; i++) { 1123 var r = res[i] = [], 1124 pa = pathArray[i]; 1125 if (pa[0] != upperCase.call(pa[0])) { 1126 r[0] = upperCase.call(pa[0]); 1127 switch (r[0]) { 1128 case "A": 1129 r[1] = pa[1]; 1130 r[2] = pa[2]; 1131 r[3] = pa[3]; 1132 r[4] = pa[4]; 1133 r[5] = pa[5]; 1134 r[6] = +(pa[6] + x); 1135 r[7] = +(pa[7] + y); 1136 break; 1137 case "V": 1138 r[1] = +pa[1] + y; 1139 break; 1140 case "H": 1141 r[1] = +pa[1] + x; 1142 break; 1143 case "M": 1144 mx = +pa[1] + x; 1145 my = +pa[2] + y; 1146 default: 1147 for (var j = 1, jj = pa.length; j < jj; j++) { 1148 r[j] = +pa[j] + ((j % 2) ? x : y); 1149 } 1150 } 1151 } else { 1152 for (var k = 0, kk = pa.length; k < kk; k++) { 1153 res[i][k] = pa[k]; 1154 } 1155 } 1156 switch (r[0]) { 1157 case "Z": 1158 x = mx; 1159 y = my; 1160 break; 1161 case "H": 1162 x = r[1]; 1163 break; 1164 case "V": 1165 y = r[1]; 1166 break; 1167 case "M": 1168 mx = res[i][res[i].length - 2]; 1169 my = res[i][res[i].length - 1]; 1170 default: 1171 x = res[i][res[i].length - 2]; 1172 y = res[i][res[i].length - 1]; 1173 } 1174 } 1175 res.toString = R._path2string; 1176 return res; 1177 }, null, pathClone), 1178 l2c = function (x1, y1, x2, y2) { 1179 return [x1, y1, x2, y2, x2, y2]; 1180 }, 1181 q2c = function (x1, y1, ax, ay, x2, y2) { 1182 var _13 = 1 / 3, 1183 _23 = 2 / 3; 1184 return [ 1185 _13 * x1 + _23 * ax, 1186 _13 * y1 + _23 * ay, 1187 _13 * x2 + _23 * ax, 1188 _13 * y2 + _23 * ay, 1189 x2, 1190 y2 1191 ]; 1192 }, 1193 a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { 1194 // for more information of where this math came from visit: 1195 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes 1196 var _120 = PI * 120 / 180, 1197 rad = PI / 180 * (+angle || 0), 1198 res = [], 1199 xy, 1200 rotate = cacher(function (x, y, rad) { 1201 var X = x * math.cos(rad) - y * math.sin(rad), 1202 Y = x * math.sin(rad) + y * math.cos(rad); 1203 return {x: X, y: Y}; 1204 }); 1205 if (!recursive) { 1206 xy = rotate(x1, y1, -rad); 1207 x1 = xy.x; 1208 y1 = xy.y; 1209 xy = rotate(x2, y2, -rad); 1210 x2 = xy.x; 1211 y2 = xy.y; 1212 var cos = math.cos(PI / 180 * angle), 1213 sin = math.sin(PI / 180 * angle), 1214 x = (x1 - x2) / 2, 1215 y = (y1 - y2) / 2; 1216 var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); 1217 if (h > 1) { 1218 h = math.sqrt(h); 1219 rx = h * rx; 1220 ry = h * ry; 1221 } 1222 var rx2 = rx * rx, 1223 ry2 = ry * ry, 1224 k = (large_arc_flag == sweep_flag ? -1 : 1) * 1225 math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), 1226 cx = k * rx * y / ry + (x1 + x2) / 2, 1227 cy = k * -ry * x / rx + (y1 + y2) / 2, 1228 f1 = math.asin(((y1 - cy) / ry).toFixed(9)), 1229 f2 = math.asin(((y2 - cy) / ry).toFixed(9)); 1230 1231 f1 = x1 < cx ? PI - f1 : f1; 1232 f2 = x2 < cx ? PI - f2 : f2; 1233 f1 < 0 && (f1 = PI * 2 + f1); 1234 f2 < 0 && (f2 = PI * 2 + f2); 1235 if (sweep_flag && f1 > f2) { 1236 f1 = f1 - PI * 2; 1237 } 1238 if (!sweep_flag && f2 > f1) { 1239 f2 = f2 - PI * 2; 1240 } 1241 } else { 1242 f1 = recursive[0]; 1243 f2 = recursive[1]; 1244 cx = recursive[2]; 1245 cy = recursive[3]; 1246 } 1247 var df = f2 - f1; 1248 if (abs(df) > _120) { 1249 var f2old = f2, 1250 x2old = x2, 1251 y2old = y2; 1252 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); 1253 x2 = cx + rx * math.cos(f2); 1254 y2 = cy + ry * math.sin(f2); 1255 res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); 1256 } 1257 df = f2 - f1; 1258 var c1 = math.cos(f1), 1259 s1 = math.sin(f1), 1260 c2 = math.cos(f2), 1261 s2 = math.sin(f2), 1262 t = math.tan(df / 4), 1263 hx = 4 / 3 * rx * t, 1264 hy = 4 / 3 * ry * t, 1265 m1 = [x1, y1], 1266 m2 = [x1 + hx * s1, y1 - hy * c1], 1267 m3 = [x2 + hx * s2, y2 - hy * c2], 1268 m4 = [x2, y2]; 1269 m2[0] = 2 * m1[0] - m2[0]; 1270 m2[1] = 2 * m1[1] - m2[1]; 1271 if (recursive) { 1272 return [m2, m3, m4][concat](res); 1273 } else { 1274 res = [m2, m3, m4][concat](res).join().split(","); 1275 var newres = []; 1276 for (var i = 0, ii = res.length; i < ii; i++) { 1277 newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; 1278 } 1279 return newres; 1280 } 1281 }, 1282 findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { 1283 var t1 = 1 - t; 1284 return { 1285 x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, 1286 y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y 1287 }; 1288 }, 1289 curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { 1290 var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), 1291 b = 2 * (c1x - p1x) - 2 * (c2x - c1x), 1292 c = p1x - c1x, 1293 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a, 1294 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a, 1295 y = [p1y, p2y], 1296 x = [p1x, p2x], 1297 dot; 1298 abs(t1) > "1e12" && (t1 = .5); 1299 abs(t2) > "1e12" && (t2 = .5); 1300 if (t1 > 0 && t1 < 1) { 1301 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); 1302 x.push(dot.x); 1303 y.push(dot.y); 1304 } 1305 if (t2 > 0 && t2 < 1) { 1306 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); 1307 x.push(dot.x); 1308 y.push(dot.y); 1309 } 1310 a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); 1311 b = 2 * (c1y - p1y) - 2 * (c2y - c1y); 1312 c = p1y - c1y; 1313 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; 1314 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; 1315 abs(t1) > "1e12" && (t1 = .5); 1316 abs(t2) > "1e12" && (t2 = .5); 1317 if (t1 > 0 && t1 < 1) { 1318 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); 1319 x.push(dot.x); 1320 y.push(dot.y); 1321 } 1322 if (t2 > 0 && t2 < 1) { 1323 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); 1324 x.push(dot.x); 1325 y.push(dot.y); 1326 } 1327 return { 1328 min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, 1329 max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} 1330 }; 1331 }), 1332 path2curve = cacher(function (path, path2) { 1333 var p = pathToAbsolute(path), 1334 p2 = path2 && pathToAbsolute(path2), 1335 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, 1336 attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, 1337 processPath = function (path, d) { 1338 var nx, ny; 1339 if (!path) { 1340 return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; 1341 } 1342 !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null); 1343 switch (path[0]) { 1344 case "M": 1345 d.X = path[1]; 1346 d.Y = path[2]; 1347 break; 1348 case "A": 1349 path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1)))); 1350 break; 1351 case "S": 1352 nx = d.x + (d.x - (d.bx || d.x)); 1353 ny = d.y + (d.y - (d.by || d.y)); 1354 path = ["C", nx, ny][concat](path.slice(1)); 1355 break; 1356 case "T": 1357 d.qx = d.x + (d.x - (d.qx || d.x)); 1358 d.qy = d.y + (d.y - (d.qy || d.y)); 1359 path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); 1360 break; 1361 case "Q": 1362 d.qx = path[1]; 1363 d.qy = path[2]; 1364 path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4])); 1365 break; 1366 case "L": 1367 path = ["C"][concat](l2c(d.x, d.y, path[1], path[2])); 1368 break; 1369 case "H": 1370 path = ["C"][concat](l2c(d.x, d.y, path[1], d.y)); 1371 break; 1372 case "V": 1373 path = ["C"][concat](l2c(d.x, d.y, d.x, path[1])); 1374 break; 1375 case "Z": 1376 path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y)); 1377 break; 1378 } 1379 return path; 1380 }, 1381 fixArc = function (pp, i) { 1382 if (pp[i].length > 7) { 1383 pp[i].shift(); 1384 var pi = pp[i]; 1385 while (pi.length) { 1386 pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); 1387 } 1388 pp.splice(i, 1); 1389 ii = mmax(p.length, p2 && p2.length || 0); 1390 } 1391 }, 1392 fixM = function (path1, path2, a1, a2, i) { 1393 if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { 1394 path2.splice(i, 0, ["M", a2.x, a2.y]); 1395 a1.bx = 0; 1396 a1.by = 0; 1397 a1.x = path1[i][1]; 1398 a1.y = path1[i][2]; 1399 ii = mmax(p.length, p2 && p2.length || 0); 1400 } 1401 }; 1402 for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { 1403 p[i] = processPath(p[i], attrs); 1404 fixArc(p, i); 1405 p2 && (p2[i] = processPath(p2[i], attrs2)); 1406 p2 && fixArc(p2, i); 1407 fixM(p, p2, attrs, attrs2, i); 1408 fixM(p2, p, attrs2, attrs, i); 1409 var seg = p[i], 1410 seg2 = p2 && p2[i], 1411 seglen = seg.length, 1412 seg2len = p2 && seg2.length; 1413 attrs.x = seg[seglen - 2]; 1414 attrs.y = seg[seglen - 1]; 1415 attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; 1416 attrs.by = toFloat(seg[seglen - 3]) || attrs.y; 1417 attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); 1418 attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); 1419 attrs2.x = p2 && seg2[seg2len - 2]; 1420 attrs2.y = p2 && seg2[seg2len - 1]; 1421 } 1422 return p2 ? [p, p2] : p; 1423 }, null, pathClone), 1424 parseDots = cacher(function (gradient) { 1425 var dots = []; 1426 for (var i = 0, ii = gradient.length; i < ii; i++) { 1427 var dot = {}, 1428 par = gradient[i].match(/^([^:]*):?([\d\.]*)/); 1429 dot.color = R.getRGB(par[1]); 1430 if (dot.color.error) { 1431 return null; 1432 } 1433 dot.color = dot.color.hex; 1434 par[2] && (dot.offset = par[2] + "%"); 1435 dots.push(dot); 1436 } 1437 for (i = 1, ii = dots.length - 1; i < ii; i++) { 1438 if (!dots[i].offset) { 1439 var start = toFloat(dots[i - 1].offset || 0), 1440 end = 0; 1441 for (var j = i + 1; j < ii; j++) { 1442 if (dots[j].offset) { 1443 end = dots[j].offset; 1444 break; 1445 } 1446 } 1447 if (!end) { 1448 end = 100; 1449 j = ii; 1450 } 1451 end = toFloat(end); 1452 var d = (end - start) / (j - i + 1); 1453 for (; i < j; i++) { 1454 start += d; 1455 dots[i].offset = start + "%"; 1456 } 1457 } 1458 } 1459 return dots; 1460 }), 1461 getContainer = function (x, y, w, h) { 1462 var container; 1463 container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x; 1464 if (container == null) { 1465 return; 1466 } 1467 if (container.tagName) { 1468 if (y == null) { 1469 return { 1470 container: container, 1471 width: container.style.pixelWidth || container.offsetWidth, 1472 height: container.style.pixelHeight || container.offsetHeight 1473 }; 1474 } else { 1475 return {container: container, width: y, height: w}; 1476 } 1477 } 1478 return {container: 1, x: x, y: y, width: w, height: h}; 1479 }, 1480 plugins = function (con, add) { 1481 var that = this; 1482 for (var prop in add) { 1483 if (add[has](prop) && !(prop in con)) { 1484 switch (typeof add[prop]) { 1485 case "function": 1486 (function (f) { 1487 con[prop] = con === that ? f : function () { return f[apply](that, arguments); }; 1488 })(add[prop]); 1489 break; 1490 case "object": 1491 con[prop] = con[prop] || {}; 1492 plugins.call(this, con[prop], add[prop]); 1493 break; 1494 default: 1495 con[prop] = add[prop]; 1496 break; 1497 } 1498 } 1499 } 1500 }, 1501 tear = function (el, paper) { 1502 el == paper.top && (paper.top = el.prev); 1503 el == paper.bottom && (paper.bottom = el.next); 1504 el.next && (el.next.prev = el.prev); 1505 el.prev && (el.prev.next = el.next); 1506 }, 1507 tofront = function (el, paper) { 1508 if (paper.top === el) { 1509 return; 1510 } 1511 tear(el, paper); 1512 el.next = null; 1513 el.prev = paper.top; 1514 paper.top.next = el; 1515 paper.top = el; 1516 }, 1517 toback = function (el, paper) { 1518 if (paper.bottom === el) { 1519 return; 1520 } 1521 tear(el, paper); 1522 el.next = paper.bottom; 1523 el.prev = null; 1524 paper.bottom.prev = el; 1525 paper.bottom = el; 1526 }, 1527 insertafter = function (el, el2, paper) { 1528 tear(el, paper); 1529 el2 == paper.top && (paper.top = el); 1530 el2.next && (el2.next.prev = el); 1531 el.next = el2.next; 1532 el.prev = el2; 1533 el2.next = el; 1534 }, 1535 insertbefore = function (el, el2, paper) { 1536 tear(el, paper); 1537 el2 == paper.bottom && (paper.bottom = el); 1538 el2.prev && (el2.prev.next = el); 1539 el.prev = el2.prev; 1540 el2.prev = el; 1541 el.next = el2; 1542 }, 1543 removed = function (methodname) { 1544 return function () { 1545 throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object"); 1546 }; 1547 }, 1548 extractTransform = function (el, tstr) { 1549 if (tstr == null) { 1550 return el._.transform; 1551 } 1552 tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E); 1553 var tdata = R.parseTransformString(tstr), 1554 deg = 0, 1555 dx = 0, 1556 dy = 0, 1557 sx = 1, 1558 sy = 1, 1559 _ = el._, 1560 m = new Matrix; 1561 _.transform = tdata || []; 1562 if (tdata) { 1563 for (var i = 0, ii = tdata.length; i < ii; i++) { 1564 var t = tdata[i], 1565 tlen = t.length, 1566 bb; 1567 t[0] = Str(t[0]).toLowerCase(); 1568 if (t[0] == "t" && tlen == 3) { 1569 m.translate(t[1], t[2]); 1570 } else if (t[0] == "r") { 1571 if (tlen == 2) { 1572 bb = bb || el.getBBox(1); 1573 m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); 1574 deg += t[1]; 1575 } else if (tlen == 4) { 1576 m.rotate(t[1], t[2], t[3]); 1577 deg += t[1]; 1578 } 1579 } else if (t[0] == "s") { 1580 if (tlen == 2 || tlen == 3) { 1581 bb = bb || el.getBBox(1); 1582 m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); 1583 sx *= t[1]; 1584 sy *= t[tlen - 1]; 1585 } else if (tlen == 5) { 1586 m.scale(t[1], t[2], t[3], t[4]); 1587 sx *= t[1]; 1588 sy *= t[2]; 1589 } 1590 } else if (t[0] == "m" && tlen == 7) { 1591 m.add(t[1], t[2], t[3], t[4], t[5], t[6]); 1592 } 1593 _.dirtyT = 1; 1594 el.matrix = m; 1595 } 1596 } 1597 1598 el.matrix = m; 1599 1600 _.sx = sx; 1601 _.sy = sy; 1602 _.deg = deg; 1603 _.dx = dx = m.m[0][2]; 1604 _.dy = dy = m.m[1][2]; 1605 1606 if (sx == 1 && sy == 1 && !deg && _.bbox) { 1607 _.bbox.x += +dx; 1608 _.bbox.y += +dy; 1609 } else { 1610 _.dirtyT = 1; 1611 } 1612 }, 1613 getEmpty = function (item) { 1614 switch (item[0]) { 1615 case "t": return ["t", 0, 0]; 1616 case "m": return ["m", 1, 0, 0, 1, 0, 0]; 1617 case "r": if (item.length == 4) { 1618 return ["r", 0, item[2], item[3]]; 1619 } else { 1620 return ["r", 0]; 1621 } 1622 case "s": if (item.length == 5) { 1623 return ["s", 1, 1, item[3], item[4]]; 1624 } else if (item.length == 3) { 1625 return ["s", 1, 1]; 1626 } else { 1627 return ["s", 1]; 1628 } 1629 } 1630 }, 1631 equaliseTransform = function (t1, t2) { 1632 t1 = R.parseTransformString(t1) || []; 1633 t2 = R.parseTransformString(t2) || []; 1634 var maxlength = mmax(t1.length, t2.length), 1635 from = [], 1636 to = [], 1637 i = 0, j, jj, 1638 tt1, tt2; 1639 for (; i < maxlength; i++) { 1640 tt1 = t1[i] || getEmpty(t2[i]); 1641 tt2 = t2[i] || getEmpty(tt1); 1642 if ( (tt1[0] != tt2[0]) || 1643 (tt1[0] == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || 1644 (tt1[0] == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) 1645 ) { 1646 return; 1647 } 1648 from[i] = []; 1649 to[i] = []; 1650 for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) { 1651 j in tt1 && (from[i][j] = tt1[j]); 1652 j in tt2 && (to[i][j] = tt2[j]); 1653 } 1654 } 1655 return { 1656 from: from, 1657 to: to 1658 }; 1659 }; 1660 /*\ 1661 * Raphael.pathToRelative 1662 [ method ] 1663 ** 1664 * Utility method 1665 ** 1666 * Converts path to relative form 1667 > Parameters 1668 - pathString (string|array) path string or array of segments 1669 = (array) array of segments. 1670 \*/ 1671 R.pathToRelative = pathToRelative; 1672 /*\ 1673 * Raphael.path2curve 1674 [ method ] 1675 ** 1676 * Utility method 1677 ** 1678 * Converts path to path where all segments are cubic bezier curves. 1679 > Parameters 1680 - pathString (string|array) path string or array of segments 1681 = (array) array of segments. 1682 \*/ 1683 R.path2curve = path2curve; 1684 // Matrix 1685 // var m = document.createElementNS("http://www.w3.org/2000/svg", "svg").createSVGMatrix(); 1686 function Matrix(a, b, c, d, e, f) { 1687 if (a != null) { 1688 this.m = [[a, c, e], [b, d, f], [0, 0, 1]]; 1689 } else { 1690 this.m = [[1, 0, 0], [0, 1, 0], [0, 0, 1]]; 1691 } 1692 } 1693 var matrixproto = Matrix.prototype; 1694 matrixproto.add = function (a, b, c, d, e, f) { 1695 var out = [[], [], []], 1696 matrix = [[a, c, e], [b, d, f], [0, 0, 1]], 1697 x, y, z, res; 1698 1699 for (x = 0; x < 3; x++) { 1700 for (y = 0; y < 3; y++) { 1701 res = 0; 1702 for (z = 0; z < 3; z++) { 1703 res += this.m[x][z] * matrix[z][y]; 1704 } 1705 out[x][y] = res; 1706 } 1707 } 1708 this.m = out; 1709 }; 1710 matrixproto.invert = function () { 1711 var a = this.m[0][0], 1712 b = this.m[1][0], 1713 c = this.m[0][1], 1714 d = this.m[1][1], 1715 e = this.m[0][2], 1716 f = this.m[1][2], 1717 x = a * d - b * c; 1718 return new Matrix(d / x, -b / x, -c / x, a / x, (c * f - d * e) / x, (b * e - a * f) / x); 1719 }; 1720 matrixproto.clone = function () { 1721 var a = this.m[0][0], 1722 b = this.m[1][0], 1723 c = this.m[0][1], 1724 d = this.m[1][1], 1725 e = this.m[0][2], 1726 f = this.m[1][2]; 1727 return new Matrix(a, b, c, d, e, f); 1728 }; 1729 matrixproto.translate = function (x, y) { 1730 this.add(1, 0, 0, 1, x, y); 1731 }; 1732 matrixproto.scale = function (x, y, cx, cy) { 1733 y == null && (y = x); 1734 this.add(1, 0, 0, 1, cx, cy); 1735 this.add(x, 0, 0, y, 0, 0); 1736 this.add(1, 0, 0, 1, -cx, -cy); 1737 }; 1738 matrixproto.rotate = function (a, x, y) { 1739 a = R.rad(a); 1740 var cos = +math.cos(a).toFixed(9), 1741 sin = +math.sin(a).toFixed(9); 1742 this.add(cos, sin, -sin, cos, x, y); 1743 this.add(1, 0, 0, 1, -x, -y); 1744 }; 1745 matrixproto.x = function (x, y) { 1746 return x * this.m[0][0] + y * this.m[0][1] + this.m[0][2]; 1747 }; 1748 matrixproto.y = function (x, y) { 1749 return x * this.m[1][0] + y * this.m[1][1] + this.m[1][2]; 1750 }; 1751 matrixproto.get = function (i, j) { 1752 return +this.m[i][j].toFixed(4); 1753 }; 1754 matrixproto.toString = function () { 1755 return R.svg ? 1756 "matrix(" + [this.get(0, 0), this.get(1, 0), this.get(0, 1), this.get(1, 1), this.get(0, 2), this.get(1, 2)].join() + ")" : 1757 [this.get(0, 0), this.get(0, 1), this.get(1, 0), this.get(1, 1), 0, 0].join(); 1758 }; 1759 matrixproto.toFilter = function () { 1760 return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0, 0) + 1761 ", M12=" + this.get(0, 1) + ", M21=" + this.get(1, 0) + ", M22=" + this.get(1, 1) + 1762 ", Dx=" + this.get(0, 2) + ", Dy=" + this.get(1, 2) + ", sizingmedthod='auto expand')"; 1763 }; 1764 matrixproto.offset = function () { 1765 return [this.m[0][2].toFixed(4), this.m[1][2].toFixed(4)]; 1766 }; 1767 1768 R.Matrix = Matrix; 1769 1770 // SVG 1771 if (R.svg) { 1772 var xlink = "http://www.w3.org/1999/xlink", 1773 markers = { 1774 block: "M5,0 0,2.5 5,5z", 1775 classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", 1776 diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", 1777 open: "M6,1 1,3.5 6,6", 1778 oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" 1779 }, 1780 markerCounter = {}; 1781 R.toString = function () { 1782 return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; 1783 }; 1784 var $ = function (el, attr) { 1785 if (attr) { 1786 if (typeof el == "string") { 1787 el = $(el); 1788 } 1789 for (var key in attr) if (attr[has](key)) { 1790 if (key.substring(0, 6) == "xlink:") { 1791 el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); 1792 } else { 1793 el[setAttribute](key, Str(attr[key])); 1794 } 1795 } 1796 } else { 1797 el = g.doc.createElementNS("http://www.w3.org/2000/svg", el); 1798 el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); 1799 } 1800 return el; 1801 }, 1802 thePath = function (pathString, SVG) { 1803 var el = $("path"); 1804 SVG.canvas && SVG.canvas.appendChild(el); 1805 var p = new Element(el, SVG); 1806 p.type = "path"; 1807 setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString}); 1808 return p; 1809 }, 1810 gradients = {}, 1811 rgGrad = /^url\(#(.*)\)$/, 1812 removeGradientFill = function (node, paper) { 1813 var oid = node.getAttribute(fillString); 1814 oid = oid && oid.match(rgGrad); 1815 if (oid && !--gradients[oid[1]]) { 1816 delete gradients[oid[1]]; 1817 paper.defs.removeChild(g.doc.getElementById(oid[1])); 1818 } 1819 }, 1820 addGradientFill = function (element, gradient) { 1821 var type = "linear", 1822 id = element.id + gradient, 1823 fx = .5, fy = .5, 1824 o = element.node, 1825 SVG = element.paper, 1826 s = o.style, 1827 el = g.doc.getElementById(id); 1828 if (!el) { 1829 gradient = Str(gradient).replace(radial_gradient, function (all, _fx, _fy) { 1830 type = "radial"; 1831 if (_fx && _fy) { 1832 fx = toFloat(_fx); 1833 fy = toFloat(_fy); 1834 var dir = ((fy > .5) * 2 - 1); 1835 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && 1836 (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && 1837 fy != .5 && 1838 (fy = fy.toFixed(5) - 1e-5 * dir); 1839 } 1840 return E; 1841 }); 1842 gradient = gradient.split(/\s*\-\s*/); 1843 if (type == "linear") { 1844 var angle = gradient.shift(); 1845 angle = -toFloat(angle); 1846 if (isNaN(angle)) { 1847 return null; 1848 } 1849 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], 1850 max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); 1851 vector[2] *= max; 1852 vector[3] *= max; 1853 if (vector[2] < 0) { 1854 vector[0] = -vector[2]; 1855 vector[2] = 0; 1856 } 1857 if (vector[3] < 0) { 1858 vector[1] = -vector[3]; 1859 vector[3] = 0; 1860 } 1861 } 1862 var dots = parseDots(gradient); 1863 if (!dots) { 1864 return null; 1865 } 1866 if (element.gradient) { 1867 SVG.defs.removeChild(element.gradient); 1868 delete element.gradient; 1869 } 1870 1871 el = $(type + "Gradient", {id: id}); 1872 element.gradient = el; 1873 $(el, type == "radial" ? { 1874 fx: fx, 1875 fy: fy 1876 } : { 1877 x1: vector[0], 1878 y1: vector[1], 1879 x2: vector[2], 1880 y2: vector[3], 1881 gradientTransform: element.matrix.invert() 1882 }); 1883 SVG.defs.appendChild(el); 1884 for (var i = 0, ii = dots.length; i < ii; i++) { 1885 el.appendChild($("stop", { 1886 offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", 1887 "stop-color": dots[i].color || "#fff" 1888 })); 1889 } 1890 } 1891 $(o, { 1892 fill: "url(#" + id + ")", 1893 opacity: 1, 1894 "fill-opacity": 1 1895 }); 1896 s.fill = E; 1897 s.opacity = 1; 1898 s.fillOpacity = 1; 1899 return 1; 1900 }, 1901 updatePosition = function (o) { 1902 var bbox = o.getBBox(1); 1903 $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); 1904 }, 1905 addArrow = function (o, value, isEnd) { 1906 if (o.type == "path") { 1907 var values = Str(value).toLowerCase().split("-"), 1908 p = o.paper, 1909 se = isEnd ? "end" : "start", 1910 node = o.node, 1911 attrs = o.attrs, 1912 stroke = attrs["stroke-width"], 1913 i = values.length, 1914 type = "classic", 1915 from, 1916 to, 1917 dx, 1918 refX, 1919 attr, 1920 w = 3, 1921 h = 3, 1922 t = 5; 1923 while (i--) { 1924 switch (values[i]) { 1925 case "block": 1926 case "classic": 1927 case "oval": 1928 case "diamond": 1929 case "open": 1930 case "none": 1931 type = values[i]; 1932 break; 1933 case "wide": h = 5; break; 1934 case "narrow": h = 2; break; 1935 case "long": w = 5; break; 1936 case "short": w = 2; break; 1937 } 1938 } 1939 if (type == "open") { 1940 w += 2; 1941 h += 2; 1942 t += 2; 1943 dx = 1; 1944 refX = isEnd ? 4 : 1; 1945 attr = { 1946 fill: "none", 1947 stroke: attrs.stroke 1948 }; 1949 } else { 1950 refX = dx = w / 2; 1951 attr = { 1952 fill: attrs.stroke, 1953 stroke: "none" 1954 }; 1955 } 1956 if (o._.arrows) { 1957 if (isEnd) { 1958 o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; 1959 o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; 1960 } else { 1961 o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; 1962 o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; 1963 } 1964 } else { 1965 o._.arrows = {}; 1966 } 1967 if (type != "none") { 1968 var pathId = "raphael-marker-" + type, 1969 markerId = "raphael-marker-" + se + type + w + h; 1970 if (!g.doc.getElementById(pathId)) { 1971 p.defs.appendChild($($("path"), { 1972 "stroke-linecap": "round", 1973 d: markers[type], 1974 id: pathId 1975 })); 1976 markerCounter[pathId] = 1; 1977 } else { 1978 markerCounter[pathId]++; 1979 } 1980 var marker = g.doc.getElementById(markerId), 1981 use; 1982 if (!marker) { 1983 marker = $($("marker"), { 1984 id: markerId, 1985 markerHeight: h, 1986 markerWidth: w, 1987 orient: "auto", 1988 refX: refX, 1989 refY: h / 2 1990 }); 1991 use = $($("use"), { 1992 "xlink:href": "#" + pathId, 1993 transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")", 1994 "stroke-width": 1 / ((w / t + h / t) / 2) 1995 }); 1996 marker.appendChild(use); 1997 p.defs.appendChild(marker); 1998 markerCounter[markerId] = 1; 1999 } else { 2000 markerCounter[markerId]++; 2001 use = marker.getElementsByTagName("use")[0]; 2002 } 2003 $(use, attr); 2004 var delta = dx * (type != "diamond" && type != "oval"); 2005 if (isEnd) { 2006 from = o._.arrows.startdx * stroke || 0; 2007 to = R.getTotalLength(attrs.path) - delta * stroke; 2008 } else { 2009 from = delta * stroke; 2010 to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); 2011 } 2012 attr = {}; 2013 attr["marker-" + se] = "url(#" + markerId + ")"; 2014 if (to || from) { 2015 attr.d = Raphael.getSubpath(attrs.path, from, to); 2016 } 2017 $(node, attr); 2018 o._.arrows[se + "Path"] = pathId; 2019 o._.arrows[se + "Marker"] = markerId; 2020 o._.arrows[se + "dx"] = delta; 2021 o._.arrows[se + "Type"] = type; 2022 o._.arrows[se + "String"] = value; 2023 } else { 2024 if (isEnd) { 2025 from = o._.arrows.startdx * stroke || 0; 2026 to = R.getTotalLength(attrs.path) - from; 2027 } else { 2028 from = 0; 2029 to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); 2030 } 2031 o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)}); 2032 delete o._.arrows[se + "Path"]; 2033 delete o._.arrows[se + "Marker"]; 2034 delete o._.arrows[se + "dx"]; 2035 delete o._.arrows[se + "Type"]; 2036 delete o._.arrows[se + "String"]; 2037 } 2038 for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { 2039 var item = g.doc.getElementById(attr); 2040 item && item.parentNode.removeChild(item); 2041 } 2042 } 2043 }, 2044 setFillAndStroke = function (o, params) { 2045 var dasharray = { 2046 "": [0], 2047 "none": [0], 2048 "-": [3, 1], 2049 ".": [1, 1], 2050 "-.": [3, 1, 1, 1], 2051 "-..": [3, 1, 1, 1, 1, 1], 2052 ". ": [1, 3], 2053 "- ": [4, 3], 2054 "--": [8, 3], 2055 "- .": [4, 3, 1, 3], 2056 "--.": [8, 3, 1, 3], 2057 "--..": [8, 3, 1, 3, 1, 3] 2058 }, 2059 node = o.node, 2060 attrs = o.attrs, 2061 addDashes = function (o, value) { 2062 value = dasharray[lowerCase.call(value)]; 2063 if (value) { 2064 var width = o.attrs["stroke-width"] || "1", 2065 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, 2066 dashes = [], 2067 i = value.length; 2068 while (i--) { 2069 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; 2070 } 2071 $(node, {"stroke-dasharray": dashes.join(",")}); 2072 } 2073 }; 2074 for (var att in params) { 2075 if (params[has](att)) { 2076 if (!availableAttrs[has](att)) { 2077 continue; 2078 } 2079 var value = params[att]; 2080 attrs[att] = value; 2081 switch (att) { 2082 case "blur": 2083 o.blur(value); 2084 break; 2085 case "href": 2086 case "title": 2087 case "target": 2088 var pn = node.parentNode; 2089 if (lowerCase.call(pn.tagName) != "a") { 2090 var hl = $("a"); 2091 pn.insertBefore(hl, node); 2092 hl.appendChild(node); 2093 pn = hl; 2094 } 2095 if (att == "target" && value == "blank") { 2096 pn.setAttributeNS(xlink, "show", "new"); 2097 } else { 2098 pn.setAttributeNS(xlink, att, value); 2099 } 2100 break; 2101 case "cursor": 2102 node.style.cursor = value; 2103 break; 2104 case "transform": 2105 o.transform(value); 2106 break; 2107 case "arrow-start": 2108 addArrow(o, value); 2109 break; 2110 case "arrow-end": 2111 addArrow(o, value, 1); 2112 break; 2113 case "clip-rect": 2114 var rect = Str(value).split(separator); 2115 if (rect.length == 4) { 2116 o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); 2117 var el = $("clipPath"), 2118 rc = $("rect"); 2119 el.id = createUUID(); 2120 $(rc, { 2121 x: rect[0], 2122 y: rect[1], 2123 width: rect[2], 2124 height: rect[3] 2125 }); 2126 el.appendChild(rc); 2127 o.paper.defs.appendChild(el); 2128 $(node, {"clip-path": "url(#" + el.id + ")"}); 2129 o.clip = rc; 2130 } 2131 if (!value) { 2132 var clip = g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E)); 2133 clip && clip.parentNode.removeChild(clip); 2134 $(node, {"clip-path": E}); 2135 delete o.clip; 2136 } 2137 break; 2138 case "path": 2139 if (o.type == "path") { 2140 $(node, {d: value ? attrs.path = pathToAbsolute(value) : "M0,0"}); 2141 o._.dirty = 1; 2142 if (o._.arrows) { 2143 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 2144 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 2145 } 2146 } 2147 break; 2148 case "width": 2149 node[setAttribute](att, value); 2150 o._.dirty = 1; 2151 if (attrs.fx) { 2152 att = "x"; 2153 value = attrs.x; 2154 } else { 2155 break; 2156 } 2157 case "x": 2158 if (attrs.fx) { 2159 value = -attrs.x - (attrs.width || 0); 2160 } 2161 case "rx": 2162 if (att == "rx" && o.type == "rect") { 2163 break; 2164 } 2165 case "cx": 2166 node[setAttribute](att, value); 2167 o.pattern && updatePosition(o); 2168 o._.dirty = 1; 2169 break; 2170 case "height": 2171 node[setAttribute](att, value); 2172 o._.dirty = 1; 2173 if (attrs.fy) { 2174 att = "y"; 2175 value = attrs.y; 2176 } else { 2177 break; 2178 } 2179 case "y": 2180 if (attrs.fy) { 2181 value = -attrs.y - (attrs.height || 0); 2182 } 2183 case "ry": 2184 if (att == "ry" && o.type == "rect") { 2185 break; 2186 } 2187 case "cy": 2188 node[setAttribute](att, value); 2189 o.pattern && updatePosition(o); 2190 o._.dirty = 1; 2191 break; 2192 case "r": 2193 if (o.type == "rect") { 2194 $(node, {rx: value, ry: value}); 2195 } else { 2196 node[setAttribute](att, value); 2197 } 2198 o._.dirty = 1; 2199 break; 2200 case "src": 2201 if (o.type == "image") { 2202 node.setAttributeNS(xlink, "href", value); 2203 } 2204 break; 2205 case "stroke-width": 2206 if (o._.sx != 1 || o._.sy != 1) { 2207 value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; 2208 } 2209 if (o.paper._vbSize) { 2210 value *= o.paper._vbSize; 2211 } 2212 node[setAttribute](att, value); 2213 if (attrs["stroke-dasharray"]) { 2214 addDashes(o, attrs["stroke-dasharray"]); 2215 } 2216 if (o._.arrows) { 2217 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 2218 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 2219 } 2220 break; 2221 case "stroke-dasharray": 2222 addDashes(o, value); 2223 break; 2224 case fillString: 2225 var isURL = Str(value).match(ISURL); 2226 if (isURL) { 2227 el = $("pattern"); 2228 var ig = $("image"); 2229 el.id = createUUID(); 2230 $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); 2231 $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); 2232 el.appendChild(ig); 2233 2234 (function (el) { 2235 preload(isURL[1], function () { 2236 var w = this.offsetWidth, 2237 h = this.offsetHeight; 2238 $(el, {width: w, height: h}); 2239 $(ig, {width: w, height: h}); 2240 o.paper.safari(); 2241 }); 2242 })(el); 2243 o.paper.defs.appendChild(el); 2244 node.style.fill = "url(#" + el.id + ")"; 2245 $(node, {fill: "url(#" + el.id + ")"}); 2246 o.pattern = el; 2247 o.pattern && updatePosition(o); 2248 break; 2249 } 2250 var clr = R.getRGB(value); 2251 if (!clr.error) { 2252 delete params.gradient; 2253 delete attrs.gradient; 2254 !R.is(attrs.opacity, "undefined") && 2255 R.is(params.opacity, "undefined") && 2256 $(node, {opacity: attrs.opacity}); 2257 !R.is(attrs["fill-opacity"], "undefined") && 2258 R.is(params["fill-opacity"], "undefined") && 2259 $(node, {"fill-opacity": attrs["fill-opacity"]}); 2260 } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { 2261 if ("opacity" in attrs || "fill-opacity" in attrs) { 2262 var gradient = g.doc.getElementById(node.getAttribute(fillString).replace(/^url\(#|\)$/g, E)); 2263 if (gradient) { 2264 var stops = gradient.getElementsByTagName("stop"); 2265 $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); 2266 } 2267 } 2268 attrs.gradient = value; 2269 attrs.fill = "none"; 2270 break; 2271 } 2272 clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); 2273 case "stroke": 2274 clr = R.getRGB(value); 2275 node[setAttribute](att, clr.hex); 2276 att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); 2277 if (att == "stroke" && o._.arrows) { 2278 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 2279 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 2280 } 2281 break; 2282 case "gradient": 2283 (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); 2284 break; 2285 case "opacity": 2286 if (attrs.gradient && !attrs[has]("stroke-opacity")) { 2287 $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); 2288 } 2289 // fall 2290 case "fill-opacity": 2291 if (attrs.gradient) { 2292 gradient = g.doc.getElementById(node.getAttribute(fillString).replace(/^url\(#|\)$/g, E)); 2293 if (gradient) { 2294 stops = gradient.getElementsByTagName("stop"); 2295 $(stops[stops.length - 1], {"stop-opacity": value}); 2296 } 2297 break; 2298 } 2299 default: 2300 att == "font-size" && (value = toInt(value, 10) + "px"); 2301 var cssrule = att.replace(/(\-.)/g, function (w) { 2302 return upperCase.call(w.substring(1)); 2303 }); 2304 node.style[cssrule] = value; 2305 o._.dirty = 1; 2306 node[setAttribute](att, value); 2307 break; 2308 } 2309 } 2310 } 2311 2312 tuneText(o, params); 2313 }, 2314 leading = 1.2, 2315 tuneText = function (el, params) { 2316 if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { 2317 return; 2318 } 2319 var a = el.attrs, 2320 node = el.node, 2321 fontSize = node.firstChild ? toInt(g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; 2322 2323 if (params[has]("text")) { 2324 a.text = params.text; 2325 while (node.firstChild) { 2326 node.removeChild(node.firstChild); 2327 } 2328 var texts = Str(params.text).split("\n"), 2329 tspans = [], 2330 tspan; 2331 for (var i = 0, ii = texts.length; i < ii; i++) if (texts[i]) { 2332 tspan = $("tspan"); 2333 i && $(tspan, {dy: fontSize * leading, x: a.x}); 2334 tspan.appendChild(g.doc.createTextNode(texts[i])); 2335 node.appendChild(tspan); 2336 tspans[i] = tspan; 2337 } 2338 } else { 2339 tspans = node.getElementsByTagName("tspan"); 2340 for (i = 0, ii = tspans.length; i < ii; i++) { 2341 i && $(tspans[i], {dy: fontSize * leading, x: a.x}); 2342 } 2343 } 2344 $(node, {y: a.y}); 2345 el._.dirty = 1; 2346 var bb = el._getBBox(), 2347 dif = a.y - (bb.y + bb.height / 2); 2348 dif && R.is(dif, "finite") && $(tspans[0], {dy: a.y + dif}); 2349 }, 2350 Element = function (node, svg) { 2351 var X = 0, 2352 Y = 0; 2353 /*\ 2354 * Element.node 2355 [ property (object) ] 2356 ** 2357 * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. 2358 > Usage 2359 | // draw a circle at coordinate 10,10 with radius of 10 2360 | var c = paper.circle(10, 10, 10); 2361 | c.node.onclick = function () { 2362 | c.attr("fill", "red"); 2363 | }; 2364 \*/ 2365 this[0] = this.node = node; 2366 /*\ 2367 * Element.raphael 2368 [ property (object) ] 2369 ** 2370 * Internal reference to @Raphael object. In case it is not available. 2371 > Usage 2372 | Raphael.el.red = function () { 2373 | var hsb = this.paper.raphael.rgb2hsb(this.attr("fill")); 2374 | hsb.h = 1; 2375 | this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex}); 2376 | } 2377 \*/ 2378 node.raphael = true; 2379 /*\ 2380 * Element.id 2381 [ property (number) ] 2382 ** 2383 * Unique id of the element. Especially usesful when you want to listen to events of the element, 2384 * because all events are fired in format `<module>.<action>.<id>`. Also useful for @Paper.getById method. 2385 \*/ 2386 this.id = R._oid++; 2387 node.raphaelid = this.id; 2388 this.matrix = new Matrix; 2389 this.realPath = null; 2390 /*\ 2391 * Element.paper 2392 [ property (object) ] 2393 ** 2394 * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions. 2395 > Usage 2396 | Raphael.el.cross = function () { 2397 | this.attr({fill: "red"}); 2398 | this.paper.path("M10,10L50,50M50,10L10,50") 2399 | .attr({stroke: "red"}); 2400 | } 2401 \*/ 2402 this.paper = svg; 2403 this.attrs = this.attrs || {}; 2404 this._ = { 2405 transform: [], 2406 sx: 1, 2407 sy: 1, 2408 deg: 0, 2409 dx: 0, 2410 dy: 0, 2411 dirty: 1 2412 }; 2413 !svg.bottom && (svg.bottom = this); 2414 /*\ 2415 * Element.prev 2416 [ property (object) ] 2417 ** 2418 * Reference to the previous element in the hierarchy. 2419 \*/ 2420 this.prev = svg.top; 2421 svg.top && (svg.top.next = this); 2422 svg.top = this; 2423 /*\ 2424 * Element.next 2425 [ property (object) ] 2426 ** 2427 * Reference to the next element in the hierarchy. 2428 \*/ 2429 this.next = null; 2430 }, 2431 elproto = Element.prototype; 2432 /*\ 2433 * Element.rotate 2434 [ method ] 2435 ** 2436 * Adds rotation by given angle around given point to the list of 2437 * transformations of the element. 2438 > Parameters 2439 - deg (number) angle in degrees 2440 - cx (number) #optional x coordinate of the centre of rotation 2441 - cy (number) #optional y coordinate of the centre of rotation 2442 * If cx & cy aren’t specified centre of the shape is used as a point of rotation. 2443 = (object) @Element 2444 \*/ 2445 elproto.rotate = function (deg, cx, cy) { 2446 if (this.removed) { 2447 return this; 2448 } 2449 deg = Str(deg).split(separator); 2450 if (deg.length - 1) { 2451 cx = toFloat(deg[1]); 2452 cy = toFloat(deg[2]); 2453 } 2454 deg = toFloat(deg[0]); 2455 (cy == null) && (cx = cy); 2456 if (cx == null || cy == null) { 2457 var bbox = this.getBBox(1); 2458 cx = bbox.x + bbox.width / 2; 2459 cy = bbox.y + bbox.height / 2; 2460 } 2461 this.transform(this._.transform.concat([["r", deg, cx, cy]])); 2462 return this; 2463 }; 2464 /*\ 2465 * Element.scale 2466 [ method ] 2467 ** 2468 * Adds scale by given amount relative to given point to the list of 2469 * transformations of the element. 2470 > Parameters 2471 - sx (number) horisontal scale amount 2472 - sy (number) vertical scale amount 2473 - cx (number) #optional x coordinate of the centre of scale 2474 - cy (number) #optional y coordinate of the centre of scale 2475 * If cx & cy aren’t specified centre of the shape is used instead. 2476 = (object) @Element 2477 \*/ 2478 elproto.scale = function (sx, sy, cx, cy) { 2479 if (this.removed) { 2480 return this; 2481 } 2482 sx = Str(sx).split(separator); 2483 if (sx.length - 1) { 2484 sy = toFloat(sx[1]); 2485 cx = toFloat(sx[2]); 2486 cy = toFloat(sx[3]); 2487 } 2488 sx = toFloat(sx[0]); 2489 (sy == null) && (sy = sx); 2490 (cy == null) && (cx = cy); 2491 if (cx == null || cy == null) { 2492 var bbox = this.getBBox(1); 2493 } 2494 cx = cx == null ? bbox.x + bbox.width / 2 : cx; 2495 cy = cy == null ? bbox.y + bbox.height / 2 : cy; 2496 this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); 2497 return this; 2498 }; 2499 /*\ 2500 * Element.translate 2501 [ method ] 2502 ** 2503 * Adds translation by given amount to the list of transformations of the element. 2504 > Parameters 2505 - dx (number) horisontal shift 2506 - dy (number) vertical shift 2507 = (object) @Element 2508 \*/ 2509 elproto.translate = function (dx, dy) { 2510 if (this.removed) { 2511 return this; 2512 } 2513 dx = Str(dx).split(separator); 2514 if (dx.length - 1) { 2515 dy = toFloat(dx[1]); 2516 } 2517 dx = toFloat(dx[0]) || 0; 2518 dy = +dy || 0; 2519 this.transform(this._.transform.concat([["t", dx, dy]])); 2520 return this; 2521 }; 2522 /*\ 2523 * Element.transform 2524 [ method ] 2525 ** 2526 * Adds transformation to the element which is separate to other attributes, 2527 * i.e. translation doesn’t change `x` or `y` of the rectange. The format 2528 * of transformation string is similar to the path string syntax: 2529 | "t100,100r30,100,100s2,2,100,100r45s1.5" 2530 * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for 2531 * scale and `m` is for matrix. 2532 * 2533 * So, example line could be read like “translate by 100, 100, rotate 30° around 100, 100, scale twice around 100, 100 2534 * rotate 45° around centre and scale 1.5 times relative to centre”. As you see rotate and scale commands has origin 2535 * coordinates as a optional parameters. 2536 * Matrix accepts six parameters. 2537 > Usage 2538 | var el = paper.rect(10, 20, 300, 200); 2539 | // translate 100, 100, rotate 45°, translate -100, 0 2540 | el.transform("t100,100r45t-100,0"); 2541 | // if you want you can append or prepend transformations 2542 | el.transform("...t50,50"); 2543 | el.transform("s2..."); 2544 | // or even wrap 2545 | el.transform("t50,50...t-50-50"); 2546 | // to reset transformation call method with empty string 2547 | el.transform(""); 2548 | // to get current value call it without parameters 2549 | console.log(el.transform()); 2550 > Parameters 2551 - tstr (string) #optional transformation string 2552 * If tstr isn’t specified 2553 = (string) current transformation string 2554 * else 2555 = (object) @Element 2556 \*/ 2557 elproto.transform = function (tstr) { 2558 var _ = this._; 2559 if (!tstr) { 2560 return _.transform; 2561 } 2562 extractTransform(this, tstr); 2563 2564 this.clip && $(this.clip, {transform: this.matrix.invert()}); 2565 // this.gradient && $(this.gradient, {gradientTransform: this.matrix.invert()}); 2566 this.pattern && updatePosition(this); 2567 this.node && $(this.node, {transform: this.matrix}); 2568 2569 if (_.sx != 1 || _.sy != 1) { 2570 var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; 2571 this.attr({"stroke-width": sw}); 2572 } 2573 2574 return this; 2575 }; 2576 /*\ 2577 * Element.hide 2578 [ method ] 2579 ** 2580 * Makes element invisible. See @Element.show. 2581 = (object) @Element 2582 \*/ 2583 elproto.hide = function () { 2584 !this.removed && this.paper.safari(this.node.style.display = "none"); 2585 return this; 2586 }; 2587 /*\ 2588 * Element.show 2589 [ method ] 2590 ** 2591 * Makes element visible. See @Element.hide. 2592 = (object) @Element 2593 \*/ 2594 elproto.show = function () { 2595 !this.removed && this.paper.safari(this.node.style.display = ""); 2596 return this; 2597 }; 2598 /*\ 2599 * Element.remove 2600 [ method ] 2601 ** 2602 * Removes element form the paper. 2603 \*/ 2604 elproto.remove = function () { 2605 if (this.removed) { 2606 return; 2607 } 2608 eve.unbind("*.*." + this.id); 2609 tear(this, this.paper); 2610 this.node.parentNode.removeChild(this.node); 2611 for (var i in this) { 2612 delete this[i]; 2613 } 2614 this.removed = true; 2615 }; 2616 elproto._getBBox = function () { 2617 if (this.node.style.display == "none") { 2618 this.show(); 2619 var hide = true; 2620 } 2621 var bbox = {}; 2622 try { 2623 bbox = this.node.getBBox(); 2624 } catch(e) { 2625 // Firefox 3.0.x plays badly here 2626 } finally { 2627 bbox = bbox || {}; 2628 } 2629 hide && this.hide(); 2630 return bbox; 2631 }; 2632 /*\ 2633 * Element.attr 2634 [ method ] 2635 ** 2636 * Sets the attributes of the element. 2637 > Parameters 2638 - attrName (string) attribute’s name 2639 - value (string) value 2640 * or 2641 - params (object) object of name/value pairs 2642 * or 2643 - attrName (string) attribute’s name 2644 * or 2645 - attrNames (array) in this case method returns array of current values for given attribute names 2646 = (object) @Element if attrsName & value or params are passed in. 2647 = (...) value of the attribute if only attrsName is passed in. 2648 = (array) array of values of the attribute if attrsNames is passed in. 2649 = (object) object of attributes if nothing is passed in. 2650 > Possible parameters 2651 # <p>Please refer to the <a href="http://www.w3.org/TR/SVG/" title="The W3C Recommendation for the SVG language describes these properties in detail.">SVG specification</a> for an explanation of these parameters.</p> 2652 o arrow-end (string) arrowhead on the end of the path. The format for string is `<type>[-<width>[-<length>]]`. Possible types: `classic`, `block`, `open`, `oval`, `diamond`, `none`, width: `wide`, `narrow`, `midium`, length: `long`, `short`, `midium`. 2653 o clip-rect (string) comma or space separated values: x, y, width and height 2654 o cursor (string) CSS type of the cursor 2655 o cx (number) 2656 o cy (number) 2657 o fill (string) colour, gradient or image 2658 o fill-opacity (number) 2659 o font (string) 2660 o font-family (string) 2661 o font-size (number) font size in pixels 2662 o font-weight (string) 2663 o height (number) 2664 o href (string) URL, if specified element behaves as hyperlink 2665 o opacity (number) 2666 o path (string) SVG path string format 2667 o r (number) 2668 o rx (number) 2669 o ry (number) 2670 o src (string) image URL, only works for @Element.image element 2671 o stroke (string) stroke colour 2672 o stroke-dasharray (string) [“”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”] 2673 o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”] 2674 o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”] 2675 o stroke-miterlimit (number) 2676 o stroke-opacity (number) 2677 o stroke-width (number) stroke width in pixels, default is '1' 2678 o target (string) used with href 2679 o text (string) contents of the text element. Use `\n` for multiline text 2680 o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`” 2681 o title (string) will create tooltip with a given text 2682 o transform (string) see @Element.transform 2683 o width (number) 2684 o x (number) 2685 o y (number) 2686 > Gradients 2687 * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90° 2688 * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black. 2689 * 2690 * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” – 2691 * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point 2692 * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses. 2693 > Path String 2694 # <p>Please refer to <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path’s data attribute’s format are described in the SVG specification.">SVG documentation regarding path string</a>. Raphaël fully supports it.</p> 2695 > Colour Parsing 2696 # <ul> 2697 # <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li> 2698 # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li> 2699 # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li> 2700 # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(2001000)</code>”)</li> 2701 # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li> 2702 # <li>rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“<code>rgba(2001000, .5)</code>”)</li> 2703 # <li>rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“<code>rgba(100%, 175%, 0%, 50%)</code>”)</li> 2704 # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.50.251)</code>”)</li> 2705 # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> 2706 # <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li> 2707 # <li>hsl(•••, •••, •••) — almost the same as hsb, see <a href="http://en.wikipedia.org/wiki/HSL_and_HSV" title="HSL and HSV - Wikipedia, the free encyclopedia">Wikipedia page</a></li> 2708 # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> 2709 # <li>hsla(•••, •••, •••) — same as above, but with opacity</li> 2710 # <li>Optionally for hsb and hsl you could specify hue as a degree: “<code>hsl(240deg, 1.5)</code>” or, if you want to go fancy, “<code>hsl(240°, 1.5)</code>”</li> 2711 # </ul> 2712 \*/ 2713 elproto.attr = function (name, value) { 2714 if (this.removed) { 2715 return this; 2716 } 2717 if (name == null) { 2718 var res = {}; 2719 for (var i in this.attrs) if (this.attrs[has](i)) { 2720 res[i] = this.attrs[i]; 2721 } 2722 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; 2723 res.transform = this._.transform; 2724 return res; 2725 } 2726 if (value == null && R.is(name, string)) { 2727 if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { 2728 return this.attrs.gradient; 2729 } 2730 if (name == "transform") { 2731 return this._.transform; 2732 } 2733 if (name in this.attrs) { 2734 return this.attrs[name]; 2735 } else if (R.is(this.paper.customAttributes[name], "function")) { 2736 return this.paper.customAttributes[name].def; 2737 } else { 2738 return availableAttrs[name]; 2739 } 2740 } 2741 if (value == null && R.is(name, array)) { 2742 var values = {}; 2743 for (var j = 0, jj = name.length; j < jj; j++) { 2744 values[name[j]] = this.attr(name[j]); 2745 } 2746 return values; 2747 } 2748 if (value != null) { 2749 var params = {}; 2750 params[name] = value; 2751 } else if (name != null && R.is(name, "object")) { 2752 params = name; 2753 } 2754 for (var key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { 2755 var par = this.paper.customAttributes[key].apply(this, [][concat](params[key])); 2756 this.attrs[key] = params[key]; 2757 for (var subkey in par) if (par[has](subkey)) { 2758 params[subkey] = par[subkey]; 2759 } 2760 } 2761 setFillAndStroke(this, params); 2762 return this; 2763 }; 2764 /*\ 2765 * Element.toFront 2766 [ method ] 2767 ** 2768 * Moves the element so it is the closest to the viewer’s eyes, on top of other elements. 2769 = (object) @Element 2770 \*/ 2771 elproto.toFront = function () { 2772 if (this.removed) { 2773 return this; 2774 } 2775 this.node.parentNode.appendChild(this.node); 2776 var svg = this.paper; 2777 svg.top != this && tofront(this, svg); 2778 return this; 2779 }; 2780 /*\ 2781 * Element.toBack 2782 [ method ] 2783 ** 2784 * Moves the element so it is the furthest from the viewer’s eyes, behind other elements. 2785 = (object) @Element 2786 \*/ 2787 elproto.toBack = function () { 2788 if (this.removed) { 2789 return this; 2790 } 2791 if (this.node.parentNode.firstChild != this.node) { 2792 this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); 2793 toback(this, this.paper); 2794 var svg = this.paper; 2795 } 2796 return this; 2797 }; 2798 /*\ 2799 * Element.insertAfter 2800 [ method ] 2801 ** 2802 * Inserts current object after the given one. 2803 = (object) @Element 2804 \*/ 2805 elproto.insertAfter = function (element) { 2806 if (this.removed) { 2807 return this; 2808 } 2809 var node = element.node || element[element.length - 1].node; 2810 if (node.nextSibling) { 2811 node.parentNode.insertBefore(this.node, node.nextSibling); 2812 } else { 2813 node.parentNode.appendChild(this.node); 2814 } 2815 insertafter(this, element, this.paper); 2816 return this; 2817 }; 2818 /*\ 2819 * Element.insertBefore 2820 [ method ] 2821 ** 2822 * Inserts current object before the given one. 2823 = (object) @Element 2824 \*/ 2825 elproto.insertBefore = function (element) { 2826 if (this.removed) { 2827 return this; 2828 } 2829 var node = element.node || element[0].node; 2830 node.parentNode.insertBefore(this.node, node); 2831 insertbefore(this, element, this.paper); 2832 return this; 2833 }; 2834 elproto.blur = function (size) { 2835 // Experimental. No Safari support. Use it on your own risk. 2836 var t = this; 2837 if (+size !== 0) { 2838 var fltr = $("filter"), 2839 blur = $("feGaussianBlur"); 2840 t.attrs.blur = size; 2841 fltr.id = createUUID(); 2842 $(blur, {stdDeviation: +size || 1.5}); 2843 fltr.appendChild(blur); 2844 t.paper.defs.appendChild(fltr); 2845 t._blur = fltr; 2846 $(t.node, {filter: "url(#" + fltr.id + ")"}); 2847 } else { 2848 if (t._blur) { 2849 t._blur.parentNode.removeChild(t._blur); 2850 delete t._blur; 2851 delete t.attrs.blur; 2852 } 2853 t.node.removeAttribute("filter"); 2854 } 2855 }; 2856 var theCircle = function (svg, x, y, r) { 2857 var el = $("circle"); 2858 svg.canvas && svg.canvas.appendChild(el); 2859 var res = new Element(el, svg); 2860 res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; 2861 res.type = "circle"; 2862 $(el, res.attrs); 2863 return res; 2864 }, 2865 theRect = function (svg, x, y, w, h, r) { 2866 var el = $("rect"); 2867 svg.canvas && svg.canvas.appendChild(el); 2868 var res = new Element(el, svg); 2869 res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; 2870 res.type = "rect"; 2871 $(el, res.attrs); 2872 return res; 2873 }, 2874 theEllipse = function (svg, x, y, rx, ry) { 2875 var el = $("ellipse"); 2876 svg.canvas && svg.canvas.appendChild(el); 2877 var res = new Element(el, svg); 2878 res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; 2879 res.type = "ellipse"; 2880 $(el, res.attrs); 2881 return res; 2882 }, 2883 theImage = function (svg, src, x, y, w, h) { 2884 var el = $("image"); 2885 $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); 2886 el.setAttributeNS(xlink, "href", src); 2887 svg.canvas && svg.canvas.appendChild(el); 2888 var res = new Element(el, svg); 2889 res.attrs = {x: x, y: y, width: w, height: h, src: src}; 2890 res.type = "image"; 2891 return res; 2892 }, 2893 theText = function (svg, x, y, text) { 2894 var el = $("text"); 2895 $(el, {x: x, y: y, "text-anchor": "middle"}); 2896 svg.canvas && svg.canvas.appendChild(el); 2897 var res = new Element(el, svg); 2898 res.attrs = {x: x, y: y, "text-anchor": "middle", text: text, font: availableAttrs.font, stroke: "none", fill: "#000"}; 2899 res.type = "text"; 2900 setFillAndStroke(res, res.attrs); 2901 return res; 2902 }, 2903 setSize = function (width, height) { 2904 this.width = width || this.width; 2905 this.height = height || this.height; 2906 this.canvas[setAttribute]("width", this.width); 2907 this.canvas[setAttribute]("height", this.height); 2908 if (this._viewBox) { 2909 this.setViewBox.apply(this, this._viewBox); 2910 } 2911 return this; 2912 }, 2913 create = function () { 2914 var con = getContainer[apply](0, arguments), 2915 container = con && con.container, 2916 x = con.x, 2917 y = con.y, 2918 width = con.width, 2919 height = con.height; 2920 if (!container) { 2921 throw new Error("SVG container not found."); 2922 } 2923 var cnvs = $("svg"), 2924 css = "overflow:hidden;"; 2925 x = x || 0; 2926 y = y || 0; 2927 width = width || 512; 2928 height = height || 342; 2929 $(cnvs, { 2930 height: height, 2931 version: 1.1, 2932 width: width, 2933 xmlns: "http://www.w3.org/2000/svg" 2934 }); 2935 if (container == 1) { 2936 cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; 2937 g.doc.body.appendChild(cnvs); 2938 } else { 2939 cnvs.style.cssText = css; 2940 if (container.firstChild) { 2941 container.insertBefore(cnvs, container.firstChild); 2942 } else { 2943 container.appendChild(cnvs); 2944 } 2945 } 2946 container = new Paper; 2947 container.width = width; 2948 container.height = height; 2949 container.canvas = cnvs; 2950 plugins.call(container, container, R.fn); 2951 container.clear(); 2952 return container; 2953 }, 2954 setViewBox = function (x, y, w, h, fit) { 2955 eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); 2956 var size = mmax(w / this.width, h / this.height), 2957 top = this.top, 2958 aspectRatio = fit ? "meet" : "xMinYMin", 2959 vb, 2960 sw; 2961 if (x == null) { 2962 if (this._vbSize) { 2963 size = 1; 2964 } 2965 delete this._vbSize; 2966 vb = "0 0 " + this.width + S + this.height; 2967 } else { 2968 this._vbSize = size; 2969 vb = x + S + y + S + w + S + h; 2970 } 2971 $(this.canvas, { 2972 viewBox: vb, 2973 preserveAspectRatio: aspectRatio 2974 }); 2975 while (size && top) { 2976 sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; 2977 top.attr({"stroke-width": sw}); 2978 top._.dirty = 1; 2979 top._.dirtyT = 1; 2980 top = top.prev; 2981 } 2982 this._viewBox = [x, y, w, h, !!fit]; 2983 return this; 2984 }; 2985 /*\ 2986 * Paper.clear 2987 [ method ] 2988 ** 2989 * Clears the paper, i.e. removes all the elements. 2990 \*/ 2991 paperproto.clear = function () { 2992 eve("clear", this); 2993 var c = this.canvas; 2994 while (c.firstChild) { 2995 c.removeChild(c.firstChild); 2996 } 2997 this.bottom = this.top = null; 2998 (this.desc = $("desc")).appendChild(g.doc.createTextNode("Created with Rapha\xebl " + R.version)); 2999 c.appendChild(this.desc); 3000 c.appendChild(this.defs = $("defs")); 3001 }; 3002 /*\ 3003 * Paper.remove 3004 [ method ] 3005 ** 3006 * Removes the paper from the DOM. 3007 \*/ 3008 paperproto.remove = function () { 3009 eve("remove", this); 3010 this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); 3011 for (var i in this) { 3012 this[i] = removed(i); 3013 } 3014 }; 3015 } 3016 3017 // VML 3018 if (R.vml) { 3019 var map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, 3020 bites = /([clmz]),?([^clmz]*)/gi, 3021 blurregexp = / progid:\S+Blur\([^\)]+\)/g, 3022 val = /-?[^,\s-]+/g, 3023 cssDot = "position:absolute;left:0;top:0;width:1px;height:1px", 3024 zoom = 21600, 3025 pathTypes = {path: 1, rect: 1}, 3026 ovalTypes = {circle: 1, ellipse: 1}, 3027 path2vml = function (path) { 3028 var total = /[ahqstv]/ig, 3029 command = pathToAbsolute; 3030 Str(path).match(total) && (command = path2curve); 3031 total = /[clmz]/g; 3032 if (command == pathToAbsolute && !Str(path).match(total)) { 3033 var res = Str(path).replace(bites, function (all, command, args) { 3034 var vals = [], 3035 isMove = lowerCase.call(command) == "m", 3036 res = map[command]; 3037 args.replace(val, function (value) { 3038 if (isMove && vals.length == 2) { 3039 res += vals + map[command == "m" ? "l" : "L"]; 3040 vals = []; 3041 } 3042 vals.push(round(value * zoom)); 3043 }); 3044 return res + vals; 3045 }); 3046 return res; 3047 } 3048 var pa = command(path), p, r; 3049 res = []; 3050 for (var i = 0, ii = pa.length; i < ii; i++) { 3051 p = pa[i]; 3052 r = lowerCase.call(pa[i][0]); 3053 r == "z" && (r = "x"); 3054 for (var j = 1, jj = p.length; j < jj; j++) { 3055 r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); 3056 } 3057 res.push(r); 3058 } 3059 return res.join(S); 3060 }, 3061 compensation = function (deg, dx, dy) { 3062 var m = new Matrix; 3063 m.rotate(-deg, .5, .5); 3064 return { 3065 dx: m.x(dx, dy), 3066 dy: m.y(dx, dy) 3067 }; 3068 }, 3069 setCoords = function (p) { 3070 var _ = p._, 3071 sx = _.sx, 3072 sy = _.sy, 3073 deg = _.deg, 3074 dx = _.dx, 3075 dy = _.dy, 3076 fillpos = _.fillpos, 3077 o = p.node, 3078 s = o.style, 3079 y = 1, 3080 m = p.matrix, 3081 flip = "", 3082 dxdy, 3083 kx = zoom / sx, 3084 ky = zoom / sy; 3085 s.visibility = "hidden"; 3086 o.coordsize = abs(kx) + S + abs(ky); 3087 s.rotation = deg * (sx * sy < 0 ? -1 : 1); 3088 if (deg) { 3089 var c = compensation(deg, dx, dy); 3090 dx = c.dx; 3091 dy = c.dy; 3092 } 3093 sx < 0 && (flip += "x"); 3094 sy < 0 && (flip += " y") && (y = -1); 3095 s.flip = flip; 3096 o.coordorigin = (dx * -kx) + S + (dy * -ky); 3097 if (fillpos || _.fillsize) { 3098 var fill = o.getElementsByTagName(fillString); 3099 fill = fill && fill[0]; 3100 o.removeChild(fill); 3101 if (fillpos) { 3102 c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); 3103 fill.position = c.dx * y + S + c.dy * y; 3104 } 3105 if (_.fillsize) { 3106 fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); 3107 } 3108 o.appendChild(fill); 3109 } 3110 s.visibility = "visible"; 3111 }; 3112 R.toString = function () { 3113 return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; 3114 }; 3115 addArrow = function (o, value, isEnd) { 3116 var values = Str(value).toLowerCase().split("-"), 3117 se = isEnd ? "end" : "start", 3118 i = values.length, 3119 type = "classic", 3120 w = "medium", 3121 h = "medium"; 3122 while (i--) { 3123 switch (values[i]) { 3124 case "block": 3125 case "classic": 3126 case "oval": 3127 case "diamond": 3128 case "open": 3129 case "none": 3130 type = values[i]; 3131 break; 3132 case "wide": 3133 case "narrow": h = values[i]; break; 3134 case "long": 3135 case "short": w = values[i]; break; 3136 } 3137 } 3138 var stroke = o.node.getElementsByTagName("stroke")[0]; 3139 stroke[se + "arrow"] = type; 3140 stroke[se + "arrowlength"] = w; 3141 stroke[se + "arrowwidth"] = h; 3142 }; 3143 setFillAndStroke = function (o, params) { 3144 o.paper.canvas.style.display = "none"; 3145 o.attrs = o.attrs || {}; 3146 var node = o.node, 3147 a = o.attrs, 3148 s = node.style, 3149 xy, 3150 newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r), 3151 isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), 3152 res = o; 3153 3154 3155 for (var par in params) if (params[has](par)) { 3156 a[par] = params[par]; 3157 } 3158 if (newpath) { 3159 a.path = getPath[o.type](o); 3160 o._.dirty = 1; 3161 } 3162 params.href && (node.href = params.href); 3163 params.title && (node.title = params.title); 3164 params.target && (node.target = params.target); 3165 params.cursor && (s.cursor = params.cursor); 3166 "blur" in params && o.blur(params.blur); 3167 "transform" in params && o.transform(params.transform); 3168 if (params.path && o.type == "path" || newpath) { 3169 node.path = path2vml(a.path); 3170 } 3171 if (isOval) { 3172 var cx = a.cx, 3173 cy = a.cy, 3174 rx = a.rx || a.r || 0, 3175 ry = a.ry || a.r || 0; 3176 node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom)); 3177 } 3178 if ("clip-rect" in params) { 3179 var rect = Str(params["clip-rect"]).split(separator); 3180 if (rect.length == 4) { 3181 rect[2] = +rect[2] + (+rect[0]); 3182 rect[3] = +rect[3] + (+rect[1]); 3183 var div = node.clipRect || g.doc.createElement("div"), 3184 dstyle = div.style, 3185 group = node.parentNode; 3186 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); 3187 if (!node.clipRect) { 3188 dstyle.position = "absolute"; 3189 dstyle.top = 0; 3190 dstyle.left = 0; 3191 dstyle.width = o.paper.width + "px"; 3192 dstyle.height = o.paper.height + "px"; 3193 group.parentNode.insertBefore(div, group); 3194 div.appendChild(group); 3195 node.clipRect = div; 3196 } 3197 } 3198 if (!params["clip-rect"]) { 3199 node.clipRect && (node.clipRect.style.clip = E); 3200 } 3201 } 3202 if (o.textpath) { 3203 var textpathStyle = o.textpath.style; 3204 params.font && (textpathStyle.font = params.font); 3205 params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); 3206 params["font-size"] && (textpathStyle.fontSize = params["font-size"]); 3207 params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); 3208 params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); 3209 } 3210 if ("arrow-start" in params) { 3211 addArrow(res, params["arrow-start"]); 3212 } 3213 if ("arrow-end" in params) { 3214 addArrow(res, params["arrow-end"], 1); 3215 } 3216 if (params.opacity != null || 3217 params["stroke-width"] != null || 3218 params.fill != null || 3219 params.src != null || 3220 params.stroke != null || 3221 params["stroke-width"] != null || 3222 params["stroke-opacity"] != null || 3223 params["fill-opacity"] != null || 3224 params["stroke-dasharray"] != null || 3225 params["stroke-miterlimit"] != null || 3226 params["stroke-linejoin"] != null || 3227 params["stroke-linecap"] != null) { 3228 var fill = node.getElementsByTagName(fillString), 3229 newfill = false; 3230 fill = fill && fill[0]; 3231 !fill && (newfill = fill = createNode(fillString)); 3232 if (o.type == "image" && params.src) { 3233 fill.src = params.src; 3234 } 3235 if ("fill-opacity" in params || "opacity" in params) { 3236 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); 3237 opacity = mmin(mmax(opacity, 0), 1); 3238 fill.opacity = opacity; 3239 } 3240 params.fill && (fill.on = true); 3241 if (fill.on == null || params.fill == "none" || params.fill === null) { 3242 fill.on = false; 3243 } 3244 if (fill.on && params.fill) { 3245 var isURL = params.fill.match(ISURL); 3246 if (isURL) { 3247 fill.parentNode == node && node.removeChild(fill); 3248 fill.rotate = true; 3249 fill.src = isURL[1]; 3250 fill.type = "tile"; 3251 var bbox = o.getBBox(1); 3252 fill.position = bbox.x + S + bbox.y; 3253 o._.fillpos = [bbox.x, bbox.y]; 3254 3255 preload(isURL[1], function () { 3256 o._.fillsize = [this.offsetWidth, this.offsetHeight]; 3257 }); 3258 } else { 3259 fill.color = R.getRGB(params.fill).hex; 3260 fill.src = E; 3261 fill.type = "solid"; 3262 if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { 3263 a.fill = "none"; 3264 a.gradient = params.fill; 3265 fill.rotate = false; 3266 } 3267 } 3268 } 3269 node.appendChild(fill); 3270 var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), 3271 newstroke = false; 3272 !stroke && (newstroke = stroke = createNode("stroke")); 3273 if ((params.stroke && params.stroke != "none") || 3274 params["stroke-width"] || 3275 params["stroke-opacity"] != null || 3276 params["stroke-dasharray"] || 3277 params["stroke-miterlimit"] || 3278 params["stroke-linejoin"] || 3279 params["stroke-linecap"]) { 3280 stroke.on = true; 3281 } 3282 (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); 3283 var strokeColor = R.getRGB(params.stroke); 3284 stroke.on && params.stroke && (stroke.color = strokeColor.hex); 3285 opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); 3286 var width = (toFloat(params["stroke-width"]) || 1) * .75; 3287 opacity = mmin(mmax(opacity, 0), 1); 3288 params["stroke-width"] == null && (width = a["stroke-width"]); 3289 params["stroke-width"] && (stroke.weight = width); 3290 width && width < 1 && (opacity *= width) && (stroke.weight = 1); 3291 stroke.opacity = opacity; 3292 3293 params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); 3294 stroke.miterlimit = params["stroke-miterlimit"] || 8; 3295 params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); 3296 if (params["stroke-dasharray"]) { 3297 var dasharray = { 3298 "-": "shortdash", 3299 ".": "shortdot", 3300 "-.": "shortdashdot", 3301 "-..": "shortdashdotdot", 3302 ". ": "dot", 3303 "- ": "dash", 3304 "--": "longdash", 3305 "- .": "dashdot", 3306 "--.": "longdashdot", 3307 "--..": "longdashdotdot" 3308 }; 3309 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; 3310 } 3311 newstroke && node.appendChild(stroke); 3312 } 3313 if (res.type == "text") { 3314 res.paper.canvas.style.display = E; 3315 var span = res.paper.span, 3316 m = 100, 3317 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); 3318 s = span.style; 3319 a.font && (s.font = a.font); 3320 a["font-family"] && (s.fontFamily = a["font-family"]); 3321 a["font-weight"] && (s.fontWeight = a["font-weight"]); 3322 a["font-style"] && (s.fontStyle = a["font-style"]); 3323 fontSize = toFloat(fontSize ? fontSize[0] : a["font-size"]); 3324 s.fontSize = fontSize * m + "px"; 3325 res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "&#60;").replace(/&/g, "&#38;").replace(/\n/g, "<br>")); 3326 var brect = span.getBoundingClientRect(); 3327 res.W = a.w = (brect.right - brect.left) / m; 3328 res.H = a.h = (brect.bottom - brect.top) / m; 3329 res.paper.canvas.style.display = "none"; 3330 res.X = a.x; 3331 res.Y = a.y + res.H / 2; 3332 3333 ("x" in params || "y" in params) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round(a.y * zoom), round(a.x * zoom) + 1)); 3334 var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; 3335 for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { 3336 res._.dirty = 1; 3337 break; 3338 } 3339 3340 // text-anchor emulation 3341 switch (a["text-anchor"]) { 3342 case "start": 3343 res.textpath.style["v-text-align"] = "left"; 3344 res.bbx = res.W / 2; 3345 break; 3346 case "end": 3347 res.textpath.style["v-text-align"] = "right"; 3348 res.bbx = -res.W / 2; 3349 break; 3350 default: 3351 res.textpath.style["v-text-align"] = "center"; 3352 res.bbx = 0; 3353 break; 3354 } 3355 res.textpath.style["v-text-kern"] = true; 3356 } 3357 res.paper.canvas.style.display = E; 3358 }; 3359 addGradientFill = function (o, gradient, fill) { 3360 o.attrs = o.attrs || {}; 3361 var attrs = o.attrs, 3362 type = "linear", 3363 fxfy = ".5 .5"; 3364 o.attrs.gradient = gradient; 3365 gradient = Str(gradient).replace(radial_gradient, function (all, fx, fy) { 3366 type = "radial"; 3367 if (fx && fy) { 3368 fx = toFloat(fx); 3369 fy = toFloat(fy); 3370 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); 3371 fxfy = fx + S + fy; 3372 } 3373 return E; 3374 }); 3375 gradient = gradient.split(/\s*\-\s*/); 3376 if (type == "linear") { 3377 var angle = gradient.shift(); 3378 angle = -toFloat(angle); 3379 if (isNaN(angle)) { 3380 return null; 3381 } 3382 } 3383 var dots = parseDots(gradient); 3384 if (!dots) { 3385 return null; 3386 } 3387 o = o.shape || o.node; 3388 if (dots.length) { 3389 o.removeChild(fill); 3390 fill.on = true; 3391 fill.method = "none"; 3392 fill.color = dots[0].color; 3393 fill.color2 = dots[dots.length - 1].color; 3394 var clrs = []; 3395 for (var i = 0, ii = dots.length; i < ii; i++) { 3396 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); 3397 } 3398 fill.colors && (fill.colors.value = clrs.length ? clrs.join() : "0% " + fill.color); 3399 if (type == "radial") { 3400 fill.type = "gradientTitle"; 3401 fill.focus = "100%"; 3402 fill.focussize = "0 0"; 3403 fill.focusposition = fxfy; 3404 fill.angle = 0; 3405 } else { 3406 // fill.rotate= true; 3407 fill.type = "gradient"; 3408 fill.angle = (270 - angle) % 360; 3409 } 3410 o.appendChild(fill); 3411 // alert(fill.outerHTML); 3412 } 3413 return 1; 3414 }; 3415 Element = function (node, vml) { 3416 this[0] = this.node = node; 3417 node.raphael = true; 3418 this.id = R._oid++; 3419 node.raphaelid = this.id; 3420 this.X = 0; 3421 this.Y = 0; 3422 this.attrs = {}; 3423 this.paper = vml; 3424 this.matrix = new Matrix; 3425 this._ = { 3426 transform: [], 3427 sx: 1, 3428 sy: 1, 3429 dx: 0, 3430 dy: 0, 3431 deg: 0, 3432 dirty: 1, 3433 dirtyT: 1 3434 }; 3435 !vml.bottom && (vml.bottom = this); 3436 this.prev = vml.top; 3437 vml.top && (vml.top.next = this); 3438 vml.top = this; 3439 this.next = null; 3440 }; 3441 elproto = Element.prototype; 3442 elproto.transform = function (tstr) { 3443 if (tstr == null) { 3444 return this._.transform; 3445 } 3446 extractTransform(this, tstr); 3447 var matrix = this.matrix.clone(), 3448 skew = this.skew; 3449 matrix.translate(-.5, -.5); 3450 if (this.type == "image") { 3451 if (Str(tstr).indexOf("m") + 1) { 3452 this.node.style.filter = matrix.toFilter(); 3453 var bb = this.getBBox(), 3454 bbt = this.getBBox(1), 3455 im = matrix.invert(), 3456 dx = im.x(bb.x, bb.y) - im.x(bbt.x, bbt.y), 3457 dy = im.y(bb.x, bb.y) - im.y(bbt.x, bbt.y); 3458 // skew.offset = dx + S + dy; 3459 // this.node.getElementsByTagName(fillString)[0].position = skew.offset; 3460 } else { 3461 this.node.style.filter = E; 3462 setCoords(this); 3463 } 3464 } else { 3465 // o = this.node, 3466 // _ = this._, 3467 // fillpos = _.fillpos, 3468 // deg, 3469 // matrix = this.matrix; 3470 // fill = o.getElementsByTagName(fillString)[0], 3471 // angle = fill.angle; 3472 3473 this.node.style.filter = E; 3474 skew.matrix = matrix; 3475 skew.offset = matrix.offset(); 3476 3477 // if (0&&angle) { 3478 // angle = R.rad(270 - angle); 3479 // var dx = 100 * math.cos(angle), 3480 // dy = 100 * math.sin(angle), 3481 // zx = matrix.x(0, 0), 3482 // zy = matrix.y(0, 0), 3483 // mx = matrix.x(dx, dy), 3484 // my = matrix.y(dx, dy); 3485 // angle = R.angle(zx, zy, mx, my); 3486 // fill.angle = (270 - angle) % 360; 3487 // } 3488 } 3489 return this; 3490 }; 3491 elproto.rotate = function (deg, cx, cy) { 3492 if (this.removed) { 3493 return this; 3494 } 3495 if (deg == null) { 3496 return; 3497 } 3498 deg = Str(deg).split(separator); 3499 if (deg.length - 1) { 3500 cx = toFloat(deg[1]); 3501 cy = toFloat(deg[2]); 3502 } 3503 deg = toFloat(deg[0]); 3504 (cy == null) && (cx = cy); 3505 if (cx == null || cy == null) { 3506 var bbox = this.getBBox(1); 3507 cx = bbox.x + bbox.width / 2; 3508 cy = bbox.y + bbox.height / 2; 3509 } 3510 this._.dirtyT = 1; 3511 this.transform(this._.transform.concat([["r", deg, cx, cy]])); 3512 return this; 3513 }; 3514 elproto.translate = function (dx, dy) { 3515 if (this.removed) { 3516 return this; 3517 } 3518 dx = Str(dx).split(separator); 3519 if (dx.length - 1) { 3520 dy = toFloat(dx[1]); 3521 } 3522 dx = toFloat(dx[0]) || 0; 3523 dy = +dy || 0; 3524 if (this._.bbox) { 3525 this._.bbox.x += dx; 3526 this._.bbox.y += dy; 3527 } 3528 this.transform(this._.transform.concat([["t", dx, dy]])); 3529 return this; 3530 }; 3531 elproto.scale = function (sx, sy, cx, cy) { 3532 if (this.removed) { 3533 return this; 3534 } 3535 sx = Str(sx).split(separator); 3536 if (sx.length - 1) { 3537 sy = toFloat(sx[1]); 3538 cx = toFloat(sx[2]); 3539 cy = toFloat(sx[3]); 3540 isNaN(cx) && (cx = null); 3541 isNaN(cy) && (cy = null); 3542 } 3543 sx = toFloat(sx[0]); 3544 (sy == null) && (sy = sx); 3545 (cy == null) && (cx = cy); 3546 if (cx == null || cy == null) { 3547 var bbox = this.getBBox(1); 3548 } 3549 cx = cx == null ? bbox.x + bbox.width / 2 : cx; 3550 cy = cy == null ? bbox.y + bbox.height / 2 : cy; 3551 3552 this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); 3553 this._.dirtyT = 1; 3554 return this; 3555 }; 3556 elproto.hide = function () { 3557 !this.removed && (this.node.style.display = "none"); 3558 return this; 3559 }; 3560 elproto.show = function () { 3561 !this.removed && (this.node.style.display = E); 3562 return this; 3563 }; 3564 elproto._getBBox = function () { 3565 if (this.removed) { 3566 return {}; 3567 } 3568 if (this.type == "text") { 3569 return { 3570 x: this.X + (this.bbx || 0) - this.W / 2, 3571 y: this.Y - this.H, 3572 width: this.W, 3573 height: this.H 3574 }; 3575 } else { 3576 return pathDimensions(this.attrs.path); 3577 } 3578 }; 3579 elproto.remove = function () { 3580 if (this.removed) { 3581 return; 3582 } 3583 eve.unbind("*.*." + this.id); 3584 tear(this, this.paper); 3585 this.node.parentNode.removeChild(this.node); 3586 this.shape && this.shape.parentNode.removeChild(this.shape); 3587 for (var i in this) { 3588 delete this[i]; 3589 } 3590 this.removed = true; 3591 }; 3592 elproto.attr = function (name, value) { 3593 if (this.removed) { 3594 return this; 3595 } 3596 if (name == null) { 3597 var res = {}; 3598 for (var i in this.attrs) if (this.attrs[has](i)) { 3599 res[i] = this.attrs[i]; 3600 } 3601 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; 3602 return res; 3603 } 3604 if (value == null && R.is(name, "string")) { 3605 if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { 3606 return this.attrs.gradient; 3607 } 3608 if (name in this.attrs) { 3609 return this.attrs[name]; 3610 } else if (R.is(this.paper.customAttributes[name], "function")) { 3611 return this.paper.customAttributes[name].def; 3612 } else { 3613 return availableAttrs[name]; 3614 } 3615 } 3616 if (this.attrs && value == null && R.is(name, array)) { 3617 var ii, values = {}; 3618 for (i = 0, ii = name.length; i < ii; i++) { 3619 values[name[i]] = this.attr(name[i]); 3620 } 3621 return values; 3622 } 3623 var params; 3624 if (value != null) { 3625 params = {}; 3626 params[name] = value; 3627 } 3628 value == null && R.is(name, "object") && (params = name); 3629 for (var key in params) { 3630 eve("attr." + key + "." + this.id, this, params[key]); 3631 } 3632 if (params) { 3633 for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { 3634 var par = this.paper.customAttributes[key].apply(this, [][concat](params[key])); 3635 this.attrs[key] = params[key]; 3636 for (var subkey in par) if (par[has](subkey)) { 3637 params[subkey] = par[subkey]; 3638 } 3639 } 3640 // this.paper.canvas.style.display = "none"; 3641 if (params.text && this.type == "text") { 3642 this.textpath.string = params.text; 3643 } 3644 setFillAndStroke(this, params); 3645 // this.paper.canvas.style.display = E; 3646 } 3647 return this; 3648 }; 3649 elproto.toFront = function () { 3650 !this.removed && this.node.parentNode.appendChild(this.node); 3651 this.paper.top != this && tofront(this, this.paper); 3652 return this; 3653 }; 3654 elproto.toBack = function () { 3655 if (this.removed) { 3656 return this; 3657 } 3658 if (this.node.parentNode.firstChild != this.node) { 3659 this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); 3660 toback(this, this.paper); 3661 } 3662 return this; 3663 }; 3664 elproto.insertAfter = function (element) { 3665 if (this.removed) { 3666 return this; 3667 } 3668 if (element.constructor == Set) { 3669 element = element[element.length - 1]; 3670 } 3671 if (element.node.nextSibling) { 3672 element.node.parentNode.insertBefore(this.node, element.node.nextSibling); 3673 } else { 3674 element.node.parentNode.appendChild(this.node); 3675 } 3676 insertafter(this, element, this.paper); 3677 return this; 3678 }; 3679 elproto.insertBefore = function (element) { 3680 if (this.removed) { 3681 return this; 3682 } 3683 if (element.constructor == Set) { 3684 element = element[0]; 3685 } 3686 element.node.parentNode.insertBefore(this.node, element.node); 3687 insertbefore(this, element, this.paper); 3688 return this; 3689 }; 3690 elproto.blur = function (size) { 3691 var s = this.node.runtimeStyle, 3692 f = s.filter; 3693 f = f.replace(blurregexp, E); 3694 if (+size !== 0) { 3695 this.attrs.blur = size; 3696 s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; 3697 s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); 3698 } else { 3699 s.filter = f; 3700 s.margin = 0; 3701 delete this.attrs.blur; 3702 } 3703 }; 3704 3705 thePath = function (pathString, vml) { 3706 var el = createNode("shape"); 3707 el.style.cssText = cssDot; 3708 el.coordsize = zoom + S + zoom; 3709 el.coordorigin = vml.coordorigin; 3710 var p = new Element(el, vml), 3711 attr = {fill: "none", stroke: "#000"}; 3712 pathString && (attr.path = pathString); 3713 p.type = "path"; 3714 p.path = []; 3715 p.Path = E; 3716 setFillAndStroke(p, attr); 3717 vml.canvas.appendChild(el); 3718 var skew = createNode("skew"); 3719 skew.on = true; 3720 el.appendChild(skew); 3721 p.skew = skew; 3722 p.transform(E); 3723 return p; 3724 }; 3725 theRect = function (vml, x, y, w, h, r) { 3726 var path = rectPath(x, y, w, h, r), 3727 res = vml.path(path), 3728 a = res.attrs; 3729 res.X = a.x = x; 3730 res.Y = a.y = y; 3731 res.W = a.width = w; 3732 res.H = a.height = h; 3733 a.r = r; 3734 a.path = path; 3735 res.type = "rect"; 3736 return res; 3737 }; 3738 theEllipse = function (vml, x, y, rx, ry) { 3739 var res = vml.path(), 3740 a = res.attrs; 3741 res.X = x - rx; 3742 res.Y = y - ry; 3743 res.W = rx * 2; 3744 res.H = ry * 2; 3745 res.type = "ellipse"; 3746 setFillAndStroke(res, { 3747 cx: x, 3748 cy: y, 3749 rx: rx, 3750 ry: ry 3751 }); 3752 return res; 3753 }; 3754 theCircle = function (vml, x, y, r) { 3755 var res = vml.path(), 3756 a = res.attrs; 3757 res.X = x - r; 3758 res.Y = y - r; 3759 res.W = res.H = r * 2; 3760 res.type = "circle"; 3761 setFillAndStroke(res, { 3762 cx: x, 3763 cy: y, 3764 r: r 3765 }); 3766 return res; 3767 }; 3768 theImage = function (vml, src, x, y, w, h) { 3769 var path = rectPath(x, y, w, h), 3770 res = vml.path(path).attr({stroke: "none"}), 3771 a = res.attrs, 3772 node = res.node, 3773 fill = node.getElementsByTagName(fillString)[0]; 3774 a.src = src; 3775 res.X = a.x = x; 3776 res.Y = a.y = y; 3777 res.W = a.width = w; 3778 res.H = a.height = h; 3779 a.path = path; 3780 res.type = "image"; 3781 fill.parentNode == node && node.removeChild(fill); 3782 fill.rotate = true; 3783 fill.src = src; 3784 fill.type = "tile"; 3785 res._.fillpos = [x, y]; 3786 res._.fillsize = [w, h]; 3787 node.appendChild(fill); 3788 setCoords(res); 3789 return res; 3790 }; 3791 theText = function (vml, x, y, text) { 3792 var el = createNode("shape"), 3793 path = createNode("path"), 3794 o = createNode("textpath"); 3795 x = x || 0; 3796 y = y || 0; 3797 text = text || ""; 3798 path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); 3799 path.textpathok = true; 3800 o.string = Str(text); 3801 o.on = true; 3802 el.style.cssText = "position:absolute;left:0;top:0;width:1;height:1"; 3803 el.coordsize = zoom + S + zoom; 3804 el.coordorigin = "0 0"; 3805 var p = new Element(el, vml), 3806 attr = {fill: "#000", stroke: "none", font: availableAttrs.font, text: text}; 3807 p.shape = el; 3808 p.path = path; 3809 p.textpath = o; 3810 p.type = "text"; 3811 p.attrs.text = Str(text); 3812 p.attrs.x = x; 3813 p.attrs.y = y; 3814 p.attrs.w = 1; 3815 p.attrs.h = 1; 3816 setFillAndStroke(p, attr); 3817 el.appendChild(o); 3818 el.appendChild(path); 3819 vml.canvas.appendChild(el); 3820 var skew = createNode("skew"); 3821 skew.on = true; 3822 el.appendChild(skew); 3823 p.skew = skew; 3824 p.transform(E); 3825 return p; 3826 }; 3827 setSize = function (width, height) { 3828 var cs = this.canvas.style; 3829 this.width = width; 3830 this.height = height; 3831 width == +width && (width += "px"); 3832 height == +height && (height += "px"); 3833 cs.width = width; 3834 cs.height = height; 3835 cs.clip = "rect(0 " + width + " " + height + " 0)"; 3836 if (this._viewBox) { 3837 setViewBox.apply(this, this._viewBox); 3838 } 3839 return this; 3840 }; 3841 setViewBox = function (x, y, w, h, fit) { 3842 eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); 3843 var width = this.width, 3844 height = this.height, 3845 size = 1e3 * mmax(w / width, h / height), 3846 H, W; 3847 if (fit) { 3848 H = height / h; 3849 W = width / w; 3850 if (w * H < width) { 3851 x -= (width - w * H) / 2 / H; 3852 } 3853 if (h * W < height) { 3854 y -= (height - h * W) / 2 / W; 3855 } 3856 } 3857 this._viewBox = [x, y, w, h, !!fit]; 3858 this.forEach(function (el) { 3859 el.transform("..."); 3860 }); 3861 return this; 3862 }; 3863 var createNode, 3864 initWin = function (win) { 3865 var doc = win.document; 3866 doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); 3867 try { 3868 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); 3869 createNode = function (tagName) { 3870 return doc.createElement('<rvml:' + tagName + ' class="rvml">'); 3871 }; 3872 } catch (e) { 3873 createNode = function (tagName) { 3874 return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); 3875 }; 3876 } 3877 }; 3878 initWin(g.win); 3879 create = function () { 3880 var con = getContainer[apply](0, arguments), 3881 container = con.container, 3882 height = con.height, 3883 s, 3884 width = con.width, 3885 x = con.x, 3886 y = con.y; 3887 if (!container) { 3888 throw new Error("VML container not found."); 3889 } 3890 var res = new Paper, 3891 c = res.canvas = g.doc.createElement("div"), 3892 cs = c.style; 3893 x = x || 0; 3894 y = y || 0; 3895 width = width || 512; 3896 height = height || 342; 3897 res.width = width; 3898 res.height = height; 3899 width == +width && (width += "px"); 3900 height == +height && (height += "px"); 3901 res.coordsize = zoom * 1e3 + S + zoom * 1e3; 3902 res.coordorigin = "0 0"; 3903 res.span = g.doc.createElement("span"); 3904 res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; 3905 c.appendChild(res.span); 3906 cs.cssText = R.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height); 3907 if (container == 1) { 3908 g.doc.body.appendChild(c); 3909 cs.left = x + "px"; 3910 cs.top = y + "px"; 3911 cs.position = "absolute"; 3912 } else { 3913 if (container.firstChild) { 3914 container.insertBefore(c, container.firstChild); 3915 } else { 3916 container.appendChild(c); 3917 } 3918 } 3919 plugins.call(res, res, R.fn); 3920 return res; 3921 }; 3922 paperproto.clear = function () { 3923 eve("clear", this); 3924 this.canvas.innerHTML = E; 3925 this.span = g.doc.createElement("span"); 3926 this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; 3927 this.canvas.appendChild(this.span); 3928 this.bottom = this.top = null; 3929 }; 3930 paperproto.remove = function () { 3931 eve("remove", this); 3932 this.canvas.parentNode.removeChild(this.canvas); 3933 for (var i in this) { 3934 this[i] = removed(i); 3935 } 3936 return true; 3937 }; 3938 } 3939 3940 // WebKit rendering bug workaround method 3941 var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/); 3942 if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") || 3943 (navigator.vendor == "Google Inc." && version && version[1] < 8)) { 3944 /*\ 3945 * Paper.safari 3946 [ method ] 3947 ** 3948 * Adds event handlers for hover for the element. 3949 > Parameters 3950 - f_in (function) handler for hover in 3951 - f_out (function) handler for hover out 3952 - icontext (object) #optional context for hover in handler 3953 - ocontext (object) #optional context for hover out handler 3954 = (object) @Element 3955 \*/ 3956 paperproto.safari = function () { 3957 var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"}); 3958 setTimeout(function () {rect.remove();}); 3959 }; 3960 } else { 3961 paperproto.safari = fun; 3962 } 3963 3964 // Events 3965 var preventDefault = function () { 3966 this.returnValue = false; 3967 }, 3968 preventTouch = function () { 3969 return this.originalEvent.preventDefault(); 3970 }, 3971 stopPropagation = function () { 3972 this.cancelBubble = true; 3973 }, 3974 stopTouch = function () { 3975 return this.originalEvent.stopPropagation(); 3976 }, 3977 addEvent = (function () { 3978 if (g.doc.addEventListener) { 3979 return function (obj, type, fn, element) { 3980 var realName = supportsTouch && touchMap[type] ? touchMap[type] : type; 3981 var f = function (e) { 3982 if (supportsTouch && touchMap[has](type)) { 3983 for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { 3984 if (e.targetTouches[i].target == obj) { 3985 var olde = e; 3986 e = e.targetTouches[i]; 3987 e.originalEvent = olde; 3988 e.preventDefault = preventTouch; 3989 e.stopPropagation = stopTouch; 3990 break; 3991 } 3992 } 3993 } 3994 return fn.call(element, e); 3995 }; 3996 obj.addEventListener(realName, f, false); 3997 return function () { 3998 obj.removeEventListener(realName, f, false); 3999 return true; 4000 }; 4001 }; 4002 } else if (g.doc.attachEvent) { 4003 return function (obj, type, fn, element) { 4004 var f = function (e) { 4005 e = e || g.win.event; 4006 e.preventDefault = e.preventDefault || preventDefault; 4007 e.stopPropagation = e.stopPropagation || stopPropagation; 4008 return fn.call(element, e); 4009 }; 4010 obj.attachEvent("on" + type, f); 4011 var detacher = function () { 4012 obj.detachEvent("on" + type, f); 4013 return true; 4014 }; 4015 return detacher; 4016 }; 4017 } 4018 })(), 4019 drag = [], 4020 dragMove = function (e) { 4021 var x = e.clientX, 4022 y = e.clientY, 4023 scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, 4024 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, 4025 dragi, 4026 j = drag.length; 4027 while (j--) { 4028 dragi = drag[j]; 4029 if (supportsTouch) { 4030 var i = e.touches.length, 4031 touch; 4032 while (i--) { 4033 touch = e.touches[i]; 4034 if (touch.identifier == dragi.el._drag.id) { 4035 x = touch.clientX; 4036 y = touch.clientY; 4037 (e.originalEvent ? e.originalEvent : e).preventDefault(); 4038 break; 4039 } 4040 } 4041 } else { 4042 e.preventDefault(); 4043 } 4044 var node = dragi.el.node, 4045 o, 4046 next = node.nextSibling, 4047 parent = node.parentNode, 4048 display = node.style.display; 4049 g.win.opera && parent.removeChild(node); 4050 node.style.display = "none"; 4051 o = dragi.el.paper.getElementByPoint(x, y); 4052 node.style.display = display; 4053 g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); 4054 o && eve("drag.over." + dragi.el.id, dragi.el, o); 4055 x += scrollX; 4056 y += scrollY; 4057 eve("drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); 4058 } 4059 }, 4060 dragUp = function (e) { 4061 R.unmousemove(dragMove).unmouseup(dragUp); 4062 var i = drag.length, 4063 dragi; 4064 while (i--) { 4065 dragi = drag[i]; 4066 dragi.el._drag = {}; 4067 eve("drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); 4068 } 4069 drag = []; 4070 }; 4071 for (var i = events.length; i--;) { 4072 (function (eventName) { 4073 R[eventName] = Element.prototype[eventName] = function (fn, scope) { 4074 if (R.is(fn, "function")) { 4075 this.events = this.events || []; 4076 this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)}); 4077 } 4078 return this; 4079 }; 4080 R["un" + eventName] = Element.prototype["un" + eventName] = function (fn) { 4081 var events = this.events, 4082 l = events.length; 4083 while (l--) if (events[l].name == eventName && events[l].f == fn) { 4084 events[l].unbind(); 4085 events.splice(l, 1); 4086 !events.length && delete this.events; 4087 return this; 4088 } 4089 return this; 4090 }; 4091 })(events[i]); 4092 } 4093 /*\ 4094 * Element.hover 4095 [ method ] 4096 ** 4097 * Adds event handlers for hover for the element. 4098 > Parameters 4099 - f_in (function) handler for hover in 4100 - f_out (function) handler for hover out 4101 - icontext (object) #optional context for hover in handler 4102 - ocontext (object) #optional context for hover out handler 4103 = (object) @Element 4104 \*/ 4105 elproto.hover = function (f_in, f_out, scope_in, scope_out) { 4106 return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); 4107 }; 4108 /*\ 4109 * Element.unhover 4110 [ method ] 4111 ** 4112 * Removes event handlers for hover for the element. 4113 > Parameters 4114 - f_in (function) handler for hover in 4115 - f_out (function) handler for hover out 4116 = (object) @Element 4117 \*/ 4118 elproto.unhover = function (f_in, f_out) { 4119 return this.unmouseover(f_in).unmouseout(f_out); 4120 }; 4121 /*\ 4122 * Element.drag 4123 [ method ] 4124 ** 4125 * Adds event handlers for drag of the element. 4126 > Parameters 4127 - onmove (function) handler for moving 4128 - onstart (function) handler for drag start 4129 - onend (function) handler for drag end 4130 - mcontext (object) #optional context for moving handler 4131 - scontext (object) #optional context for drag start handler 4132 - econtext (object) #optional context for drag end handler 4133 * Additionaly following `drag` events will be triggered: `drag.start.<id>` on start, 4134 * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element will be dragged over another element 4135 * `drag.over.<id>` will be fired as well. 4136 * 4137 * Start event and start handler will be called in specified context or in context of the element with following parameters: 4138 o x (number) x position of the mouse 4139 o y (number) y position of the mouse 4140 o event (object) DOM event object 4141 * Move event and move handler will be called in specified context or in context of the element with following parameters: 4142 o dx (number) shift by x from the start point 4143 o dy (number) shift by y from the start point 4144 o x (number) x position of the mouse 4145 o y (number) y position of the mouse 4146 o event (object) DOM event object 4147 * End event and end handler will be called in specified context or in context of the element with following parameters: 4148 o event (object) DOM event object 4149 = (object) @Element 4150 \*/ 4151 elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { 4152 function start(e) { 4153 (e.originalEvent || e).preventDefault(); 4154 var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, 4155 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; 4156 this._drag.x = e.clientX + scrollX; 4157 this._drag.y = e.clientY + scrollY; 4158 this._drag.id = e.identifier; 4159 !drag.length && R.mousemove(dragMove).mouseup(dragUp); 4160 drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); 4161 onstart && eve.on("drag.start." + this.id, onstart); 4162 onmove && eve.on("drag.move." + this.id, onmove); 4163 onend && eve.on("drag.end." + this.id, onend); 4164 eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e); 4165 } 4166 this._drag = {}; 4167 this.mousedown(start); 4168 return this; 4169 }; 4170 /*\ 4171 * Element.onDragOver 4172 [ method ] 4173 ** 4174 * Shortcut for assigning event handler for `drag.over.<id>` event, where id is id of the element (see @Element.id). 4175 > Parameters 4176 - f (function) handler for event 4177 \*/ 4178 elproto.onDragOver = function (f) { 4179 f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id); 4180 }; 4181 /*\ 4182 * Element.undrag 4183 [ method ] 4184 ** 4185 * Removes all drag event handlers from given element. 4186 \*/ 4187 elproto.undrag = function () { 4188 var i = drag.length; 4189 while (i--) if (drag[i].el == this) { 4190 R.unmousedown(drag[i].start); 4191 drag.splice(i++, 1); 4192 eve.unbind("drag.*." + this.id); 4193 } 4194 !drag.length && R.unmousemove(dragMove).unmouseup(dragUp); 4195 }; 4196 /*\ 4197 * Paper.circle 4198 [ method ] 4199 ** 4200 * Draws a circle. 4201 ** 4202 > Parameters 4203 ** 4204 - x (number) x coordinate of the centre 4205 - y (number) y coordinate of the centre 4206 - r (number) radius 4207 = (object) Raphaël element object with type “circle” 4208 ** 4209 > Usage 4210 | var c = paper.circle(50, 50, 40); 4211 \*/ 4212 paperproto.circle = function (x, y, r) { 4213 return theCircle(this, x || 0, y || 0, r || 0); 4214 }; 4215 /*\ 4216 * Paper.rect 4217 [ method ] 4218 * 4219 * Draws a rectangle. 4220 ** 4221 > Parameters 4222 ** 4223 - x (number) x coordinate of the top left corner 4224 - y (number) y coordinate of the top left corner 4225 - width (number) width 4226 - height (number) height 4227 - r (number) @optional radius for rounded corners, default is 0 4228 = (object) Raphaël element object with type “rect” 4229 ** 4230 > Usage 4231 | // regular rectangle 4232 | var c = paper.rect(10, 10, 50, 50); 4233 | // rectangle with rounded corners 4234 | var c = paper.rect(40, 40, 50, 50, 10); 4235 \*/ 4236 paperproto.rect = function (x, y, w, h, r) { 4237 return theRect(this, x || 0, y || 0, w || 0, h || 0, r || 0); 4238 }; 4239 /*\ 4240 * Paper.ellipse 4241 [ method ] 4242 ** 4243 * Draws an ellipse. 4244 ** 4245 > Parameters 4246 ** 4247 - x (number) x coordinate of the centre 4248 - y (number) y coordinate of the centre 4249 - rx (number) horisontal radius 4250 - ry (number) vertical radius 4251 = (object) Raphaël element object with type “ellipse” 4252 ** 4253 > Usage 4254 | var c = paper.ellipse(50, 50, 40, 20); 4255 \*/ 4256 paperproto.ellipse = function (x, y, rx, ry) { 4257 return theEllipse(this, x || 0, y || 0, rx || 0, ry || 0); 4258 }; 4259 /*\ 4260 * Paper.path 4261 [ method ] 4262 ** 4263 * Creates a path element by given path data string. 4264 ** 4265 > Parameters 4266 ** 4267 - pathString (string) path data in SVG path string format. 4268 = (object) Raphaël element object with type “ellipse” 4269 # Details of a path's data attribute's format are described in the <a href="http://www.w3.org/TR/SVG/paths.html#PathData">SVG specification</a>. 4270 ** 4271 > Usage 4272 | var c = paper.path("M10 10L90 90"); 4273 | // draw a diagonal line: 4274 | // move to 10,10, line to 90,90 4275 \*/ 4276 paperproto.path = function (pathString) { 4277 pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E); 4278 return thePath(R.format[apply](R, arguments), this); 4279 }; 4280 /*\ 4281 * Paper.image 4282 [ method ] 4283 ** 4284 * Embeds an image into the surface. 4285 ** 4286 > Parameters 4287 ** 4288 - src (string) URI of the source image 4289 - x (number) x coordinate position 4290 - y (number) y coordinate position 4291 - width (number) width of the image 4292 - height (number) height of the image 4293 = (object) Raphaël element object with type “image” 4294 ** 4295 > Usage 4296 | var c = paper.image("apple.png", 10, 10, 80, 80); 4297 \*/ 4298 paperproto.image = function (src, x, y, w, h) { 4299 return theImage(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); 4300 }; 4301 /*\ 4302 * Paper.text 4303 [ method ] 4304 ** 4305 * Draws a text string. If you need line breaks, put “\n” in the string. 4306 ** 4307 > Parameters 4308 ** 4309 - x (number) x coordinate position 4310 - y (number) y coordinate position 4311 - text (string) The text string to draw 4312 = (object) Raphaël element object with type “text” 4313 ** 4314 > Usage 4315 | var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!"); 4316 \*/ 4317 paperproto.text = function (x, y, text) { 4318 return theText(this, x || 0, y || 0, Str(text)); 4319 }; 4320 /*\ 4321 * Paper.set 4322 [ method ] 4323 ** 4324 * Creates array-like object to keep and operate couple of elements at once. 4325 * Warning: it doesn’t create any elements for itself in the page. 4326 = (object) array-like object that represents set of elements 4327 ** 4328 > Usage 4329 | var st = paper.set(); 4330 | st.push( 4331 | paper.circle(10, 10, 5), 4332 | paper.circle(30, 10, 5) 4333 | ); 4334 | st.attr({fill: "red"}); 4335 \*/ 4336 paperproto.set = function (itemsArray) { 4337 arguments.length > 1 && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length)); 4338 return new Set(itemsArray); 4339 }; 4340 /*\ 4341 * Paper.setSize 4342 [ method ] 4343 ** 4344 * If you need to change dimensions of the canvas call this method 4345 ** 4346 > Parameters 4347 ** 4348 - width (number) new width of the canvas 4349 - height (number) new height of the canvas 4350 > Usage 4351 | var st = paper.set(); 4352 | st.push( 4353 | paper.circle(10, 10, 5), 4354 | paper.circle(30, 10, 5) 4355 | ); 4356 | st.attr({fill: "red"}); 4357 \*/ 4358 paperproto.setSize = setSize; 4359 /*\ 4360 * Paper.setViewBox 4361 [ method ] 4362 ** 4363 * Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by 4364 * specifying new boundaries. 4365 ** 4366 > Parameters 4367 ** 4368 x, y, w, h, fit 4369 - x (number) new x position, default is `0` 4370 - y (number) new y position, default is `0` 4371 - w (number) new width of the canvas 4372 - h (number) new height of the canvas 4373 - fit (boolean) `true` if you want graphics to fit into new boundary box 4374 \*/ 4375 paperproto.setViewBox = setViewBox; 4376 /*\ 4377 * Paper.top 4378 [ property ] 4379 ** 4380 * Points to the topmost element on the paper 4381 \*/ 4382 /*\ 4383 * Paper.bottom 4384 [ property ] 4385 ** 4386 * Points to the bottom element on the paper 4387 \*/ 4388 paperproto.top = paperproto.bottom = null; 4389 /*\ 4390 * Paper.raphael 4391 [ property ] 4392 ** 4393 * Points to the @Raphael object/function 4394 \*/ 4395 paperproto.raphael = R; 4396 var getOffset = function (elem) { 4397 var box = elem.getBoundingClientRect(), 4398 doc = elem.ownerDocument, 4399 body = doc.body, 4400 docElem = doc.documentElement, 4401 clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, 4402 top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, 4403 left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; 4404 return { 4405 y: top, 4406 x: left 4407 }; 4408 }; 4409 /*\ 4410 * Paper.getElementByPoint 4411 [ method ] 4412 ** 4413 * Returns you topmost element under given point. 4414 ** 4415 = (object) Raphaël element object 4416 > Parameters 4417 ** 4418 - x (number) x coordinate from the top left corner of the window 4419 - y (number) y coordinate from the top left corner of the window 4420 > Usage 4421 | paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); 4422 \*/ 4423 paperproto.getElementByPoint = function (x, y) { 4424 var paper = this, 4425 svg = paper.canvas, 4426 target = g.doc.elementFromPoint(x, y); 4427 if (g.win.opera && target.tagName == "svg") { 4428 var so = getOffset(svg), 4429 sr = svg.createSVGRect(); 4430 sr.x = x - so.x; 4431 sr.y = y - so.y; 4432 sr.width = sr.height = 1; 4433 var hits = svg.getIntersectionList(sr, null); 4434 if (hits.length) { 4435 target = hits[hits.length - 1]; 4436 } 4437 } 4438 if (!target) { 4439 return null; 4440 } 4441 while (target.parentNode && target != svg.parentNode && !target.raphael) { 4442 target = target.parentNode; 4443 } 4444 target == paper.canvas.parentNode && (target = svg); 4445 target = target && target.raphael ? paper.getById(target.raphaelid) : null; 4446 return target; 4447 }; 4448 /*\ 4449 * Paper.getById 4450 [ method ] 4451 ** 4452 * Returns you element by it’s internal ID. 4453 ** 4454 > Parameters 4455 ** 4456 - id (number) id 4457 = (object) Raphaël element object 4458 \*/ 4459 paperproto.getById = function (id) { 4460 var bot = this.bottom; 4461 while (bot) { 4462 if (bot.id == id) { 4463 return bot; 4464 } 4465 bot = bot.next; 4466 } 4467 return null; 4468 }; 4469 /*\ 4470 * Paper.forEach 4471 [ method ] 4472 ** 4473 * Executes given function for each element on the paper 4474 * 4475 * If function returns `false` it will stop loop running. 4476 ** 4477 > Parameters 4478 ** 4479 - callback (function) function to run 4480 - thisArg (object) context object for the callback 4481 = (object) Paper object 4482 \*/ 4483 paperproto.forEach = function (callback, thisArg) { 4484 var bot = this.bottom; 4485 while (bot) { 4486 if (callback.call(thisArg, bot) === false) { 4487 return this; 4488 } 4489 bot = bot.next; 4490 } 4491 return this; 4492 }; 4493 function x_y() { 4494 return this.x + S + this.y; 4495 } 4496 function x_y_w_h() { 4497 return this.x + S + this.y + S + this.width + "\xd7" + this.height; 4498 } 4499 /*\ 4500 * Element.getBBox 4501 [ method ] 4502 ** 4503 * Return bounding box for a given element 4504 ** 4505 > Parameters 4506 ** 4507 - isWithoutTransform (boolean) flag, `true` if you want to have bounding box before transformations. Default is `false`. 4508 = (object) Bounding box object: 4509 o { 4510 o x: (number) top left corner x 4511 o y: (number) top left corner y 4512 o width: (number) width 4513 o height: (number) height 4514 o } 4515 \*/ 4516 elproto.getBBox = function (isWithoutTransform) { 4517 if (this.removed) { 4518 return {}; 4519 } 4520 var _ = this._; 4521 if (isWithoutTransform) { 4522 if (_.dirty || !_.bboxwt) { 4523 this.realPath = getPath[this.type](this); 4524 _.bboxwt = pathDimensions(this.realPath); 4525 _.bboxwt.toString = x_y_w_h; 4526 _.dirty = 0; 4527 } 4528 return _.bboxwt; 4529 } 4530 if (_.dirty || _.dirtyT || !_.bbox) { 4531 if (_.dirty || !this.realPath) { 4532 _.bboxwt = 0; 4533 this.realPath = getPath[this.type](this); 4534 } 4535 _.bbox = pathDimensions(mapPath(this.realPath, this.matrix)); 4536 _.bbox.toString = x_y_w_h; 4537 _.dirty = _.dirtyT = 0; 4538 } 4539 return _.bbox; 4540 }; 4541 /*\ 4542 * Element.clone 4543 [ method ] 4544 ** 4545 = (object) clone of a given element 4546 ** 4547 \*/ 4548 elproto.clone = function () { 4549 if (this.removed) { 4550 return null; 4551 } 4552 var attr = this.attr(); 4553 delete attr.scale; 4554 delete attr.translation; 4555 return this.paper[this.type]().attr(attr); 4556 }; 4557 /*\ 4558 * Element.glow 4559 [ method ] 4560 ** 4561 * Return set of elements that create glow-like effect around given element. See @Paper.set. 4562 * 4563 * Note: Glow is not connected to the elment. If you change element attributes it won’t adjust itself. 4564 ** 4565 = (object) @Paper.set of elements that represents glow 4566 \*/ 4567 elproto.glow = function (glow) { 4568 if (this.type == "text") { 4569 return null; 4570 } 4571 glow = glow || {}; 4572 var s = { 4573 width: glow.width || 10, 4574 fill: glow.fill || false, 4575 opacity: glow.opacity || .5, 4576 offsetx: glow.offsetx || 0, 4577 offsety: glow.offsety || 0, 4578 color: glow.color || "#000" 4579 }, 4580 c = s.width / 2, 4581 r = this.paper, 4582 out = r.set(), 4583 path = this.realPath || getPath[this.type](this); 4584 path = this.matrix ? mapPath(path, this.matrix) : path; 4585 for (var i = 1; i < c + 1; i++) { 4586 out.push(r.path(path).attr({stroke: s.color, fill: s.fill ? s.color : "none", "stroke-linejoin": "round", "stroke-linecap": "round", "stroke-width": +(s.width / c * i).toFixed(3), opacity: +(s.opacity / c).toFixed(3)})); 4587 } 4588 return out.insertBefore(this).translate(s.offsetx, s.offsety); 4589 }; 4590 var curveslengths = {}, 4591 getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { 4592 var len = 0, 4593 precision = 100, 4594 name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(), 4595 cache = curveslengths[name], 4596 old, dot; 4597 !cache && (curveslengths[name] = cache = {data: []}); 4598 cache.timer && clearTimeout(cache.timer); 4599 cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3); 4600 if (length != null && !cache.precision) { 4601 var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); 4602 cache.precision = ~~total * 10; 4603 cache.data = []; 4604 } 4605 precision = cache.precision || precision; 4606 for (var i = 0; i < precision + 1; i++) { 4607 if (cache.data[i * precision]) { 4608 dot = cache.data[i * precision]; 4609 } else { 4610 dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision); 4611 cache.data[i * precision] = dot; 4612 } 4613 i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5)); 4614 if (length != null && len >= length) { 4615 return dot; 4616 } 4617 old = dot; 4618 } 4619 if (length == null) { 4620 return len; 4621 } 4622 }, 4623 getLengthFactory = function (istotal, subpath) { 4624 return function (path, length, onlystart) { 4625 path = path2curve(path); 4626 var x, y, p, l, sp = "", subpaths = {}, point, 4627 len = 0; 4628 for (var i = 0, ii = path.length; i < ii; i++) { 4629 p = path[i]; 4630 if (p[0] == "M") { 4631 x = +p[1]; 4632 y = +p[2]; 4633 } else { 4634 l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); 4635 if (len + l > length) { 4636 if (subpath && !subpaths.start) { 4637 point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); 4638 sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; 4639 if (onlystart) {return sp;} 4640 subpaths.start = sp; 4641 sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join(); 4642 len += l; 4643 x = +p[5]; 4644 y = +p[6]; 4645 continue; 4646 } 4647 if (!istotal && !subpath) { 4648 point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); 4649 return {x: point.x, y: point.y, alpha: point.alpha}; 4650 } 4651 } 4652 len += l; 4653 x = +p[5]; 4654 y = +p[6]; 4655 } 4656 sp += p.shift() + p; 4657 } 4658 subpaths.end = sp; 4659 point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[1], p[2], p[3], p[4], p[5], p[6], 1); 4660 point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); 4661 return point; 4662 }; 4663 }; 4664 var getTotalLength = getLengthFactory(1), 4665 getPointAtLength = getLengthFactory(), 4666 getSubpathsAtLength = getLengthFactory(0, 1); 4667 /*\ 4668 * Raphael.getTotalLength 4669 [ method ] 4670 ** 4671 * Returns length of the given path in pixels. 4672 ** 4673 > Parameters 4674 ** 4675 - path (string) SVG path string. 4676 ** 4677 = (number) length. 4678 \*/ 4679 R.getTotalLength = getTotalLength; 4680 /*\ 4681 * Raphael.getPointAtLength 4682 [ method ] 4683 ** 4684 * Return coordinates of the point located at the given length on the given path. 4685 ** 4686 > Parameters 4687 ** 4688 - path (string) SVG path string 4689 - length (number) 4690 ** 4691 = (object) representation of the point: 4692 o { 4693 o x: (number) x coordinate 4694 o y: (number) y coordinate 4695 o alpha: (number) angle of derivative 4696 o } 4697 \*/ 4698 R.getPointAtLength = getPointAtLength; 4699 /*\ 4700 * Raphael.getSubpath 4701 [ method ] 4702 ** 4703 * Return subpath of a given path from given length to given length. 4704 ** 4705 > Parameters 4706 ** 4707 - path (string) SVG path string 4708 - from (number) position of the start of the segment 4709 - to (number) position of the end of the segment 4710 ** 4711 = (string) pathstring for the segment 4712 \*/ 4713 R.getSubpath = function (path, from, to) { 4714 if (abs(this.getTotalLength(path) - to) < 1e-6) { 4715 return getSubpathsAtLength(path, from).end; 4716 } 4717 var a = getSubpathsAtLength(path, to, 1); 4718 return from ? getSubpathsAtLength(a, from).end : a; 4719 }; 4720 /*\ 4721 * Element.getTotalLength 4722 [ method ] 4723 ** 4724 * Returns length of the path in pixels. Only works for element of “path” type. 4725 = (number) length. 4726 \*/ 4727 elproto.getTotalLength = function () { 4728 if (this.type != "path") {return;} 4729 if (this.node.getTotalLength) { 4730 return this.node.getTotalLength(); 4731 } 4732 return getTotalLength(this.attrs.path); 4733 }; 4734 /*\ 4735 * Element.getPointAtLength 4736 [ method ] 4737 ** 4738 * Return coordinates of the point located at the given length on the given path. Only works for element of “path” type. 4739 ** 4740 > Parameters 4741 ** 4742 - length (number) 4743 ** 4744 = (object) representation of the point: 4745 o { 4746 o x: (number) x coordinate 4747 o y: (number) y coordinate 4748 o alpha: (number) angle of derivative 4749 o } 4750 \*/ 4751 elproto.getPointAtLength = function (length) { 4752 if (this.type != "path") {return;} 4753 return getPointAtLength(this.attrs.path, length); 4754 }; 4755 /*\ 4756 * Element.getSubpath 4757 [ method ] 4758 ** 4759 * Return subpath of a given element from given length to given length. Only works for element of “path” type. 4760 ** 4761 > Parameters 4762 ** 4763 - from (number) position of the start of the segment 4764 - to (number) position of the end of the segment 4765 ** 4766 = (string) pathstring for the segment 4767 \*/ 4768 elproto.getSubpath = function (from, to) { 4769 if (this.type != "path") {return;} 4770 return R.getSubpath(this.attrs.path, from, to); 4771 }; 4772 /*\ 4773 * Raphael.easing_formulas 4774 [ property ] 4775 ** 4776 * Object that contains easing formulas for animation. You could extend it with your owns. By default it has following list of easing: 4777 # <ul> 4778 # <li>“linear”</li> 4779 # <li>“<” or “easeIn” or “ease-in”</li> 4780 # <li>“>” or “easeOut” or “ease-out”</li> 4781 # <li>“<>” or “easeInOut” or “ease-in-out”</li> 4782 # <li>“backIn” or “back-in”</li> 4783 # <li>“backOut” or “back-out”</li> 4784 # <li>“elastic”</li> 4785 # <li>“bounce”</li> 4786 # </ul> 4787 # <p>See also <a href="http://raphaeljs.com/easing.html">Easing demo</a>.</p> 4788 \*/ 4789 var ef = R.easing_formulas = { 4790 linear: function (n) { 4791 return n; 4792 }, 4793 "<": function (n) { 4794 return pow(n, 1.7); 4795 }, 4796 ">": function (n) { 4797 return pow(n, .48); 4798 }, 4799 "<>": function (n) { 4800 var q = .48 - n / 1.04, 4801 Q = math.sqrt(.1734 + q * q), 4802 x = Q - q, 4803 X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1), 4804 y = -Q - q, 4805 Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1), 4806 t = X + Y + .5; 4807 return (1 - t) * 3 * t * t + t * t * t; 4808 }, 4809 backIn: function (n) { 4810 var s = 1.70158; 4811 return n * n * ((s + 1) * n - s); 4812 }, 4813 backOut: function (n) { 4814 n = n - 1; 4815 var s = 1.70158; 4816 return n * n * ((s + 1) * n + s) + 1; 4817 }, 4818 elastic: function (n) { 4819 if (n == !!n) { 4820 return n; 4821 } 4822 return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1; 4823 }, 4824 bounce: function (n) { 4825 var s = 7.5625, 4826 p = 2.75, 4827 l; 4828 if (n < (1 / p)) { 4829 l = s * n * n; 4830 } else { 4831 if (n < (2 / p)) { 4832 n -= (1.5 / p); 4833 l = s * n * n + .75; 4834 } else { 4835 if (n < (2.5 / p)) { 4836 n -= (2.25 / p); 4837 l = s * n * n + .9375; 4838 } else { 4839 n -= (2.625 / p); 4840 l = s * n * n + .984375; 4841 } 4842 } 4843 } 4844 return l; 4845 } 4846 }; 4847 ef.easeIn = ef["ease-in"] = ef["<"]; 4848 ef.easeOut = ef["ease-out"] = ef[">"]; 4849 ef.easeInOut = ef["ease-in-out"] = ef["<>"]; 4850 ef["back-in"] = ef.backIn; 4851 ef["back-out"] = ef.backOut; 4852 4853 var animationElements = [], 4854 requestAnimFrame = window.requestAnimationFrame || 4855 window.webkitRequestAnimationFrame || 4856 window.mozRequestAnimationFrame || 4857 window.oRequestAnimationFrame || 4858 window.msRequestAnimationFrame || 4859 function (callback) { 4860 setTimeout(callback, 16); 4861 }, 4862 animation = function () { 4863 var Now = +new Date, 4864 l = 0; 4865 for (; l < animationElements.length; l++) { 4866 var e = animationElements[l]; 4867 if (e.el.removed || e.paused) { 4868 continue; 4869 } 4870 var time = Now - e.start, 4871 ms = e.ms, 4872 easing = e.easing, 4873 from = e.from, 4874 diff = e.diff, 4875 to = e.to, 4876 t = e.t, 4877 that = e.el, 4878 set = {}, 4879 now; 4880 if (e.initstatus) { 4881 time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; 4882 e.status = e.initstatus; 4883 delete e.initstatus; 4884 e.stop && animationElements.splice(l--, 1); 4885 } else { 4886 e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top; 4887 } 4888 if (time < 0) { 4889 continue; 4890 } 4891 if (time < ms) { 4892 var pos = easing(time / ms); 4893 for (var attr in from) if (from[has](attr)) { 4894 switch (availableAnimAttrs[attr]) { 4895 case nu: 4896 now = +from[attr] + pos * ms * diff[attr]; 4897 break; 4898 case "colour": 4899 now = "rgb(" + [ 4900 upto255(round(from[attr].r + pos * ms * diff[attr].r)), 4901 upto255(round(from[attr].g + pos * ms * diff[attr].g)), 4902 upto255(round(from[attr].b + pos * ms * diff[attr].b)) 4903 ].join(",") + ")"; 4904 break; 4905 case "path": 4906 now = []; 4907 for (var i = 0, ii = from[attr].length; i < ii; i++) { 4908 now[i] = [from[attr][i][0]]; 4909 for (var j = 1, jj = from[attr][i].length; j < jj; j++) { 4910 now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; 4911 } 4912 now[i] = now[i].join(S); 4913 } 4914 now = now.join(S); 4915 break; 4916 case "transform": 4917 if (diff[attr].real) { 4918 now = []; 4919 for (i = 0, ii = from[attr].length; i < ii; i++) { 4920 now[i] = [from[attr][i][0]]; 4921 for (j = 1, jj = from[attr][i].length; j < jj; j++) { 4922 now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j]; 4923 } 4924 } 4925 } else { 4926 var get = function (i) { 4927 return +from[attr][i] + pos * ms * diff[attr][i]; 4928 }; 4929 // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]]; 4930 now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]]; 4931 } 4932 break; 4933 case "csv": 4934 if (attr == "clip-rect") { 4935 now = []; 4936 i = 4; 4937 while (i--) { 4938 now[i] = +from[attr][i] + pos * ms * diff[attr][i]; 4939 } 4940 } 4941 break; 4942 default: 4943 var from2 = [].concat(from[attr]); 4944 now = []; 4945 i = that.paper.customAttributes[attr].length; 4946 while (i--) { 4947 now[i] = +from2[i] + pos * ms * diff[attr][i]; 4948 } 4949 break; 4950 } 4951 set[attr] = now; 4952 } 4953 that.attr(set); 4954 (function (id, that, anim) { 4955 setTimeout(function () { 4956 eve("anim.frame." + id, that, anim); 4957 }); 4958 })(that.id, that, e.anim); 4959 } else { 4960 (function(f, el, a) { 4961 setTimeout(function() { 4962 eve("anim.finish." + el.id, el, a); 4963 R.is(f, "function") && f.call(el); 4964 }); 4965 })(e.callback, that, e.anim); 4966 if (--e.repeat) { 4967 that.attr(e.origin); 4968 e.start = Now; 4969 } else { 4970 that.attr(to); 4971 animationElements.splice(l--, 1); 4972 } 4973 if (e.next && !e.stop) { 4974 runAnimation(e.anim, e.el, e.next, null, e.totalOrigin); 4975 } 4976 } 4977 } 4978 R.svg && that && that.paper && that.paper.safari(); 4979 animationElements.length && requestAnimFrame(animation); 4980 }, 4981 upto255 = function (color) { 4982 return mmax(mmin(color, 255), 0); 4983 }; 4984 /*\ 4985 * Element.animateWith 4986 [ method ] 4987 ** 4988 * Acts similar to @Element.animate, but ensure that given animation runs in sync with another given element. 4989 ** 4990 > Parameters 4991 ** 4992 - params (object) final attributes for the element, see also @Element.attr 4993 - ms (number) number of milliseconds for animation to run 4994 - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX,&#160;XX,&#160;XX,&#160;XX)` 4995 - callback (function) #optional callback function. Will be called at the end of animation. 4996 * or 4997 - animation (object) animation object, see @Raphael.animation 4998 ** 4999 = (object) original element 5000 \*/ 5001 elproto.animateWith = function (element, params, ms, easing, callback) { 5002 for (var i = 0, ii = animationElements.length; i < ii; i++) { 5003 if (animationElements[i].el.id == element.id) { 5004 params.start = animationElements[i].timestamp; 5005 break; 5006 } 5007 } 5008 return this.animate(params, ms, easing, callback); 5009 }; 5010 function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { 5011 var cx = 3 * p1x, 5012 bx = 3 * (p2x - p1x) - cx, 5013 ax = 1 - cx - bx, 5014 cy = 3 * p1y, 5015 by = 3 * (p2y - p1y) - cy, 5016 ay = 1 - cy - by; 5017 function sampleCurveX(t) { 5018 return ((ax * t + bx) * t + cx) * t; 5019 } 5020 function solve(x, epsilon) { 5021 var t = solveCurveX(x, epsilon); 5022 return ((ay * t + by) * t + cy) * t; 5023 } 5024 function solveCurveX(x, epsilon) { 5025 var t0, t1, t2, x2, d2, i; 5026 for(t2 = x, i = 0; i < 8; i++) { 5027 x2 = sampleCurveX(t2) - x; 5028 if (abs(x2) < epsilon) { 5029 return t2; 5030 } 5031 d2 = (3 * ax * t2 + 2 * bx) * t2 + cx; 5032 if (abs(d2) < 1e-6) { 5033 break; 5034 } 5035 t2 = t2 - x2 / d2; 5036 } 5037 t0 = 0; 5038 t1 = 1; 5039 t2 = x; 5040 if (t2 < t0) { 5041 return t0; 5042 } 5043 if (t2 > t1) { 5044 return t1; 5045 } 5046 while (t0 < t1) { 5047 x2 = sampleCurveX(t2); 5048 if (abs(x2 - x) < epsilon) { 5049 return t2; 5050 } 5051 if (x > x2) { 5052 t0 = t2; 5053 } else { 5054 t1 = t2; 5055 } 5056 t2 = (t1 - t0) / 2 + t0; 5057 } 5058 return t2; 5059 } 5060 return solve(t, 1 / (200 * duration)); 5061 } 5062 elproto.onAnimation = function (f) { 5063 f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id); 5064 return this; 5065 }; 5066 function Animation(anim, ms) { 5067 var percents = []; 5068 this.anim = anim; 5069 this.ms = ms; 5070 this.times = 1; 5071 if (this.anim) { 5072 for (var attr in this.anim) if (this.anim[has](attr)) { 5073 percents.push(+attr); 5074 } 5075 percents.sort(sortByNumber); 5076 } 5077 this.top = percents[percents.length - 1]; 5078 this.percents = percents; 5079 } 5080 /*\ 5081 * Animation.delay 5082 [ method ] 5083 ** 5084 * Creates copy of existing animation object with given delay. 5085 ** 5086 > Parameters 5087 ** 5088 - delay (number) number of ms to pass between animation start and actual animation 5089 ** 5090 = (object) new altered Animation object 5091 \*/ 5092 Animation.prototype.delay = function (delay) { 5093 var a = new Animation(this.anim, this.ms); 5094 a.times = this.times; 5095 a.del = +delay || 0; 5096 return a; 5097 }; 5098 /*\ 5099 * Animation.repeat 5100 [ method ] 5101 ** 5102 * Creates copy of existing animation object with given repetition. 5103 ** 5104 > Parameters 5105 ** 5106 - repeat (number) number iterations of animation. For infinite animation pass `Infinity` 5107 ** 5108 = (object) new altered Animation object 5109 \*/ 5110 Animation.prototype.repeat = function (times) { 5111 var a = new Animation(this.anim, this.ms); 5112 a.del = this.del; 5113 a.times = math.floor(mmax(times, 0)) || 1; 5114 return a; 5115 }; 5116 function runAnimation(anim, element, percent, status, totalOrigin) { 5117 percent = toFloat(percent); 5118 var params, 5119 isInAnim, 5120 isInAnimSet, 5121 percents = [], 5122 next, 5123 prev, 5124 timestamp, 5125 ms = anim.ms, 5126 from = {}, 5127 to = {}, 5128 diff = {}; 5129 if (status) { 5130 for (i = 0, ii = animationElements.length; i < ii; i++) { 5131 var e = animationElements[i]; 5132 if (e.el.id == element.id && e.anim == anim) { 5133 if (e.percent != percent) { 5134 animationElements.splice(i, 1); 5135 isInAnimSet = 1; 5136 } else { 5137 isInAnim = e; 5138 } 5139 element.attr(e.totalOrigin); 5140 break; 5141 } 5142 } 5143 } else { 5144 status = 0 / 0; 5145 } 5146 for (var i = 0, ii = anim.percents.length; i < ii; i++) { 5147 if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) { 5148 percent = anim.percents[i]; 5149 prev = anim.percents[i - 1] || 0; 5150 ms = ms / anim.top * (percent - prev); 5151 next = anim.percents[i + 1]; 5152 params = anim.anim[percent]; 5153 break; 5154 } else if (status) { 5155 element.attr(anim.anim[anim.percents[i]]); 5156 } 5157 } 5158 if (!params) { 5159 return; 5160 } 5161 if (!isInAnim) { 5162 for (attr in params) if (params[has](attr)) { 5163 if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) { 5164 from[attr] = element.attr(attr); 5165 (from[attr] == null) && (from[attr] = availableAttrs[attr]); 5166 to[attr] = params[attr]; 5167 switch (availableAnimAttrs[attr]) { 5168 case nu: 5169 diff[attr] = (to[attr] - from[attr]) / ms; 5170 break; 5171 case "colour": 5172 from[attr] = R.getRGB(from[attr]); 5173 var toColour = R.getRGB(to[attr]); 5174 diff[attr] = { 5175 r: (toColour.r - from[attr].r) / ms, 5176 g: (toColour.g - from[attr].g) / ms, 5177 b: (toColour.b - from[attr].b) / ms 5178 }; 5179 break; 5180 case "path": 5181 var pathes = path2curve(from[attr], to[attr]), 5182 toPath = pathes[1]; 5183 from[attr] = pathes[0]; 5184 diff[attr] = []; 5185 for (i = 0, ii = from[attr].length; i < ii; i++) { 5186 diff[attr][i] = [0]; 5187 for (var j = 1, jj = from[attr][i].length; j < jj; j++) { 5188 diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; 5189 } 5190 } 5191 break; 5192 case "transform": 5193 var _ = element._, 5194 eq = equaliseTransform(_[attr], to[attr]); 5195 if (eq) { 5196 from[attr] = eq.from; 5197 to[attr] = eq.to; 5198 diff[attr] = []; 5199 diff[attr].real = true; 5200 for (i = 0, ii = from[attr].length; i < ii; i++) { 5201 diff[attr][i] = [from[attr][i][0]]; 5202 for (j = 1, jj = from[attr][i].length; j < jj; j++) { 5203 diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; 5204 } 5205 } 5206 } else { 5207 var m = (element.matrix || new Matrix).m, 5208 to2 = {_:{transform: _.transform}, getBBox: function () { return element.getBBox(); }}; 5209 from[attr] = [ 5210 m[0][0], 5211 m[1][0], 5212 m[0][1], 5213 m[1][1], 5214 m[0][2], 5215 m[1][2] 5216 ]; 5217 extractTransform(to2, to[attr]); 5218 to[attr] = to2._.transform; 5219 diff[attr] = [ 5220 (to2.matrix.m[0][0] - m[0][0]) / ms, 5221 (to2.matrix.m[1][0] - m[1][0]) / ms, 5222 (to2.matrix.m[0][1] - m[0][1]) / ms, 5223 (to2.matrix.m[1][1] - m[1][1]) / ms, 5224 (to2.matrix.m[0][2] - m[0][2]) / ms, 5225 (to2.matrix.m[1][2] - m[1][2]) / ms 5226 ]; 5227 // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy]; 5228 // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }}; 5229 // extractTransform(to2, to[attr]); 5230 // diff[attr] = [ 5231 // (to2._.sx - _.sx) / ms, 5232 // (to2._.sy - _.sy) / ms, 5233 // (to2._.deg - _.deg) / ms, 5234 // (to2._.dx - _.dx) / ms, 5235 // (to2._.dy - _.dy) / ms 5236 // ]; 5237 } 5238 break; 5239 case "csv": 5240 var values = Str(params[attr]).split(separator), 5241 from2 = Str(from[attr]).split(separator); 5242 if (attr == "clip-rect") { 5243 from[attr] = from2; 5244 diff[attr] = []; 5245 i = from2.length; 5246 while (i--) { 5247 diff[attr][i] = (values[i] - from[attr][i]) / ms; 5248 } 5249 } 5250 to[attr] = values; 5251 break; 5252 default: 5253 values = [].concat(params[attr]); 5254 from2 = [].concat(from[attr]); 5255 diff[attr] = []; 5256 i = element.paper.customAttributes[attr].length; 5257 while (i--) { 5258 diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms; 5259 } 5260 break; 5261 } 5262 } 5263 } 5264 var easing = params.easing, 5265 easyeasy = R.easing_formulas[easing]; 5266 if (!easyeasy) { 5267 easyeasy = Str(easing).match(bezierrg); 5268 if (easyeasy && easyeasy.length == 5) { 5269 var curve = easyeasy; 5270 easyeasy = function (t) { 5271 return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms); 5272 }; 5273 } else { 5274 easyeasy = pipe; 5275 } 5276 } 5277 timestamp = params.start || anim.start || +new Date; 5278 e = { 5279 anim: anim, 5280 percent: percent, 5281 timestamp: timestamp, 5282 start: timestamp + (anim.del || 0), 5283 status: 0, 5284 initstatus: status || 0, 5285 stop: false, 5286 ms: ms, 5287 easing: easyeasy, 5288 from: from, 5289 diff: diff, 5290 to: to, 5291 el: element, 5292 callback: params.callback, 5293 prev: prev, 5294 next: next, 5295 repeat: anim.times, 5296 origin: element.attr(), 5297 totalOrigin: totalOrigin 5298 }; 5299 animationElements.push(e); 5300 if (status && !isInAnim) { 5301 e.stop = true; 5302 e.start = new Date - ms * status; 5303 if (animationElements.length == 1) { 5304 return animation(); 5305 } 5306 } 5307 animationElements.length == 1 && requestAnimFrame(animation); 5308 } else { 5309 isInAnim.initstatus = status; 5310 isInAnim.start = new Date - isInAnim.ms * status; 5311 } 5312 eve("anim.start." + element.id, element, anim); 5313 } 5314 /*\ 5315 * Raphael.animation 5316 [ method ] 5317 ** 5318 * Creates animation object. That later could be used for @Element.animate or @Element.animateWith methods. 5319 * See also @Animation.delay and @Animation.repeat methods. 5320 ** 5321 > Parameters 5322 ** 5323 - params (object) final attributes for the element, see also @Element.attr 5324 - ms (number) number of milliseconds for animation to run 5325 - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX,&#160;XX,&#160;XX,&#160;XX)` 5326 - callback (function) #optional callback function. Will be called at the end of animation. 5327 ** 5328 = (object) @Animation 5329 \*/ 5330 R.animation = function (params, ms, easing, callback) { 5331 if (R.is(easing, "function") || !easing) { 5332 callback = callback || easing || null; 5333 easing = null; 5334 } 5335 params = Object(params); 5336 ms = +ms || 0; 5337 var p = {}, 5338 json, 5339 attr; 5340 for (attr in params) if (params[has](attr) && toFloat(attr) != attr) { 5341 json = true; 5342 p[attr] = params[attr]; 5343 } 5344 if (!json) { 5345 return new Animation(params, ms); 5346 } else { 5347 easing && (p.easing = easing); 5348 callback && (p.callback = callback); 5349 return new Animation({100: p}, ms); 5350 } 5351 }; 5352 /*\ 5353 * Element.animate 5354 [ method ] 5355 ** 5356 * Creates and starts animation for given element. 5357 ** 5358 > Parameters 5359 ** 5360 - params (object) final attributes for the element, see also @Element.attr 5361 - ms (number) number of milliseconds for animation to run 5362 - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX,&#160;XX,&#160;XX,&#160;XX)` 5363 - callback (function) #optional callback function. Will be called at the end of animation. 5364 * or 5365 - animation (object) animation object, see @Raphael.animation 5366 ** 5367 = (object) original element 5368 \*/ 5369 elproto.animate = function (params, ms, easing, callback) { 5370 var element = this; 5371 if (element.removed) { 5372 callback && callback.call(element); 5373 return element; 5374 } 5375 var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback); 5376 runAnimation(anim, element, anim.percents[0], null, element.attr()); 5377 return element; 5378 }; 5379 /*\ 5380 * Element.setTime 5381 [ method ] 5382 ** 5383 * Sets the status of animation of the element in milliseconds. Similar to @Element.status method. 5384 ** 5385 > Parameters 5386 ** 5387 - anim (object) animation object 5388 - value (number) number of milliseconds from the beginning of the animation 5389 ** 5390 = (object) original element if `value` is specified 5391 * Note, that during animation following events are triggered: 5392 * 5393 * On each animation frame event `anim.frame.<id>`, on start `anim.start.<id>` and on end `anim.finish.<id>`. 5394 \*/ 5395 elproto.setTime = function (anim, value) { 5396 if (anim && value != null) { 5397 this.status(anim, mmin(value, anim.ms) / anim.ms); 5398 } 5399 return this; 5400 }; 5401 /*\ 5402 * Element.status 5403 [ method ] 5404 ** 5405 * Gets or sets the status of animation of the element. 5406 ** 5407 > Parameters 5408 ** 5409 - anim (object) #optional animation object 5410 - value (number) #optional 01. If specified, method works like a setter and sets the status of a given animation to the value. This will cause animation to jump to the given position. 5411 ** 5412 = (number) status 5413 * or 5414 = (array) status if `anim` is not specified. Array of objects in format: 5415 o { 5416 o anim: (object) animation object 5417 o status: (number) status 5418 o } 5419 * or 5420 = (object) original element if `value` is specified 5421 \*/ 5422 elproto.status = function (anim, value) { 5423 var out = [], 5424 i = 0, 5425 len, 5426 e; 5427 if (value != null) { 5428 runAnimation(anim, this, -1, mmin(value, 1)); 5429 return this; 5430 } else { 5431 len = animationElements.length; 5432 for (; i < len; i++) { 5433 e = animationElements[i]; 5434 if (e.el.id == this.id && (!anim || e.anim == anim)) { 5435 if (anim) { 5436 return e.status; 5437 } 5438 out.push({anim: e.anim, status: e.status}); 5439 } 5440 } 5441 if (anim) { 5442 return 0; 5443 } 5444 return out; 5445 } 5446 }; 5447 /*\ 5448 * Element.pause 5449 [ method ] 5450 ** 5451 * Stops animation of the element with ability to resume it later on. 5452 ** 5453 > Parameters 5454 ** 5455 - anim (object) #optional animation object 5456 ** 5457 = (object) original element 5458 \*/ 5459 elproto.pause = function (anim) { 5460 for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { 5461 if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) { 5462 animationElements[i].paused = true; 5463 } 5464 } 5465 return this; 5466 }; 5467 /*\ 5468 * Element.resume 5469 [ method ] 5470 ** 5471 * Resumes animation if it was paused with @Element.pause method. 5472 ** 5473 > Parameters 5474 ** 5475 - anim (object) #optional animation object 5476 ** 5477 = (object) original element 5478 \*/ 5479 elproto.resume = function (anim) { 5480 for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { 5481 var e = animationElements[i]; 5482 if (eve("anim.resume." + this.id, this, e.anim) !== false) { 5483 delete e.paused; 5484 this.status(e.anim, e.status); 5485 } 5486 } 5487 return this; 5488 }; 5489 /*\ 5490 * Element.stop 5491 [ method ] 5492 ** 5493 * Stops animation of the element. 5494 ** 5495 > Parameters 5496 ** 5497 - anim (object) #optional animation object 5498 ** 5499 = (object) original element 5500 \*/ 5501 elproto.stop = function (anim) { 5502 for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { 5503 if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) { 5504 animationElements.splice(i--, 1); 5505 } 5506 } 5507 return this; 5508 }; 5509 elproto.toString = function () { 5510 return "Rapha\xebl\u2019s object"; 5511 }; 5512 5513 // Set 5514 var Set = function (items) { 5515 this.items = []; 5516 this.length = 0; 5517 this.type = "set"; 5518 if (items) { 5519 for (var i = 0, ii = items.length; i < ii; i++) { 5520 if (items[i] && (items[i].constructor == Element || items[i].constructor == Set)) { 5521 this[this.items.length] = this.items[this.items.length] = items[i]; 5522 this.length++; 5523 } 5524 } 5525 } 5526 }, 5527 setproto = Set.prototype; 5528 /*\ 5529 * Set.push 5530 [ method ] 5531 ** 5532 * Adds each argument to the current set. 5533 = (object) original element 5534 \*/ 5535 setproto.push = function () { 5536 var item, 5537 len; 5538 for (var i = 0, ii = arguments.length; i < ii; i++) { 5539 item = arguments[i]; 5540 if (item && (item.constructor == Element || item.constructor == Set)) { 5541 len = this.items.length; 5542 this[len] = this.items[len] = item; 5543 this.length++; 5544 } 5545 } 5546 return this; 5547 }; 5548 /*\ 5549 * Set.pop 5550 [ method ] 5551 ** 5552 * Removes last element and returns it. 5553 = (object) element 5554 \*/ 5555 setproto.pop = function () { 5556 this.length && delete this[this.length--]; 5557 return this.items.pop(); 5558 }; 5559 /*\ 5560 * Set.forEach 5561 [ method ] 5562 ** 5563 * Executes given function for each element in the set. 5564 * 5565 * If function returns `false` it will stop loop running. 5566 ** 5567 > Parameters 5568 ** 5569 - callback (function) function to run 5570 - thisArg (object) context object for the callback 5571 = (object) Set object 5572 \*/ 5573 setproto.forEach = function (callback, thisArg) { 5574 for (var i = 0, ii = this.items.length; i < ii; i++) { 5575 if (callback.call(thisArg, this.items[i]) === false) { 5576 return this; 5577 } 5578 } 5579 return this; 5580 }; 5581 for (var method in elproto) if (elproto[has](method)) { 5582 setproto[method] = (function (methodname) { 5583 return function () { 5584 var arg = arguments; 5585 return this.forEach(function (el) { 5586 el[methodname][apply](el, arg); 5587 }); 5588 }; 5589 })(method); 5590 } 5591 setproto.attr = function (name, value) { 5592 if (name && R.is(name, array) && R.is(name[0], "object")) { 5593 for (var j = 0, jj = name.length; j < jj; j++) { 5594 this.items[j].attr(name[j]); 5595 } 5596 } else { 5597 for (var i = 0, ii = this.items.length; i < ii; i++) { 5598 this.items[i].attr(name, value); 5599 } 5600 } 5601 return this; 5602 }; 5603 setproto.animate = function (params, ms, easing, callback) { 5604 (R.is(easing, "function") || !easing) && (callback = easing || null); 5605 var len = this.items.length, 5606 i = len, 5607 item, 5608 set = this, 5609 collector; 5610 callback && (collector = function () { 5611 !--len && callback.call(set); 5612 }); 5613 easing = R.is(easing, string) ? easing : collector; 5614 var anim = params instanceof Animation ? params : R.animation(params, ms, easing, collector); 5615 item = this.items[--i].animate(anim); 5616 while (i--) { 5617 this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim); 5618 } 5619 return this; 5620 }; 5621 setproto.insertAfter = function (el) { 5622 var i = this.items.length; 5623 while (i--) { 5624 this.items[i].insertAfter(el); 5625 } 5626 return this; 5627 }; 5628 setproto.getBBox = function () { 5629 var x = [], 5630 y = [], 5631 w = [], 5632 h = []; 5633 for (var i = this.items.length; i--;) if (!this.items[i].removed) { 5634 var box = this.items[i].getBBox(); 5635 x.push(box.x); 5636 y.push(box.y); 5637 w.push(box.x + box.width); 5638 h.push(box.y + box.height); 5639 } 5640 x = mmin[apply](0, x); 5641 y = mmin[apply](0, y); 5642 return { 5643 x: x, 5644 y: y, 5645 width: mmax[apply](0, w) - x, 5646 height: mmax[apply](0, h) - y 5647 }; 5648 }; 5649 setproto.clone = function (s) { 5650 s = new Set; 5651 for (var i = 0, ii = this.items.length; i < ii; i++) { 5652 s.push(this.items[i].clone()); 5653 } 5654 return s; 5655 }; 5656 setproto.toString = function () { 5657 return "Rapha\xebl\u2018s set"; 5658 }; 5659 5660 R.registerFont = function (font) { 5661 if (!font.face) { 5662 return font; 5663 } 5664 this.fonts = this.fonts || {}; 5665 var fontcopy = { 5666 w: font.w, 5667 face: {}, 5668 glyphs: {} 5669 }, 5670 family = font.face["font-family"]; 5671 for (var prop in font.face) if (font.face[has](prop)) { 5672 fontcopy.face[prop] = font.face[prop]; 5673 } 5674 if (this.fonts[family]) { 5675 this.fonts[family].push(fontcopy); 5676 } else { 5677 this.fonts[family] = [fontcopy]; 5678 } 5679 if (!font.svg) { 5680 fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); 5681 for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { 5682 var path = font.glyphs[glyph]; 5683 fontcopy.glyphs[glyph] = { 5684 w: path.w, 5685 k: {}, 5686 d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { 5687 return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; 5688 }) + "z" 5689 }; 5690 if (path.k) { 5691 for (var k in path.k) if (path[has](k)) { 5692 fontcopy.glyphs[glyph].k[k] = path.k[k]; 5693 } 5694 } 5695 } 5696 } 5697 return font; 5698 }; 5699 paperproto.getFont = function (family, weight, style, stretch) { 5700 stretch = stretch || "normal"; 5701 style = style || "normal"; 5702 weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; 5703 if (!R.fonts) { 5704 return; 5705 } 5706 var font = R.fonts[family]; 5707 if (!font) { 5708 var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); 5709 for (var fontName in R.fonts) if (R.fonts[has](fontName)) { 5710 if (name.test(fontName)) { 5711 font = R.fonts[fontName]; 5712 break; 5713 } 5714 } 5715 } 5716 var thefont; 5717 if (font) { 5718 for (var i = 0, ii = font.length; i < ii; i++) { 5719 thefont = font[i]; 5720 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { 5721 break; 5722 } 5723 } 5724 } 5725 return thefont; 5726 }; 5727 paperproto.print = function (x, y, string, font, size, origin, letter_spacing) { 5728 origin = origin || "middle"; // baseline|middle 5729 letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); 5730 var out = this.set(), 5731 letters = Str(string).split(E), 5732 shift = 0, 5733 path = E, 5734 scale; 5735 R.is(font, string) && (font = this.getFont(font)); 5736 if (font) { 5737 scale = (size || 16) / font.face["units-per-em"]; 5738 var bb = font.face.bbox.split(separator), 5739 top = +bb[0], 5740 height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2); 5741 for (var i = 0, ii = letters.length; i < ii; i++) { 5742 var prev = i && font.glyphs[letters[i - 1]] || {}, 5743 curr = font.glyphs[letters[i]]; 5744 shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; 5745 curr && curr.d && out.push(this.path(curr.d).attr({fill: "#000", stroke: "none", transform: [["t", shift, 0]]})); 5746 } 5747 out.scale(scale, scale, top, height).translate(x - top, y - height); 5748 } 5749 return out; 5750 }; 5751 5752 R.format = function (token, params) { 5753 var args = R.is(params, array) ? [0][concat](params) : arguments; 5754 token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { 5755 return args[++i] == null ? E : args[i]; 5756 })); 5757 return token || E; 5758 }; 5759 R.ninja = function () { 5760 oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; 5761 return R; 5762 }; 5763 /*\ 5764 * Raphael.el 5765 [ property (object) ] 5766 ** 5767 * You can add your own method to elements. This is usefull when you want to hack default functionality or 5768 * want to wrap some common transformation or attributes in one method. In difference to canvas methods, 5769 * you can redefine element method at any time. Expending element methods wouldn’t affect set 5770 > Usage 5771 | Raphael.el.red = function () { 5772 | this.attr({fill: "#f00"}); 5773 | }; 5774 | // then use it 5775 | paper.circle(100, 100, 20).red(); 5776 \*/ 5777 R.el = elproto; 5778 R.st = setproto; 5779 // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html 5780 (function (doc, loaded, f) { 5781 if (doc.readyState == null && doc.addEventListener){ 5782 doc.addEventListener(loaded, f = function () { 5783 doc.removeEventListener(loaded, f, false); 5784 doc.readyState = "complete"; 5785 }, false); 5786 doc.readyState = "loading"; 5787 } 5788 function isLoaded() { 5789 (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : eve("DOMload"); 5790 } 5791 isLoaded(); 5792 })(document, "DOMContentLoaded"); 5793 5794 oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); 5795 5796 /* 5797 * Eve 0.2.1 - JavaScript Events Library 5798 * 5799 * Copyright (c) 2010 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) 5800 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. 5801 */ 5802 5803 var eve = R.eve = (function () { 5804 var version = "0.2.1", 5805 has = "hasOwnProperty", 5806 separator = /[\.\/]/, 5807 wildcard = "*", 5808 events = {n: {}}, 5809 eve = function (name, scope) { 5810 var e = events, 5811 args = Array.prototype.slice.call(arguments, 2), 5812 listeners = eve.listeners(name), 5813 errors = []; 5814 for (var i = 0, ii = listeners.length; i < ii; i++) { 5815 try { 5816 listeners[i].apply(scope, args); 5817 } catch (ex) { 5818 errors.push({error: ex && ex.message || ex, func: listeners[i]}); 5819 } 5820 } 5821 if (errors.length) { 5822 return errors; 5823 } 5824 }; 5825 eve.listeners = function (name) { 5826 var names = name.split(separator), 5827 e = events, 5828 item, 5829 items, 5830 k, 5831 i, 5832 ii, 5833 j, 5834 jj, 5835 nes, 5836 es = [e], 5837 out = []; 5838 for (i = 0, ii = names.length; i < ii; i++) { 5839 nes = []; 5840 for (j = 0, jj = es.length; j < jj; j++) { 5841 e = es[j].n; 5842 items = [e[names[i]], e[wildcard]]; 5843 k = 2; 5844 while (k--) { 5845 item = items[k]; 5846 if (item) { 5847 nes.push(item); 5848 out = out.concat(item.f || []); 5849 } 5850 } 5851 } 5852 es = nes; 5853 } 5854 return out; 5855 }; 5856 eve.on = function (name, f) { 5857 var names = name.split(separator), 5858 e = events; 5859 for (var i = 0, ii = names.length; i < ii; i++) { 5860 e = e.n; 5861 !e[names[i]] && (e[names[i]] = {n: {}}); 5862 e = e[names[i]]; 5863 } 5864 e.f = e.f || []; 5865 for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { 5866 return false; 5867 } 5868 e.f.push(f); 5869 }; 5870 eve.unbind = function (name, f) { 5871 var names = name.split(separator), 5872 e, 5873 key, 5874 splice, 5875 cur = [events]; 5876 for (var i = 0, ii = names.length; i < ii; i++) { 5877 for (var j = 0; j < cur.length; j += splice.length - 2) { 5878 splice = [j, 1]; 5879 e = cur[j].n; 5880 if (names[i] != wildcard) { 5881 if (e[names[i]]) { 5882 splice.push(e[names[i]]); 5883 } 5884 } else { 5885 for (key in e) if (e[has](key)) { 5886 splice.push(e[key]); 5887 } 5888 } 5889 cur.splice.apply(cur, splice); 5890 } 5891 } 5892 for (i = 0, ii = cur.length; i < ii; i++) { 5893 e = cur[i]; 5894 while (e.n) { 5895 if (f) { 5896 if (e.f) { 5897 for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { 5898 e.f.splice(i, 1); 5899 break; 5900 } 5901 !e.f.length && delete e.f; 5902 } 5903 for (key in e.n) if (e.n[has](key) && e.n[key].f) { 5904 var funcs = e.n[key].f; 5905 for (i = 0, ii = funcs.length; i < ii; i++) if (funcs[i] == f) { 5906 funcs.splice(i, 1); 5907 break; 5908 } 5909 !funcs.length && delete e.n[key].f; 5910 } 5911 } else { 5912 delete e.f; 5913 for (key in e.n) if (e.n[has](key) && e.n[key].f) { 5914 delete e.n[key].f; 5915 } 5916 } 5917 e = e.n; 5918 } 5919 } 5920 return true; 5921 }; 5922 eve.version = version; 5923 eve.toString = function () { 5924 return "You are running Eve " + version; 5925 }; 5926 return eve; 5927 })(); 5928})();