1// ┌────────────────────────────────────────────────────────────────────┐ \\ 2// │ Raphaël 2.1.1 - JavaScript Vector Library │ \\ 3// ├────────────────────────────────────────────────────────────────────┤ \\ 4// │ Copyright © 2008-2012 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ 5// │ Copyright © 2008-2012 Sencha Labs (http://sencha.com) │ \\ 6// ├────────────────────────────────────────────────────────────────────┤ \\ 7// │ Licensed under the MIT (http://raphaeljs.com/license.html) license.│ \\ 8// └────────────────────────────────────────────────────────────────────┘ \\ 9// Copyright (c) 2013 Adobe Systems Incorporated. All rights reserved. 10// 11// Licensed under the Apache License, Version 2.0 (the "License"); 12// you may not use this file except in compliance with the License. 13// You may obtain a copy of the License at 14// 15// http://www.apache.org/licenses/LICENSE-2.0 16// 17// Unless required by applicable law or agreed to in writing, software 18// distributed under the License is distributed on an "AS IS" BASIS, 19// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20// See the License for the specific language governing permissions and 21// limitations under the License. 22// ┌────────────────────────────────────────────────────────────┐ \\ 23// │ Eve 0.4.2 - JavaScript Events Library │ \\ 24// ├────────────────────────────────────────────────────────────┤ \\ 25// │ Author Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ 26// └────────────────────────────────────────────────────────────┘ \\ 27 28(function (glob) { 29 var version = "0.4.2", 30 has = "hasOwnProperty", 31 separator = /[\.\/]/, 32 wildcard = "*", 33 fun = function () {}, 34 numsort = function (a, b) { 35 return a - b; 36 }, 37 current_event, 38 stop, 39 events = {n: {}}, 40 /*\ 41 * eve 42 [ method ] 43 44 * Fires event with given `name`, given scope and other parameters. 45 46 > Arguments 47 48 - name (string) name of the *event*, dot (`.`) or slash (`/`) separated 49 - scope (object) context for the event handlers 50 - varargs (...) the rest of arguments will be sent to event handlers 51 52 = (object) array of returned values from the listeners 53 \*/ 54 eve = function (name, scope) { 55 name = String(name); 56 var e = events, 57 oldstop = stop, 58 args = Array.prototype.slice.call(arguments, 2), 59 listeners = eve.listeners(name), 60 z = 0, 61 f = false, 62 l, 63 indexed = [], 64 queue = {}, 65 out = [], 66 ce = current_event, 67 errors = []; 68 current_event = name; 69 stop = 0; 70 for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { 71 indexed.push(listeners[i].zIndex); 72 if (listeners[i].zIndex < 0) { 73 queue[listeners[i].zIndex] = listeners[i]; 74 } 75 } 76 indexed.sort(numsort); 77 while (indexed[z] < 0) { 78 l = queue[indexed[z++]]; 79 out.push(l.apply(scope, args)); 80 if (stop) { 81 stop = oldstop; 82 return out; 83 } 84 } 85 for (i = 0; i < ii; i++) { 86 l = listeners[i]; 87 if ("zIndex" in l) { 88 if (l.zIndex == indexed[z]) { 89 out.push(l.apply(scope, args)); 90 if (stop) { 91 break; 92 } 93 do { 94 z++; 95 l = queue[indexed[z]]; 96 l && out.push(l.apply(scope, args)); 97 if (stop) { 98 break; 99 } 100 } while (l) 101 } else { 102 queue[l.zIndex] = l; 103 } 104 } else { 105 out.push(l.apply(scope, args)); 106 if (stop) { 107 break; 108 } 109 } 110 } 111 stop = oldstop; 112 current_event = ce; 113 return out.length ? out : null; 114 }; 115 // Undocumented. Debug only. 116 eve._events = events; 117 /*\ 118 * eve.listeners 119 [ method ] 120 121 * Internal method which gives you array of all event handlers that will be triggered by the given `name`. 122 123 > Arguments 124 125 - name (string) name of the event, dot (`.`) or slash (`/`) separated 126 127 = (array) array of event handlers 128 \*/ 129 eve.listeners = function (name) { 130 var names = name.split(separator), 131 e = events, 132 item, 133 items, 134 k, 135 i, 136 ii, 137 j, 138 jj, 139 nes, 140 es = [e], 141 out = []; 142 for (i = 0, ii = names.length; i < ii; i++) { 143 nes = []; 144 for (j = 0, jj = es.length; j < jj; j++) { 145 e = es[j].n; 146 items = [e[names[i]], e[wildcard]]; 147 k = 2; 148 while (k--) { 149 item = items[k]; 150 if (item) { 151 nes.push(item); 152 out = out.concat(item.f || []); 153 } 154 } 155 } 156 es = nes; 157 } 158 return out; 159 }; 160 161 /*\ 162 * eve.on 163 [ method ] 164 ** 165 * Binds given event handler with a given name. You can use wildcards “`*`” for the names: 166 | eve.on("*.under.*", f); 167 | eve("mouse.under.floor"); // triggers f 168 * Use @eve to trigger the listener. 169 ** 170 > Arguments 171 ** 172 - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards 173 - f (function) event handler function 174 ** 175 = (function) returned function accepts a single numeric parameter that represents z-index of the handler. It is an optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. 176 > Example: 177 | eve.on("mouse", eatIt)(2); 178 | eve.on("mouse", scream); 179 | eve.on("mouse", catchIt)(1); 180 * This will ensure that `catchIt()` function will be called before `eatIt()`. 181 * 182 * If you want to put your handler before non-indexed handlers, specify a negative value. 183 * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. 184 \*/ 185 eve.on = function (name, f) { 186 name = String(name); 187 if (typeof f != "function") { 188 return function () {}; 189 } 190 var names = name.split(separator), 191 e = events; 192 for (var i = 0, ii = names.length; i < ii; i++) { 193 e = e.n; 194 e = e.hasOwnProperty(names[i]) && e[names[i]] || (e[names[i]] = {n: {}}); 195 } 196 e.f = e.f || []; 197 for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { 198 return fun; 199 } 200 e.f.push(f); 201 return function (zIndex) { 202 if (+zIndex == +zIndex) { 203 f.zIndex = +zIndex; 204 } 205 }; 206 }; 207 /*\ 208 * eve.f 209 [ method ] 210 ** 211 * Returns function that will fire given event with optional arguments. 212 * Arguments that will be passed to the result function will be also 213 * concated to the list of final arguments. 214 | el.onclick = eve.f("click", 1, 2); 215 | eve.on("click", function (a, b, c) { 216 | console.log(a, b, c); // 1, 2, [event object] 217 | }); 218 > Arguments 219 - event (string) event name 220 - varargs (…) and any other arguments 221 = (function) possible event handler function 222 \*/ 223 eve.f = function (event) { 224 var attrs = [].slice.call(arguments, 1); 225 return function () { 226 eve.apply(null, [event, null].concat(attrs).concat([].slice.call(arguments, 0))); 227 }; 228 }; 229 /*\ 230 * eve.stop 231 [ method ] 232 ** 233 * Is used inside an event handler to stop the event, preventing any subsequent listeners from firing. 234 \*/ 235 eve.stop = function () { 236 stop = 1; 237 }; 238 /*\ 239 * eve.nt 240 [ method ] 241 ** 242 * Could be used inside event handler to figure out actual name of the event. 243 ** 244 > Arguments 245 ** 246 - subname (string) #optional subname of the event 247 ** 248 = (string) name of the event, if `subname` is not specified 249 * or 250 = (boolean) `true`, if current event’s name contains `subname` 251 \*/ 252 eve.nt = function (subname) { 253 if (subname) { 254 return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); 255 } 256 return current_event; 257 }; 258 /*\ 259 * eve.nts 260 [ method ] 261 ** 262 * Could be used inside event handler to figure out actual name of the event. 263 ** 264 ** 265 = (array) names of the event 266 \*/ 267 eve.nts = function () { 268 return current_event.split(separator); 269 }; 270 /*\ 271 * eve.off 272 [ method ] 273 ** 274 * Removes given function from the list of event listeners assigned to given name. 275 * If no arguments specified all the events will be cleared. 276 ** 277 > Arguments 278 ** 279 - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards 280 - f (function) event handler function 281 \*/ 282 /*\ 283 * eve.unbind 284 [ method ] 285 ** 286 * See @eve.off 287 \*/ 288 eve.off = eve.unbind = function (name, f) { 289 if (!name) { 290 eve._events = events = {n: {}}; 291 return; 292 } 293 var names = name.split(separator), 294 e, 295 key, 296 splice, 297 i, ii, j, jj, 298 cur = [events]; 299 for (i = 0, ii = names.length; i < ii; i++) { 300 for (j = 0; j < cur.length; j += splice.length - 2) { 301 splice = [j, 1]; 302 e = cur[j].n; 303 if (names[i] != wildcard) { 304 if (e[names[i]]) { 305 splice.push(e[names[i]]); 306 } 307 } else { 308 for (key in e) if (e[has](key)) { 309 splice.push(e[key]); 310 } 311 } 312 cur.splice.apply(cur, splice); 313 } 314 } 315 for (i = 0, ii = cur.length; i < ii; i++) { 316 e = cur[i]; 317 while (e.n) { 318 if (f) { 319 if (e.f) { 320 for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { 321 e.f.splice(j, 1); 322 break; 323 } 324 !e.f.length && delete e.f; 325 } 326 for (key in e.n) if (e.n[has](key) && e.n[key].f) { 327 var funcs = e.n[key].f; 328 for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { 329 funcs.splice(j, 1); 330 break; 331 } 332 !funcs.length && delete e.n[key].f; 333 } 334 } else { 335 delete e.f; 336 for (key in e.n) if (e.n[has](key) && e.n[key].f) { 337 delete e.n[key].f; 338 } 339 } 340 e = e.n; 341 } 342 } 343 }; 344 /*\ 345 * eve.once 346 [ method ] 347 ** 348 * Binds given event handler with a given name to only run once then unbind itself. 349 | eve.once("login", f); 350 | eve("login"); // triggers f 351 | eve("login"); // no listeners 352 * Use @eve to trigger the listener. 353 ** 354 > Arguments 355 ** 356 - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards 357 - f (function) event handler function 358 ** 359 = (function) same return function as @eve.on 360 \*/ 361 eve.once = function (name, f) { 362 var f2 = function () { 363 eve.unbind(name, f2); 364 return f.apply(this, arguments); 365 }; 366 return eve.on(name, f2); 367 }; 368 /*\ 369 * eve.version 370 [ property (string) ] 371 ** 372 * Current version of the library. 373 \*/ 374 eve.version = version; 375 eve.toString = function () { 376 return "You are running Eve " + version; 377 }; 378 (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (typeof define != "undefined" ? (define("eve", [], function() { return eve; })) : (glob.eve = eve)); 379})(this); 380// ┌─────────────────────────────────────────────────────────────────────┐ \\ 381// │ "Raphaël 2.1.0" - JavaScript Vector Library │ \\ 382// ├─────────────────────────────────────────────────────────────────────┤ \\ 383// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ 384// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ 385// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ 386// └─────────────────────────────────────────────────────────────────────┘ \\ 387 388(function (glob, factory) { 389 // AMD support 390 if (typeof define === "function" && define.amd) { 391 // Define as an anonymous module 392 define(["."], function( eve ) { 393 return factory(glob, eve); 394 }); 395 } else { 396 // Browser globals (glob is window) 397 // Raphael adds itself to window 398 factory(glob, glob.eve); 399 } 400}(this, function (window, eve) { 401 /*\ 402 * Raphael 403 [ method ] 404 ** 405 * Creates a canvas object on which to draw. 406 * You must do this first, as all future calls to drawing methods 407 * from this instance will be bound to this canvas. 408 > Parameters 409 ** 410 - container (HTMLElement|string) DOM element or its ID which is going to be a parent for drawing surface 411 - width (number) 412 - height (number) 413 - callback (function) #optional callback function which is going to be executed in the context of newly created paper 414 * or 415 - x (number) 416 - y (number) 417 - width (number) 418 - height (number) 419 - callback (function) #optional callback function which is going to be executed in the context of newly created paper 420 * or 421 - 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>}). See @Paper.add. 422 - callback (function) #optional callback function which is going to be executed in the context of newly created paper 423 * or 424 - 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`. 425 = (object) @Paper 426 > Usage 427 | // Each of the following examples create a canvas 428 | // that is 320px wide by 200px high. 429 | // Canvas is created at the viewport’s 10,50 coordinate. 430 | var paper = Raphael(10, 50, 320, 200); 431 | // Canvas is created at the top left corner of the #notepad element 432 | // (or its top right corner in dir="rtl" elements) 433 | var paper = Raphael(document.getElementById("notepad"), 320, 200); 434 | // Same as above 435 | var paper = Raphael("notepad", 320, 200); 436 | // Image dump 437 | var set = Raphael(["notepad", 320, 200, { 438 | type: "rect", 439 | x: 10, 440 | y: 10, 441 | width: 25, 442 | height: 25, 443 | stroke: "#f00" 444 | }, { 445 | type: "text", 446 | x: 30, 447 | y: 40, 448 | text: "Dump" 449 | }]); 450 \*/ 451 function R(first) { 452 if (R.is(first, "function")) { 453 return loaded ? first() : eve.on("raphael.DOMload", first); 454 } else if (R.is(first, array)) { 455 return R._engine.create[apply](R, first.splice(0, 3 + R.is(first[0], nu))).add(first); 456 } else { 457 var args = Array.prototype.slice.call(arguments, 0); 458 if (R.is(args[args.length - 1], "function")) { 459 var f = args.pop(); 460 return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("raphael.DOMload", function () { 461 f.call(R._engine.create[apply](R, args)); 462 }); 463 } else { 464 return R._engine.create[apply](R, arguments); 465 } 466 } 467 } 468 R.version = "2.1.0"; 469 R.eve = eve; 470 var loaded, 471 separator = /[, ]+/, 472 elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1}, 473 formatrg = /\{(\d+)\}/g, 474 proto = "prototype", 475 has = "hasOwnProperty", 476 g = { 477 doc: document, 478 win: window 479 }, 480 oldRaphael = { 481 was: Object.prototype[has].call(g.win, "Raphael"), 482 is: g.win.Raphael 483 }, 484 Paper = function () { 485 /*\ 486 * Paper.ca 487 [ property (object) ] 488 ** 489 * Shortcut for @Paper.customAttributes 490 \*/ 491 /*\ 492 * Paper.customAttributes 493 [ property (object) ] 494 ** 495 * If you have a set of attributes that you would like to represent 496 * as a function of some number you can do it easily with custom attributes: 497 > Usage 498 | paper.customAttributes.hue = function (num) { 499 | num = num % 1; 500 | return {fill: "hsb(" + num + ", 0.75, 1)"}; 501 | }; 502 | // Custom attribute “hue” will change fill 503 | // to be given hue with fixed saturation and brightness. 504 | // Now you can use it like this: 505 | var c = paper.circle(10, 10, 10).attr({hue: .45}); 506 | // or even like this: 507 | c.animate({hue: 1}, 1e3); 508 | 509 | // You could also create custom attribute 510 | // with multiple parameters: 511 | paper.customAttributes.hsb = function (h, s, b) { 512 | return {fill: "hsb(" + [h, s, b].join(",") + ")"}; 513 | }; 514 | c.attr({hsb: "0.5 .8 1"}); 515 | c.animate({hsb: [1, 0, 0.5]}, 1e3); 516 \*/ 517 this.ca = this.customAttributes = {}; 518 }, 519 paperproto, 520 appendChild = "appendChild", 521 apply = "apply", 522 concat = "concat", 523 supportsTouch = ('ontouchstart' in g.win) || g.win.DocumentTouch && g.doc instanceof DocumentTouch, //taken from Modernizr touch test 524 E = "", 525 S = " ", 526 Str = String, 527 split = "split", 528 events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S), 529 touchMap = { 530 mousedown: "touchstart", 531 mousemove: "touchmove", 532 mouseup: "touchend" 533 }, 534 lowerCase = Str.prototype.toLowerCase, 535 math = Math, 536 mmax = math.max, 537 mmin = math.min, 538 abs = math.abs, 539 pow = math.pow, 540 PI = math.PI, 541 nu = "number", 542 string = "string", 543 array = "array", 544 toString = "toString", 545 fillString = "fill", 546 objectToString = Object.prototype.toString, 547 paper = {}, 548 push = "push", 549 ISURL = R._ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, 550 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, 551 isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1}, 552 bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, 553 round = math.round, 554 setAttribute = "setAttribute", 555 toFloat = parseFloat, 556 toInt = parseInt, 557 upperCase = Str.prototype.toUpperCase, 558 availableAttrs = R._availableAttrs = { 559 "arrow-end": "none", 560 "arrow-start": "none", 561 blur: 0, 562 "clip-rect": "0 0 1e9 1e9", 563 cursor: "default", 564 cx: 0, 565 cy: 0, 566 fill: "#fff", 567 "fill-opacity": 1, 568 font: '10px "Arial"', 569 "font-family": '"Arial"', 570 "font-size": "10", 571 "font-style": "normal", 572 "font-weight": 400, 573 gradient: 0, 574 height: 0, 575 href: "http://raphaeljs.com/", 576 "letter-spacing": 0, 577 opacity: 1, 578 path: "M0,0", 579 r: 0, 580 rx: 0, 581 ry: 0, 582 src: "", 583 stroke: "#000", 584 "stroke-dasharray": "", 585 "stroke-linecap": "butt", 586 "stroke-linejoin": "butt", 587 "stroke-miterlimit": 0, 588 "stroke-opacity": 1, 589 "stroke-width": 1, 590 target: "_blank", 591 "text-anchor": "middle", 592 title: "Raphael", 593 transform: "", 594 width: 0, 595 x: 0, 596 y: 0 597 }, 598 availableAnimAttrs = R._availableAnimAttrs = { 599 blur: nu, 600 "clip-rect": "csv", 601 cx: nu, 602 cy: nu, 603 fill: "colour", 604 "fill-opacity": nu, 605 "font-size": nu, 606 height: nu, 607 opacity: nu, 608 path: "path", 609 r: nu, 610 rx: nu, 611 ry: nu, 612 stroke: "colour", 613 "stroke-opacity": nu, 614 "stroke-width": nu, 615 transform: "transform", 616 width: nu, 617 x: nu, 618 y: nu 619 }, 620 whitespace = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]/g, 621 commaSpaces = /[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/, 622 hsrg = {hs: 1, rg: 1}, 623 p2s = /,?([achlmqrstvxz]),?/gi, 624 pathCommand = /([achlmrqstvz])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig, 625 tCommand = /([rstm])[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*)+)/ig, 626 pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,?[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*/ig, 627 radial_gradient = R._radial_gradient = /^r(?:\(([^,]+?)[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*,[\x09\x0a\x0b\x0c\x0d\x20\xa0\u1680\u180e\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029]*([^\)]+?)\))?/, 628 eldata = {}, 629 sortByKey = function (a, b) { 630 return a.key - b.key; 631 }, 632 sortByNumber = function (a, b) { 633 return toFloat(a) - toFloat(b); 634 }, 635 fun = function () {}, 636 pipe = function (x) { 637 return x; 638 }, 639 rectPath = R._rectPath = function (x, y, w, h, r) { 640 if (r) { 641 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"]]; 642 } 643 return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; 644 }, 645 ellipsePath = function (x, y, rx, ry) { 646 if (ry == null) { 647 ry = rx; 648 } 649 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"]]; 650 }, 651 getPath = R._getPath = { 652 path: function (el) { 653 return el.attr("path"); 654 }, 655 circle: function (el) { 656 var a = el.attrs; 657 return ellipsePath(a.cx, a.cy, a.r); 658 }, 659 ellipse: function (el) { 660 var a = el.attrs; 661 return ellipsePath(a.cx, a.cy, a.rx, a.ry); 662 }, 663 rect: function (el) { 664 var a = el.attrs; 665 return rectPath(a.x, a.y, a.width, a.height, a.r); 666 }, 667 image: function (el) { 668 var a = el.attrs; 669 return rectPath(a.x, a.y, a.width, a.height); 670 }, 671 text: function (el) { 672 var bbox = el._getBBox(); 673 return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); 674 }, 675 set : function(el) { 676 var bbox = el._getBBox(); 677 return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); 678 } 679 }, 680 /*\ 681 * Raphael.mapPath 682 [ method ] 683 ** 684 * Transform the path string with given matrix. 685 > Parameters 686 - path (string) path string 687 - matrix (object) see @Matrix 688 = (string) transformed path string 689 \*/ 690 mapPath = R.mapPath = function (path, matrix) { 691 if (!matrix) { 692 return path; 693 } 694 var x, y, i, j, ii, jj, pathi; 695 path = path2curve(path); 696 for (i = 0, ii = path.length; i < ii; i++) { 697 pathi = path[i]; 698 for (j = 1, jj = pathi.length; j < jj; j += 2) { 699 x = matrix.x(pathi[j], pathi[j + 1]); 700 y = matrix.y(pathi[j], pathi[j + 1]); 701 pathi[j] = x; 702 pathi[j + 1] = y; 703 } 704 } 705 return path; 706 }; 707 708 R._g = g; 709 /*\ 710 * Raphael.type 711 [ property (string) ] 712 ** 713 * Can be “SVG”, “VML” or empty, depending on browser support. 714 \*/ 715 R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); 716 if (R.type == "VML") { 717 var d = g.doc.createElement("div"), 718 b; 719 d.innerHTML = '<v:shape adj="1"/>'; 720 b = d.firstChild; 721 b.style.behavior = "url(#default#VML)"; 722 if (!(b && typeof b.adj == "object")) { 723 return (R.type = E); 724 } 725 d = null; 726 } 727 /*\ 728 * Raphael.svg 729 [ property (boolean) ] 730 ** 731 * `true` if browser supports SVG. 732 \*/ 733 /*\ 734 * Raphael.vml 735 [ property (boolean) ] 736 ** 737 * `true` if browser supports VML. 738 \*/ 739 R.svg = !(R.vml = R.type == "VML"); 740 R._Paper = Paper; 741 /*\ 742 * Raphael.fn 743 [ property (object) ] 744 ** 745 * You can add your own method to the canvas. For example if you want to draw a pie chart, 746 * you can create your own pie chart function and ship it as a Raphaël plugin. To do this 747 * you need to extend the `Raphael.fn` object. You should modify the `fn` object before a 748 * Raphaël instance is created, otherwise it will take no effect. Please note that the 749 * ability for namespaced plugins was removed in Raphael 2.0. It is up to the plugin to 750 * ensure any namespacing ensures proper context. 751 > Usage 752 | Raphael.fn.arrow = function (x1, y1, x2, y2, size) { 753 | return this.path( ... ); 754 | }; 755 | // or create namespace 756 | Raphael.fn.mystuff = { 757 | arrow: function () {…}, 758 | star: function () {…}, 759 | // etc… 760 | }; 761 | var paper = Raphael(10, 10, 630, 480); 762 | // then use it 763 | paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"}); 764 | paper.mystuff.arrow(); 765 | paper.mystuff.star(); 766 \*/ 767 R.fn = paperproto = Paper.prototype = R.prototype; 768 R._id = 0; 769 R._oid = 0; 770 /*\ 771 * Raphael.is 772 [ method ] 773 ** 774 * Handfull replacement for `typeof` operator. 775 > Parameters 776 - o (…) any object or primitive 777 - type (string) name of the type, i.e. “string”, “function”, “number”, etc. 778 = (boolean) is given value is of given type 779 \*/ 780 R.is = function (o, type) { 781 type = lowerCase.call(type); 782 if (type == "finite") { 783 return !isnan[has](+o); 784 } 785 if (type == "array") { 786 return o instanceof Array; 787 } 788 return (type == "null" && o === null) || 789 (type == typeof o && o !== null) || 790 (type == "object" && o === Object(o)) || 791 (type == "array" && Array.isArray && Array.isArray(o)) || 792 objectToString.call(o).slice(8, -1).toLowerCase() == type; 793 }; 794 795 function clone(obj) { 796 if (Object(obj) !== obj) { 797 return obj; 798 } 799 var res = new obj.constructor; 800 for (var key in obj) if (obj[has](key)) { 801 res[key] = clone(obj[key]); 802 } 803 return res; 804 } 805 806 /*\ 807 * Raphael.angle 808 [ method ] 809 ** 810 * Returns angle between two or three points 811 > Parameters 812 - x1 (number) x coord of first point 813 - y1 (number) y coord of first point 814 - x2 (number) x coord of second point 815 - y2 (number) y coord of second point 816 - x3 (number) #optional x coord of third point 817 - y3 (number) #optional y coord of third point 818 = (number) angle in degrees. 819 \*/ 820 R.angle = function (x1, y1, x2, y2, x3, y3) { 821 if (x3 == null) { 822 var x = x1 - x2, 823 y = y1 - y2; 824 if (!x && !y) { 825 return 0; 826 } 827 return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; 828 } else { 829 return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3); 830 } 831 }; 832 /*\ 833 * Raphael.rad 834 [ method ] 835 ** 836 * Transform angle to radians 837 > Parameters 838 - deg (number) angle in degrees 839 = (number) angle in radians. 840 \*/ 841 R.rad = function (deg) { 842 return deg % 360 * PI / 180; 843 }; 844 /*\ 845 * Raphael.deg 846 [ method ] 847 ** 848 * Transform angle to degrees 849 > Parameters 850 - deg (number) angle in radians 851 = (number) angle in degrees. 852 \*/ 853 R.deg = function (rad) { 854 return rad * 180 / PI % 360; 855 }; 856 /*\ 857 * Raphael.snapTo 858 [ method ] 859 ** 860 * Snaps given value to given grid. 861 > Parameters 862 - values (array|number) given array of values or step of the grid 863 - value (number) value to adjust 864 - tolerance (number) #optional tolerance for snapping. Default is `10`. 865 = (number) adjusted value. 866 \*/ 867 R.snapTo = function (values, value, tolerance) { 868 tolerance = R.is(tolerance, "finite") ? tolerance : 10; 869 if (R.is(values, array)) { 870 var i = values.length; 871 while (i--) if (abs(values[i] - value) <= tolerance) { 872 return values[i]; 873 } 874 } else { 875 values = +values; 876 var rem = value % values; 877 if (rem < tolerance) { 878 return value - rem; 879 } 880 if (rem > values - tolerance) { 881 return value - rem + values; 882 } 883 } 884 return value; 885 }; 886 887 /*\ 888 * Raphael.createUUID 889 [ method ] 890 ** 891 * Returns RFC4122, version 4 ID 892 \*/ 893 var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { 894 return function () { 895 return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); 896 }; 897 })(/[xy]/g, function (c) { 898 var r = math.random() * 16 | 0, 899 v = c == "x" ? r : (r & 3 | 8); 900 return v.toString(16); 901 }); 902 903 /*\ 904 * Raphael.setWindow 905 [ method ] 906 ** 907 * Used when you need to draw in `<iframe>`. Switched window to the iframe one. 908 > Parameters 909 - newwin (window) new window object 910 \*/ 911 R.setWindow = function (newwin) { 912 eve("raphael.setWindow", R, g.win, newwin); 913 g.win = newwin; 914 g.doc = g.win.document; 915 if (R._engine.initWin) { 916 R._engine.initWin(g.win); 917 } 918 }; 919 var toHex = function (color) { 920 if (R.vml) { 921 // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ 922 var trim = /^\s+|\s+$/g; 923 var bod; 924 try { 925 var docum = new ActiveXObject("htmlfile"); 926 docum.write("<body>"); 927 docum.close(); 928 bod = docum.body; 929 } catch(e) { 930 bod = createPopup().document.body; 931 } 932 var range = bod.createTextRange(); 933 toHex = cacher(function (color) { 934 try { 935 bod.style.color = Str(color).replace(trim, E); 936 var value = range.queryCommandValue("ForeColor"); 937 value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); 938 return "#" + ("000000" + value.toString(16)).slice(-6); 939 } catch(e) { 940 return "none"; 941 } 942 }); 943 } else { 944 var i = g.doc.createElement("i"); 945 i.title = "Rapha\xebl Colour Picker"; 946 i.style.display = "none"; 947 g.doc.body.appendChild(i); 948 toHex = cacher(function (color) { 949 i.style.color = color; 950 return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); 951 }); 952 } 953 return toHex(color); 954 }, 955 hsbtoString = function () { 956 return "hsb(" + [this.h, this.s, this.b] + ")"; 957 }, 958 hsltoString = function () { 959 return "hsl(" + [this.h, this.s, this.l] + ")"; 960 }, 961 rgbtoString = function () { 962 return this.hex; 963 }, 964 prepareRGB = function (r, g, b) { 965 if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) { 966 b = r.b; 967 g = r.g; 968 r = r.r; 969 } 970 if (g == null && R.is(r, string)) { 971 var clr = R.getRGB(r); 972 r = clr.r; 973 g = clr.g; 974 b = clr.b; 975 } 976 if (r > 1 || g > 1 || b > 1) { 977 r /= 255; 978 g /= 255; 979 b /= 255; 980 } 981 982 return [r, g, b]; 983 }, 984 packageRGB = function (r, g, b, o) { 985 r *= 255; 986 g *= 255; 987 b *= 255; 988 var rgb = { 989 r: r, 990 g: g, 991 b: b, 992 hex: R.rgb(r, g, b), 993 toString: rgbtoString 994 }; 995 R.is(o, "finite") && (rgb.opacity = o); 996 return rgb; 997 }; 998 999 /*\ 1000 * Raphael.color 1001 [ method ] 1002 ** 1003 * Parses the color string and returns object with all values for the given color. 1004 > Parameters 1005 - clr (string) color string in one of the supported formats (see @Raphael.getRGB) 1006 = (object) Combined RGB & HSB object in format: 1007 o { 1008 o r (number) red, 1009 o g (number) green, 1010 o b (number) blue, 1011 o hex (string) color in HTML/CSS format: #••••••, 1012 o error (boolean) `true` if string can’t be parsed, 1013 o h (number) hue, 1014 o s (number) saturation, 1015 o v (number) value (brightness), 1016 o l (number) lightness 1017 o } 1018 \*/ 1019 R.color = function (clr) { 1020 var rgb; 1021 if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { 1022 rgb = R.hsb2rgb(clr); 1023 clr.r = rgb.r; 1024 clr.g = rgb.g; 1025 clr.b = rgb.b; 1026 clr.hex = rgb.hex; 1027 } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { 1028 rgb = R.hsl2rgb(clr); 1029 clr.r = rgb.r; 1030 clr.g = rgb.g; 1031 clr.b = rgb.b; 1032 clr.hex = rgb.hex; 1033 } else { 1034 if (R.is(clr, "string")) { 1035 clr = R.getRGB(clr); 1036 } 1037 if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) { 1038 rgb = R.rgb2hsl(clr); 1039 clr.h = rgb.h; 1040 clr.s = rgb.s; 1041 clr.l = rgb.l; 1042 rgb = R.rgb2hsb(clr); 1043 clr.v = rgb.b; 1044 } else { 1045 clr = {hex: "none"}; 1046 clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; 1047 } 1048 } 1049 clr.toString = rgbtoString; 1050 return clr; 1051 }; 1052 /*\ 1053 * Raphael.hsb2rgb 1054 [ method ] 1055 ** 1056 * Converts HSB values to RGB object. 1057 > Parameters 1058 - h (number) hue 1059 - s (number) saturation 1060 - v (number) value or brightness 1061 = (object) RGB object in format: 1062 o { 1063 o r (number) red, 1064 o g (number) green, 1065 o b (number) blue, 1066 o hex (string) color in HTML/CSS format: #•••••• 1067 o } 1068 \*/ 1069 R.hsb2rgb = function (h, s, v, o) { 1070 if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { 1071 v = h.b; 1072 s = h.s; 1073 h = h.h; 1074 o = h.o; 1075 } 1076 h *= 360; 1077 var R, G, B, X, C; 1078 h = (h % 360) / 60; 1079 C = v * s; 1080 X = C * (1 - abs(h % 2 - 1)); 1081 R = G = B = v - C; 1082 1083 h = ~~h; 1084 R += [C, X, 0, 0, X, C][h]; 1085 G += [X, C, C, X, 0, 0][h]; 1086 B += [0, 0, X, C, C, X][h]; 1087 return packageRGB(R, G, B, o); 1088 }; 1089 /*\ 1090 * Raphael.hsl2rgb 1091 [ method ] 1092 ** 1093 * Converts HSL values to RGB object. 1094 > Parameters 1095 - h (number) hue 1096 - s (number) saturation 1097 - l (number) luminosity 1098 = (object) RGB object in format: 1099 o { 1100 o r (number) red, 1101 o g (number) green, 1102 o b (number) blue, 1103 o hex (string) color in HTML/CSS format: #•••••• 1104 o } 1105 \*/ 1106 R.hsl2rgb = function (h, s, l, o) { 1107 if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) { 1108 l = h.l; 1109 s = h.s; 1110 h = h.h; 1111 } 1112 if (h > 1 || s > 1 || l > 1) { 1113 h /= 360; 1114 s /= 100; 1115 l /= 100; 1116 } 1117 h *= 360; 1118 var R, G, B, X, C; 1119 h = (h % 360) / 60; 1120 C = 2 * s * (l < .5 ? l : 1 - l); 1121 X = C * (1 - abs(h % 2 - 1)); 1122 R = G = B = l - C / 2; 1123 1124 h = ~~h; 1125 R += [C, X, 0, 0, X, C][h]; 1126 G += [X, C, C, X, 0, 0][h]; 1127 B += [0, 0, X, C, C, X][h]; 1128 return packageRGB(R, G, B, o); 1129 }; 1130 /*\ 1131 * Raphael.rgb2hsb 1132 [ method ] 1133 ** 1134 * Converts RGB values to HSB object. 1135 > Parameters 1136 - r (number) red 1137 - g (number) green 1138 - b (number) blue 1139 = (object) HSB object in format: 1140 o { 1141 o h (number) hue 1142 o s (number) saturation 1143 o b (number) brightness 1144 o } 1145 \*/ 1146 R.rgb2hsb = function (r, g, b) { 1147 b = prepareRGB(r, g, b); 1148 r = b[0]; 1149 g = b[1]; 1150 b = b[2]; 1151 1152 var H, S, V, C; 1153 V = mmax(r, g, b); 1154 C = V - mmin(r, g, b); 1155 H = (C == 0 ? null : 1156 V == r ? (g - b) / C : 1157 V == g ? (b - r) / C + 2 : 1158 (r - g) / C + 4 1159 ); 1160 H = ((H + 360) % 6) * 60 / 360; 1161 S = C == 0 ? 0 : C / V; 1162 return {h: H, s: S, b: V, toString: hsbtoString}; 1163 }; 1164 /*\ 1165 * Raphael.rgb2hsl 1166 [ method ] 1167 ** 1168 * Converts RGB values to HSL object. 1169 > Parameters 1170 - r (number) red 1171 - g (number) green 1172 - b (number) blue 1173 = (object) HSL object in format: 1174 o { 1175 o h (number) hue 1176 o s (number) saturation 1177 o l (number) luminosity 1178 o } 1179 \*/ 1180 R.rgb2hsl = function (r, g, b) { 1181 b = prepareRGB(r, g, b); 1182 r = b[0]; 1183 g = b[1]; 1184 b = b[2]; 1185 1186 var H, S, L, M, m, C; 1187 M = mmax(r, g, b); 1188 m = mmin(r, g, b); 1189 C = M - m; 1190 H = (C == 0 ? null : 1191 M == r ? (g - b) / C : 1192 M == g ? (b - r) / C + 2 : 1193 (r - g) / C + 4); 1194 H = ((H + 360) % 6) * 60 / 360; 1195 L = (M + m) / 2; 1196 S = (C == 0 ? 0 : 1197 L < .5 ? C / (2 * L) : 1198 C / (2 - 2 * L)); 1199 return {h: H, s: S, l: L, toString: hsltoString}; 1200 }; 1201 R._path2string = function () { 1202 return this.join(",").replace(p2s, "$1"); 1203 }; 1204 function repush(array, item) { 1205 for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { 1206 return array.push(array.splice(i, 1)[0]); 1207 } 1208 } 1209 function cacher(f, scope, postprocessor) { 1210 function newf() { 1211 var arg = Array.prototype.slice.call(arguments, 0), 1212 args = arg.join("\u2400"), 1213 cache = newf.cache = newf.cache || {}, 1214 count = newf.count = newf.count || []; 1215 if (cache[has](args)) { 1216 repush(count, args); 1217 return postprocessor ? postprocessor(cache[args]) : cache[args]; 1218 } 1219 count.length >= 1e3 && delete cache[count.shift()]; 1220 count.push(args); 1221 cache[args] = f[apply](scope, arg); 1222 return postprocessor ? postprocessor(cache[args]) : cache[args]; 1223 } 1224 return newf; 1225 } 1226 1227 var preload = R._preload = function (src, f) { 1228 var img = g.doc.createElement("img"); 1229 img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; 1230 img.onload = function () { 1231 f.call(this); 1232 this.onload = null; 1233 g.doc.body.removeChild(this); 1234 }; 1235 img.onerror = function () { 1236 g.doc.body.removeChild(this); 1237 }; 1238 g.doc.body.appendChild(img); 1239 img.src = src; 1240 }; 1241 1242 function clrToString() { 1243 return this.hex; 1244 } 1245 1246 /*\ 1247 * Raphael.getRGB 1248 [ method ] 1249 ** 1250 * Parses colour string as RGB object 1251 > Parameters 1252 - colour (string) colour string in one of formats: 1253 # <ul> 1254 # <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li> 1255 # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li> 1256 # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li> 1257 # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200, 100, 0)</code>”)</li> 1258 # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li> 1259 # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5, 0.25, 1)</code>”)</li> 1260 # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> 1261 # <li>hsl(•••, •••, •••) — same as hsb</li> 1262 # <li>hsl(•••%, •••%, •••%) — same as hsb</li> 1263 # </ul> 1264 = (object) RGB object in format: 1265 o { 1266 o r (number) red, 1267 o g (number) green, 1268 o b (number) blue 1269 o hex (string) color in HTML/CSS format: #••••••, 1270 o error (boolean) true if string can’t be parsed 1271 o } 1272 \*/ 1273 R.getRGB = cacher(function (colour) { 1274 if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { 1275 return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; 1276 } 1277 if (colour == "none") { 1278 return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString}; 1279 } 1280 !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); 1281 var res, 1282 red, 1283 green, 1284 blue, 1285 opacity, 1286 t, 1287 values, 1288 rgb = colour.match(colourRegExp); 1289 if (rgb) { 1290 if (rgb[2]) { 1291 blue = toInt(rgb[2].substring(5), 16); 1292 green = toInt(rgb[2].substring(3, 5), 16); 1293 red = toInt(rgb[2].substring(1, 3), 16); 1294 } 1295 if (rgb[3]) { 1296 blue = toInt((t = rgb[3].charAt(3)) + t, 16); 1297 green = toInt((t = rgb[3].charAt(2)) + t, 16); 1298 red = toInt((t = rgb[3].charAt(1)) + t, 16); 1299 } 1300 if (rgb[4]) { 1301 values = rgb[4][split](commaSpaces); 1302 red = toFloat(values[0]); 1303 values[0].slice(-1) == "%" && (red *= 2.55); 1304 green = toFloat(values[1]); 1305 values[1].slice(-1) == "%" && (green *= 2.55); 1306 blue = toFloat(values[2]); 1307 values[2].slice(-1) == "%" && (blue *= 2.55); 1308 rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); 1309 values[3] && values[3].slice(-1) == "%" && (opacity /= 100); 1310 } 1311 if (rgb[5]) { 1312 values = rgb[5][split](commaSpaces); 1313 red = toFloat(values[0]); 1314 values[0].slice(-1) == "%" && (red *= 2.55); 1315 green = toFloat(values[1]); 1316 values[1].slice(-1) == "%" && (green *= 2.55); 1317 blue = toFloat(values[2]); 1318 values[2].slice(-1) == "%" && (blue *= 2.55); 1319 (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); 1320 rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); 1321 values[3] && values[3].slice(-1) == "%" && (opacity /= 100); 1322 return R.hsb2rgb(red, green, blue, opacity); 1323 } 1324 if (rgb[6]) { 1325 values = rgb[6][split](commaSpaces); 1326 red = toFloat(values[0]); 1327 values[0].slice(-1) == "%" && (red *= 2.55); 1328 green = toFloat(values[1]); 1329 values[1].slice(-1) == "%" && (green *= 2.55); 1330 blue = toFloat(values[2]); 1331 values[2].slice(-1) == "%" && (blue *= 2.55); 1332 (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); 1333 rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); 1334 values[3] && values[3].slice(-1) == "%" && (opacity /= 100); 1335 return R.hsl2rgb(red, green, blue, opacity); 1336 } 1337 rgb = {r: red, g: green, b: blue, toString: clrToString}; 1338 rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); 1339 R.is(opacity, "finite") && (rgb.opacity = opacity); 1340 return rgb; 1341 } 1342 return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; 1343 }, R); 1344 /*\ 1345 * Raphael.hsb 1346 [ method ] 1347 ** 1348 * Converts HSB values to hex representation of the colour. 1349 > Parameters 1350 - h (number) hue 1351 - s (number) saturation 1352 - b (number) value or brightness 1353 = (string) hex representation of the colour. 1354 \*/ 1355 R.hsb = cacher(function (h, s, b) { 1356 return R.hsb2rgb(h, s, b).hex; 1357 }); 1358 /*\ 1359 * Raphael.hsl 1360 [ method ] 1361 ** 1362 * Converts HSL values to hex representation of the colour. 1363 > Parameters 1364 - h (number) hue 1365 - s (number) saturation 1366 - l (number) luminosity 1367 = (string) hex representation of the colour. 1368 \*/ 1369 R.hsl = cacher(function (h, s, l) { 1370 return R.hsl2rgb(h, s, l).hex; 1371 }); 1372 /*\ 1373 * Raphael.rgb 1374 [ method ] 1375 ** 1376 * Converts RGB values to hex representation of the colour. 1377 > Parameters 1378 - r (number) red 1379 - g (number) green 1380 - b (number) blue 1381 = (string) hex representation of the colour. 1382 \*/ 1383 R.rgb = cacher(function (r, g, b) { 1384 return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); 1385 }); 1386 /*\ 1387 * Raphael.getColor 1388 [ method ] 1389 ** 1390 * On each call returns next colour in the spectrum. To reset it back to red call @Raphael.getColor.reset 1391 > Parameters 1392 - value (number) #optional brightness, default is `0.75` 1393 = (string) hex representation of the colour. 1394 \*/ 1395 R.getColor = function (value) { 1396 var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, 1397 rgb = this.hsb2rgb(start.h, start.s, start.b); 1398 start.h += .075; 1399 if (start.h > 1) { 1400 start.h = 0; 1401 start.s -= .2; 1402 start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b}); 1403 } 1404 return rgb.hex; 1405 }; 1406 /*\ 1407 * Raphael.getColor.reset 1408 [ method ] 1409 ** 1410 * Resets spectrum position for @Raphael.getColor back to red. 1411 \*/ 1412 R.getColor.reset = function () { 1413 delete this.start; 1414 }; 1415 1416 // http://schepers.cc/getting-to-the-point 1417 function catmullRom2bezier(crp, z) { 1418 var d = []; 1419 for (var i = 0, iLen = crp.length; iLen - 2 * !z > i; i += 2) { 1420 var p = [ 1421 {x: +crp[i - 2], y: +crp[i - 1]}, 1422 {x: +crp[i], y: +crp[i + 1]}, 1423 {x: +crp[i + 2], y: +crp[i + 3]}, 1424 {x: +crp[i + 4], y: +crp[i + 5]} 1425 ]; 1426 if (z) { 1427 if (!i) { 1428 p[0] = {x: +crp[iLen - 2], y: +crp[iLen - 1]}; 1429 } else if (iLen - 4 == i) { 1430 p[3] = {x: +crp[0], y: +crp[1]}; 1431 } else if (iLen - 2 == i) { 1432 p[2] = {x: +crp[0], y: +crp[1]}; 1433 p[3] = {x: +crp[2], y: +crp[3]}; 1434 } 1435 } else { 1436 if (iLen - 4 == i) { 1437 p[3] = p[2]; 1438 } else if (!i) { 1439 p[0] = {x: +crp[i], y: +crp[i + 1]}; 1440 } 1441 } 1442 d.push(["C", 1443 (-p[0].x + 6 * p[1].x + p[2].x) / 6, 1444 (-p[0].y + 6 * p[1].y + p[2].y) / 6, 1445 (p[1].x + 6 * p[2].x - p[3].x) / 6, 1446 (p[1].y + 6*p[2].y - p[3].y) / 6, 1447 p[2].x, 1448 p[2].y 1449 ]); 1450 } 1451 1452 return d; 1453 } 1454 /*\ 1455 * Raphael.parsePathString 1456 [ method ] 1457 ** 1458 * Utility method 1459 ** 1460 * Parses given path string into an array of arrays of path segments. 1461 > Parameters 1462 - pathString (string|array) path string or array of segments (in the last case it will be returned straight away) 1463 = (array) array of segments. 1464 \*/ 1465 R.parsePathString = function (pathString) { 1466 if (!pathString) { 1467 return null; 1468 } 1469 var pth = paths(pathString); 1470 if (pth.arr) { 1471 return pathClone(pth.arr); 1472 } 1473 1474 var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0}, 1475 data = []; 1476 if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption 1477 data = pathClone(pathString); 1478 } 1479 if (!data.length) { 1480 Str(pathString).replace(pathCommand, function (a, b, c) { 1481 var params = [], 1482 name = b.toLowerCase(); 1483 c.replace(pathValues, function (a, b) { 1484 b && params.push(+b); 1485 }); 1486 if (name == "m" && params.length > 2) { 1487 data.push([b][concat](params.splice(0, 2))); 1488 name = "l"; 1489 b = b == "m" ? "l" : "L"; 1490 } 1491 if (name == "r") { 1492 data.push([b][concat](params)); 1493 } else while (params.length >= paramCounts[name]) { 1494 data.push([b][concat](params.splice(0, paramCounts[name]))); 1495 if (!paramCounts[name]) { 1496 break; 1497 } 1498 } 1499 }); 1500 } 1501 data.toString = R._path2string; 1502 pth.arr = pathClone(data); 1503 return data; 1504 }; 1505 /*\ 1506 * Raphael.parseTransformString 1507 [ method ] 1508 ** 1509 * Utility method 1510 ** 1511 * Parses given path string into an array of transformations. 1512 > Parameters 1513 - TString (string|array) transform string or array of transformations (in the last case it will be returned straight away) 1514 = (array) array of transformations. 1515 \*/ 1516 R.parseTransformString = cacher(function (TString) { 1517 if (!TString) { 1518 return null; 1519 } 1520 var paramCounts = {r: 3, s: 4, t: 2, m: 6}, 1521 data = []; 1522 if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption 1523 data = pathClone(TString); 1524 } 1525 if (!data.length) { 1526 Str(TString).replace(tCommand, function (a, b, c) { 1527 var params = [], 1528 name = lowerCase.call(b); 1529 c.replace(pathValues, function (a, b) { 1530 b && params.push(+b); 1531 }); 1532 data.push([b][concat](params)); 1533 }); 1534 } 1535 data.toString = R._path2string; 1536 return data; 1537 }); 1538 // PATHS 1539 var paths = function (ps) { 1540 var p = paths.ps = paths.ps || {}; 1541 if (p[ps]) { 1542 p[ps].sleep = 100; 1543 } else { 1544 p[ps] = { 1545 sleep: 100 1546 }; 1547 } 1548 setTimeout(function () { 1549 for (var key in p) if (p[has](key) && key != ps) { 1550 p[key].sleep--; 1551 !p[key].sleep && delete p[key]; 1552 } 1553 }); 1554 return p[ps]; 1555 }; 1556 /*\ 1557 * Raphael.findDotsAtSegment 1558 [ method ] 1559 ** 1560 * Utility method 1561 ** 1562 * Find dot coordinates on the given cubic bezier curve at the given t. 1563 > Parameters 1564 - p1x (number) x of the first point of the curve 1565 - p1y (number) y of the first point of the curve 1566 - c1x (number) x of the first anchor of the curve 1567 - c1y (number) y of the first anchor of the curve 1568 - c2x (number) x of the second anchor of the curve 1569 - c2y (number) y of the second anchor of the curve 1570 - p2x (number) x of the second point of the curve 1571 - p2y (number) y of the second point of the curve 1572 - t (number) position on the curve (0..1) 1573 = (object) point information in format: 1574 o { 1575 o x: (number) x coordinate of the point 1576 o y: (number) y coordinate of the point 1577 o m: { 1578 o x: (number) x coordinate of the left anchor 1579 o y: (number) y coordinate of the left anchor 1580 o } 1581 o n: { 1582 o x: (number) x coordinate of the right anchor 1583 o y: (number) y coordinate of the right anchor 1584 o } 1585 o start: { 1586 o x: (number) x coordinate of the start of the curve 1587 o y: (number) y coordinate of the start of the curve 1588 o } 1589 o end: { 1590 o x: (number) x coordinate of the end of the curve 1591 o y: (number) y coordinate of the end of the curve 1592 o } 1593 o alpha: (number) angle of the curve derivative at the point 1594 o } 1595 \*/ 1596 R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { 1597 var t1 = 1 - t, 1598 t13 = pow(t1, 3), 1599 t12 = pow(t1, 2), 1600 t2 = t * t, 1601 t3 = t2 * t, 1602 x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, 1603 y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, 1604 mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), 1605 my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), 1606 nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), 1607 ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), 1608 ax = t1 * p1x + t * c1x, 1609 ay = t1 * p1y + t * c1y, 1610 cx = t1 * c2x + t * p2x, 1611 cy = t1 * c2y + t * p2y, 1612 alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); 1613 (mx > nx || my < ny) && (alpha += 180); 1614 return { 1615 x: x, 1616 y: y, 1617 m: {x: mx, y: my}, 1618 n: {x: nx, y: ny}, 1619 start: {x: ax, y: ay}, 1620 end: {x: cx, y: cy}, 1621 alpha: alpha 1622 }; 1623 }; 1624 /*\ 1625 * Raphael.bezierBBox 1626 [ method ] 1627 ** 1628 * Utility method 1629 ** 1630 * Return bounding box of a given cubic bezier curve 1631 > Parameters 1632 - p1x (number) x of the first point of the curve 1633 - p1y (number) y of the first point of the curve 1634 - c1x (number) x of the first anchor of the curve 1635 - c1y (number) y of the first anchor of the curve 1636 - c2x (number) x of the second anchor of the curve 1637 - c2y (number) y of the second anchor of the curve 1638 - p2x (number) x of the second point of the curve 1639 - p2y (number) y of the second point of the curve 1640 * or 1641 - bez (array) array of six points for bezier curve 1642 = (object) point information in format: 1643 o { 1644 o min: { 1645 o x: (number) x coordinate of the left point 1646 o y: (number) y coordinate of the top point 1647 o } 1648 o max: { 1649 o x: (number) x coordinate of the right point 1650 o y: (number) y coordinate of the bottom point 1651 o } 1652 o } 1653 \*/ 1654 R.bezierBBox = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { 1655 if (!R.is(p1x, "array")) { 1656 p1x = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y]; 1657 } 1658 var bbox = curveDim.apply(null, p1x); 1659 return { 1660 x: bbox.min.x, 1661 y: bbox.min.y, 1662 x2: bbox.max.x, 1663 y2: bbox.max.y, 1664 width: bbox.max.x - bbox.min.x, 1665 height: bbox.max.y - bbox.min.y 1666 }; 1667 }; 1668 /*\ 1669 * Raphael.isPointInsideBBox 1670 [ method ] 1671 ** 1672 * Utility method 1673 ** 1674 * Returns `true` if given point is inside bounding boxes. 1675 > Parameters 1676 - bbox (string) bounding box 1677 - x (string) x coordinate of the point 1678 - y (string) y coordinate of the point 1679 = (boolean) `true` if point inside 1680 \*/ 1681 R.isPointInsideBBox = function (bbox, x, y) { 1682 return x >= bbox.x && x <= bbox.x2 && y >= bbox.y && y <= bbox.y2; 1683 }; 1684 /*\ 1685 * Raphael.isBBoxIntersect 1686 [ method ] 1687 ** 1688 * Utility method 1689 ** 1690 * Returns `true` if two bounding boxes intersect 1691 > Parameters 1692 - bbox1 (string) first bounding box 1693 - bbox2 (string) second bounding box 1694 = (boolean) `true` if they intersect 1695 \*/ 1696 R.isBBoxIntersect = function (bbox1, bbox2) { 1697 var i = R.isPointInsideBBox; 1698 return i(bbox2, bbox1.x, bbox1.y) 1699 || i(bbox2, bbox1.x2, bbox1.y) 1700 || i(bbox2, bbox1.x, bbox1.y2) 1701 || i(bbox2, bbox1.x2, bbox1.y2) 1702 || i(bbox1, bbox2.x, bbox2.y) 1703 || i(bbox1, bbox2.x2, bbox2.y) 1704 || i(bbox1, bbox2.x, bbox2.y2) 1705 || i(bbox1, bbox2.x2, bbox2.y2) 1706 || (bbox1.x < bbox2.x2 && bbox1.x > bbox2.x || bbox2.x < bbox1.x2 && bbox2.x > bbox1.x) 1707 && (bbox1.y < bbox2.y2 && bbox1.y > bbox2.y || bbox2.y < bbox1.y2 && bbox2.y > bbox1.y); 1708 }; 1709 function base3(t, p1, p2, p3, p4) { 1710 var t1 = -3 * p1 + 9 * p2 - 9 * p3 + 3 * p4, 1711 t2 = t * t1 + 6 * p1 - 12 * p2 + 6 * p3; 1712 return t * t2 - 3 * p1 + 3 * p2; 1713 } 1714 function bezlen(x1, y1, x2, y2, x3, y3, x4, y4, z) { 1715 if (z == null) { 1716 z = 1; 1717 } 1718 z = z > 1 ? 1 : z < 0 ? 0 : z; 1719 var z2 = z / 2, 1720 n = 12, 1721 Tvalues = [-0.1252,0.1252,-0.3678,0.3678,-0.5873,0.5873,-0.7699,0.7699,-0.9041,0.9041,-0.9816,0.9816], 1722 Cvalues = [0.2491,0.2491,0.2335,0.2335,0.2032,0.2032,0.1601,0.1601,0.1069,0.1069,0.0472,0.0472], 1723 sum = 0; 1724 for (var i = 0; i < n; i++) { 1725 var ct = z2 * Tvalues[i] + z2, 1726 xbase = base3(ct, x1, x2, x3, x4), 1727 ybase = base3(ct, y1, y2, y3, y4), 1728 comb = xbase * xbase + ybase * ybase; 1729 sum += Cvalues[i] * math.sqrt(comb); 1730 } 1731 return z2 * sum; 1732 } 1733 function getTatLen(x1, y1, x2, y2, x3, y3, x4, y4, ll) { 1734 if (ll < 0 || bezlen(x1, y1, x2, y2, x3, y3, x4, y4) < ll) { 1735 return; 1736 } 1737 var t = 1, 1738 step = t / 2, 1739 t2 = t - step, 1740 l, 1741 e = .01; 1742 l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); 1743 while (abs(l - ll) > e) { 1744 step /= 2; 1745 t2 += (l < ll ? 1 : -1) * step; 1746 l = bezlen(x1, y1, x2, y2, x3, y3, x4, y4, t2); 1747 } 1748 return t2; 1749 } 1750 function intersect(x1, y1, x2, y2, x3, y3, x4, y4) { 1751 if ( 1752 mmax(x1, x2) < mmin(x3, x4) || 1753 mmin(x1, x2) > mmax(x3, x4) || 1754 mmax(y1, y2) < mmin(y3, y4) || 1755 mmin(y1, y2) > mmax(y3, y4) 1756 ) { 1757 return; 1758 } 1759 var nx = (x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4), 1760 ny = (x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4), 1761 denominator = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); 1762 1763 if (!denominator) { 1764 return; 1765 } 1766 var px = nx / denominator, 1767 py = ny / denominator, 1768 px2 = +px.toFixed(2), 1769 py2 = +py.toFixed(2); 1770 if ( 1771 px2 < +mmin(x1, x2).toFixed(2) || 1772 px2 > +mmax(x1, x2).toFixed(2) || 1773 px2 < +mmin(x3, x4).toFixed(2) || 1774 px2 > +mmax(x3, x4).toFixed(2) || 1775 py2 < +mmin(y1, y2).toFixed(2) || 1776 py2 > +mmax(y1, y2).toFixed(2) || 1777 py2 < +mmin(y3, y4).toFixed(2) || 1778 py2 > +mmax(y3, y4).toFixed(2) 1779 ) { 1780 return; 1781 } 1782 return {x: px, y: py}; 1783 } 1784 function inter(bez1, bez2) { 1785 return interHelper(bez1, bez2); 1786 } 1787 function interCount(bez1, bez2) { 1788 return interHelper(bez1, bez2, 1); 1789 } 1790 function interHelper(bez1, bez2, justCount) { 1791 var bbox1 = R.bezierBBox(bez1), 1792 bbox2 = R.bezierBBox(bez2); 1793 if (!R.isBBoxIntersect(bbox1, bbox2)) { 1794 return justCount ? 0 : []; 1795 } 1796 var l1 = bezlen.apply(0, bez1), 1797 l2 = bezlen.apply(0, bez2), 1798 n1 = ~~(l1 / 5), 1799 n2 = ~~(l2 / 5), 1800 dots1 = [], 1801 dots2 = [], 1802 xy = {}, 1803 res = justCount ? 0 : []; 1804 for (var i = 0; i < n1 + 1; i++) { 1805 var p = R.findDotsAtSegment.apply(R, bez1.concat(i / n1)); 1806 dots1.push({x: p.x, y: p.y, t: i / n1}); 1807 } 1808 for (i = 0; i < n2 + 1; i++) { 1809 p = R.findDotsAtSegment.apply(R, bez2.concat(i / n2)); 1810 dots2.push({x: p.x, y: p.y, t: i / n2}); 1811 } 1812 for (i = 0; i < n1; i++) { 1813 for (var j = 0; j < n2; j++) { 1814 var di = dots1[i], 1815 di1 = dots1[i + 1], 1816 dj = dots2[j], 1817 dj1 = dots2[j + 1], 1818 ci = abs(di1.x - di.x) < .001 ? "y" : "x", 1819 cj = abs(dj1.x - dj.x) < .001 ? "y" : "x", 1820 is = intersect(di.x, di.y, di1.x, di1.y, dj.x, dj.y, dj1.x, dj1.y); 1821 if (is) { 1822 if (xy[is.x.toFixed(4)] == is.y.toFixed(4)) { 1823 continue; 1824 } 1825 xy[is.x.toFixed(4)] = is.y.toFixed(4); 1826 var t1 = di.t + abs((is[ci] - di[ci]) / (di1[ci] - di[ci])) * (di1.t - di.t), 1827 t2 = dj.t + abs((is[cj] - dj[cj]) / (dj1[cj] - dj[cj])) * (dj1.t - dj.t); 1828 if (t1 >= 0 && t1 <= 1 && t2 >= 0 && t2 <= 1) { 1829 if (justCount) { 1830 res++; 1831 } else { 1832 res.push({ 1833 x: is.x, 1834 y: is.y, 1835 t1: t1, 1836 t2: t2 1837 }); 1838 } 1839 } 1840 } 1841 } 1842 } 1843 return res; 1844 } 1845 /*\ 1846 * Raphael.pathIntersection 1847 [ method ] 1848 ** 1849 * Utility method 1850 ** 1851 * Finds intersections of two paths 1852 > Parameters 1853 - path1 (string) path string 1854 - path2 (string) path string 1855 = (array) dots of intersection 1856 o [ 1857 o { 1858 o x: (number) x coordinate of the point 1859 o y: (number) y coordinate of the point 1860 o t1: (number) t value for segment of path1 1861 o t2: (number) t value for segment of path2 1862 o segment1: (number) order number for segment of path1 1863 o segment2: (number) order number for segment of path2 1864 o bez1: (array) eight coordinates representing beziér curve for the segment of path1 1865 o bez2: (array) eight coordinates representing beziér curve for the segment of path2 1866 o } 1867 o ] 1868 \*/ 1869 R.pathIntersection = function (path1, path2) { 1870 return interPathHelper(path1, path2); 1871 }; 1872 R.pathIntersectionNumber = function (path1, path2) { 1873 return interPathHelper(path1, path2, 1); 1874 }; 1875 function interPathHelper(path1, path2, justCount) { 1876 path1 = R._path2curve(path1); 1877 path2 = R._path2curve(path2); 1878 var x1, y1, x2, y2, x1m, y1m, x2m, y2m, bez1, bez2, 1879 res = justCount ? 0 : []; 1880 for (var i = 0, ii = path1.length; i < ii; i++) { 1881 var pi = path1[i]; 1882 if (pi[0] == "M") { 1883 x1 = x1m = pi[1]; 1884 y1 = y1m = pi[2]; 1885 } else { 1886 if (pi[0] == "C") { 1887 bez1 = [x1, y1].concat(pi.slice(1)); 1888 x1 = bez1[6]; 1889 y1 = bez1[7]; 1890 } else { 1891 bez1 = [x1, y1, x1, y1, x1m, y1m, x1m, y1m]; 1892 x1 = x1m; 1893 y1 = y1m; 1894 } 1895 for (var j = 0, jj = path2.length; j < jj; j++) { 1896 var pj = path2[j]; 1897 if (pj[0] == "M") { 1898 x2 = x2m = pj[1]; 1899 y2 = y2m = pj[2]; 1900 } else { 1901 if (pj[0] == "C") { 1902 bez2 = [x2, y2].concat(pj.slice(1)); 1903 x2 = bez2[6]; 1904 y2 = bez2[7]; 1905 } else { 1906 bez2 = [x2, y2, x2, y2, x2m, y2m, x2m, y2m]; 1907 x2 = x2m; 1908 y2 = y2m; 1909 } 1910 var intr = interHelper(bez1, bez2, justCount); 1911 if (justCount) { 1912 res += intr; 1913 } else { 1914 for (var k = 0, kk = intr.length; k < kk; k++) { 1915 intr[k].segment1 = i; 1916 intr[k].segment2 = j; 1917 intr[k].bez1 = bez1; 1918 intr[k].bez2 = bez2; 1919 } 1920 res = res.concat(intr); 1921 } 1922 } 1923 } 1924 } 1925 } 1926 return res; 1927 } 1928 /*\ 1929 * Raphael.isPointInsidePath 1930 [ method ] 1931 ** 1932 * Utility method 1933 ** 1934 * Returns `true` if given point is inside a given closed path. 1935 > Parameters 1936 - path (string) path string 1937 - x (number) x of the point 1938 - y (number) y of the point 1939 = (boolean) true, if point is inside the path 1940 \*/ 1941 R.isPointInsidePath = function (path, x, y) { 1942 var bbox = R.pathBBox(path); 1943 return R.isPointInsideBBox(bbox, x, y) && 1944 interPathHelper(path, [["M", x, y], ["H", bbox.x2 + 10]], 1) % 2 == 1; 1945 }; 1946 R._removedFactory = function (methodname) { 1947 return function () { 1948 eve("raphael.log", null, "Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object", methodname); 1949 }; 1950 }; 1951 /*\ 1952 * Raphael.pathBBox 1953 [ method ] 1954 ** 1955 * Utility method 1956 ** 1957 * Return bounding box of a given path 1958 > Parameters 1959 - path (string) path string 1960 = (object) bounding box 1961 o { 1962 o x: (number) x coordinate of the left top point of the box 1963 o y: (number) y coordinate of the left top point of the box 1964 o x2: (number) x coordinate of the right bottom point of the box 1965 o y2: (number) y coordinate of the right bottom point of the box 1966 o width: (number) width of the box 1967 o height: (number) height of the box 1968 o cx: (number) x coordinate of the center of the box 1969 o cy: (number) y coordinate of the center of the box 1970 o } 1971 \*/ 1972 var pathDimensions = R.pathBBox = function (path) { 1973 var pth = paths(path); 1974 if (pth.bbox) { 1975 return clone(pth.bbox); 1976 } 1977 if (!path) { 1978 return {x: 0, y: 0, width: 0, height: 0, x2: 0, y2: 0}; 1979 } 1980 path = path2curve(path); 1981 var x = 0, 1982 y = 0, 1983 X = [], 1984 Y = [], 1985 p; 1986 for (var i = 0, ii = path.length; i < ii; i++) { 1987 p = path[i]; 1988 if (p[0] == "M") { 1989 x = p[1]; 1990 y = p[2]; 1991 X.push(x); 1992 Y.push(y); 1993 } else { 1994 var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); 1995 X = X[concat](dim.min.x, dim.max.x); 1996 Y = Y[concat](dim.min.y, dim.max.y); 1997 x = p[5]; 1998 y = p[6]; 1999 } 2000 } 2001 var xmin = mmin[apply](0, X), 2002 ymin = mmin[apply](0, Y), 2003 xmax = mmax[apply](0, X), 2004 ymax = mmax[apply](0, Y), 2005 width = xmax - xmin, 2006 height = ymax - ymin, 2007 bb = { 2008 x: xmin, 2009 y: ymin, 2010 x2: xmax, 2011 y2: ymax, 2012 width: width, 2013 height: height, 2014 cx: xmin + width / 2, 2015 cy: ymin + height / 2 2016 }; 2017 pth.bbox = clone(bb); 2018 return bb; 2019 }, 2020 pathClone = function (pathArray) { 2021 var res = clone(pathArray); 2022 res.toString = R._path2string; 2023 return res; 2024 }, 2025 pathToRelative = R._pathToRelative = function (pathArray) { 2026 var pth = paths(pathArray); 2027 if (pth.rel) { 2028 return pathClone(pth.rel); 2029 } 2030 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption 2031 pathArray = R.parsePathString(pathArray); 2032 } 2033 var res = [], 2034 x = 0, 2035 y = 0, 2036 mx = 0, 2037 my = 0, 2038 start = 0; 2039 if (pathArray[0][0] == "M") { 2040 x = pathArray[0][1]; 2041 y = pathArray[0][2]; 2042 mx = x; 2043 my = y; 2044 start++; 2045 res.push(["M", x, y]); 2046 } 2047 for (var i = start, ii = pathArray.length; i < ii; i++) { 2048 var r = res[i] = [], 2049 pa = pathArray[i]; 2050 if (pa[0] != lowerCase.call(pa[0])) { 2051 r[0] = lowerCase.call(pa[0]); 2052 switch (r[0]) { 2053 case "a": 2054 r[1] = pa[1]; 2055 r[2] = pa[2]; 2056 r[3] = pa[3]; 2057 r[4] = pa[4]; 2058 r[5] = pa[5]; 2059 r[6] = +(pa[6] - x).toFixed(3); 2060 r[7] = +(pa[7] - y).toFixed(3); 2061 break; 2062 case "v": 2063 r[1] = +(pa[1] - y).toFixed(3); 2064 break; 2065 case "m": 2066 mx = pa[1]; 2067 my = pa[2]; 2068 default: 2069 for (var j = 1, jj = pa.length; j < jj; j++) { 2070 r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); 2071 } 2072 } 2073 } else { 2074 r = res[i] = []; 2075 if (pa[0] == "m") { 2076 mx = pa[1] + x; 2077 my = pa[2] + y; 2078 } 2079 for (var k = 0, kk = pa.length; k < kk; k++) { 2080 res[i][k] = pa[k]; 2081 } 2082 } 2083 var len = res[i].length; 2084 switch (res[i][0]) { 2085 case "z": 2086 x = mx; 2087 y = my; 2088 break; 2089 case "h": 2090 x += +res[i][len - 1]; 2091 break; 2092 case "v": 2093 y += +res[i][len - 1]; 2094 break; 2095 default: 2096 x += +res[i][len - 2]; 2097 y += +res[i][len - 1]; 2098 } 2099 } 2100 res.toString = R._path2string; 2101 pth.rel = pathClone(res); 2102 return res; 2103 }, 2104 pathToAbsolute = R._pathToAbsolute = function (pathArray) { 2105 var pth = paths(pathArray); 2106 if (pth.abs) { 2107 return pathClone(pth.abs); 2108 } 2109 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption 2110 pathArray = R.parsePathString(pathArray); 2111 } 2112 if (!pathArray || !pathArray.length) { 2113 return [["M", 0, 0]]; 2114 } 2115 var res = [], 2116 x = 0, 2117 y = 0, 2118 mx = 0, 2119 my = 0, 2120 start = 0; 2121 if (pathArray[0][0] == "M") { 2122 x = +pathArray[0][1]; 2123 y = +pathArray[0][2]; 2124 mx = x; 2125 my = y; 2126 start++; 2127 res[0] = ["M", x, y]; 2128 } 2129 var crz = pathArray.length == 3 && pathArray[0][0] == "M" && pathArray[1][0].toUpperCase() == "R" && pathArray[2][0].toUpperCase() == "Z"; 2130 for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { 2131 res.push(r = []); 2132 pa = pathArray[i]; 2133 if (pa[0] != upperCase.call(pa[0])) { 2134 r[0] = upperCase.call(pa[0]); 2135 switch (r[0]) { 2136 case "A": 2137 r[1] = pa[1]; 2138 r[2] = pa[2]; 2139 r[3] = pa[3]; 2140 r[4] = pa[4]; 2141 r[5] = pa[5]; 2142 r[6] = +(pa[6] + x); 2143 r[7] = +(pa[7] + y); 2144 break; 2145 case "V": 2146 r[1] = +pa[1] + y; 2147 break; 2148 case "H": 2149 r[1] = +pa[1] + x; 2150 break; 2151 case "R": 2152 var dots = [x, y][concat](pa.slice(1)); 2153 for (var j = 2, jj = dots.length; j < jj; j++) { 2154 dots[j] = +dots[j] + x; 2155 dots[++j] = +dots[j] + y; 2156 } 2157 res.pop(); 2158 res = res[concat](catmullRom2bezier(dots, crz)); 2159 break; 2160 case "M": 2161 mx = +pa[1] + x; 2162 my = +pa[2] + y; 2163 default: 2164 for (j = 1, jj = pa.length; j < jj; j++) { 2165 r[j] = +pa[j] + ((j % 2) ? x : y); 2166 } 2167 } 2168 } else if (pa[0] == "R") { 2169 dots = [x, y][concat](pa.slice(1)); 2170 res.pop(); 2171 res = res[concat](catmullRom2bezier(dots, crz)); 2172 r = ["R"][concat](pa.slice(-2)); 2173 } else { 2174 for (var k = 0, kk = pa.length; k < kk; k++) { 2175 r[k] = pa[k]; 2176 } 2177 } 2178 switch (r[0]) { 2179 case "Z": 2180 x = mx; 2181 y = my; 2182 break; 2183 case "H": 2184 x = r[1]; 2185 break; 2186 case "V": 2187 y = r[1]; 2188 break; 2189 case "M": 2190 mx = r[r.length - 2]; 2191 my = r[r.length - 1]; 2192 default: 2193 x = r[r.length - 2]; 2194 y = r[r.length - 1]; 2195 } 2196 } 2197 res.toString = R._path2string; 2198 pth.abs = pathClone(res); 2199 return res; 2200 }, 2201 l2c = function (x1, y1, x2, y2) { 2202 return [x1, y1, x2, y2, x2, y2]; 2203 }, 2204 q2c = function (x1, y1, ax, ay, x2, y2) { 2205 var _13 = 1 / 3, 2206 _23 = 2 / 3; 2207 return [ 2208 _13 * x1 + _23 * ax, 2209 _13 * y1 + _23 * ay, 2210 _13 * x2 + _23 * ax, 2211 _13 * y2 + _23 * ay, 2212 x2, 2213 y2 2214 ]; 2215 }, 2216 a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { 2217 // for more information of where this math came from visit: 2218 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes 2219 var _120 = PI * 120 / 180, 2220 rad = PI / 180 * (+angle || 0), 2221 res = [], 2222 xy, 2223 rotate = cacher(function (x, y, rad) { 2224 var X = x * math.cos(rad) - y * math.sin(rad), 2225 Y = x * math.sin(rad) + y * math.cos(rad); 2226 return {x: X, y: Y}; 2227 }); 2228 if (!recursive) { 2229 xy = rotate(x1, y1, -rad); 2230 x1 = xy.x; 2231 y1 = xy.y; 2232 xy = rotate(x2, y2, -rad); 2233 x2 = xy.x; 2234 y2 = xy.y; 2235 var cos = math.cos(PI / 180 * angle), 2236 sin = math.sin(PI / 180 * angle), 2237 x = (x1 - x2) / 2, 2238 y = (y1 - y2) / 2; 2239 var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); 2240 if (h > 1) { 2241 h = math.sqrt(h); 2242 rx = h * rx; 2243 ry = h * ry; 2244 } 2245 var rx2 = rx * rx, 2246 ry2 = ry * ry, 2247 k = (large_arc_flag == sweep_flag ? -1 : 1) * 2248 math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), 2249 cx = k * rx * y / ry + (x1 + x2) / 2, 2250 cy = k * -ry * x / rx + (y1 + y2) / 2, 2251 f1 = math.asin(((y1 - cy) / ry).toFixed(9)), 2252 f2 = math.asin(((y2 - cy) / ry).toFixed(9)); 2253 2254 f1 = x1 < cx ? PI - f1 : f1; 2255 f2 = x2 < cx ? PI - f2 : f2; 2256 f1 < 0 && (f1 = PI * 2 + f1); 2257 f2 < 0 && (f2 = PI * 2 + f2); 2258 if (sweep_flag && f1 > f2) { 2259 f1 = f1 - PI * 2; 2260 } 2261 if (!sweep_flag && f2 > f1) { 2262 f2 = f2 - PI * 2; 2263 } 2264 } else { 2265 f1 = recursive[0]; 2266 f2 = recursive[1]; 2267 cx = recursive[2]; 2268 cy = recursive[3]; 2269 } 2270 var df = f2 - f1; 2271 if (abs(df) > _120) { 2272 var f2old = f2, 2273 x2old = x2, 2274 y2old = y2; 2275 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); 2276 x2 = cx + rx * math.cos(f2); 2277 y2 = cy + ry * math.sin(f2); 2278 res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); 2279 } 2280 df = f2 - f1; 2281 var c1 = math.cos(f1), 2282 s1 = math.sin(f1), 2283 c2 = math.cos(f2), 2284 s2 = math.sin(f2), 2285 t = math.tan(df / 4), 2286 hx = 4 / 3 * rx * t, 2287 hy = 4 / 3 * ry * t, 2288 m1 = [x1, y1], 2289 m2 = [x1 + hx * s1, y1 - hy * c1], 2290 m3 = [x2 + hx * s2, y2 - hy * c2], 2291 m4 = [x2, y2]; 2292 m2[0] = 2 * m1[0] - m2[0]; 2293 m2[1] = 2 * m1[1] - m2[1]; 2294 if (recursive) { 2295 return [m2, m3, m4][concat](res); 2296 } else { 2297 res = [m2, m3, m4][concat](res).join()[split](","); 2298 var newres = []; 2299 for (var i = 0, ii = res.length; i < ii; i++) { 2300 newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; 2301 } 2302 return newres; 2303 } 2304 }, 2305 findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { 2306 var t1 = 1 - t; 2307 return { 2308 x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, 2309 y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y 2310 }; 2311 }, 2312 curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { 2313 var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), 2314 b = 2 * (c1x - p1x) - 2 * (c2x - c1x), 2315 c = p1x - c1x, 2316 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a, 2317 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a, 2318 y = [p1y, p2y], 2319 x = [p1x, p2x], 2320 dot; 2321 abs(t1) > "1e12" && (t1 = .5); 2322 abs(t2) > "1e12" && (t2 = .5); 2323 if (t1 > 0 && t1 < 1) { 2324 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); 2325 x.push(dot.x); 2326 y.push(dot.y); 2327 } 2328 if (t2 > 0 && t2 < 1) { 2329 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); 2330 x.push(dot.x); 2331 y.push(dot.y); 2332 } 2333 a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); 2334 b = 2 * (c1y - p1y) - 2 * (c2y - c1y); 2335 c = p1y - c1y; 2336 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; 2337 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; 2338 abs(t1) > "1e12" && (t1 = .5); 2339 abs(t2) > "1e12" && (t2 = .5); 2340 if (t1 > 0 && t1 < 1) { 2341 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); 2342 x.push(dot.x); 2343 y.push(dot.y); 2344 } 2345 if (t2 > 0 && t2 < 1) { 2346 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); 2347 x.push(dot.x); 2348 y.push(dot.y); 2349 } 2350 return { 2351 min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, 2352 max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} 2353 }; 2354 }), 2355 path2curve = R._path2curve = cacher(function (path, path2) { 2356 var pth = !path2 && paths(path); 2357 if (!path2 && pth.curve) { 2358 return pathClone(pth.curve); 2359 } 2360 var p = pathToAbsolute(path), 2361 p2 = path2 && pathToAbsolute(path2), 2362 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, 2363 attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, 2364 processPath = function (path, d) { 2365 var nx, ny; 2366 if (!path) { 2367 return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; 2368 } 2369 !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null); 2370 switch (path[0]) { 2371 case "M": 2372 d.X = path[1]; 2373 d.Y = path[2]; 2374 break; 2375 case "A": 2376 path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1)))); 2377 break; 2378 case "S": 2379 if (pcom == "C" || pcom == "S") { // In "S" case we have to take into account, if the previous command is C/S. 2380 nx = d.x * 2 - d.bx; // And reflect the previous 2381 ny = d.y * 2 - d.by; // command's control point relative to the current point. 2382 } 2383 else { // or some else or nothing 2384 nx = d.x; 2385 ny = d.y; 2386 } 2387 path = ["C", nx, ny][concat](path.slice(1)); 2388 break; 2389 case "T": 2390 if (pcom == "Q" || pcom == "T") { // In "T" case we have to take into account, if the previous command is Q/T. 2391 d.qx = d.x * 2 - d.qx; // And make a reflection similar 2392 d.qy = d.y * 2 - d.qy; // to case "S". 2393 } 2394 else { // or something else or nothing 2395 d.qx = d.x; 2396 d.qy = d.y; 2397 } 2398 path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); 2399 break; 2400 case "Q": 2401 d.qx = path[1]; 2402 d.qy = path[2]; 2403 path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4])); 2404 break; 2405 case "L": 2406 path = ["C"][concat](l2c(d.x, d.y, path[1], path[2])); 2407 break; 2408 case "H": 2409 path = ["C"][concat](l2c(d.x, d.y, path[1], d.y)); 2410 break; 2411 case "V": 2412 path = ["C"][concat](l2c(d.x, d.y, d.x, path[1])); 2413 break; 2414 case "Z": 2415 path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y)); 2416 break; 2417 } 2418 return path; 2419 }, 2420 fixArc = function (pp, i) { 2421 if (pp[i].length > 7) { 2422 pp[i].shift(); 2423 var pi = pp[i]; 2424 while (pi.length) { 2425 pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); 2426 } 2427 pp.splice(i, 1); 2428 ii = mmax(p.length, p2 && p2.length || 0); 2429 } 2430 }, 2431 fixM = function (path1, path2, a1, a2, i) { 2432 if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { 2433 path2.splice(i, 0, ["M", a2.x, a2.y]); 2434 a1.bx = 0; 2435 a1.by = 0; 2436 a1.x = path1[i][1]; 2437 a1.y = path1[i][2]; 2438 ii = mmax(p.length, p2 && p2.length || 0); 2439 } 2440 }; 2441 for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { 2442 p[i] = processPath(p[i], attrs); 2443 fixArc(p, i); 2444 p2 && (p2[i] = processPath(p2[i], attrs2)); 2445 p2 && fixArc(p2, i); 2446 fixM(p, p2, attrs, attrs2, i); 2447 fixM(p2, p, attrs2, attrs, i); 2448 var seg = p[i], 2449 seg2 = p2 && p2[i], 2450 seglen = seg.length, 2451 seg2len = p2 && seg2.length; 2452 attrs.x = seg[seglen - 2]; 2453 attrs.y = seg[seglen - 1]; 2454 attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; 2455 attrs.by = toFloat(seg[seglen - 3]) || attrs.y; 2456 attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); 2457 attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); 2458 attrs2.x = p2 && seg2[seg2len - 2]; 2459 attrs2.y = p2 && seg2[seg2len - 1]; 2460 } 2461 if (!p2) { 2462 pth.curve = pathClone(p); 2463 } 2464 return p2 ? [p, p2] : p; 2465 }, null, pathClone), 2466 parseDots = R._parseDots = cacher(function (gradient) { 2467 var dots = []; 2468 for (var i = 0, ii = gradient.length; i < ii; i++) { 2469 var dot = {}, 2470 par = gradient[i].match(/^([^:]*):?([\d\.]*)/); 2471 dot.color = R.getRGB(par[1]); 2472 if (dot.color.error) { 2473 return null; 2474 } 2475 dot.color = dot.color.hex; 2476 par[2] && (dot.offset = par[2] + "%"); 2477 dots.push(dot); 2478 } 2479 for (i = 1, ii = dots.length - 1; i < ii; i++) { 2480 if (!dots[i].offset) { 2481 var start = toFloat(dots[i - 1].offset || 0), 2482 end = 0; 2483 for (var j = i + 1; j < ii; j++) { 2484 if (dots[j].offset) { 2485 end = dots[j].offset; 2486 break; 2487 } 2488 } 2489 if (!end) { 2490 end = 100; 2491 j = ii; 2492 } 2493 end = toFloat(end); 2494 var d = (end - start) / (j - i + 1); 2495 for (; i < j; i++) { 2496 start += d; 2497 dots[i].offset = start + "%"; 2498 } 2499 } 2500 } 2501 return dots; 2502 }), 2503 tear = R._tear = function (el, paper) { 2504 el == paper.top && (paper.top = el.prev); 2505 el == paper.bottom && (paper.bottom = el.next); 2506 el.next && (el.next.prev = el.prev); 2507 el.prev && (el.prev.next = el.next); 2508 }, 2509 tofront = R._tofront = function (el, paper) { 2510 if (paper.top === el) { 2511 return; 2512 } 2513 tear(el, paper); 2514 el.next = null; 2515 el.prev = paper.top; 2516 paper.top.next = el; 2517 paper.top = el; 2518 }, 2519 toback = R._toback = function (el, paper) { 2520 if (paper.bottom === el) { 2521 return; 2522 } 2523 tear(el, paper); 2524 el.next = paper.bottom; 2525 el.prev = null; 2526 paper.bottom.prev = el; 2527 paper.bottom = el; 2528 }, 2529 insertafter = R._insertafter = function (el, el2, paper) { 2530 tear(el, paper); 2531 el2 == paper.top && (paper.top = el); 2532 el2.next && (el2.next.prev = el); 2533 el.next = el2.next; 2534 el.prev = el2; 2535 el2.next = el; 2536 }, 2537 insertbefore = R._insertbefore = function (el, el2, paper) { 2538 tear(el, paper); 2539 el2 == paper.bottom && (paper.bottom = el); 2540 el2.prev && (el2.prev.next = el); 2541 el.prev = el2.prev; 2542 el2.prev = el; 2543 el.next = el2; 2544 }, 2545 /*\ 2546 * Raphael.toMatrix 2547 [ method ] 2548 ** 2549 * Utility method 2550 ** 2551 * Returns matrix of transformations applied to a given path 2552 > Parameters 2553 - path (string) path string 2554 - transform (string|array) transformation string 2555 = (object) @Matrix 2556 \*/ 2557 toMatrix = R.toMatrix = function (path, transform) { 2558 var bb = pathDimensions(path), 2559 el = { 2560 _: { 2561 transform: E 2562 }, 2563 getBBox: function () { 2564 return bb; 2565 } 2566 }; 2567 extractTransform(el, transform); 2568 return el.matrix; 2569 }, 2570 /*\ 2571 * Raphael.transformPath 2572 [ method ] 2573 ** 2574 * Utility method 2575 ** 2576 * Returns path transformed by a given transformation 2577 > Parameters 2578 - path (string) path string 2579 - transform (string|array) transformation string 2580 = (string) path 2581 \*/ 2582 transformPath = R.transformPath = function (path, transform) { 2583 return mapPath(path, toMatrix(path, transform)); 2584 }, 2585 extractTransform = R._extractTransform = function (el, tstr) { 2586 if (tstr == null) { 2587 return el._.transform; 2588 } 2589 tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E); 2590 var tdata = R.parseTransformString(tstr), 2591 deg = 0, 2592 dx = 0, 2593 dy = 0, 2594 sx = 1, 2595 sy = 1, 2596 _ = el._, 2597 m = new Matrix; 2598 _.transform = tdata || []; 2599 if (tdata) { 2600 for (var i = 0, ii = tdata.length; i < ii; i++) { 2601 var t = tdata[i], 2602 tlen = t.length, 2603 command = Str(t[0]).toLowerCase(), 2604 absolute = t[0] != command, 2605 inver = absolute ? m.invert() : 0, 2606 x1, 2607 y1, 2608 x2, 2609 y2, 2610 bb; 2611 if (command == "t" && tlen == 3) { 2612 if (absolute) { 2613 x1 = inver.x(0, 0); 2614 y1 = inver.y(0, 0); 2615 x2 = inver.x(t[1], t[2]); 2616 y2 = inver.y(t[1], t[2]); 2617 m.translate(x2 - x1, y2 - y1); 2618 } else { 2619 m.translate(t[1], t[2]); 2620 } 2621 } else if (command == "r") { 2622 if (tlen == 2) { 2623 bb = bb || el.getBBox(1); 2624 m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); 2625 deg += t[1]; 2626 } else if (tlen == 4) { 2627 if (absolute) { 2628 x2 = inver.x(t[2], t[3]); 2629 y2 = inver.y(t[2], t[3]); 2630 m.rotate(t[1], x2, y2); 2631 } else { 2632 m.rotate(t[1], t[2], t[3]); 2633 } 2634 deg += t[1]; 2635 } 2636 } else if (command == "s") { 2637 if (tlen == 2 || tlen == 3) { 2638 bb = bb || el.getBBox(1); 2639 m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); 2640 sx *= t[1]; 2641 sy *= t[tlen - 1]; 2642 } else if (tlen == 5) { 2643 if (absolute) { 2644 x2 = inver.x(t[3], t[4]); 2645 y2 = inver.y(t[3], t[4]); 2646 m.scale(t[1], t[2], x2, y2); 2647 } else { 2648 m.scale(t[1], t[2], t[3], t[4]); 2649 } 2650 sx *= t[1]; 2651 sy *= t[2]; 2652 } 2653 } else if (command == "m" && tlen == 7) { 2654 m.add(t[1], t[2], t[3], t[4], t[5], t[6]); 2655 } 2656 _.dirtyT = 1; 2657 el.matrix = m; 2658 } 2659 } 2660 2661 /*\ 2662 * Element.matrix 2663 [ property (object) ] 2664 ** 2665 * Keeps @Matrix object, which represents element transformation 2666 \*/ 2667 el.matrix = m; 2668 2669 _.sx = sx; 2670 _.sy = sy; 2671 _.deg = deg; 2672 _.dx = dx = m.e; 2673 _.dy = dy = m.f; 2674 2675 if (sx == 1 && sy == 1 && !deg && _.bbox) { 2676 _.bbox.x += +dx; 2677 _.bbox.y += +dy; 2678 } else { 2679 _.dirtyT = 1; 2680 } 2681 }, 2682 getEmpty = function (item) { 2683 var l = item[0]; 2684 switch (l.toLowerCase()) { 2685 case "t": return [l, 0, 0]; 2686 case "m": return [l, 1, 0, 0, 1, 0, 0]; 2687 case "r": if (item.length == 4) { 2688 return [l, 0, item[2], item[3]]; 2689 } else { 2690 return [l, 0]; 2691 } 2692 case "s": if (item.length == 5) { 2693 return [l, 1, 1, item[3], item[4]]; 2694 } else if (item.length == 3) { 2695 return [l, 1, 1]; 2696 } else { 2697 return [l, 1]; 2698 } 2699 } 2700 }, 2701 equaliseTransform = R._equaliseTransform = function (t1, t2) { 2702 t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); 2703 t1 = R.parseTransformString(t1) || []; 2704 t2 = R.parseTransformString(t2) || []; 2705 var maxlength = mmax(t1.length, t2.length), 2706 from = [], 2707 to = [], 2708 i = 0, j, jj, 2709 tt1, tt2; 2710 for (; i < maxlength; i++) { 2711 tt1 = t1[i] || getEmpty(t2[i]); 2712 tt2 = t2[i] || getEmpty(tt1); 2713 if ((tt1[0] != tt2[0]) || 2714 (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || 2715 (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) 2716 ) { 2717 return; 2718 } 2719 from[i] = []; 2720 to[i] = []; 2721 for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) { 2722 j in tt1 && (from[i][j] = tt1[j]); 2723 j in tt2 && (to[i][j] = tt2[j]); 2724 } 2725 } 2726 return { 2727 from: from, 2728 to: to 2729 }; 2730 }; 2731 R._getContainer = function (x, y, w, h) { 2732 var container; 2733 container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x; 2734 if (container == null) { 2735 return; 2736 } 2737 if (container.tagName) { 2738 if (y == null) { 2739 return { 2740 container: container, 2741 width: container.style.pixelWidth || container.offsetWidth, 2742 height: container.style.pixelHeight || container.offsetHeight 2743 }; 2744 } else { 2745 return { 2746 container: container, 2747 width: y, 2748 height: w 2749 }; 2750 } 2751 } 2752 return { 2753 container: 1, 2754 x: x, 2755 y: y, 2756 width: w, 2757 height: h 2758 }; 2759 }; 2760 /*\ 2761 * Raphael.pathToRelative 2762 [ method ] 2763 ** 2764 * Utility method 2765 ** 2766 * Converts path to relative form 2767 > Parameters 2768 - pathString (string|array) path string or array of segments 2769 = (array) array of segments. 2770 \*/ 2771 R.pathToRelative = pathToRelative; 2772 R._engine = {}; 2773 /*\ 2774 * Raphael.path2curve 2775 [ method ] 2776 ** 2777 * Utility method 2778 ** 2779 * Converts path to a new path where all segments are cubic bezier curves. 2780 > Parameters 2781 - pathString (string|array) path string or array of segments 2782 = (array) array of segments. 2783 \*/ 2784 R.path2curve = path2curve; 2785 /*\ 2786 * Raphael.matrix 2787 [ method ] 2788 ** 2789 * Utility method 2790 ** 2791 * Returns matrix based on given parameters. 2792 > Parameters 2793 - a (number) 2794 - b (number) 2795 - c (number) 2796 - d (number) 2797 - e (number) 2798 - f (number) 2799 = (object) @Matrix 2800 \*/ 2801 R.matrix = function (a, b, c, d, e, f) { 2802 return new Matrix(a, b, c, d, e, f); 2803 }; 2804 function Matrix(a, b, c, d, e, f) { 2805 if (a != null) { 2806 this.a = +a; 2807 this.b = +b; 2808 this.c = +c; 2809 this.d = +d; 2810 this.e = +e; 2811 this.f = +f; 2812 } else { 2813 this.a = 1; 2814 this.b = 0; 2815 this.c = 0; 2816 this.d = 1; 2817 this.e = 0; 2818 this.f = 0; 2819 } 2820 } 2821 (function (matrixproto) { 2822 /*\ 2823 * Matrix.add 2824 [ method ] 2825 ** 2826 * Adds given matrix to existing one. 2827 > Parameters 2828 - a (number) 2829 - b (number) 2830 - c (number) 2831 - d (number) 2832 - e (number) 2833 - f (number) 2834 or 2835 - matrix (object) @Matrix 2836 \*/ 2837 matrixproto.add = function (a, b, c, d, e, f) { 2838 var out = [[], [], []], 2839 m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], 2840 matrix = [[a, c, e], [b, d, f], [0, 0, 1]], 2841 x, y, z, res; 2842 2843 if (a && a instanceof Matrix) { 2844 matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; 2845 } 2846 2847 for (x = 0; x < 3; x++) { 2848 for (y = 0; y < 3; y++) { 2849 res = 0; 2850 for (z = 0; z < 3; z++) { 2851 res += m[x][z] * matrix[z][y]; 2852 } 2853 out[x][y] = res; 2854 } 2855 } 2856 this.a = out[0][0]; 2857 this.b = out[1][0]; 2858 this.c = out[0][1]; 2859 this.d = out[1][1]; 2860 this.e = out[0][2]; 2861 this.f = out[1][2]; 2862 }; 2863 /*\ 2864 * Matrix.invert 2865 [ method ] 2866 ** 2867 * Returns inverted version of the matrix 2868 = (object) @Matrix 2869 \*/ 2870 matrixproto.invert = function () { 2871 var me = this, 2872 x = me.a * me.d - me.b * me.c; 2873 return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); 2874 }; 2875 /*\ 2876 * Matrix.clone 2877 [ method ] 2878 ** 2879 * Returns copy of the matrix 2880 = (object) @Matrix 2881 \*/ 2882 matrixproto.clone = function () { 2883 return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); 2884 }; 2885 /*\ 2886 * Matrix.translate 2887 [ method ] 2888 ** 2889 * Translate the matrix 2890 > Parameters 2891 - x (number) 2892 - y (number) 2893 \*/ 2894 matrixproto.translate = function (x, y) { 2895 this.add(1, 0, 0, 1, x, y); 2896 }; 2897 /*\ 2898 * Matrix.scale 2899 [ method ] 2900 ** 2901 * Scales the matrix 2902 > Parameters 2903 - x (number) 2904 - y (number) #optional 2905 - cx (number) #optional 2906 - cy (number) #optional 2907 \*/ 2908 matrixproto.scale = function (x, y, cx, cy) { 2909 y == null && (y = x); 2910 (cx || cy) && this.add(1, 0, 0, 1, cx, cy); 2911 this.add(x, 0, 0, y, 0, 0); 2912 (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); 2913 }; 2914 /*\ 2915 * Matrix.rotate 2916 [ method ] 2917 ** 2918 * Rotates the matrix 2919 > Parameters 2920 - a (number) 2921 - x (number) 2922 - y (number) 2923 \*/ 2924 matrixproto.rotate = function (a, x, y) { 2925 a = R.rad(a); 2926 x = x || 0; 2927 y = y || 0; 2928 var cos = +math.cos(a).toFixed(9), 2929 sin = +math.sin(a).toFixed(9); 2930 this.add(cos, sin, -sin, cos, x, y); 2931 this.add(1, 0, 0, 1, -x, -y); 2932 }; 2933 /*\ 2934 * Matrix.x 2935 [ method ] 2936 ** 2937 * Return x coordinate for given point after transformation described by the matrix. See also @Matrix.y 2938 > Parameters 2939 - x (number) 2940 - y (number) 2941 = (number) x 2942 \*/ 2943 matrixproto.x = function (x, y) { 2944 return x * this.a + y * this.c + this.e; 2945 }; 2946 /*\ 2947 * Matrix.y 2948 [ method ] 2949 ** 2950 * Return y coordinate for given point after transformation described by the matrix. See also @Matrix.x 2951 > Parameters 2952 - x (number) 2953 - y (number) 2954 = (number) y 2955 \*/ 2956 matrixproto.y = function (x, y) { 2957 return x * this.b + y * this.d + this.f; 2958 }; 2959 matrixproto.get = function (i) { 2960 return +this[Str.fromCharCode(97 + i)].toFixed(4); 2961 }; 2962 matrixproto.toString = function () { 2963 return R.svg ? 2964 "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" : 2965 [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join(); 2966 }; 2967 matrixproto.toFilter = function () { 2968 return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) + 2969 ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) + 2970 ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')"; 2971 }; 2972 matrixproto.offset = function () { 2973 return [this.e.toFixed(4), this.f.toFixed(4)]; 2974 }; 2975 function norm(a) { 2976 return a[0] * a[0] + a[1] * a[1]; 2977 } 2978 function normalize(a) { 2979 var mag = math.sqrt(norm(a)); 2980 a[0] && (a[0] /= mag); 2981 a[1] && (a[1] /= mag); 2982 } 2983 /*\ 2984 * Matrix.split 2985 [ method ] 2986 ** 2987 * Splits matrix into primitive transformations 2988 = (object) in format: 2989 o dx (number) translation by x 2990 o dy (number) translation by y 2991 o scalex (number) scale by x 2992 o scaley (number) scale by y 2993 o shear (number) shear 2994 o rotate (number) rotation in deg 2995 o isSimple (boolean) could it be represented via simple transformations 2996 \*/ 2997 matrixproto.split = function () { 2998 var out = {}; 2999 // translation 3000 out.dx = this.e; 3001 out.dy = this.f; 3002 3003 // scale and shear 3004 var row = [[this.a, this.c], [this.b, this.d]]; 3005 out.scalex = math.sqrt(norm(row[0])); 3006 normalize(row[0]); 3007 3008 out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; 3009 row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; 3010 3011 out.scaley = math.sqrt(norm(row[1])); 3012 normalize(row[1]); 3013 out.shear /= out.scaley; 3014 3015 // rotation 3016 var sin = -row[0][1], 3017 cos = row[1][1]; 3018 if (cos < 0) { 3019 out.rotate = R.deg(math.acos(cos)); 3020 if (sin < 0) { 3021 out.rotate = 360 - out.rotate; 3022 } 3023 } else { 3024 out.rotate = R.deg(math.asin(sin)); 3025 } 3026 3027 out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); 3028 out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; 3029 out.noRotation = !+out.shear.toFixed(9) && !out.rotate; 3030 return out; 3031 }; 3032 /*\ 3033 * Matrix.toTransformString 3034 [ method ] 3035 ** 3036 * Return transform string that represents given matrix 3037 = (string) transform string 3038 \*/ 3039 matrixproto.toTransformString = function (shorter) { 3040 var s = shorter || this[split](); 3041 if (s.isSimple) { 3042 s.scalex = +s.scalex.toFixed(4); 3043 s.scaley = +s.scaley.toFixed(4); 3044 s.rotate = +s.rotate.toFixed(4); 3045 return (s.dx || s.dy ? "t" + [s.dx, s.dy] : E) + 3046 (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + 3047 (s.rotate ? "r" + [s.rotate, 0, 0] : E); 3048 } else { 3049 return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; 3050 } 3051 }; 3052 })(Matrix.prototype); 3053 3054 // WebKit rendering bug workaround method 3055 var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/); 3056 if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") || 3057 (navigator.vendor == "Google Inc." && version && version[1] < 8)) { 3058 /*\ 3059 * Paper.safari 3060 [ method ] 3061 ** 3062 * There is an inconvenient rendering bug in Safari (WebKit): 3063 * sometimes the rendering should be forced. 3064 * This method should help with dealing with this bug. 3065 \*/ 3066 paperproto.safari = function () { 3067 var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"}); 3068 setTimeout(function () {rect.remove();}); 3069 }; 3070 } else { 3071 paperproto.safari = fun; 3072 } 3073 3074 var preventDefault = function () { 3075 this.returnValue = false; 3076 }, 3077 preventTouch = function () { 3078 return this.originalEvent.preventDefault(); 3079 }, 3080 stopPropagation = function () { 3081 this.cancelBubble = true; 3082 }, 3083 stopTouch = function () { 3084 return this.originalEvent.stopPropagation(); 3085 }, 3086 getEventPosition = function (e) { 3087 var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, 3088 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; 3089 3090 return { 3091 x: e.clientX + scrollX, 3092 y: e.clientY + scrollY 3093 }; 3094 }, 3095 addEvent = (function () { 3096 if (g.doc.addEventListener) { 3097 return function (obj, type, fn, element) { 3098 var f = function (e) { 3099 var pos = getEventPosition(e); 3100 return fn.call(element, e, pos.x, pos.y); 3101 }; 3102 obj.addEventListener(type, f, false); 3103 3104 if (supportsTouch && touchMap[type]) { 3105 var _f = function (e) { 3106 var pos = getEventPosition(e), 3107 olde = e; 3108 3109 for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { 3110 if (e.targetTouches[i].target == obj) { 3111 e = e.targetTouches[i]; 3112 e.originalEvent = olde; 3113 e.preventDefault = preventTouch; 3114 e.stopPropagation = stopTouch; 3115 break; 3116 } 3117 } 3118 3119 return fn.call(element, e, pos.x, pos.y); 3120 }; 3121 obj.addEventListener(touchMap[type], _f, false); 3122 } 3123 3124 return function () { 3125 obj.removeEventListener(type, f, false); 3126 3127 if (supportsTouch && touchMap[type]) 3128 obj.removeEventListener(touchMap[type], f, false); 3129 3130 return true; 3131 }; 3132 }; 3133 } else if (g.doc.attachEvent) { 3134 return function (obj, type, fn, element) { 3135 var f = function (e) { 3136 e = e || g.win.event; 3137 var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, 3138 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, 3139 x = e.clientX + scrollX, 3140 y = e.clientY + scrollY; 3141 e.preventDefault = e.preventDefault || preventDefault; 3142 e.stopPropagation = e.stopPropagation || stopPropagation; 3143 return fn.call(element, e, x, y); 3144 }; 3145 obj.attachEvent("on" + type, f); 3146 var detacher = function () { 3147 obj.detachEvent("on" + type, f); 3148 return true; 3149 }; 3150 return detacher; 3151 }; 3152 } 3153 })(), 3154 drag = [], 3155 dragMove = function (e) { 3156 var x = e.clientX, 3157 y = e.clientY, 3158 scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, 3159 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, 3160 dragi, 3161 j = drag.length; 3162 while (j--) { 3163 dragi = drag[j]; 3164 if (supportsTouch && e.touches) { 3165 var i = e.touches.length, 3166 touch; 3167 while (i--) { 3168 touch = e.touches[i]; 3169 if (touch.identifier == dragi.el._drag.id) { 3170 x = touch.clientX; 3171 y = touch.clientY; 3172 (e.originalEvent ? e.originalEvent : e).preventDefault(); 3173 break; 3174 } 3175 } 3176 } else { 3177 e.preventDefault(); 3178 } 3179 var node = dragi.el.node, 3180 o, 3181 next = node.nextSibling, 3182 parent = node.parentNode, 3183 display = node.style.display; 3184 g.win.opera && parent.removeChild(node); 3185 node.style.display = "none"; 3186 o = dragi.el.paper.getElementByPoint(x, y); 3187 node.style.display = display; 3188 g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); 3189 o && eve("raphael.drag.over." + dragi.el.id, dragi.el, o); 3190 x += scrollX; 3191 y += scrollY; 3192 eve("raphael.drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); 3193 } 3194 }, 3195 dragUp = function (e) { 3196 R.unmousemove(dragMove).unmouseup(dragUp); 3197 var i = drag.length, 3198 dragi; 3199 while (i--) { 3200 dragi = drag[i]; 3201 dragi.el._drag = {}; 3202 eve("raphael.drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); 3203 } 3204 drag = []; 3205 }, 3206 /*\ 3207 * Raphael.el 3208 [ property (object) ] 3209 ** 3210 * You can add your own method to elements. This is usefull when you want to hack default functionality or 3211 * want to wrap some common transformation or attributes in one method. In difference to canvas methods, 3212 * you can redefine element method at any time. Expending element methods wouldn’t affect set. 3213 > Usage 3214 | Raphael.el.red = function () { 3215 | this.attr({fill: "#f00"}); 3216 | }; 3217 | // then use it 3218 | paper.circle(100, 100, 20).red(); 3219 \*/ 3220 elproto = R.el = {}; 3221 /*\ 3222 * Element.click 3223 [ method ] 3224 ** 3225 * Adds event handler for click for the element. 3226 > Parameters 3227 - handler (function) handler for the event 3228 = (object) @Element 3229 \*/ 3230 /*\ 3231 * Element.unclick 3232 [ method ] 3233 ** 3234 * Removes event handler for click for the element. 3235 > Parameters 3236 - handler (function) #optional handler for the event 3237 = (object) @Element 3238 \*/ 3239 3240 /*\ 3241 * Element.dblclick 3242 [ method ] 3243 ** 3244 * Adds event handler for double click for the element. 3245 > Parameters 3246 - handler (function) handler for the event 3247 = (object) @Element 3248 \*/ 3249 /*\ 3250 * Element.undblclick 3251 [ method ] 3252 ** 3253 * Removes event handler for double click for the element. 3254 > Parameters 3255 - handler (function) #optional handler for the event 3256 = (object) @Element 3257 \*/ 3258 3259 /*\ 3260 * Element.mousedown 3261 [ method ] 3262 ** 3263 * Adds event handler for mousedown for the element. 3264 > Parameters 3265 - handler (function) handler for the event 3266 = (object) @Element 3267 \*/ 3268 /*\ 3269 * Element.unmousedown 3270 [ method ] 3271 ** 3272 * Removes event handler for mousedown for the element. 3273 > Parameters 3274 - handler (function) #optional handler for the event 3275 = (object) @Element 3276 \*/ 3277 3278 /*\ 3279 * Element.mousemove 3280 [ method ] 3281 ** 3282 * Adds event handler for mousemove for the element. 3283 > Parameters 3284 - handler (function) handler for the event 3285 = (object) @Element 3286 \*/ 3287 /*\ 3288 * Element.unmousemove 3289 [ method ] 3290 ** 3291 * Removes event handler for mousemove for the element. 3292 > Parameters 3293 - handler (function) #optional handler for the event 3294 = (object) @Element 3295 \*/ 3296 3297 /*\ 3298 * Element.mouseout 3299 [ method ] 3300 ** 3301 * Adds event handler for mouseout for the element. 3302 > Parameters 3303 - handler (function) handler for the event 3304 = (object) @Element 3305 \*/ 3306 /*\ 3307 * Element.unmouseout 3308 [ method ] 3309 ** 3310 * Removes event handler for mouseout for the element. 3311 > Parameters 3312 - handler (function) #optional handler for the event 3313 = (object) @Element 3314 \*/ 3315 3316 /*\ 3317 * Element.mouseover 3318 [ method ] 3319 ** 3320 * Adds event handler for mouseover for the element. 3321 > Parameters 3322 - handler (function) handler for the event 3323 = (object) @Element 3324 \*/ 3325 /*\ 3326 * Element.unmouseover 3327 [ method ] 3328 ** 3329 * Removes event handler for mouseover for the element. 3330 > Parameters 3331 - handler (function) #optional handler for the event 3332 = (object) @Element 3333 \*/ 3334 3335 /*\ 3336 * Element.mouseup 3337 [ method ] 3338 ** 3339 * Adds event handler for mouseup for the element. 3340 > Parameters 3341 - handler (function) handler for the event 3342 = (object) @Element 3343 \*/ 3344 /*\ 3345 * Element.unmouseup 3346 [ method ] 3347 ** 3348 * Removes event handler for mouseup for the element. 3349 > Parameters 3350 - handler (function) #optional handler for the event 3351 = (object) @Element 3352 \*/ 3353 3354 /*\ 3355 * Element.touchstart 3356 [ method ] 3357 ** 3358 * Adds event handler for touchstart for the element. 3359 > Parameters 3360 - handler (function) handler for the event 3361 = (object) @Element 3362 \*/ 3363 /*\ 3364 * Element.untouchstart 3365 [ method ] 3366 ** 3367 * Removes event handler for touchstart for the element. 3368 > Parameters 3369 - handler (function) #optional handler for the event 3370 = (object) @Element 3371 \*/ 3372 3373 /*\ 3374 * Element.touchmove 3375 [ method ] 3376 ** 3377 * Adds event handler for touchmove for the element. 3378 > Parameters 3379 - handler (function) handler for the event 3380 = (object) @Element 3381 \*/ 3382 /*\ 3383 * Element.untouchmove 3384 [ method ] 3385 ** 3386 * Removes event handler for touchmove for the element. 3387 > Parameters 3388 - handler (function) #optional handler for the event 3389 = (object) @Element 3390 \*/ 3391 3392 /*\ 3393 * Element.touchend 3394 [ method ] 3395 ** 3396 * Adds event handler for touchend for the element. 3397 > Parameters 3398 - handler (function) handler for the event 3399 = (object) @Element 3400 \*/ 3401 /*\ 3402 * Element.untouchend 3403 [ method ] 3404 ** 3405 * Removes event handler for touchend for the element. 3406 > Parameters 3407 - handler (function) #optional handler for the event 3408 = (object) @Element 3409 \*/ 3410 3411 /*\ 3412 * Element.touchcancel 3413 [ method ] 3414 ** 3415 * Adds event handler for touchcancel for the element. 3416 > Parameters 3417 - handler (function) handler for the event 3418 = (object) @Element 3419 \*/ 3420 /*\ 3421 * Element.untouchcancel 3422 [ method ] 3423 ** 3424 * Removes event handler for touchcancel for the element. 3425 > Parameters 3426 - handler (function) #optional handler for the event 3427 = (object) @Element 3428 \*/ 3429 for (var i = events.length; i--;) { 3430 (function (eventName) { 3431 R[eventName] = elproto[eventName] = function (fn, scope) { 3432 if (R.is(fn, "function")) { 3433 this.events = this.events || []; 3434 this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)}); 3435 } 3436 return this; 3437 }; 3438 R["un" + eventName] = elproto["un" + eventName] = function (fn) { 3439 var events = this.events || [], 3440 l = events.length; 3441 while (l--){ 3442 if (events[l].name == eventName && (R.is(fn, "undefined") || events[l].f == fn)) { 3443 events[l].unbind(); 3444 events.splice(l, 1); 3445 !events.length && delete this.events; 3446 } 3447 } 3448 return this; 3449 }; 3450 })(events[i]); 3451 } 3452 3453 /*\ 3454 * Element.data 3455 [ method ] 3456 ** 3457 * Adds or retrieves given value asociated with given key. 3458 ** 3459 * See also @Element.removeData 3460 > Parameters 3461 - key (string) key to store data 3462 - value (any) #optional value to store 3463 = (object) @Element 3464 * or, if value is not specified: 3465 = (any) value 3466 * or, if key and value are not specified: 3467 = (object) Key/value pairs for all the data associated with the element. 3468 > Usage 3469 | for (var i = 0, i < 5, i++) { 3470 | paper.circle(10 + 15 * i, 10, 10) 3471 | .attr({fill: "#000"}) 3472 | .data("i", i) 3473 | .click(function () { 3474 | alert(this.data("i")); 3475 | }); 3476 | } 3477 \*/ 3478 elproto.data = function (key, value) { 3479 var data = eldata[this.id] = eldata[this.id] || {}; 3480 if (arguments.length == 0) { 3481 return data; 3482 } 3483 if (arguments.length == 1) { 3484 if (R.is(key, "object")) { 3485 for (var i in key) if (key[has](i)) { 3486 this.data(i, key[i]); 3487 } 3488 return this; 3489 } 3490 eve("raphael.data.get." + this.id, this, data[key], key); 3491 return data[key]; 3492 } 3493 data[key] = value; 3494 eve("raphael.data.set." + this.id, this, value, key); 3495 return this; 3496 }; 3497 /*\ 3498 * Element.removeData 3499 [ method ] 3500 ** 3501 * Removes value associated with an element by given key. 3502 * If key is not provided, removes all the data of the element. 3503 > Parameters 3504 - key (string) #optional key 3505 = (object) @Element 3506 \*/ 3507 elproto.removeData = function (key) { 3508 if (key == null) { 3509 eldata[this.id] = {}; 3510 } else { 3511 eldata[this.id] && delete eldata[this.id][key]; 3512 } 3513 return this; 3514 }; 3515 /*\ 3516 * Element.getData 3517 [ method ] 3518 ** 3519 * Retrieves the element data 3520 = (object) data 3521 \*/ 3522 elproto.getData = function () { 3523 return clone(eldata[this.id] || {}); 3524 }; 3525 /*\ 3526 * Element.hover 3527 [ method ] 3528 ** 3529 * Adds event handlers for hover for the element. 3530 > Parameters 3531 - f_in (function) handler for hover in 3532 - f_out (function) handler for hover out 3533 - icontext (object) #optional context for hover in handler 3534 - ocontext (object) #optional context for hover out handler 3535 = (object) @Element 3536 \*/ 3537 elproto.hover = function (f_in, f_out, scope_in, scope_out) { 3538 return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); 3539 }; 3540 /*\ 3541 * Element.unhover 3542 [ method ] 3543 ** 3544 * Removes event handlers for hover for the element. 3545 > Parameters 3546 - f_in (function) handler for hover in 3547 - f_out (function) handler for hover out 3548 = (object) @Element 3549 \*/ 3550 elproto.unhover = function (f_in, f_out) { 3551 return this.unmouseover(f_in).unmouseout(f_out); 3552 }; 3553 var draggable = []; 3554 /*\ 3555 * Element.drag 3556 [ method ] 3557 ** 3558 * Adds event handlers for drag of the element. 3559 > Parameters 3560 - onmove (function) handler for moving 3561 - onstart (function) handler for drag start 3562 - onend (function) handler for drag end 3563 - mcontext (object) #optional context for moving handler 3564 - scontext (object) #optional context for drag start handler 3565 - econtext (object) #optional context for drag end handler 3566 * Additionaly following `drag` events will be triggered: `drag.start.<id>` on start, 3567 * `drag.end.<id>` on end and `drag.move.<id>` on every move. When element will be dragged over another element 3568 * `drag.over.<id>` will be fired as well. 3569 * 3570 * Start event and start handler will be called in specified context or in context of the element with following parameters: 3571 o x (number) x position of the mouse 3572 o y (number) y position of the mouse 3573 o event (object) DOM event object 3574 * Move event and move handler will be called in specified context or in context of the element with following parameters: 3575 o dx (number) shift by x from the start point 3576 o dy (number) shift by y from the start point 3577 o x (number) x position of the mouse 3578 o y (number) y position of the mouse 3579 o event (object) DOM event object 3580 * End event and end handler will be called in specified context or in context of the element with following parameters: 3581 o event (object) DOM event object 3582 = (object) @Element 3583 \*/ 3584 elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { 3585 function start(e) { 3586 (e.originalEvent || e).preventDefault(); 3587 var x = e.clientX, 3588 y = e.clientY, 3589 scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, 3590 scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; 3591 this._drag.id = e.identifier; 3592 if (supportsTouch && e.touches) { 3593 var i = e.touches.length, touch; 3594 while (i--) { 3595 touch = e.touches[i]; 3596 this._drag.id = touch.identifier; 3597 if (touch.identifier == this._drag.id) { 3598 x = touch.clientX; 3599 y = touch.clientY; 3600 break; 3601 } 3602 } 3603 } 3604 this._drag.x = x + scrollX; 3605 this._drag.y = y + scrollY; 3606 !drag.length && R.mousemove(dragMove).mouseup(dragUp); 3607 drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); 3608 onstart && eve.on("raphael.drag.start." + this.id, onstart); 3609 onmove && eve.on("raphael.drag.move." + this.id, onmove); 3610 onend && eve.on("raphael.drag.end." + this.id, onend); 3611 eve("raphael.drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e); 3612 } 3613 this._drag = {}; 3614 draggable.push({el: this, start: start}); 3615 this.mousedown(start); 3616 return this; 3617 }; 3618 /*\ 3619 * Element.onDragOver 3620 [ method ] 3621 ** 3622 * Shortcut for assigning event handler for `drag.over.<id>` event, where id is id of the element (see @Element.id). 3623 > Parameters 3624 - f (function) handler for event, first argument would be the element you are dragging over 3625 \*/ 3626 elproto.onDragOver = function (f) { 3627 f ? eve.on("raphael.drag.over." + this.id, f) : eve.unbind("raphael.drag.over." + this.id); 3628 }; 3629 /*\ 3630 * Element.undrag 3631 [ method ] 3632 ** 3633 * Removes all drag event handlers from given element. 3634 \*/ 3635 elproto.undrag = function () { 3636 var i = draggable.length; 3637 while (i--) if (draggable[i].el == this) { 3638 this.unmousedown(draggable[i].start); 3639 draggable.splice(i, 1); 3640 eve.unbind("raphael.drag.*." + this.id); 3641 } 3642 !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp); 3643 drag = []; 3644 }; 3645 /*\ 3646 * Paper.circle 3647 [ method ] 3648 ** 3649 * Draws a circle. 3650 ** 3651 > Parameters 3652 ** 3653 - x (number) x coordinate of the centre 3654 - y (number) y coordinate of the centre 3655 - r (number) radius 3656 = (object) Raphaël element object with type “circle” 3657 ** 3658 > Usage 3659 | var c = paper.circle(50, 50, 40); 3660 \*/ 3661 paperproto.circle = function (x, y, r) { 3662 var out = R._engine.circle(this, x || 0, y || 0, r || 0); 3663 this.__set__ && this.__set__.push(out); 3664 return out; 3665 }; 3666 /*\ 3667 * Paper.rect 3668 [ method ] 3669 * 3670 * Draws a rectangle. 3671 ** 3672 > Parameters 3673 ** 3674 - x (number) x coordinate of the top left corner 3675 - y (number) y coordinate of the top left corner 3676 - width (number) width 3677 - height (number) height 3678 - r (number) #optional radius for rounded corners, default is 0 3679 = (object) Raphaël element object with type “rect” 3680 ** 3681 > Usage 3682 | // regular rectangle 3683 | var c = paper.rect(10, 10, 50, 50); 3684 | // rectangle with rounded corners 3685 | var c = paper.rect(40, 40, 50, 50, 10); 3686 \*/ 3687 paperproto.rect = function (x, y, w, h, r) { 3688 var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0); 3689 this.__set__ && this.__set__.push(out); 3690 return out; 3691 }; 3692 /*\ 3693 * Paper.ellipse 3694 [ method ] 3695 ** 3696 * Draws an ellipse. 3697 ** 3698 > Parameters 3699 ** 3700 - x (number) x coordinate of the centre 3701 - y (number) y coordinate of the centre 3702 - rx (number) horizontal radius 3703 - ry (number) vertical radius 3704 = (object) Raphaël element object with type “ellipse” 3705 ** 3706 > Usage 3707 | var c = paper.ellipse(50, 50, 40, 20); 3708 \*/ 3709 paperproto.ellipse = function (x, y, rx, ry) { 3710 var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0); 3711 this.__set__ && this.__set__.push(out); 3712 return out; 3713 }; 3714 /*\ 3715 * Paper.path 3716 [ method ] 3717 ** 3718 * Creates a path element by given path data string. 3719 > Parameters 3720 - pathString (string) #optional path string in SVG format. 3721 * Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example: 3722 | "M10,20L30,40" 3723 * Here we can see two commands: “M”, with arguments `(10, 20)` and “L” with arguments `(30, 40)`. Upper case letter mean command is absolute, lower case—relative. 3724 * 3725 # <p>Here is short list of commands available, for more details see <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 path string format</a>.</p> 3726 # <table><thead><tr><th>Command</th><th>Name</th><th>Parameters</th></tr></thead><tbody> 3727 # <tr><td>M</td><td>moveto</td><td>(x y)+</td></tr> 3728 # <tr><td>Z</td><td>closepath</td><td>(none)</td></tr> 3729 # <tr><td>L</td><td>lineto</td><td>(x y)+</td></tr> 3730 # <tr><td>H</td><td>horizontal lineto</td><td>x+</td></tr> 3731 # <tr><td>V</td><td>vertical lineto</td><td>y+</td></tr> 3732 # <tr><td>C</td><td>curveto</td><td>(x1 y1 x2 y2 x y)+</td></tr> 3733 # <tr><td>S</td><td>smooth curveto</td><td>(x2 y2 x y)+</td></tr> 3734 # <tr><td>Q</td><td>quadratic Bézier curveto</td><td>(x1 y1 x y)+</td></tr> 3735 # <tr><td>T</td><td>smooth quadratic Bézier curveto</td><td>(x y)+</td></tr> 3736 # <tr><td>A</td><td>elliptical arc</td><td>(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+</td></tr> 3737 # <tr><td>R</td><td><a href="http://en.wikipedia.org/wiki/Catmull–Rom_spline#Catmull.E2.80.93Rom_spline">Catmull-Rom curveto</a>*</td><td>x1 y1 (x y)+</td></tr></tbody></table> 3738 * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier. 3739 * Note: there is a special case when path consist of just three commands: “M10,10R…z”. In this case path will smoothly connects to its beginning. 3740 > Usage 3741 | var c = paper.path("M10 10L90 90"); 3742 | // draw a diagonal line: 3743 | // move to 10,10, line to 90,90 3744 * For example of path strings, check out these icons: http://raphaeljs.com/icons/ 3745 \*/ 3746 paperproto.path = function (pathString) { 3747 pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E); 3748 var out = R._engine.path(R.format[apply](R, arguments), this); 3749 this.__set__ && this.__set__.push(out); 3750 return out; 3751 }; 3752 /*\ 3753 * Paper.image 3754 [ method ] 3755 ** 3756 * Embeds an image into the surface. 3757 ** 3758 > Parameters 3759 ** 3760 - src (string) URI of the source image 3761 - x (number) x coordinate position 3762 - y (number) y coordinate position 3763 - width (number) width of the image 3764 - height (number) height of the image 3765 = (object) Raphaël element object with type “image” 3766 ** 3767 > Usage 3768 | var c = paper.image("apple.png", 10, 10, 80, 80); 3769 \*/ 3770 paperproto.image = function (src, x, y, w, h) { 3771 var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); 3772 this.__set__ && this.__set__.push(out); 3773 return out; 3774 }; 3775 /*\ 3776 * Paper.text 3777 [ method ] 3778 ** 3779 * Draws a text string. If you need line breaks, put “\n” in the string. 3780 ** 3781 > Parameters 3782 ** 3783 - x (number) x coordinate position 3784 - y (number) y coordinate position 3785 - text (string) The text string to draw 3786 = (object) Raphaël element object with type “text” 3787 ** 3788 > Usage 3789 | var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!"); 3790 \*/ 3791 paperproto.text = function (x, y, text) { 3792 var out = R._engine.text(this, x || 0, y || 0, Str(text)); 3793 this.__set__ && this.__set__.push(out); 3794 return out; 3795 }; 3796 /*\ 3797 * Paper.set 3798 [ method ] 3799 ** 3800 * Creates array-like object to keep and operate several elements at once. 3801 * Warning: it doesn’t create any elements for itself in the page, it just groups existing elements. 3802 * Sets act as pseudo elements — all methods available to an element can be used on a set. 3803 = (object) array-like object that represents set of elements 3804 ** 3805 > Usage 3806 | var st = paper.set(); 3807 | st.push( 3808 | paper.circle(10, 10, 5), 3809 | paper.circle(30, 10, 5) 3810 | ); 3811 | st.attr({fill: "red"}); // changes the fill of both circles 3812 \*/ 3813 paperproto.set = function (itemsArray) { 3814 !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length)); 3815 var out = new Set(itemsArray); 3816 this.__set__ && this.__set__.push(out); 3817 out["paper"] = this; 3818 out["type"] = "set"; 3819 return out; 3820 }; 3821 /*\ 3822 * Paper.setStart 3823 [ method ] 3824 ** 3825 * Creates @Paper.set. All elements that will be created after calling this method and before calling 3826 * @Paper.setFinish will be added to the set. 3827 ** 3828 > Usage 3829 | paper.setStart(); 3830 | paper.circle(10, 10, 5), 3831 | paper.circle(30, 10, 5) 3832 | var st = paper.setFinish(); 3833 | st.attr({fill: "red"}); // changes the fill of both circles 3834 \*/ 3835 paperproto.setStart = function (set) { 3836 this.__set__ = set || this.set(); 3837 }; 3838 /*\ 3839 * Paper.setFinish 3840 [ method ] 3841 ** 3842 * See @Paper.setStart. This method finishes catching and returns resulting set. 3843 ** 3844 = (object) set 3845 \*/ 3846 paperproto.setFinish = function (set) { 3847 var out = this.__set__; 3848 delete this.__set__; 3849 return out; 3850 }; 3851 /*\ 3852 * Paper.setSize 3853 [ method ] 3854 ** 3855 * If you need to change dimensions of the canvas call this method 3856 ** 3857 > Parameters 3858 ** 3859 - width (number) new width of the canvas 3860 - height (number) new height of the canvas 3861 \*/ 3862 paperproto.setSize = function (width, height) { 3863 return R._engine.setSize.call(this, width, height); 3864 }; 3865 /*\ 3866 * Paper.setViewBox 3867 [ method ] 3868 ** 3869 * Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by 3870 * specifying new boundaries. 3871 ** 3872 > Parameters 3873 ** 3874 - x (number) new x position, default is `0` 3875 - y (number) new y position, default is `0` 3876 - w (number) new width of the canvas 3877 - h (number) new height of the canvas 3878 - fit (boolean) `true` if you want graphics to fit into new boundary box 3879 \*/ 3880 paperproto.setViewBox = function (x, y, w, h, fit) { 3881 return R._engine.setViewBox.call(this, x, y, w, h, fit); 3882 }; 3883 /*\ 3884 * Paper.top 3885 [ property ] 3886 ** 3887 * Points to the topmost element on the paper 3888 \*/ 3889 /*\ 3890 * Paper.bottom 3891 [ property ] 3892 ** 3893 * Points to the bottom element on the paper 3894 \*/ 3895 paperproto.top = paperproto.bottom = null; 3896 /*\ 3897 * Paper.raphael 3898 [ property ] 3899 ** 3900 * Points to the @Raphael object/function 3901 \*/ 3902 paperproto.raphael = R; 3903 var getOffset = function (elem) { 3904 var box = elem.getBoundingClientRect(), 3905 doc = elem.ownerDocument, 3906 body = doc.body, 3907 docElem = doc.documentElement, 3908 clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, 3909 top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, 3910 left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; 3911 return { 3912 y: top, 3913 x: left 3914 }; 3915 }; 3916 /*\ 3917 * Paper.getElementByPoint 3918 [ method ] 3919 ** 3920 * Returns you topmost element under given point. 3921 ** 3922 = (object) Raphaël element object 3923 > Parameters 3924 ** 3925 - x (number) x coordinate from the top left corner of the window 3926 - y (number) y coordinate from the top left corner of the window 3927 > Usage 3928 | paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); 3929 \*/ 3930 paperproto.getElementByPoint = function (x, y) { 3931 var paper = this, 3932 svg = paper.canvas, 3933 target = g.doc.elementFromPoint(x, y); 3934 if (g.win.opera && target.tagName == "svg") { 3935 var so = getOffset(svg), 3936 sr = svg.createSVGRect(); 3937 sr.x = x - so.x; 3938 sr.y = y - so.y; 3939 sr.width = sr.height = 1; 3940 var hits = svg.getIntersectionList(sr, null); 3941 if (hits.length) { 3942 target = hits[hits.length - 1]; 3943 } 3944 } 3945 if (!target) { 3946 return null; 3947 } 3948 while (target.parentNode && target != svg.parentNode && !target.raphael) { 3949 target = target.parentNode; 3950 } 3951 target == paper.canvas.parentNode && (target = svg); 3952 target = target && target.raphael ? paper.getById(target.raphaelid) : null; 3953 return target; 3954 }; 3955 3956 /*\ 3957 * Paper.getElementsByBBox 3958 [ method ] 3959 ** 3960 * Returns set of elements that have an intersecting bounding box 3961 ** 3962 > Parameters 3963 ** 3964 - bbox (object) bbox to check with 3965 = (object) @Set 3966 \*/ 3967 paperproto.getElementsByBBox = function (bbox) { 3968 var set = this.set(); 3969 this.forEach(function (el) { 3970 if (R.isBBoxIntersect(el.getBBox(), bbox)) { 3971 set.push(el); 3972 } 3973 }); 3974 return set; 3975 }; 3976 3977 /*\ 3978 * Paper.getById 3979 [ method ] 3980 ** 3981 * Returns you element by its internal ID. 3982 ** 3983 > Parameters 3984 ** 3985 - id (number) id 3986 = (object) Raphaël element object 3987 \*/ 3988 paperproto.getById = function (id) { 3989 var bot = this.bottom; 3990 while (bot) { 3991 if (bot.id == id) { 3992 return bot; 3993 } 3994 bot = bot.next; 3995 } 3996 return null; 3997 }; 3998 /*\ 3999 * Paper.forEach 4000 [ method ] 4001 ** 4002 * Executes given function for each element on the paper 4003 * 4004 * If callback function returns `false` it will stop loop running. 4005 ** 4006 > Parameters 4007 ** 4008 - callback (function) function to run 4009 - thisArg (object) context object for the callback 4010 = (object) Paper object 4011 > Usage 4012 | paper.forEach(function (el) { 4013 | el.attr({ stroke: "blue" }); 4014 | }); 4015 \*/ 4016 paperproto.forEach = function (callback, thisArg) { 4017 var bot = this.bottom; 4018 while (bot) { 4019 if (callback.call(thisArg, bot) === false) { 4020 return this; 4021 } 4022 bot = bot.next; 4023 } 4024 return this; 4025 }; 4026 /*\ 4027 * Paper.getElementsByPoint 4028 [ method ] 4029 ** 4030 * Returns set of elements that have common point inside 4031 ** 4032 > Parameters 4033 ** 4034 - x (number) x coordinate of the point 4035 - y (number) y coordinate of the point 4036 = (object) @Set 4037 \*/ 4038 paperproto.getElementsByPoint = function (x, y) { 4039 var set = this.set(); 4040 this.forEach(function (el) { 4041 if (el.isPointInside(x, y)) { 4042 set.push(el); 4043 } 4044 }); 4045 return set; 4046 }; 4047 function x_y() { 4048 return this.x + S + this.y; 4049 } 4050 function x_y_w_h() { 4051 return this.x + S + this.y + S + this.width + " \xd7 " + this.height; 4052 } 4053 /*\ 4054 * Element.isPointInside 4055 [ method ] 4056 ** 4057 * Determine if given point is inside this element’s shape 4058 ** 4059 > Parameters 4060 ** 4061 - x (number) x coordinate of the point 4062 - y (number) y coordinate of the point 4063 = (boolean) `true` if point inside the shape 4064 \*/ 4065 elproto.isPointInside = function (x, y) { 4066 var rp = this.realPath = getPath[this.type](this); 4067 if (this.attr('transform') && this.attr('transform').length) { 4068 rp = R.transformPath(rp, this.attr('transform')); 4069 } 4070 return R.isPointInsidePath(rp, x, y); 4071 }; 4072 /*\ 4073 * Element.getBBox 4074 [ method ] 4075 ** 4076 * Return bounding box for a given element 4077 ** 4078 > Parameters 4079 ** 4080 - isWithoutTransform (boolean) flag, `true` if you want to have bounding box before transformations. Default is `false`. 4081 = (object) Bounding box object: 4082 o { 4083 o x: (number) top left corner x 4084 o y: (number) top left corner y 4085 o x2: (number) bottom right corner x 4086 o y2: (number) bottom right corner y 4087 o width: (number) width 4088 o height: (number) height 4089 o } 4090 \*/ 4091 elproto.getBBox = function (isWithoutTransform) { 4092 if (this.removed) { 4093 return {}; 4094 } 4095 var _ = this._; 4096 if (isWithoutTransform) { 4097 if (_.dirty || !_.bboxwt) { 4098 this.realPath = getPath[this.type](this); 4099 _.bboxwt = pathDimensions(this.realPath); 4100 _.bboxwt.toString = x_y_w_h; 4101 _.dirty = 0; 4102 } 4103 return _.bboxwt; 4104 } 4105 if (_.dirty || _.dirtyT || !_.bbox) { 4106 if (_.dirty || !this.realPath) { 4107 _.bboxwt = 0; 4108 this.realPath = getPath[this.type](this); 4109 } 4110 _.bbox = pathDimensions(mapPath(this.realPath, this.matrix)); 4111 _.bbox.toString = x_y_w_h; 4112 _.dirty = _.dirtyT = 0; 4113 } 4114 return _.bbox; 4115 }; 4116 /*\ 4117 * Element.clone 4118 [ method ] 4119 ** 4120 = (object) clone of a given element 4121 ** 4122 \*/ 4123 elproto.clone = function () { 4124 if (this.removed) { 4125 return null; 4126 } 4127 var out = this.paper[this.type]().attr(this.attr()); 4128 this.__set__ && this.__set__.push(out); 4129 return out; 4130 }; 4131 /*\ 4132 * Element.glow 4133 [ method ] 4134 ** 4135 * Return set of elements that create glow-like effect around given element. See @Paper.set. 4136 * 4137 * Note: Glow is not connected to the element. If you change element attributes it won’t adjust itself. 4138 ** 4139 > Parameters 4140 ** 4141 - glow (object) #optional parameters object with all properties optional: 4142 o { 4143 o width (number) size of the glow, default is `10` 4144 o fill (boolean) will it be filled, default is `false` 4145 o opacity (number) opacity, default is `0.5` 4146 o offsetx (number) horizontal offset, default is `0` 4147 o offsety (number) vertical offset, default is `0` 4148 o color (string) glow colour, default is `black` 4149 o } 4150 = (object) @Paper.set of elements that represents glow 4151 \*/ 4152 elproto.glow = function (glow) { 4153 if (this.type == "text") { 4154 return null; 4155 } 4156 glow = glow || {}; 4157 var s = { 4158 width: (glow.width || 10) + (+this.attr("stroke-width") || 1), 4159 fill: glow.fill || false, 4160 opacity: glow.opacity || .5, 4161 offsetx: glow.offsetx || 0, 4162 offsety: glow.offsety || 0, 4163 color: glow.color || "#000" 4164 }, 4165 c = s.width / 2, 4166 r = this.paper, 4167 out = r.set(), 4168 path = this.realPath || getPath[this.type](this); 4169 path = this.matrix ? mapPath(path, this.matrix) : path; 4170 for (var i = 1; i < c + 1; i++) { 4171 out.push(r.path(path).attr({ 4172 stroke: s.color, 4173 fill: s.fill ? s.color : "none", 4174 "stroke-linejoin": "round", 4175 "stroke-linecap": "round", 4176 "stroke-width": +(s.width / c * i).toFixed(3), 4177 opacity: +(s.opacity / c).toFixed(3) 4178 })); 4179 } 4180 return out.insertBefore(this).translate(s.offsetx, s.offsety); 4181 }; 4182 var curveslengths = {}, 4183 getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { 4184 if (length == null) { 4185 return bezlen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); 4186 } else { 4187 return R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, getTatLen(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length)); 4188 } 4189 }, 4190 getLengthFactory = function (istotal, subpath) { 4191 return function (path, length, onlystart) { 4192 path = path2curve(path); 4193 var x, y, p, l, sp = "", subpaths = {}, point, 4194 len = 0; 4195 for (var i = 0, ii = path.length; i < ii; i++) { 4196 p = path[i]; 4197 if (p[0] == "M") { 4198 x = +p[1]; 4199 y = +p[2]; 4200 } else { 4201 l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); 4202 if (len + l > length) { 4203 if (subpath && !subpaths.start) { 4204 point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); 4205 sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; 4206 if (onlystart) {return sp;} 4207 subpaths.start = sp; 4208 sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join(); 4209 len += l; 4210 x = +p[5]; 4211 y = +p[6]; 4212 continue; 4213 } 4214 if (!istotal && !subpath) { 4215 point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); 4216 return {x: point.x, y: point.y, alpha: point.alpha}; 4217 } 4218 } 4219 len += l; 4220 x = +p[5]; 4221 y = +p[6]; 4222 } 4223 sp += p.shift() + p; 4224 } 4225 subpaths.end = sp; 4226 point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); 4227 point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); 4228 return point; 4229 }; 4230 }; 4231 var getTotalLength = getLengthFactory(1), 4232 getPointAtLength = getLengthFactory(), 4233 getSubpathsAtLength = getLengthFactory(0, 1); 4234 /*\ 4235 * Raphael.getTotalLength 4236 [ method ] 4237 ** 4238 * Returns length of the given path in pixels. 4239 ** 4240 > Parameters 4241 ** 4242 - path (string) SVG path string. 4243 ** 4244 = (number) length. 4245 \*/ 4246 R.getTotalLength = getTotalLength; 4247 /*\ 4248 * Raphael.getPointAtLength 4249 [ method ] 4250 ** 4251 * Return coordinates of the point located at the given length on the given path. 4252 ** 4253 > Parameters 4254 ** 4255 - path (string) SVG path string 4256 - length (number) 4257 ** 4258 = (object) representation of the point: 4259 o { 4260 o x: (number) x coordinate 4261 o y: (number) y coordinate 4262 o alpha: (number) angle of derivative 4263 o } 4264 \*/ 4265 R.getPointAtLength = getPointAtLength; 4266 /*\ 4267 * Raphael.getSubpath 4268 [ method ] 4269 ** 4270 * Return subpath of a given path from given length to given length. 4271 ** 4272 > Parameters 4273 ** 4274 - path (string) SVG path string 4275 - from (number) position of the start of the segment 4276 - to (number) position of the end of the segment 4277 ** 4278 = (string) pathstring for the segment 4279 \*/ 4280 R.getSubpath = function (path, from, to) { 4281 if (this.getTotalLength(path) - to < 1e-6) { 4282 return getSubpathsAtLength(path, from).end; 4283 } 4284 var a = getSubpathsAtLength(path, to, 1); 4285 return from ? getSubpathsAtLength(a, from).end : a; 4286 }; 4287 /*\ 4288 * Element.getTotalLength 4289 [ method ] 4290 ** 4291 * Returns length of the path in pixels. Only works for element of “path” type. 4292 = (number) length. 4293 \*/ 4294 elproto.getTotalLength = function () { 4295 var path = this.getPath(); 4296 if (!path) { 4297 return; 4298 } 4299 4300 if (this.node.getTotalLength) { 4301 return this.node.getTotalLength(); 4302 } 4303 4304 return getTotalLength(path); 4305 }; 4306 /*\ 4307 * Element.getPointAtLength 4308 [ method ] 4309 ** 4310 * Return coordinates of the point located at the given length on the given path. Only works for element of “path” type. 4311 ** 4312 > Parameters 4313 ** 4314 - length (number) 4315 ** 4316 = (object) representation of the point: 4317 o { 4318 o x: (number) x coordinate 4319 o y: (number) y coordinate 4320 o alpha: (number) angle of derivative 4321 o } 4322 \*/ 4323 elproto.getPointAtLength = function (length) { 4324 var path = this.getPath(); 4325 if (!path) { 4326 return; 4327 } 4328 4329 return getPointAtLength(path, length); 4330 }; 4331 /*\ 4332 * Element.getPath 4333 [ method ] 4334 ** 4335 * Returns path of the element. Only works for elements of “path” type and simple elements like circle. 4336 = (object) path 4337 ** 4338 \*/ 4339 elproto.getPath = function () { 4340 var path, 4341 getPath = R._getPath[this.type]; 4342 4343 if (this.type == "text" || this.type == "set") { 4344 return; 4345 } 4346 4347 if (getPath) { 4348 path = getPath(this); 4349 } 4350 4351 return path; 4352 }; 4353 /*\ 4354 * Element.getSubpath 4355 [ method ] 4356 ** 4357 * Return subpath of a given element from given length to given length. Only works for element of “path” type. 4358 ** 4359 > Parameters 4360 ** 4361 - from (number) position of the start of the segment 4362 - to (number) position of the end of the segment 4363 ** 4364 = (string) pathstring for the segment 4365 \*/ 4366 elproto.getSubpath = function (from, to) { 4367 var path = this.getPath(); 4368 if (!path) { 4369 return; 4370 } 4371 4372 return R.getSubpath(path, from, to); 4373 }; 4374 /*\ 4375 * Raphael.easing_formulas 4376 [ property ] 4377 ** 4378 * Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing: 4379 # <ul> 4380 # <li>“linear”</li> 4381 # <li>“<” or “easeIn” or “ease-in”</li> 4382 # <li>“>” or “easeOut” or “ease-out”</li> 4383 # <li>“<>” or “easeInOut” or “ease-in-out”</li> 4384 # <li>“backIn” or “back-in”</li> 4385 # <li>“backOut” or “back-out”</li> 4386 # <li>“elastic”</li> 4387 # <li>“bounce”</li> 4388 # </ul> 4389 # <p>See also <a href="http://raphaeljs.com/easing.html">Easing demo</a>.</p> 4390 \*/ 4391 var ef = R.easing_formulas = { 4392 linear: function (n) { 4393 return n; 4394 }, 4395 "<": function (n) { 4396 return pow(n, 1.7); 4397 }, 4398 ">": function (n) { 4399 return pow(n, .48); 4400 }, 4401 "<>": function (n) { 4402 var q = .48 - n / 1.04, 4403 Q = math.sqrt(.1734 + q * q), 4404 x = Q - q, 4405 X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1), 4406 y = -Q - q, 4407 Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1), 4408 t = X + Y + .5; 4409 return (1 - t) * 3 * t * t + t * t * t; 4410 }, 4411 backIn: function (n) { 4412 var s = 1.70158; 4413 return n * n * ((s + 1) * n - s); 4414 }, 4415 backOut: function (n) { 4416 n = n - 1; 4417 var s = 1.70158; 4418 return n * n * ((s + 1) * n + s) + 1; 4419 }, 4420 elastic: function (n) { 4421 if (n == !!n) { 4422 return n; 4423 } 4424 return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1; 4425 }, 4426 bounce: function (n) { 4427 var s = 7.5625, 4428 p = 2.75, 4429 l; 4430 if (n < (1 / p)) { 4431 l = s * n * n; 4432 } else { 4433 if (n < (2 / p)) { 4434 n -= (1.5 / p); 4435 l = s * n * n + .75; 4436 } else { 4437 if (n < (2.5 / p)) { 4438 n -= (2.25 / p); 4439 l = s * n * n + .9375; 4440 } else { 4441 n -= (2.625 / p); 4442 l = s * n * n + .984375; 4443 } 4444 } 4445 } 4446 return l; 4447 } 4448 }; 4449 ef.easeIn = ef["ease-in"] = ef["<"]; 4450 ef.easeOut = ef["ease-out"] = ef[">"]; 4451 ef.easeInOut = ef["ease-in-out"] = ef["<>"]; 4452 ef["back-in"] = ef.backIn; 4453 ef["back-out"] = ef.backOut; 4454 4455 var animationElements = [], 4456 requestAnimFrame = window.requestAnimationFrame || 4457 window.webkitRequestAnimationFrame || 4458 window.mozRequestAnimationFrame || 4459 window.oRequestAnimationFrame || 4460 window.msRequestAnimationFrame || 4461 function (callback) { 4462 setTimeout(callback, 16); 4463 }, 4464 animation = function () { 4465 var Now = +new Date, 4466 l = 0; 4467 for (; l < animationElements.length; l++) { 4468 var e = animationElements[l]; 4469 if (e.el.removed || e.paused) { 4470 continue; 4471 } 4472 var time = Now - e.start, 4473 ms = e.ms, 4474 easing = e.easing, 4475 from = e.from, 4476 diff = e.diff, 4477 to = e.to, 4478 t = e.t, 4479 that = e.el, 4480 set = {}, 4481 now, 4482 init = {}, 4483 key; 4484 if (e.initstatus) { 4485 time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; 4486 e.status = e.initstatus; 4487 delete e.initstatus; 4488 e.stop && animationElements.splice(l--, 1); 4489 } else { 4490 e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top; 4491 } 4492 if (time < 0) { 4493 continue; 4494 } 4495 if (time < ms) { 4496 var pos = easing(time / ms); 4497 for (var attr in from) if (from[has](attr)) { 4498 switch (availableAnimAttrs[attr]) { 4499 case nu: 4500 now = +from[attr] + pos * ms * diff[attr]; 4501 break; 4502 case "colour": 4503 now = "rgb(" + [ 4504 upto255(round(from[attr].r + pos * ms * diff[attr].r)), 4505 upto255(round(from[attr].g + pos * ms * diff[attr].g)), 4506 upto255(round(from[attr].b + pos * ms * diff[attr].b)) 4507 ].join(",") + ")"; 4508 break; 4509 case "path": 4510 now = []; 4511 for (var i = 0, ii = from[attr].length; i < ii; i++) { 4512 now[i] = [from[attr][i][0]]; 4513 for (var j = 1, jj = from[attr][i].length; j < jj; j++) { 4514 now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; 4515 } 4516 now[i] = now[i].join(S); 4517 } 4518 now = now.join(S); 4519 break; 4520 case "transform": 4521 if (diff[attr].real) { 4522 now = []; 4523 for (i = 0, ii = from[attr].length; i < ii; i++) { 4524 now[i] = [from[attr][i][0]]; 4525 for (j = 1, jj = from[attr][i].length; j < jj; j++) { 4526 now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j]; 4527 } 4528 } 4529 } else { 4530 var get = function (i) { 4531 return +from[attr][i] + pos * ms * diff[attr][i]; 4532 }; 4533 // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]]; 4534 now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]]; 4535 } 4536 break; 4537 case "csv": 4538 if (attr == "clip-rect") { 4539 now = []; 4540 i = 4; 4541 while (i--) { 4542 now[i] = +from[attr][i] + pos * ms * diff[attr][i]; 4543 } 4544 } 4545 break; 4546 default: 4547 var from2 = [][concat](from[attr]); 4548 now = []; 4549 i = that.paper.customAttributes[attr].length; 4550 while (i--) { 4551 now[i] = +from2[i] + pos * ms * diff[attr][i]; 4552 } 4553 break; 4554 } 4555 set[attr] = now; 4556 } 4557 that.attr(set); 4558 (function (id, that, anim) { 4559 setTimeout(function () { 4560 eve("raphael.anim.frame." + id, that, anim); 4561 }); 4562 })(that.id, that, e.anim); 4563 } else { 4564 (function(f, el, a) { 4565 setTimeout(function() { 4566 eve("raphael.anim.frame." + el.id, el, a); 4567 eve("raphael.anim.finish." + el.id, el, a); 4568 R.is(f, "function") && f.call(el); 4569 }); 4570 })(e.callback, that, e.anim); 4571 that.attr(to); 4572 animationElements.splice(l--, 1); 4573 if (e.repeat > 1 && !e.next) { 4574 for (key in to) if (to[has](key)) { 4575 init[key] = e.totalOrigin[key]; 4576 } 4577 e.el.attr(init); 4578 runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1); 4579 } 4580 if (e.next && !e.stop) { 4581 runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat); 4582 } 4583 } 4584 } 4585 R.svg && that && that.paper && that.paper.safari(); 4586 animationElements.length && requestAnimFrame(animation); 4587 }, 4588 upto255 = function (color) { 4589 return color > 255 ? 255 : color < 0 ? 0 : color; 4590 }; 4591 /*\ 4592 * Element.animateWith 4593 [ method ] 4594 ** 4595 * Acts similar to @Element.animate, but ensure that given animation runs in sync with another given element. 4596 ** 4597 > Parameters 4598 ** 4599 - el (object) element to sync with 4600 - anim (object) animation to sync with 4601 - params (object) #optional final attributes for the element, see also @Element.attr 4602 - ms (number) #optional number of milliseconds for animation to run 4603 - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` 4604 - callback (function) #optional callback function. Will be called at the end of animation. 4605 * or 4606 - element (object) element to sync with 4607 - anim (object) animation to sync with 4608 - animation (object) #optional animation object, see @Raphael.animation 4609 ** 4610 = (object) original element 4611 \*/ 4612 elproto.animateWith = function (el, anim, params, ms, easing, callback) { 4613 var element = this; 4614 if (element.removed) { 4615 callback && callback.call(element); 4616 return element; 4617 } 4618 var a = params instanceof Animation ? params : R.animation(params, ms, easing, callback), 4619 x, y; 4620 runAnimation(a, element, a.percents[0], null, element.attr()); 4621 for (var i = 0, ii = animationElements.length; i < ii; i++) { 4622 if (animationElements[i].anim == anim && animationElements[i].el == el) { 4623 animationElements[ii - 1].start = animationElements[i].start; 4624 break; 4625 } 4626 } 4627 return element; 4628 // 4629 // 4630 // var a = params ? R.animation(params, ms, easing, callback) : anim, 4631 // status = element.status(anim); 4632 // return this.animate(a).status(a, status * anim.ms / a.ms); 4633 }; 4634 function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { 4635 var cx = 3 * p1x, 4636 bx = 3 * (p2x - p1x) - cx, 4637 ax = 1 - cx - bx, 4638 cy = 3 * p1y, 4639 by = 3 * (p2y - p1y) - cy, 4640 ay = 1 - cy - by; 4641 function sampleCurveX(t) { 4642 return ((ax * t + bx) * t + cx) * t; 4643 } 4644 function solve(x, epsilon) { 4645 var t = solveCurveX(x, epsilon); 4646 return ((ay * t + by) * t + cy) * t; 4647 } 4648 function solveCurveX(x, epsilon) { 4649 var t0, t1, t2, x2, d2, i; 4650 for(t2 = x, i = 0; i < 8; i++) { 4651 x2 = sampleCurveX(t2) - x; 4652 if (abs(x2) < epsilon) { 4653 return t2; 4654 } 4655 d2 = (3 * ax * t2 + 2 * bx) * t2 + cx; 4656 if (abs(d2) < 1e-6) { 4657 break; 4658 } 4659 t2 = t2 - x2 / d2; 4660 } 4661 t0 = 0; 4662 t1 = 1; 4663 t2 = x; 4664 if (t2 < t0) { 4665 return t0; 4666 } 4667 if (t2 > t1) { 4668 return t1; 4669 } 4670 while (t0 < t1) { 4671 x2 = sampleCurveX(t2); 4672 if (abs(x2 - x) < epsilon) { 4673 return t2; 4674 } 4675 if (x > x2) { 4676 t0 = t2; 4677 } else { 4678 t1 = t2; 4679 } 4680 t2 = (t1 - t0) / 2 + t0; 4681 } 4682 return t2; 4683 } 4684 return solve(t, 1 / (200 * duration)); 4685 } 4686 elproto.onAnimation = function (f) { 4687 f ? eve.on("raphael.anim.frame." + this.id, f) : eve.unbind("raphael.anim.frame." + this.id); 4688 return this; 4689 }; 4690 function Animation(anim, ms) { 4691 var percents = [], 4692 newAnim = {}; 4693 this.ms = ms; 4694 this.times = 1; 4695 if (anim) { 4696 for (var attr in anim) if (anim[has](attr)) { 4697 newAnim[toFloat(attr)] = anim[attr]; 4698 percents.push(toFloat(attr)); 4699 } 4700 percents.sort(sortByNumber); 4701 } 4702 this.anim = newAnim; 4703 this.top = percents[percents.length - 1]; 4704 this.percents = percents; 4705 } 4706 /*\ 4707 * Animation.delay 4708 [ method ] 4709 ** 4710 * Creates a copy of existing animation object with given delay. 4711 ** 4712 > Parameters 4713 ** 4714 - delay (number) number of ms to pass between animation start and actual animation 4715 ** 4716 = (object) new altered Animation object 4717 | var anim = Raphael.animation({cx: 10, cy: 20}, 2e3); 4718 | circle1.animate(anim); // run the given animation immediately 4719 | circle2.animate(anim.delay(500)); // run the given animation after 500 ms 4720 \*/ 4721 Animation.prototype.delay = function (delay) { 4722 var a = new Animation(this.anim, this.ms); 4723 a.times = this.times; 4724 a.del = +delay || 0; 4725 return a; 4726 }; 4727 /*\ 4728 * Animation.repeat 4729 [ method ] 4730 ** 4731 * Creates a copy of existing animation object with given repetition. 4732 ** 4733 > Parameters 4734 ** 4735 - repeat (number) number iterations of animation. For infinite animation pass `Infinity` 4736 ** 4737 = (object) new altered Animation object 4738 \*/ 4739 Animation.prototype.repeat = function (times) { 4740 var a = new Animation(this.anim, this.ms); 4741 a.del = this.del; 4742 a.times = math.floor(mmax(times, 0)) || 1; 4743 return a; 4744 }; 4745 function runAnimation(anim, element, percent, status, totalOrigin, times) { 4746 percent = toFloat(percent); 4747 var params, 4748 isInAnim, 4749 isInAnimSet, 4750 percents = [], 4751 next, 4752 prev, 4753 timestamp, 4754 ms = anim.ms, 4755 from = {}, 4756 to = {}, 4757 diff = {}; 4758 if (status) { 4759 for (i = 0, ii = animationElements.length; i < ii; i++) { 4760 var e = animationElements[i]; 4761 if (e.el.id == element.id && e.anim == anim) { 4762 if (e.percent != percent) { 4763 animationElements.splice(i, 1); 4764 isInAnimSet = 1; 4765 } else { 4766 isInAnim = e; 4767 } 4768 element.attr(e.totalOrigin); 4769 break; 4770 } 4771 } 4772 } else { 4773 status = +to; // NaN 4774 } 4775 for (var i = 0, ii = anim.percents.length; i < ii; i++) { 4776 if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) { 4777 percent = anim.percents[i]; 4778 prev = anim.percents[i - 1] || 0; 4779 ms = ms / anim.top * (percent - prev); 4780 next = anim.percents[i + 1]; 4781 params = anim.anim[percent]; 4782 break; 4783 } else if (status) { 4784 element.attr(anim.anim[anim.percents[i]]); 4785 } 4786 } 4787 if (!params) { 4788 return; 4789 } 4790 if (!isInAnim) { 4791 for (var attr in params) if (params[has](attr)) { 4792 if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) { 4793 from[attr] = element.attr(attr); 4794 (from[attr] == null) && (from[attr] = availableAttrs[attr]); 4795 to[attr] = params[attr]; 4796 switch (availableAnimAttrs[attr]) { 4797 case nu: 4798 diff[attr] = (to[attr] - from[attr]) / ms; 4799 break; 4800 case "colour": 4801 from[attr] = R.getRGB(from[attr]); 4802 var toColour = R.getRGB(to[attr]); 4803 diff[attr] = { 4804 r: (toColour.r - from[attr].r) / ms, 4805 g: (toColour.g - from[attr].g) / ms, 4806 b: (toColour.b - from[attr].b) / ms 4807 }; 4808 break; 4809 case "path": 4810 var pathes = path2curve(from[attr], to[attr]), 4811 toPath = pathes[1]; 4812 from[attr] = pathes[0]; 4813 diff[attr] = []; 4814 for (i = 0, ii = from[attr].length; i < ii; i++) { 4815 diff[attr][i] = [0]; 4816 for (var j = 1, jj = from[attr][i].length; j < jj; j++) { 4817 diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; 4818 } 4819 } 4820 break; 4821 case "transform": 4822 var _ = element._, 4823 eq = equaliseTransform(_[attr], to[attr]); 4824 if (eq) { 4825 from[attr] = eq.from; 4826 to[attr] = eq.to; 4827 diff[attr] = []; 4828 diff[attr].real = true; 4829 for (i = 0, ii = from[attr].length; i < ii; i++) { 4830 diff[attr][i] = [from[attr][i][0]]; 4831 for (j = 1, jj = from[attr][i].length; j < jj; j++) { 4832 diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; 4833 } 4834 } 4835 } else { 4836 var m = (element.matrix || new Matrix), 4837 to2 = { 4838 _: {transform: _.transform}, 4839 getBBox: function () { 4840 return element.getBBox(1); 4841 } 4842 }; 4843 from[attr] = [ 4844 m.a, 4845 m.b, 4846 m.c, 4847 m.d, 4848 m.e, 4849 m.f 4850 ]; 4851 extractTransform(to2, to[attr]); 4852 to[attr] = to2._.transform; 4853 diff[attr] = [ 4854 (to2.matrix.a - m.a) / ms, 4855 (to2.matrix.b - m.b) / ms, 4856 (to2.matrix.c - m.c) / ms, 4857 (to2.matrix.d - m.d) / ms, 4858 (to2.matrix.e - m.e) / ms, 4859 (to2.matrix.f - m.f) / ms 4860 ]; 4861 // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy]; 4862 // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }}; 4863 // extractTransform(to2, to[attr]); 4864 // diff[attr] = [ 4865 // (to2._.sx - _.sx) / ms, 4866 // (to2._.sy - _.sy) / ms, 4867 // (to2._.deg - _.deg) / ms, 4868 // (to2._.dx - _.dx) / ms, 4869 // (to2._.dy - _.dy) / ms 4870 // ]; 4871 } 4872 break; 4873 case "csv": 4874 var values = Str(params[attr])[split](separator), 4875 from2 = Str(from[attr])[split](separator); 4876 if (attr == "clip-rect") { 4877 from[attr] = from2; 4878 diff[attr] = []; 4879 i = from2.length; 4880 while (i--) { 4881 diff[attr][i] = (values[i] - from[attr][i]) / ms; 4882 } 4883 } 4884 to[attr] = values; 4885 break; 4886 default: 4887 values = [][concat](params[attr]); 4888 from2 = [][concat](from[attr]); 4889 diff[attr] = []; 4890 i = element.paper.customAttributes[attr].length; 4891 while (i--) { 4892 diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms; 4893 } 4894 break; 4895 } 4896 } 4897 } 4898 var easing = params.easing, 4899 easyeasy = R.easing_formulas[easing]; 4900 if (!easyeasy) { 4901 easyeasy = Str(easing).match(bezierrg); 4902 if (easyeasy && easyeasy.length == 5) { 4903 var curve = easyeasy; 4904 easyeasy = function (t) { 4905 return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms); 4906 }; 4907 } else { 4908 easyeasy = pipe; 4909 } 4910 } 4911 timestamp = params.start || anim.start || +new Date; 4912 e = { 4913 anim: anim, 4914 percent: percent, 4915 timestamp: timestamp, 4916 start: timestamp + (anim.del || 0), 4917 status: 0, 4918 initstatus: status || 0, 4919 stop: false, 4920 ms: ms, 4921 easing: easyeasy, 4922 from: from, 4923 diff: diff, 4924 to: to, 4925 el: element, 4926 callback: params.callback, 4927 prev: prev, 4928 next: next, 4929 repeat: times || anim.times, 4930 origin: element.attr(), 4931 totalOrigin: totalOrigin 4932 }; 4933 animationElements.push(e); 4934 if (status && !isInAnim && !isInAnimSet) { 4935 e.stop = true; 4936 e.start = new Date - ms * status; 4937 if (animationElements.length == 1) { 4938 return animation(); 4939 } 4940 } 4941 if (isInAnimSet) { 4942 e.start = new Date - e.ms * status; 4943 } 4944 animationElements.length == 1 && requestAnimFrame(animation); 4945 } else { 4946 isInAnim.initstatus = status; 4947 isInAnim.start = new Date - isInAnim.ms * status; 4948 } 4949 eve("raphael.anim.start." + element.id, element, anim); 4950 } 4951 /*\ 4952 * Raphael.animation 4953 [ method ] 4954 ** 4955 * Creates an animation object that can be passed to the @Element.animate or @Element.animateWith methods. 4956 * See also @Animation.delay and @Animation.repeat methods. 4957 ** 4958 > Parameters 4959 ** 4960 - params (object) final attributes for the element, see also @Element.attr 4961 - ms (number) number of milliseconds for animation to run 4962 - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` 4963 - callback (function) #optional callback function. Will be called at the end of animation. 4964 ** 4965 = (object) @Animation 4966 \*/ 4967 R.animation = function (params, ms, easing, callback) { 4968 if (params instanceof Animation) { 4969 return params; 4970 } 4971 if (R.is(easing, "function") || !easing) { 4972 callback = callback || easing || null; 4973 easing = null; 4974 } 4975 params = Object(params); 4976 ms = +ms || 0; 4977 var p = {}, 4978 json, 4979 attr; 4980 for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) { 4981 json = true; 4982 p[attr] = params[attr]; 4983 } 4984 if (!json) { 4985 return new Animation(params, ms); 4986 } else { 4987 easing && (p.easing = easing); 4988 callback && (p.callback = callback); 4989 return new Animation({100: p}, ms); 4990 } 4991 }; 4992 /*\ 4993 * Element.animate 4994 [ method ] 4995 ** 4996 * Creates and starts animation for given element. 4997 ** 4998 > Parameters 4999 ** 5000 - params (object) final attributes for the element, see also @Element.attr 5001 - ms (number) number of milliseconds for animation to run 5002 - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` 5003 - callback (function) #optional callback function. Will be called at the end of animation. 5004 * or 5005 - animation (object) animation object, see @Raphael.animation 5006 ** 5007 = (object) original element 5008 \*/ 5009 elproto.animate = function (params, ms, easing, callback) { 5010 var element = this; 5011 if (element.removed) { 5012 callback && callback.call(element); 5013 return element; 5014 } 5015 var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback); 5016 runAnimation(anim, element, anim.percents[0], null, element.attr()); 5017 return element; 5018 }; 5019 /*\ 5020 * Element.setTime 5021 [ method ] 5022 ** 5023 * Sets the status of animation of the element in milliseconds. Similar to @Element.status method. 5024 ** 5025 > Parameters 5026 ** 5027 - anim (object) animation object 5028 - value (number) number of milliseconds from the beginning of the animation 5029 ** 5030 = (object) original element if `value` is specified 5031 * Note, that during animation following events are triggered: 5032 * 5033 * On each animation frame event `anim.frame.<id>`, on start `anim.start.<id>` and on end `anim.finish.<id>`. 5034 \*/ 5035 elproto.setTime = function (anim, value) { 5036 if (anim && value != null) { 5037 this.status(anim, mmin(value, anim.ms) / anim.ms); 5038 } 5039 return this; 5040 }; 5041 /*\ 5042 * Element.status 5043 [ method ] 5044 ** 5045 * Gets or sets the status of animation of the element. 5046 ** 5047 > Parameters 5048 ** 5049 - anim (object) #optional animation object 5050 - value (number) #optional 0 – 1. 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. 5051 ** 5052 = (number) status 5053 * or 5054 = (array) status if `anim` is not specified. Array of objects in format: 5055 o { 5056 o anim: (object) animation object 5057 o status: (number) status 5058 o } 5059 * or 5060 = (object) original element if `value` is specified 5061 \*/ 5062 elproto.status = function (anim, value) { 5063 var out = [], 5064 i = 0, 5065 len, 5066 e; 5067 if (value != null) { 5068 runAnimation(anim, this, -1, mmin(value, 1)); 5069 return this; 5070 } else { 5071 len = animationElements.length; 5072 for (; i < len; i++) { 5073 e = animationElements[i]; 5074 if (e.el.id == this.id && (!anim || e.anim == anim)) { 5075 if (anim) { 5076 return e.status; 5077 } 5078 out.push({ 5079 anim: e.anim, 5080 status: e.status 5081 }); 5082 } 5083 } 5084 if (anim) { 5085 return 0; 5086 } 5087 return out; 5088 } 5089 }; 5090 /*\ 5091 * Element.pause 5092 [ method ] 5093 ** 5094 * Stops animation of the element with ability to resume it later on. 5095 ** 5096 > Parameters 5097 ** 5098 - anim (object) #optional animation object 5099 ** 5100 = (object) original element 5101 \*/ 5102 elproto.pause = function (anim) { 5103 for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { 5104 if (eve("raphael.anim.pause." + this.id, this, animationElements[i].anim) !== false) { 5105 animationElements[i].paused = true; 5106 } 5107 } 5108 return this; 5109 }; 5110 /*\ 5111 * Element.resume 5112 [ method ] 5113 ** 5114 * Resumes animation if it was paused with @Element.pause method. 5115 ** 5116 > Parameters 5117 ** 5118 - anim (object) #optional animation object 5119 ** 5120 = (object) original element 5121 \*/ 5122 elproto.resume = function (anim) { 5123 for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { 5124 var e = animationElements[i]; 5125 if (eve("raphael.anim.resume." + this.id, this, e.anim) !== false) { 5126 delete e.paused; 5127 this.status(e.anim, e.status); 5128 } 5129 } 5130 return this; 5131 }; 5132 /*\ 5133 * Element.stop 5134 [ method ] 5135 ** 5136 * Stops animation of the element. 5137 ** 5138 > Parameters 5139 ** 5140 - anim (object) #optional animation object 5141 ** 5142 = (object) original element 5143 \*/ 5144 elproto.stop = function (anim) { 5145 for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { 5146 if (eve("raphael.anim.stop." + this.id, this, animationElements[i].anim) !== false) { 5147 animationElements.splice(i--, 1); 5148 } 5149 } 5150 return this; 5151 }; 5152 function stopAnimation(paper) { 5153 for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.paper == paper) { 5154 animationElements.splice(i--, 1); 5155 } 5156 } 5157 eve.on("raphael.remove", stopAnimation); 5158 eve.on("raphael.clear", stopAnimation); 5159 elproto.toString = function () { 5160 return "Rapha\xebl\u2019s object"; 5161 }; 5162 5163 // Set 5164 var Set = function (items) { 5165 this.items = []; 5166 this.length = 0; 5167 this.type = "set"; 5168 if (items) { 5169 for (var i = 0, ii = items.length; i < ii; i++) { 5170 if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) { 5171 this[this.items.length] = this.items[this.items.length] = items[i]; 5172 this.length++; 5173 } 5174 } 5175 } 5176 }, 5177 setproto = Set.prototype; 5178 /*\ 5179 * Set.push 5180 [ method ] 5181 ** 5182 * Adds each argument to the current set. 5183 = (object) original element 5184 \*/ 5185 setproto.push = function () { 5186 var item, 5187 len; 5188 for (var i = 0, ii = arguments.length; i < ii; i++) { 5189 item = arguments[i]; 5190 if (item && (item.constructor == elproto.constructor || item.constructor == Set)) { 5191 len = this.items.length; 5192 this[len] = this.items[len] = item; 5193 this.length++; 5194 } 5195 } 5196 return this; 5197 }; 5198 /*\ 5199 * Set.pop 5200 [ method ] 5201 ** 5202 * Removes last element and returns it. 5203 = (object) element 5204 \*/ 5205 setproto.pop = function () { 5206 this.length && delete this[this.length--]; 5207 return this.items.pop(); 5208 }; 5209 /*\ 5210 * Set.forEach 5211 [ method ] 5212 ** 5213 * Executes given function for each element in the set. 5214 * 5215 * If function returns `false` it will stop loop running. 5216 ** 5217 > Parameters 5218 ** 5219 - callback (function) function to run 5220 - thisArg (object) context object for the callback 5221 = (object) Set object 5222 \*/ 5223 setproto.forEach = function (callback, thisArg) { 5224 for (var i = 0, ii = this.items.length; i < ii; i++) { 5225 if (callback.call(thisArg, this.items[i], i) === false) { 5226 return this; 5227 } 5228 } 5229 return this; 5230 }; 5231 for (var method in elproto) if (elproto[has](method)) { 5232 setproto[method] = (function (methodname) { 5233 return function () { 5234 var arg = arguments; 5235 return this.forEach(function (el) { 5236 el[methodname][apply](el, arg); 5237 }); 5238 }; 5239 })(method); 5240 } 5241 setproto.attr = function (name, value) { 5242 if (name && R.is(name, array) && R.is(name[0], "object")) { 5243 for (var j = 0, jj = name.length; j < jj; j++) { 5244 this.items[j].attr(name[j]); 5245 } 5246 } else { 5247 for (var i = 0, ii = this.items.length; i < ii; i++) { 5248 this.items[i].attr(name, value); 5249 } 5250 } 5251 return this; 5252 }; 5253 /*\ 5254 * Set.clear 5255 [ method ] 5256 ** 5257 * Removeds all elements from the set 5258 \*/ 5259 setproto.clear = function () { 5260 while (this.length) { 5261 this.pop(); 5262 } 5263 }; 5264 /*\ 5265 * Set.splice 5266 [ method ] 5267 ** 5268 * Removes given element from the set 5269 ** 5270 > Parameters 5271 ** 5272 - index (number) position of the deletion 5273 - count (number) number of element to remove 5274 - insertion… (object) #optional elements to insert 5275 = (object) set elements that were deleted 5276 \*/ 5277 setproto.splice = function (index, count, insertion) { 5278 index = index < 0 ? mmax(this.length + index, 0) : index; 5279 count = mmax(0, mmin(this.length - index, count)); 5280 var tail = [], 5281 todel = [], 5282 args = [], 5283 i; 5284 for (i = 2; i < arguments.length; i++) { 5285 args.push(arguments[i]); 5286 } 5287 for (i = 0; i < count; i++) { 5288 todel.push(this[index + i]); 5289 } 5290 for (; i < this.length - index; i++) { 5291 tail.push(this[index + i]); 5292 } 5293 var arglen = args.length; 5294 for (i = 0; i < arglen + tail.length; i++) { 5295 this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; 5296 } 5297 i = this.items.length = this.length -= count - arglen; 5298 while (this[i]) { 5299 delete this[i++]; 5300 } 5301 return new Set(todel); 5302 }; 5303 /*\ 5304 * Set.exclude 5305 [ method ] 5306 ** 5307 * Removes given element from the set 5308 ** 5309 > Parameters 5310 ** 5311 - element (object) element to remove 5312 = (boolean) `true` if object was found & removed from the set 5313 \*/ 5314 setproto.exclude = function (el) { 5315 for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { 5316 this.splice(i, 1); 5317 return true; 5318 } 5319 }; 5320 setproto.animate = function (params, ms, easing, callback) { 5321 (R.is(easing, "function") || !easing) && (callback = easing || null); 5322 var len = this.items.length, 5323 i = len, 5324 item, 5325 set = this, 5326 collector; 5327 if (!len) { 5328 return this; 5329 } 5330 callback && (collector = function () { 5331 !--len && callback.call(set); 5332 }); 5333 easing = R.is(easing, string) ? easing : collector; 5334 var anim = R.animation(params, ms, easing, collector); 5335 item = this.items[--i].animate(anim); 5336 while (i--) { 5337 this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim, anim); 5338 (this.items[i] && !this.items[i].removed) || len--; 5339 } 5340 return this; 5341 }; 5342 setproto.insertAfter = function (el) { 5343 var i = this.items.length; 5344 while (i--) { 5345 this.items[i].insertAfter(el); 5346 } 5347 return this; 5348 }; 5349 setproto.getBBox = function () { 5350 var x = [], 5351 y = [], 5352 x2 = [], 5353 y2 = []; 5354 for (var i = this.items.length; i--;) if (!this.items[i].removed) { 5355 var box = this.items[i].getBBox(); 5356 x.push(box.x); 5357 y.push(box.y); 5358 x2.push(box.x + box.width); 5359 y2.push(box.y + box.height); 5360 } 5361 x = mmin[apply](0, x); 5362 y = mmin[apply](0, y); 5363 x2 = mmax[apply](0, x2); 5364 y2 = mmax[apply](0, y2); 5365 return { 5366 x: x, 5367 y: y, 5368 x2: x2, 5369 y2: y2, 5370 width: x2 - x, 5371 height: y2 - y 5372 }; 5373 }; 5374 setproto.clone = function (s) { 5375 s = this.paper.set(); 5376 for (var i = 0, ii = this.items.length; i < ii; i++) { 5377 s.push(this.items[i].clone()); 5378 } 5379 return s; 5380 }; 5381 setproto.toString = function () { 5382 return "Rapha\xebl\u2018s set"; 5383 }; 5384 5385 setproto.glow = function(glowConfig) { 5386 var ret = this.paper.set(); 5387 this.forEach(function(shape, index){ 5388 var g = shape.glow(glowConfig); 5389 if(g != null){ 5390 g.forEach(function(shape2, index2){ 5391 ret.push(shape2); 5392 }); 5393 } 5394 }); 5395 return ret; 5396 }; 5397 5398 5399 /*\ 5400 * Set.isPointInside 5401 [ method ] 5402 ** 5403 * Determine if given point is inside this set’s elements 5404 ** 5405 > Parameters 5406 ** 5407 - x (number) x coordinate of the point 5408 - y (number) y coordinate of the point 5409 = (boolean) `true` if point is inside any of the set's elements 5410 \*/ 5411 setproto.isPointInside = function (x, y) { 5412 var isPointInside = false; 5413 this.forEach(function (el) { 5414 if (el.isPointInside(x, y)) { 5415 console.log('runned'); 5416 isPointInside = true; 5417 return false; // stop loop 5418 } 5419 }); 5420 return isPointInside; 5421 }; 5422 5423 /*\ 5424 * Raphael.registerFont 5425 [ method ] 5426 ** 5427 * Adds given font to the registered set of fonts for Raphaël. Should be used as an internal call from within Cufón’s font file. 5428 * Returns original parameter, so it could be used with chaining. 5429 # <a href="http://wiki.github.com/sorccu/cufon/about">More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file.</a> 5430 ** 5431 > Parameters 5432 ** 5433 - font (object) the font to register 5434 = (object) the font you passed in 5435 > Usage 5436 | Cufon.registerFont(Raphael.registerFont({…})); 5437 \*/ 5438 R.registerFont = function (font) { 5439 if (!font.face) { 5440 return font; 5441 } 5442 this.fonts = this.fonts || {}; 5443 var fontcopy = { 5444 w: font.w, 5445 face: {}, 5446 glyphs: {} 5447 }, 5448 family = font.face["font-family"]; 5449 for (var prop in font.face) if (font.face[has](prop)) { 5450 fontcopy.face[prop] = font.face[prop]; 5451 } 5452 if (this.fonts[family]) { 5453 this.fonts[family].push(fontcopy); 5454 } else { 5455 this.fonts[family] = [fontcopy]; 5456 } 5457 if (!font.svg) { 5458 fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); 5459 for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { 5460 var path = font.glyphs[glyph]; 5461 fontcopy.glyphs[glyph] = { 5462 w: path.w, 5463 k: {}, 5464 d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { 5465 return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; 5466 }) + "z" 5467 }; 5468 if (path.k) { 5469 for (var k in path.k) if (path[has](k)) { 5470 fontcopy.glyphs[glyph].k[k] = path.k[k]; 5471 } 5472 } 5473 } 5474 } 5475 return font; 5476 }; 5477 /*\ 5478 * Paper.getFont 5479 [ method ] 5480 ** 5481 * Finds font object in the registered fonts by given parameters. You could specify only one word from the font name, like “Myriad” for “Myriad Pro”. 5482 ** 5483 > Parameters 5484 ** 5485 - family (string) font family name or any word from it 5486 - weight (string) #optional font weight 5487 - style (string) #optional font style 5488 - stretch (string) #optional font stretch 5489 = (object) the font object 5490 > Usage 5491 | paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30); 5492 \*/ 5493 paperproto.getFont = function (family, weight, style, stretch) { 5494 stretch = stretch || "normal"; 5495 style = style || "normal"; 5496 weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; 5497 if (!R.fonts) { 5498 return; 5499 } 5500 var font = R.fonts[family]; 5501 if (!font) { 5502 var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); 5503 for (var fontName in R.fonts) if (R.fonts[has](fontName)) { 5504 if (name.test(fontName)) { 5505 font = R.fonts[fontName]; 5506 break; 5507 } 5508 } 5509 } 5510 var thefont; 5511 if (font) { 5512 for (var i = 0, ii = font.length; i < ii; i++) { 5513 thefont = font[i]; 5514 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { 5515 break; 5516 } 5517 } 5518 } 5519 return thefont; 5520 }; 5521 /*\ 5522 * Paper.print 5523 [ method ] 5524 ** 5525 * Creates path that represent given text written using given font at given position with given size. 5526 * Result of the method is path element that contains whole text as a separate path. 5527 ** 5528 > Parameters 5529 ** 5530 - x (number) x position of the text 5531 - y (number) y position of the text 5532 - string (string) text to print 5533 - font (object) font object, see @Paper.getFont 5534 - size (number) #optional size of the font, default is `16` 5535 - origin (string) #optional could be `"baseline"` or `"middle"`, default is `"middle"` 5536 - letter_spacing (number) #optional number in range `-1..1`, default is `0` 5537 - line_spacing (number) #optional number in range `1..3`, default is `1` 5538 = (object) resulting path element, which consist of all letters 5539 > Usage 5540 | var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"}); 5541 \*/ 5542 paperproto.print = function (x, y, string, font, size, origin, letter_spacing, line_spacing) { 5543 origin = origin || "middle"; // baseline|middle 5544 letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); 5545 line_spacing = mmax(mmin(line_spacing || 1, 3), 1); 5546 var letters = Str(string)[split](E), 5547 shift = 0, 5548 notfirst = 0, 5549 path = E, 5550 scale; 5551 R.is(font, "string") && (font = this.getFont(font)); 5552 if (font) { 5553 scale = (size || 16) / font.face["units-per-em"]; 5554 var bb = font.face.bbox[split](separator), 5555 top = +bb[0], 5556 lineHeight = bb[3] - bb[1], 5557 shifty = 0, 5558 height = +bb[1] + (origin == "baseline" ? lineHeight + (+font.face.descent) : lineHeight / 2); 5559 for (var i = 0, ii = letters.length; i < ii; i++) { 5560 if (letters[i] == "\n") { 5561 shift = 0; 5562 curr = 0; 5563 notfirst = 0; 5564 shifty += lineHeight * line_spacing; 5565 } else { 5566 var prev = notfirst && font.glyphs[letters[i - 1]] || {}, 5567 curr = font.glyphs[letters[i]]; 5568 shift += notfirst ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; 5569 notfirst = 1; 5570 } 5571 if (curr && curr.d) { 5572 path += R.transformPath(curr.d, ["t", shift * scale, shifty * scale, "s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]); 5573 } 5574 } 5575 } 5576 return this.path(path).attr({ 5577 fill: "#000", 5578 stroke: "none" 5579 }); 5580 }; 5581 5582 /*\ 5583 * Paper.add 5584 [ method ] 5585 ** 5586 * Imports elements in JSON array in format `{type: type, <attributes>}` 5587 ** 5588 > Parameters 5589 ** 5590 - json (array) 5591 = (object) resulting set of imported elements 5592 > Usage 5593 | paper.add([ 5594 | { 5595 | type: "circle", 5596 | cx: 10, 5597 | cy: 10, 5598 | r: 5 5599 | }, 5600 | { 5601 | type: "rect", 5602 | x: 10, 5603 | y: 10, 5604 | width: 10, 5605 | height: 10, 5606 | fill: "#fc0" 5607 | } 5608 | ]); 5609 \*/ 5610 paperproto.add = function (json) { 5611 if (R.is(json, "array")) { 5612 var res = this.set(), 5613 i = 0, 5614 ii = json.length, 5615 j; 5616 for (; i < ii; i++) { 5617 j = json[i] || {}; 5618 elements[has](j.type) && res.push(this[j.type]().attr(j)); 5619 } 5620 } 5621 return res; 5622 }; 5623 5624 /*\ 5625 * Raphael.format 5626 [ method ] 5627 ** 5628 * Simple format function. Replaces construction of type “`{<number>}`” to the corresponding argument. 5629 ** 5630 > Parameters 5631 ** 5632 - token (string) string to format 5633 - … (string) rest of arguments will be treated as parameters for replacement 5634 = (string) formated string 5635 > Usage 5636 | var x = 10, 5637 | y = 20, 5638 | width = 40, 5639 | height = 50; 5640 | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z" 5641 | paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width)); 5642 \*/ 5643 R.format = function (token, params) { 5644 var args = R.is(params, array) ? [0][concat](params) : arguments; 5645 token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { 5646 return args[++i] == null ? E : args[i]; 5647 })); 5648 return token || E; 5649 }; 5650 /*\ 5651 * Raphael.fullfill 5652 [ method ] 5653 ** 5654 * A little bit more advanced format function than @Raphael.format. Replaces construction of type “`{<name>}`” to the corresponding argument. 5655 ** 5656 > Parameters 5657 ** 5658 - token (string) string to format 5659 - json (object) object which properties will be used as a replacement 5660 = (string) formated string 5661 > Usage 5662 | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z" 5663 | paper.path(Raphael.fullfill("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { 5664 | x: 10, 5665 | y: 20, 5666 | dim: { 5667 | width: 40, 5668 | height: 50, 5669 | "negative width": -40 5670 | } 5671 | })); 5672 \*/ 5673 R.fullfill = (function () { 5674 var tokenRegex = /\{([^\}]+)\}/g, 5675 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties 5676 replacer = function (all, key, obj) { 5677 var res = obj; 5678 key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { 5679 name = name || quotedName; 5680 if (res) { 5681 if (name in res) { 5682 res = res[name]; 5683 } 5684 typeof res == "function" && isFunc && (res = res()); 5685 } 5686 }); 5687 res = (res == null || res == obj ? all : res) + ""; 5688 return res; 5689 }; 5690 return function (str, obj) { 5691 return String(str).replace(tokenRegex, function (all, key) { 5692 return replacer(all, key, obj); 5693 }); 5694 }; 5695 })(); 5696 /*\ 5697 * Raphael.ninja 5698 [ method ] 5699 ** 5700 * If you want to leave no trace of Raphaël (Well, Raphaël creates only one global variable `Raphael`, but anyway.) You can use `ninja` method. 5701 * Beware, that in this case plugins could stop working, because they are depending on global variable existance. 5702 ** 5703 = (object) Raphael object 5704 > Usage 5705 | (function (local_raphael) { 5706 | var paper = local_raphael(10, 10, 320, 200); 5707 | … 5708 | })(Raphael.ninja()); 5709 \*/ 5710 R.ninja = function () { 5711 oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; 5712 return R; 5713 }; 5714 /*\ 5715 * Raphael.st 5716 [ property (object) ] 5717 ** 5718 * You can add your own method to elements and sets. It is wise to add a set method for each element method 5719 * you added, so you will be able to call the same method on sets too. 5720 ** 5721 * See also @Raphael.el. 5722 > Usage 5723 | Raphael.el.red = function () { 5724 | this.attr({fill: "#f00"}); 5725 | }; 5726 | Raphael.st.red = function () { 5727 | this.forEach(function (el) { 5728 | el.red(); 5729 | }); 5730 | }; 5731 | // then use it 5732 | paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red(); 5733 \*/ 5734 R.st = setproto; 5735 // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html 5736 (function (doc, loaded, f) { 5737 if (doc.readyState == null && doc.addEventListener){ 5738 doc.addEventListener(loaded, f = function () { 5739 doc.removeEventListener(loaded, f, false); 5740 doc.readyState = "complete"; 5741 }, false); 5742 doc.readyState = "loading"; 5743 } 5744 function isLoaded() { 5745 (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("raphael.DOMload"); 5746 } 5747 isLoaded(); 5748 })(document, "DOMContentLoaded"); 5749 5750 eve.on("raphael.DOMload", function () { 5751 loaded = true; 5752 }); 5753 5754// ┌─────────────────────────────────────────────────────────────────────┐ \\ 5755// │ Raphaël - JavaScript Vector Library │ \\ 5756// ├─────────────────────────────────────────────────────────────────────┤ \\ 5757// │ SVG Module │ \\ 5758// ├─────────────────────────────────────────────────────────────────────┤ \\ 5759// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ 5760// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ 5761// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ 5762// └─────────────────────────────────────────────────────────────────────┘ \\ 5763 5764(function(){ 5765 if (!R.svg) { 5766 return; 5767 } 5768 var has = "hasOwnProperty", 5769 Str = String, 5770 toFloat = parseFloat, 5771 toInt = parseInt, 5772 math = Math, 5773 mmax = math.max, 5774 abs = math.abs, 5775 pow = math.pow, 5776 separator = /[, ]+/, 5777 eve = R.eve, 5778 E = "", 5779 S = " "; 5780 var xlink = "http://www.w3.org/1999/xlink", 5781 markers = { 5782 block: "M5,0 0,2.5 5,5z", 5783 classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", 5784 diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", 5785 open: "M6,1 1,3.5 6,6", 5786 oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" 5787 }, 5788 markerCounter = {}; 5789 R.toString = function () { 5790 return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; 5791 }; 5792 var $ = function (el, attr) { 5793 if (attr) { 5794 if (typeof el == "string") { 5795 el = $(el); 5796 } 5797 for (var key in attr) if (attr[has](key)) { 5798 if (key.substring(0, 6) == "xlink:") { 5799 el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); 5800 } else { 5801 el.setAttribute(key, Str(attr[key])); 5802 } 5803 } 5804 } else { 5805 el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el); 5806 el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); 5807 } 5808 return el; 5809 }, 5810 addGradientFill = function (element, gradient) { 5811 var type = "linear", 5812 id = element.id + gradient, 5813 fx = .5, fy = .5, 5814 o = element.node, 5815 SVG = element.paper, 5816 s = o.style, 5817 el = R._g.doc.getElementById(id); 5818 if (!el) { 5819 gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) { 5820 type = "radial"; 5821 if (_fx && _fy) { 5822 fx = toFloat(_fx); 5823 fy = toFloat(_fy); 5824 var dir = ((fy > .5) * 2 - 1); 5825 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && 5826 (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && 5827 fy != .5 && 5828 (fy = fy.toFixed(5) - 1e-5 * dir); 5829 } 5830 return E; 5831 }); 5832 gradient = gradient.split(/\s*\-\s*/); 5833 if (type == "linear") { 5834 var angle = gradient.shift(); 5835 angle = -toFloat(angle); 5836 if (isNaN(angle)) { 5837 return null; 5838 } 5839 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], 5840 max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); 5841 vector[2] *= max; 5842 vector[3] *= max; 5843 if (vector[2] < 0) { 5844 vector[0] = -vector[2]; 5845 vector[2] = 0; 5846 } 5847 if (vector[3] < 0) { 5848 vector[1] = -vector[3]; 5849 vector[3] = 0; 5850 } 5851 } 5852 var dots = R._parseDots(gradient); 5853 if (!dots) { 5854 return null; 5855 } 5856 id = id.replace(/[\(\)\s,\xb0#]/g, "_"); 5857 5858 if (element.gradient && id != element.gradient.id) { 5859 SVG.defs.removeChild(element.gradient); 5860 delete element.gradient; 5861 } 5862 5863 if (!element.gradient) { 5864 el = $(type + "Gradient", {id: id}); 5865 element.gradient = el; 5866 $(el, type == "radial" ? { 5867 fx: fx, 5868 fy: fy 5869 } : { 5870 x1: vector[0], 5871 y1: vector[1], 5872 x2: vector[2], 5873 y2: vector[3], 5874 gradientTransform: element.matrix.invert() 5875 }); 5876 SVG.defs.appendChild(el); 5877 for (var i = 0, ii = dots.length; i < ii; i++) { 5878 el.appendChild($("stop", { 5879 offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", 5880 "stop-color": dots[i].color || "#fff" 5881 })); 5882 } 5883 } 5884 } 5885 $(o, { 5886 fill: "url(#" + id + ")", 5887 opacity: 1, 5888 "fill-opacity": 1 5889 }); 5890 s.fill = E; 5891 s.opacity = 1; 5892 s.fillOpacity = 1; 5893 return 1; 5894 }, 5895 updatePosition = function (o) { 5896 var bbox = o.getBBox(1); 5897 $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); 5898 }, 5899 addArrow = function (o, value, isEnd) { 5900 if (o.type == "path") { 5901 var values = Str(value).toLowerCase().split("-"), 5902 p = o.paper, 5903 se = isEnd ? "end" : "start", 5904 node = o.node, 5905 attrs = o.attrs, 5906 stroke = attrs["stroke-width"], 5907 i = values.length, 5908 type = "classic", 5909 from, 5910 to, 5911 dx, 5912 refX, 5913 attr, 5914 w = 3, 5915 h = 3, 5916 t = 5; 5917 while (i--) { 5918 switch (values[i]) { 5919 case "block": 5920 case "classic": 5921 case "oval": 5922 case "diamond": 5923 case "open": 5924 case "none": 5925 type = values[i]; 5926 break; 5927 case "wide": h = 5; break; 5928 case "narrow": h = 2; break; 5929 case "long": w = 5; break; 5930 case "short": w = 2; break; 5931 } 5932 } 5933 if (type == "open") { 5934 w += 2; 5935 h += 2; 5936 t += 2; 5937 dx = 1; 5938 refX = isEnd ? 4 : 1; 5939 attr = { 5940 fill: "none", 5941 stroke: attrs.stroke 5942 }; 5943 } else { 5944 refX = dx = w / 2; 5945 attr = { 5946 fill: attrs.stroke, 5947 stroke: "none" 5948 }; 5949 } 5950 if (o._.arrows) { 5951 if (isEnd) { 5952 o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; 5953 o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; 5954 } else { 5955 o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; 5956 o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; 5957 } 5958 } else { 5959 o._.arrows = {}; 5960 } 5961 if (type != "none") { 5962 var pathId = "raphael-marker-" + type, 5963 markerId = "raphael-marker-" + se + type + w + h; 5964 if (!R._g.doc.getElementById(pathId)) { 5965 p.defs.appendChild($($("path"), { 5966 "stroke-linecap": "round", 5967 d: markers[type], 5968 id: pathId 5969 })); 5970 markerCounter[pathId] = 1; 5971 } else { 5972 markerCounter[pathId]++; 5973 } 5974 var marker = R._g.doc.getElementById(markerId), 5975 use; 5976 if (!marker) { 5977 marker = $($("marker"), { 5978 id: markerId, 5979 markerHeight: h, 5980 markerWidth: w, 5981 orient: "auto", 5982 refX: refX, 5983 refY: h / 2 5984 }); 5985 use = $($("use"), { 5986 "xlink:href": "#" + pathId, 5987 transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")", 5988 "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4) 5989 }); 5990 marker.appendChild(use); 5991 p.defs.appendChild(marker); 5992 markerCounter[markerId] = 1; 5993 } else { 5994 markerCounter[markerId]++; 5995 use = marker.getElementsByTagName("use")[0]; 5996 } 5997 $(use, attr); 5998 var delta = dx * (type != "diamond" && type != "oval"); 5999 if (isEnd) { 6000 from = o._.arrows.startdx * stroke || 0; 6001 to = R.getTotalLength(attrs.path) - delta * stroke; 6002 } else { 6003 from = delta * stroke; 6004 to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); 6005 } 6006 attr = {}; 6007 attr["marker-" + se] = "url(#" + markerId + ")"; 6008 if (to || from) { 6009 attr.d = R.getSubpath(attrs.path, from, to); 6010 } 6011 $(node, attr); 6012 o._.arrows[se + "Path"] = pathId; 6013 o._.arrows[se + "Marker"] = markerId; 6014 o._.arrows[se + "dx"] = delta; 6015 o._.arrows[se + "Type"] = type; 6016 o._.arrows[se + "String"] = value; 6017 } else { 6018 if (isEnd) { 6019 from = o._.arrows.startdx * stroke || 0; 6020 to = R.getTotalLength(attrs.path) - from; 6021 } else { 6022 from = 0; 6023 to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); 6024 } 6025 o._.arrows[se + "Path"] && $(node, {d: R.getSubpath(attrs.path, from, to)}); 6026 delete o._.arrows[se + "Path"]; 6027 delete o._.arrows[se + "Marker"]; 6028 delete o._.arrows[se + "dx"]; 6029 delete o._.arrows[se + "Type"]; 6030 delete o._.arrows[se + "String"]; 6031 } 6032 for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { 6033 var item = R._g.doc.getElementById(attr); 6034 item && item.parentNode.removeChild(item); 6035 } 6036 } 6037 }, 6038 dasharray = { 6039 "": [0], 6040 "none": [0], 6041 "-": [3, 1], 6042 ".": [1, 1], 6043 "-.": [3, 1, 1, 1], 6044 "-..": [3, 1, 1, 1, 1, 1], 6045 ". ": [1, 3], 6046 "- ": [4, 3], 6047 "--": [8, 3], 6048 "- .": [4, 3, 1, 3], 6049 "--.": [8, 3, 1, 3], 6050 "--..": [8, 3, 1, 3, 1, 3] 6051 }, 6052 addDashes = function (o, value, params) { 6053 value = dasharray[Str(value).toLowerCase()]; 6054 if (value) { 6055 var width = o.attrs["stroke-width"] || "1", 6056 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, 6057 dashes = [], 6058 i = value.length; 6059 while (i--) { 6060 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; 6061 } 6062 $(o.node, {"stroke-dasharray": dashes.join(",")}); 6063 } 6064 }, 6065 setFillAndStroke = function (o, params) { 6066 var node = o.node, 6067 attrs = o.attrs, 6068 vis = node.style.visibility; 6069 node.style.visibility = "hidden"; 6070 for (var att in params) { 6071 if (params[has](att)) { 6072 if (!R._availableAttrs[has](att)) { 6073 continue; 6074 } 6075 var value = params[att]; 6076 attrs[att] = value; 6077 switch (att) { 6078 case "blur": 6079 o.blur(value); 6080 break; 6081 case "href": 6082 case "title": 6083 var hl = $("title"); 6084 var val = R._g.doc.createTextNode(value); 6085 hl.appendChild(val); 6086 node.appendChild(hl); 6087 break; 6088 case "target": 6089 var pn = node.parentNode; 6090 if (pn.tagName.toLowerCase() != "a") { 6091 var hl = $("a"); 6092 pn.insertBefore(hl, node); 6093 hl.appendChild(node); 6094 pn = hl; 6095 } 6096 if (att == "target") { 6097 pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value); 6098 } else { 6099 pn.setAttributeNS(xlink, att, value); 6100 } 6101 break; 6102 case "cursor": 6103 node.style.cursor = value; 6104 break; 6105 case "transform": 6106 o.transform(value); 6107 break; 6108 case "arrow-start": 6109 addArrow(o, value); 6110 break; 6111 case "arrow-end": 6112 addArrow(o, value, 1); 6113 break; 6114 case "clip-rect": 6115 var rect = Str(value).split(separator); 6116 if (rect.length == 4) { 6117 o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); 6118 var el = $("clipPath"), 6119 rc = $("rect"); 6120 el.id = R.createUUID(); 6121 $(rc, { 6122 x: rect[0], 6123 y: rect[1], 6124 width: rect[2], 6125 height: rect[3] 6126 }); 6127 el.appendChild(rc); 6128 o.paper.defs.appendChild(el); 6129 $(node, {"clip-path": "url(#" + el.id + ")"}); 6130 o.clip = rc; 6131 } 6132 if (!value) { 6133 var path = node.getAttribute("clip-path"); 6134 if (path) { 6135 var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E)); 6136 clip && clip.parentNode.removeChild(clip); 6137 $(node, {"clip-path": E}); 6138 delete o.clip; 6139 } 6140 } 6141 break; 6142 case "path": 6143 if (o.type == "path") { 6144 $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"}); 6145 o._.dirty = 1; 6146 if (o._.arrows) { 6147 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 6148 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 6149 } 6150 } 6151 break; 6152 case "width": 6153 node.setAttribute(att, value); 6154 o._.dirty = 1; 6155 if (attrs.fx) { 6156 att = "x"; 6157 value = attrs.x; 6158 } else { 6159 break; 6160 } 6161 case "x": 6162 if (attrs.fx) { 6163 value = -attrs.x - (attrs.width || 0); 6164 } 6165 case "rx": 6166 if (att == "rx" && o.type == "rect") { 6167 break; 6168 } 6169 case "cx": 6170 node.setAttribute(att, value); 6171 o.pattern && updatePosition(o); 6172 o._.dirty = 1; 6173 break; 6174 case "height": 6175 node.setAttribute(att, value); 6176 o._.dirty = 1; 6177 if (attrs.fy) { 6178 att = "y"; 6179 value = attrs.y; 6180 } else { 6181 break; 6182 } 6183 case "y": 6184 if (attrs.fy) { 6185 value = -attrs.y - (attrs.height || 0); 6186 } 6187 case "ry": 6188 if (att == "ry" && o.type == "rect") { 6189 break; 6190 } 6191 case "cy": 6192 node.setAttribute(att, value); 6193 o.pattern && updatePosition(o); 6194 o._.dirty = 1; 6195 break; 6196 case "r": 6197 if (o.type == "rect") { 6198 $(node, {rx: value, ry: value}); 6199 } else { 6200 node.setAttribute(att, value); 6201 } 6202 o._.dirty = 1; 6203 break; 6204 case "src": 6205 if (o.type == "image") { 6206 node.setAttributeNS(xlink, "href", value); 6207 } 6208 break; 6209 case "stroke-width": 6210 if (o._.sx != 1 || o._.sy != 1) { 6211 value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; 6212 } 6213 if (o.paper._vbSize) { 6214 value *= o.paper._vbSize; 6215 } 6216 node.setAttribute(att, value); 6217 if (attrs["stroke-dasharray"]) { 6218 addDashes(o, attrs["stroke-dasharray"], params); 6219 } 6220 if (o._.arrows) { 6221 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 6222 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 6223 } 6224 break; 6225 case "stroke-dasharray": 6226 addDashes(o, value, params); 6227 break; 6228 case "fill": 6229 var isURL = Str(value).match(R._ISURL); 6230 if (isURL) { 6231 el = $("pattern"); 6232 var ig = $("image"); 6233 el.id = R.createUUID(); 6234 $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); 6235 $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); 6236 el.appendChild(ig); 6237 6238 (function (el) { 6239 R._preload(isURL[1], function () { 6240 var w = this.offsetWidth, 6241 h = this.offsetHeight; 6242 $(el, {width: w, height: h}); 6243 $(ig, {width: w, height: h}); 6244 o.paper.safari(); 6245 }); 6246 })(el); 6247 o.paper.defs.appendChild(el); 6248 $(node, {fill: "url(#" + el.id + ")"}); 6249 o.pattern = el; 6250 o.pattern && updatePosition(o); 6251 break; 6252 } 6253 var clr = R.getRGB(value); 6254 if (!clr.error) { 6255 delete params.gradient; 6256 delete attrs.gradient; 6257 !R.is(attrs.opacity, "undefined") && 6258 R.is(params.opacity, "undefined") && 6259 $(node, {opacity: attrs.opacity}); 6260 !R.is(attrs["fill-opacity"], "undefined") && 6261 R.is(params["fill-opacity"], "undefined") && 6262 $(node, {"fill-opacity": attrs["fill-opacity"]}); 6263 } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { 6264 if ("opacity" in attrs || "fill-opacity" in attrs) { 6265 var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); 6266 if (gradient) { 6267 var stops = gradient.getElementsByTagName("stop"); 6268 $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); 6269 } 6270 } 6271 attrs.gradient = value; 6272 attrs.fill = "none"; 6273 break; 6274 } 6275 clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); 6276 case "stroke": 6277 clr = R.getRGB(value); 6278 node.setAttribute(att, clr.hex); 6279 att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); 6280 if (att == "stroke" && o._.arrows) { 6281 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 6282 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 6283 } 6284 break; 6285 case "gradient": 6286 (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); 6287 break; 6288 case "opacity": 6289 if (attrs.gradient && !attrs[has]("stroke-opacity")) { 6290 $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); 6291 } 6292 // fall 6293 case "fill-opacity": 6294 if (attrs.gradient) { 6295 gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); 6296 if (gradient) { 6297 stops = gradient.getElementsByTagName("stop"); 6298 $(stops[stops.length - 1], {"stop-opacity": value}); 6299 } 6300 break; 6301 } 6302 default: 6303 att == "font-size" && (value = toInt(value, 10) + "px"); 6304 var cssrule = att.replace(/(\-.)/g, function (w) { 6305 return w.substring(1).toUpperCase(); 6306 }); 6307 node.style[cssrule] = value; 6308 o._.dirty = 1; 6309 node.setAttribute(att, value); 6310 break; 6311 } 6312 } 6313 } 6314 6315 tuneText(o, params); 6316 node.style.visibility = vis; 6317 }, 6318 leading = 1.2, 6319 tuneText = function (el, params) { 6320 if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { 6321 return; 6322 } 6323 var a = el.attrs, 6324 node = el.node, 6325 fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; 6326 6327 if (params[has]("text")) { 6328 a.text = params.text; 6329 while (node.firstChild) { 6330 node.removeChild(node.firstChild); 6331 } 6332 var texts = Str(params.text).split("\n"), 6333 tspans = [], 6334 tspan; 6335 for (var i = 0, ii = texts.length; i < ii; i++) { 6336 tspan = $("tspan"); 6337 i && $(tspan, {dy: fontSize * leading, x: a.x}); 6338 tspan.appendChild(R._g.doc.createTextNode(texts[i])); 6339 node.appendChild(tspan); 6340 tspans[i] = tspan; 6341 } 6342 } else { 6343 tspans = node.getElementsByTagName("tspan"); 6344 for (i = 0, ii = tspans.length; i < ii; i++) if (i) { 6345 $(tspans[i], {dy: fontSize * leading, x: a.x}); 6346 } else { 6347 $(tspans[0], {dy: 0}); 6348 } 6349 } 6350 $(node, {x: a.x, y: a.y}); 6351 el._.dirty = 1; 6352 var bb = el._getBBox(), 6353 dif = a.y - (bb.y + bb.height / 2); 6354 dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); 6355 }, 6356 Element = function (node, svg) { 6357 var X = 0, 6358 Y = 0; 6359 /*\ 6360 * Element.node 6361 [ property (object) ] 6362 ** 6363 * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. 6364 ** 6365 * Note: Don’t mess with it. 6366 > Usage 6367 | // draw a circle at coordinate 10,10 with radius of 10 6368 | var c = paper.circle(10, 10, 10); 6369 | c.node.onclick = function () { 6370 | c.attr("fill", "red"); 6371 | }; 6372 \*/ 6373 this[0] = this.node = node; 6374 /*\ 6375 * Element.raphael 6376 [ property (object) ] 6377 ** 6378 * Internal reference to @Raphael object. In case it is not available. 6379 > Usage 6380 | Raphael.el.red = function () { 6381 | var hsb = this.paper.raphael.rgb2hsb(this.attr("fill")); 6382 | hsb.h = 1; 6383 | this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex}); 6384 | } 6385 \*/ 6386 node.raphael = true; 6387 /*\ 6388 * Element.id 6389 [ property (number) ] 6390 ** 6391 * Unique id of the element. Especially usesful when you want to listen to events of the element, 6392 * because all events are fired in format `<module>.<action>.<id>`. Also useful for @Paper.getById method. 6393 \*/ 6394 this.id = R._oid++; 6395 node.raphaelid = this.id; 6396 this.matrix = R.matrix(); 6397 this.realPath = null; 6398 /*\ 6399 * Element.paper 6400 [ property (object) ] 6401 ** 6402 * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions. 6403 > Usage 6404 | Raphael.el.cross = function () { 6405 | this.attr({fill: "red"}); 6406 | this.paper.path("M10,10L50,50M50,10L10,50") 6407 | .attr({stroke: "red"}); 6408 | } 6409 \*/ 6410 this.paper = svg; 6411 this.attrs = this.attrs || {}; 6412 this._ = { 6413 transform: [], 6414 sx: 1, 6415 sy: 1, 6416 deg: 0, 6417 dx: 0, 6418 dy: 0, 6419 dirty: 1 6420 }; 6421 !svg.bottom && (svg.bottom = this); 6422 /*\ 6423 * Element.prev 6424 [ property (object) ] 6425 ** 6426 * Reference to the previous element in the hierarchy. 6427 \*/ 6428 this.prev = svg.top; 6429 svg.top && (svg.top.next = this); 6430 svg.top = this; 6431 /*\ 6432 * Element.next 6433 [ property (object) ] 6434 ** 6435 * Reference to the next element in the hierarchy. 6436 \*/ 6437 this.next = null; 6438 }, 6439 elproto = R.el; 6440 6441 Element.prototype = elproto; 6442 elproto.constructor = Element; 6443 6444 R._engine.path = function (pathString, SVG) { 6445 var el = $("path"); 6446 SVG.canvas && SVG.canvas.appendChild(el); 6447 var p = new Element(el, SVG); 6448 p.type = "path"; 6449 setFillAndStroke(p, { 6450 fill: "none", 6451 stroke: "#000", 6452 path: pathString 6453 }); 6454 return p; 6455 }; 6456 /*\ 6457 * Element.rotate 6458 [ method ] 6459 ** 6460 * Deprecated! Use @Element.transform instead. 6461 * Adds rotation by given angle around given point to the list of 6462 * transformations of the element. 6463 > Parameters 6464 - deg (number) angle in degrees 6465 - cx (number) #optional x coordinate of the centre of rotation 6466 - cy (number) #optional y coordinate of the centre of rotation 6467 * If cx & cy aren’t specified centre of the shape is used as a point of rotation. 6468 = (object) @Element 6469 \*/ 6470 elproto.rotate = function (deg, cx, cy) { 6471 if (this.removed) { 6472 return this; 6473 } 6474 deg = Str(deg).split(separator); 6475 if (deg.length - 1) { 6476 cx = toFloat(deg[1]); 6477 cy = toFloat(deg[2]); 6478 } 6479 deg = toFloat(deg[0]); 6480 (cy == null) && (cx = cy); 6481 if (cx == null || cy == null) { 6482 var bbox = this.getBBox(1); 6483 cx = bbox.x + bbox.width / 2; 6484 cy = bbox.y + bbox.height / 2; 6485 } 6486 this.transform(this._.transform.concat([["r", deg, cx, cy]])); 6487 return this; 6488 }; 6489 /*\ 6490 * Element.scale 6491 [ method ] 6492 ** 6493 * Deprecated! Use @Element.transform instead. 6494 * Adds scale by given amount relative to given point to the list of 6495 * transformations of the element. 6496 > Parameters 6497 - sx (number) horisontal scale amount 6498 - sy (number) vertical scale amount 6499 - cx (number) #optional x coordinate of the centre of scale 6500 - cy (number) #optional y coordinate of the centre of scale 6501 * If cx & cy aren’t specified centre of the shape is used instead. 6502 = (object) @Element 6503 \*/ 6504 elproto.scale = function (sx, sy, cx, cy) { 6505 if (this.removed) { 6506 return this; 6507 } 6508 sx = Str(sx).split(separator); 6509 if (sx.length - 1) { 6510 sy = toFloat(sx[1]); 6511 cx = toFloat(sx[2]); 6512 cy = toFloat(sx[3]); 6513 } 6514 sx = toFloat(sx[0]); 6515 (sy == null) && (sy = sx); 6516 (cy == null) && (cx = cy); 6517 if (cx == null || cy == null) { 6518 var bbox = this.getBBox(1); 6519 } 6520 cx = cx == null ? bbox.x + bbox.width / 2 : cx; 6521 cy = cy == null ? bbox.y + bbox.height / 2 : cy; 6522 this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); 6523 return this; 6524 }; 6525 /*\ 6526 * Element.translate 6527 [ method ] 6528 ** 6529 * Deprecated! Use @Element.transform instead. 6530 * Adds translation by given amount to the list of transformations of the element. 6531 > Parameters 6532 - dx (number) horisontal shift 6533 - dy (number) vertical shift 6534 = (object) @Element 6535 \*/ 6536 elproto.translate = function (dx, dy) { 6537 if (this.removed) { 6538 return this; 6539 } 6540 dx = Str(dx).split(separator); 6541 if (dx.length - 1) { 6542 dy = toFloat(dx[1]); 6543 } 6544 dx = toFloat(dx[0]) || 0; 6545 dy = +dy || 0; 6546 this.transform(this._.transform.concat([["t", dx, dy]])); 6547 return this; 6548 }; 6549 /*\ 6550 * Element.transform 6551 [ method ] 6552 ** 6553 * Adds transformation to the element which is separate to other attributes, 6554 * i.e. translation doesn’t change `x` or `y` of the rectange. The format 6555 * of transformation string is similar to the path string syntax: 6556 | "t100,100r30,100,100s2,2,100,100r45s1.5" 6557 * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for 6558 * scale and `m` is for matrix. 6559 * 6560 * There are also alternative “absolute” translation, rotation and scale: `T`, `R` and `S`. They will not take previous transformation into account. For example, `...T100,0` will always move element 100 px horisontally, while `...t100,0` could move it vertically if there is `r90` before. Just compare results of `r90t100,0` and `r90T100,0`. 6561 * 6562 * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100; 6563 * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin 6564 * coordinates as optional parameters, the default is the centre point of the element. 6565 * Matrix accepts six parameters. 6566 > Usage 6567 | var el = paper.rect(10, 20, 300, 200); 6568 | // translate 100, 100, rotate 45°, translate -100, 0 6569 | el.transform("t100,100r45t-100,0"); 6570 | // if you want you can append or prepend transformations 6571 | el.transform("...t50,50"); 6572 | el.transform("s2..."); 6573 | // or even wrap 6574 | el.transform("t50,50...t-50-50"); 6575 | // to reset transformation call method with empty string 6576 | el.transform(""); 6577 | // to get current value call it without parameters 6578 | console.log(el.transform()); 6579 > Parameters 6580 - tstr (string) #optional transformation string 6581 * If tstr isn’t specified 6582 = (string) current transformation string 6583 * else 6584 = (object) @Element 6585 \*/ 6586 elproto.transform = function (tstr) { 6587 var _ = this._; 6588 if (tstr == null) { 6589 return _.transform; 6590 } 6591 R._extractTransform(this, tstr); 6592 6593 this.clip && $(this.clip, {transform: this.matrix.invert()}); 6594 this.pattern && updatePosition(this); 6595 this.node && $(this.node, {transform: this.matrix}); 6596 6597 if (_.sx != 1 || _.sy != 1) { 6598 var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; 6599 this.attr({"stroke-width": sw}); 6600 } 6601 6602 return this; 6603 }; 6604 /*\ 6605 * Element.hide 6606 [ method ] 6607 ** 6608 * Makes element invisible. See @Element.show. 6609 = (object) @Element 6610 \*/ 6611 elproto.hide = function () { 6612 !this.removed && this.paper.safari(this.node.style.display = "none"); 6613 return this; 6614 }; 6615 /*\ 6616 * Element.show 6617 [ method ] 6618 ** 6619 * Makes element visible. See @Element.hide. 6620 = (object) @Element 6621 \*/ 6622 elproto.show = function () { 6623 !this.removed && this.paper.safari(this.node.style.display = ""); 6624 return this; 6625 }; 6626 /*\ 6627 * Element.remove 6628 [ method ] 6629 ** 6630 * Removes element from the paper. 6631 \*/ 6632 elproto.remove = function () { 6633 if (this.removed || !this.node.parentNode) { 6634 return; 6635 } 6636 var paper = this.paper; 6637 paper.__set__ && paper.__set__.exclude(this); 6638 eve.unbind("raphael.*.*." + this.id); 6639 if (this.gradient) { 6640 paper.defs.removeChild(this.gradient); 6641 } 6642 R._tear(this, paper); 6643 if (this.node.parentNode.tagName.toLowerCase() == "a") { 6644 this.node.parentNode.parentNode.removeChild(this.node.parentNode); 6645 } else { 6646 this.node.parentNode.removeChild(this.node); 6647 } 6648 for (var i in this) { 6649 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 6650 } 6651 this.removed = true; 6652 }; 6653 elproto._getBBox = function () { 6654 if (this.node.style.display == "none") { 6655 this.show(); 6656 var hide = true; 6657 } 6658 var bbox = {}; 6659 try { 6660 bbox = this.node.getBBox(); 6661 } catch(e) { 6662 // Firefox 3.0.x plays badly here 6663 } finally { 6664 bbox = bbox || {}; 6665 } 6666 hide && this.hide(); 6667 return bbox; 6668 }; 6669 /*\ 6670 * Element.attr 6671 [ method ] 6672 ** 6673 * Sets the attributes of the element. 6674 > Parameters 6675 - attrName (string) attribute’s name 6676 - value (string) value 6677 * or 6678 - params (object) object of name/value pairs 6679 * or 6680 - attrName (string) attribute’s name 6681 * or 6682 - attrNames (array) in this case method returns array of current values for given attribute names 6683 = (object) @Element if attrsName & value or params are passed in. 6684 = (...) value of the attribute if only attrsName is passed in. 6685 = (array) array of values of the attribute if attrsNames is passed in. 6686 = (object) object of attributes if nothing is passed in. 6687 > Possible parameters 6688 # <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> 6689 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`, `medium`, length: `long`, `short`, `midium`. 6690 o clip-rect (string) comma or space separated values: x, y, width and height 6691 o cursor (string) CSS type of the cursor 6692 o cx (number) the x-axis coordinate of the center of the circle, or ellipse 6693 o cy (number) the y-axis coordinate of the center of the circle, or ellipse 6694 o fill (string) colour, gradient or image 6695 o fill-opacity (number) 6696 o font (string) 6697 o font-family (string) 6698 o font-size (number) font size in pixels 6699 o font-weight (string) 6700 o height (number) 6701 o href (string) URL, if specified element behaves as hyperlink 6702 o opacity (number) 6703 o path (string) SVG path string format 6704 o r (number) radius of the circle, ellipse or rounded corner on the rect 6705 o rx (number) horisontal radius of the ellipse 6706 o ry (number) vertical radius of the ellipse 6707 o src (string) image URL, only works for @Element.image element 6708 o stroke (string) stroke colour 6709 o stroke-dasharray (string) [“”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”] 6710 o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”] 6711 o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”] 6712 o stroke-miterlimit (number) 6713 o stroke-opacity (number) 6714 o stroke-width (number) stroke width in pixels, default is '1' 6715 o target (string) used with href 6716 o text (string) contents of the text element. Use `\n` for multiline text 6717 o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`” 6718 o title (string) will create tooltip with a given text 6719 o transform (string) see @Element.transform 6720 o width (number) 6721 o x (number) 6722 o y (number) 6723 > Gradients 6724 * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90° 6725 * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black. 6726 * 6727 * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” – 6728 * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point 6729 * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses. 6730 > Path String 6731 # <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> 6732 > Colour Parsing 6733 # <ul> 6734 # <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li> 6735 # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li> 6736 # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li> 6737 # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200, 100, 0)</code>”)</li> 6738 # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li> 6739 # <li>rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“<code>rgba(200, 100, 0, .5)</code>”)</li> 6740 # <li>rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“<code>rgba(100%, 175%, 0%, 50%)</code>”)</li> 6741 # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5, 0.25, 1)</code>”)</li> 6742 # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> 6743 # <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li> 6744 # <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> 6745 # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> 6746 # <li>hsla(•••, •••, •••, •••) — same as above, but with opacity</li> 6747 # <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> 6748 # </ul> 6749 \*/ 6750 elproto.attr = function (name, value) { 6751 if (this.removed) { 6752 return this; 6753 } 6754 if (name == null) { 6755 var res = {}; 6756 for (var a in this.attrs) if (this.attrs[has](a)) { 6757 res[a] = this.attrs[a]; 6758 } 6759 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; 6760 res.transform = this._.transform; 6761 return res; 6762 } 6763 if (value == null && R.is(name, "string")) { 6764 if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { 6765 return this.attrs.gradient; 6766 } 6767 if (name == "transform") { 6768 return this._.transform; 6769 } 6770 var names = name.split(separator), 6771 out = {}; 6772 for (var i = 0, ii = names.length; i < ii; i++) { 6773 name = names[i]; 6774 if (name in this.attrs) { 6775 out[name] = this.attrs[name]; 6776 } else if (R.is(this.paper.customAttributes[name], "function")) { 6777 out[name] = this.paper.customAttributes[name].def; 6778 } else { 6779 out[name] = R._availableAttrs[name]; 6780 } 6781 } 6782 return ii - 1 ? out : out[names[0]]; 6783 } 6784 if (value == null && R.is(name, "array")) { 6785 out = {}; 6786 for (i = 0, ii = name.length; i < ii; i++) { 6787 out[name[i]] = this.attr(name[i]); 6788 } 6789 return out; 6790 } 6791 if (value != null) { 6792 var params = {}; 6793 params[name] = value; 6794 } else if (name != null && R.is(name, "object")) { 6795 params = name; 6796 } 6797 for (var key in params) { 6798 eve("raphael.attr." + key + "." + this.id, this, params[key]); 6799 } 6800 for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { 6801 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); 6802 this.attrs[key] = params[key]; 6803 for (var subkey in par) if (par[has](subkey)) { 6804 params[subkey] = par[subkey]; 6805 } 6806 } 6807 setFillAndStroke(this, params); 6808 return this; 6809 }; 6810 /*\ 6811 * Element.toFront 6812 [ method ] 6813 ** 6814 * Moves the element so it is the closest to the viewer’s eyes, on top of other elements. 6815 = (object) @Element 6816 \*/ 6817 elproto.toFront = function () { 6818 if (this.removed) { 6819 return this; 6820 } 6821 if (this.node.parentNode.tagName.toLowerCase() == "a") { 6822 this.node.parentNode.parentNode.appendChild(this.node.parentNode); 6823 } else { 6824 this.node.parentNode.appendChild(this.node); 6825 } 6826 var svg = this.paper; 6827 svg.top != this && R._tofront(this, svg); 6828 return this; 6829 }; 6830 /*\ 6831 * Element.toBack 6832 [ method ] 6833 ** 6834 * Moves the element so it is the furthest from the viewer’s eyes, behind other elements. 6835 = (object) @Element 6836 \*/ 6837 elproto.toBack = function () { 6838 if (this.removed) { 6839 return this; 6840 } 6841 var parent = this.node.parentNode; 6842 if (parent.tagName.toLowerCase() == "a") { 6843 parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild); 6844 } else if (parent.firstChild != this.node) { 6845 parent.insertBefore(this.node, this.node.parentNode.firstChild); 6846 } 6847 R._toback(this, this.paper); 6848 var svg = this.paper; 6849 return this; 6850 }; 6851 /*\ 6852 * Element.insertAfter 6853 [ method ] 6854 ** 6855 * Inserts current object after the given one. 6856 = (object) @Element 6857 \*/ 6858 elproto.insertAfter = function (element) { 6859 if (this.removed) { 6860 return this; 6861 } 6862 var node = element.node || element[element.length - 1].node; 6863 if (node.nextSibling) { 6864 node.parentNode.insertBefore(this.node, node.nextSibling); 6865 } else { 6866 node.parentNode.appendChild(this.node); 6867 } 6868 R._insertafter(this, element, this.paper); 6869 return this; 6870 }; 6871 /*\ 6872 * Element.insertBefore 6873 [ method ] 6874 ** 6875 * Inserts current object before the given one. 6876 = (object) @Element 6877 \*/ 6878 elproto.insertBefore = function (element) { 6879 if (this.removed) { 6880 return this; 6881 } 6882 var node = element.node || element[0].node; 6883 node.parentNode.insertBefore(this.node, node); 6884 R._insertbefore(this, element, this.paper); 6885 return this; 6886 }; 6887 elproto.blur = function (size) { 6888 // Experimental. No Safari support. Use it on your own risk. 6889 var t = this; 6890 if (+size !== 0) { 6891 var fltr = $("filter"), 6892 blur = $("feGaussianBlur"); 6893 t.attrs.blur = size; 6894 fltr.id = R.createUUID(); 6895 $(blur, {stdDeviation: +size || 1.5}); 6896 fltr.appendChild(blur); 6897 t.paper.defs.appendChild(fltr); 6898 t._blur = fltr; 6899 $(t.node, {filter: "url(#" + fltr.id + ")"}); 6900 } else { 6901 if (t._blur) { 6902 t._blur.parentNode.removeChild(t._blur); 6903 delete t._blur; 6904 delete t.attrs.blur; 6905 } 6906 t.node.removeAttribute("filter"); 6907 } 6908 return t; 6909 }; 6910 R._engine.circle = function (svg, x, y, r) { 6911 var el = $("circle"); 6912 svg.canvas && svg.canvas.appendChild(el); 6913 var res = new Element(el, svg); 6914 res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; 6915 res.type = "circle"; 6916 $(el, res.attrs); 6917 return res; 6918 }; 6919 R._engine.rect = function (svg, x, y, w, h, r) { 6920 var el = $("rect"); 6921 svg.canvas && svg.canvas.appendChild(el); 6922 var res = new Element(el, svg); 6923 res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; 6924 res.type = "rect"; 6925 $(el, res.attrs); 6926 return res; 6927 }; 6928 R._engine.ellipse = function (svg, x, y, rx, ry) { 6929 var el = $("ellipse"); 6930 svg.canvas && svg.canvas.appendChild(el); 6931 var res = new Element(el, svg); 6932 res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; 6933 res.type = "ellipse"; 6934 $(el, res.attrs); 6935 return res; 6936 }; 6937 R._engine.image = function (svg, src, x, y, w, h) { 6938 var el = $("image"); 6939 $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); 6940 el.setAttributeNS(xlink, "href", src); 6941 svg.canvas && svg.canvas.appendChild(el); 6942 var res = new Element(el, svg); 6943 res.attrs = {x: x, y: y, width: w, height: h, src: src}; 6944 res.type = "image"; 6945 return res; 6946 }; 6947 R._engine.text = function (svg, x, y, text) { 6948 var el = $("text"); 6949 svg.canvas && svg.canvas.appendChild(el); 6950 var res = new Element(el, svg); 6951 res.attrs = { 6952 x: x, 6953 y: y, 6954 "text-anchor": "middle", 6955 text: text, 6956 font: R._availableAttrs.font, 6957 stroke: "none", 6958 fill: "#000" 6959 }; 6960 res.type = "text"; 6961 setFillAndStroke(res, res.attrs); 6962 return res; 6963 }; 6964 R._engine.setSize = function (width, height) { 6965 this.width = width || this.width; 6966 this.height = height || this.height; 6967 this.canvas.setAttribute("width", this.width); 6968 this.canvas.setAttribute("height", this.height); 6969 if (this._viewBox) { 6970 this.setViewBox.apply(this, this._viewBox); 6971 } 6972 return this; 6973 }; 6974 R._engine.create = function () { 6975 var con = R._getContainer.apply(0, arguments), 6976 container = con && con.container, 6977 x = con.x, 6978 y = con.y, 6979 width = con.width, 6980 height = con.height; 6981 if (!container) { 6982 throw new Error("SVG container not found."); 6983 } 6984 var cnvs = $("svg"), 6985 css = "overflow:hidden;", 6986 isFloating; 6987 x = x || 0; 6988 y = y || 0; 6989 width = width || 512; 6990 height = height || 342; 6991 $(cnvs, { 6992 height: height, 6993 version: 1.1, 6994 width: width, 6995 xmlns: "http://www.w3.org/2000/svg" 6996 }); 6997 if (container == 1) { 6998 cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; 6999 R._g.doc.body.appendChild(cnvs); 7000 isFloating = 1; 7001 } else { 7002 cnvs.style.cssText = css + "position:relative"; 7003 if (container.firstChild) { 7004 container.insertBefore(cnvs, container.firstChild); 7005 } else { 7006 container.appendChild(cnvs); 7007 } 7008 } 7009 container = new R._Paper; 7010 container.width = width; 7011 container.height = height; 7012 container.canvas = cnvs; 7013 container.clear(); 7014 container._left = container._top = 0; 7015 isFloating && (container.renderfix = function () {}); 7016 container.renderfix(); 7017 return container; 7018 }; 7019 R._engine.setViewBox = function (x, y, w, h, fit) { 7020 eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]); 7021 var size = mmax(w / this.width, h / this.height), 7022 top = this.top, 7023 aspectRatio = fit ? "meet" : "xMinYMin", 7024 vb, 7025 sw; 7026 if (x == null) { 7027 if (this._vbSize) { 7028 size = 1; 7029 } 7030 delete this._vbSize; 7031 vb = "0 0 " + this.width + S + this.height; 7032 } else { 7033 this._vbSize = size; 7034 vb = x + S + y + S + w + S + h; 7035 } 7036 $(this.canvas, { 7037 viewBox: vb, 7038 preserveAspectRatio: aspectRatio 7039 }); 7040 while (size && top) { 7041 sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; 7042 top.attr({"stroke-width": sw}); 7043 top._.dirty = 1; 7044 top._.dirtyT = 1; 7045 top = top.prev; 7046 } 7047 this._viewBox = [x, y, w, h, !!fit]; 7048 return this; 7049 }; 7050 /*\ 7051 * Paper.renderfix 7052 [ method ] 7053 ** 7054 * Fixes the issue of Firefox and IE9 regarding subpixel rendering. If paper is dependant 7055 * on other elements after reflow it could shift half pixel which cause for lines to lost their crispness. 7056 * This method fixes the issue. 7057 ** 7058 Special thanks to Mariusz Nowak (http://www.medikoo.com/) for this method. 7059 \*/ 7060 R.prototype.renderfix = function () { 7061 var cnvs = this.canvas, 7062 s = cnvs.style, 7063 pos; 7064 try { 7065 pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(); 7066 } catch (e) { 7067 pos = cnvs.createSVGMatrix(); 7068 } 7069 var left = -pos.e % 1, 7070 top = -pos.f % 1; 7071 if (left || top) { 7072 if (left) { 7073 this._left = (this._left + left) % 1; 7074 s.left = this._left + "px"; 7075 } 7076 if (top) { 7077 this._top = (this._top + top) % 1; 7078 s.top = this._top + "px"; 7079 } 7080 } 7081 }; 7082 /*\ 7083 * Paper.clear 7084 [ method ] 7085 ** 7086 * Clears the paper, i.e. removes all the elements. 7087 \*/ 7088 R.prototype.clear = function () { 7089 R.eve("raphael.clear", this); 7090 var c = this.canvas; 7091 while (c.firstChild) { 7092 c.removeChild(c.firstChild); 7093 } 7094 this.bottom = this.top = null; 7095 (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version)); 7096 c.appendChild(this.desc); 7097 c.appendChild(this.defs = $("defs")); 7098 }; 7099 /*\ 7100 * Paper.remove 7101 [ method ] 7102 ** 7103 * Removes the paper from the DOM. 7104 \*/ 7105 R.prototype.remove = function () { 7106 eve("raphael.remove", this); 7107 this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); 7108 for (var i in this) { 7109 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 7110 } 7111 }; 7112 var setproto = R.st; 7113 for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { 7114 setproto[method] = (function (methodname) { 7115 return function () { 7116 var arg = arguments; 7117 return this.forEach(function (el) { 7118 el[methodname].apply(el, arg); 7119 }); 7120 }; 7121 })(method); 7122 } 7123})(); 7124 7125// ┌─────────────────────────────────────────────────────────────────────┐ \\ 7126// │ Raphaël - JavaScript Vector Library │ \\ 7127// ├─────────────────────────────────────────────────────────────────────┤ \\ 7128// │ VML Module │ \\ 7129// ├─────────────────────────────────────────────────────────────────────┤ \\ 7130// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ 7131// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ 7132// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ 7133// └─────────────────────────────────────────────────────────────────────┘ \\ 7134 7135(function(){ 7136 if (!R.vml) { 7137 return; 7138 } 7139 var has = "hasOwnProperty", 7140 Str = String, 7141 toFloat = parseFloat, 7142 math = Math, 7143 round = math.round, 7144 mmax = math.max, 7145 mmin = math.min, 7146 abs = math.abs, 7147 fillString = "fill", 7148 separator = /[, ]+/, 7149 eve = R.eve, 7150 ms = " progid:DXImageTransform.Microsoft", 7151 S = " ", 7152 E = "", 7153 map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, 7154 bites = /([clmz]),?([^clmz]*)/gi, 7155 blurregexp = / progid:\S+Blur\([^\)]+\)/g, 7156 val = /-?[^,\s-]+/g, 7157 cssDot = "position:absolute;left:0;top:0;width:1px;height:1px", 7158 zoom = 21600, 7159 pathTypes = {path: 1, rect: 1, image: 1}, 7160 ovalTypes = {circle: 1, ellipse: 1}, 7161 path2vml = function (path) { 7162 var total = /[ahqstv]/ig, 7163 command = R._pathToAbsolute; 7164 Str(path).match(total) && (command = R._path2curve); 7165 total = /[clmz]/g; 7166 if (command == R._pathToAbsolute && !Str(path).match(total)) { 7167 var res = Str(path).replace(bites, function (all, command, args) { 7168 var vals = [], 7169 isMove = command.toLowerCase() == "m", 7170 res = map[command]; 7171 args.replace(val, function (value) { 7172 if (isMove && vals.length == 2) { 7173 res += vals + map[command == "m" ? "l" : "L"]; 7174 vals = []; 7175 } 7176 vals.push(round(value * zoom)); 7177 }); 7178 return res + vals; 7179 }); 7180 return res; 7181 } 7182 var pa = command(path), p, r; 7183 res = []; 7184 for (var i = 0, ii = pa.length; i < ii; i++) { 7185 p = pa[i]; 7186 r = pa[i][0].toLowerCase(); 7187 r == "z" && (r = "x"); 7188 for (var j = 1, jj = p.length; j < jj; j++) { 7189 r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); 7190 } 7191 res.push(r); 7192 } 7193 return res.join(S); 7194 }, 7195 compensation = function (deg, dx, dy) { 7196 var m = R.matrix(); 7197 m.rotate(-deg, .5, .5); 7198 return { 7199 dx: m.x(dx, dy), 7200 dy: m.y(dx, dy) 7201 }; 7202 }, 7203 setCoords = function (p, sx, sy, dx, dy, deg) { 7204 var _ = p._, 7205 m = p.matrix, 7206 fillpos = _.fillpos, 7207 o = p.node, 7208 s = o.style, 7209 y = 1, 7210 flip = "", 7211 dxdy, 7212 kx = zoom / sx, 7213 ky = zoom / sy; 7214 s.visibility = "hidden"; 7215 if (!sx || !sy) { 7216 return; 7217 } 7218 o.coordsize = abs(kx) + S + abs(ky); 7219 s.rotation = deg * (sx * sy < 0 ? -1 : 1); 7220 if (deg) { 7221 var c = compensation(deg, dx, dy); 7222 dx = c.dx; 7223 dy = c.dy; 7224 } 7225 sx < 0 && (flip += "x"); 7226 sy < 0 && (flip += " y") && (y = -1); 7227 s.flip = flip; 7228 o.coordorigin = (dx * -kx) + S + (dy * -ky); 7229 if (fillpos || _.fillsize) { 7230 var fill = o.getElementsByTagName(fillString); 7231 fill = fill && fill[0]; 7232 o.removeChild(fill); 7233 if (fillpos) { 7234 c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); 7235 fill.position = c.dx * y + S + c.dy * y; 7236 } 7237 if (_.fillsize) { 7238 fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); 7239 } 7240 o.appendChild(fill); 7241 } 7242 s.visibility = "visible"; 7243 }; 7244 R.toString = function () { 7245 return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; 7246 }; 7247 var addArrow = function (o, value, isEnd) { 7248 var values = Str(value).toLowerCase().split("-"), 7249 se = isEnd ? "end" : "start", 7250 i = values.length, 7251 type = "classic", 7252 w = "medium", 7253 h = "medium"; 7254 while (i--) { 7255 switch (values[i]) { 7256 case "block": 7257 case "classic": 7258 case "oval": 7259 case "diamond": 7260 case "open": 7261 case "none": 7262 type = values[i]; 7263 break; 7264 case "wide": 7265 case "narrow": h = values[i]; break; 7266 case "long": 7267 case "short": w = values[i]; break; 7268 } 7269 } 7270 var stroke = o.node.getElementsByTagName("stroke")[0]; 7271 stroke[se + "arrow"] = type; 7272 stroke[se + "arrowlength"] = w; 7273 stroke[se + "arrowwidth"] = h; 7274 }, 7275 setFillAndStroke = function (o, params) { 7276 // o.paper.canvas.style.display = "none"; 7277 o.attrs = o.attrs || {}; 7278 var node = o.node, 7279 a = o.attrs, 7280 s = node.style, 7281 xy, 7282 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), 7283 isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), 7284 res = o; 7285 7286 7287 for (var par in params) if (params[has](par)) { 7288 a[par] = params[par]; 7289 } 7290 if (newpath) { 7291 a.path = R._getPath[o.type](o); 7292 o._.dirty = 1; 7293 } 7294 params.href && (node.href = params.href); 7295 params.title && (node.title = params.title); 7296 params.target && (node.target = params.target); 7297 params.cursor && (s.cursor = params.cursor); 7298 "blur" in params && o.blur(params.blur); 7299 if (params.path && o.type == "path" || newpath) { 7300 node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path); 7301 if (o.type == "image") { 7302 o._.fillpos = [a.x, a.y]; 7303 o._.fillsize = [a.width, a.height]; 7304 setCoords(o, 1, 1, 0, 0, 0); 7305 } 7306 } 7307 "transform" in params && o.transform(params.transform); 7308 if (isOval) { 7309 var cx = +a.cx, 7310 cy = +a.cy, 7311 rx = +a.rx || +a.r || 0, 7312 ry = +a.ry || +a.r || 0; 7313 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)); 7314 o._.dirty = 1; 7315 } 7316 if ("clip-rect" in params) { 7317 var rect = Str(params["clip-rect"]).split(separator); 7318 if (rect.length == 4) { 7319 rect[2] = +rect[2] + (+rect[0]); 7320 rect[3] = +rect[3] + (+rect[1]); 7321 var div = node.clipRect || R._g.doc.createElement("div"), 7322 dstyle = div.style; 7323 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); 7324 if (!node.clipRect) { 7325 dstyle.position = "absolute"; 7326 dstyle.top = 0; 7327 dstyle.left = 0; 7328 dstyle.width = o.paper.width + "px"; 7329 dstyle.height = o.paper.height + "px"; 7330 node.parentNode.insertBefore(div, node); 7331 div.appendChild(node); 7332 node.clipRect = div; 7333 } 7334 } 7335 if (!params["clip-rect"]) { 7336 node.clipRect && (node.clipRect.style.clip = "auto"); 7337 } 7338 } 7339 if (o.textpath) { 7340 var textpathStyle = o.textpath.style; 7341 params.font && (textpathStyle.font = params.font); 7342 params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); 7343 params["font-size"] && (textpathStyle.fontSize = params["font-size"]); 7344 params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); 7345 params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); 7346 } 7347 if ("arrow-start" in params) { 7348 addArrow(res, params["arrow-start"]); 7349 } 7350 if ("arrow-end" in params) { 7351 addArrow(res, params["arrow-end"], 1); 7352 } 7353 if (params.opacity != null || 7354 params["stroke-width"] != null || 7355 params.fill != null || 7356 params.src != null || 7357 params.stroke != null || 7358 params["stroke-width"] != null || 7359 params["stroke-opacity"] != null || 7360 params["fill-opacity"] != null || 7361 params["stroke-dasharray"] != null || 7362 params["stroke-miterlimit"] != null || 7363 params["stroke-linejoin"] != null || 7364 params["stroke-linecap"] != null) { 7365 var fill = node.getElementsByTagName(fillString), 7366 newfill = false; 7367 fill = fill && fill[0]; 7368 !fill && (newfill = fill = createNode(fillString)); 7369 if (o.type == "image" && params.src) { 7370 fill.src = params.src; 7371 } 7372 params.fill && (fill.on = true); 7373 if (fill.on == null || params.fill == "none" || params.fill === null) { 7374 fill.on = false; 7375 } 7376 if (fill.on && params.fill) { 7377 var isURL = Str(params.fill).match(R._ISURL); 7378 if (isURL) { 7379 fill.parentNode == node && node.removeChild(fill); 7380 fill.rotate = true; 7381 fill.src = isURL[1]; 7382 fill.type = "tile"; 7383 var bbox = o.getBBox(1); 7384 fill.position = bbox.x + S + bbox.y; 7385 o._.fillpos = [bbox.x, bbox.y]; 7386 7387 R._preload(isURL[1], function () { 7388 o._.fillsize = [this.offsetWidth, this.offsetHeight]; 7389 }); 7390 } else { 7391 fill.color = R.getRGB(params.fill).hex; 7392 fill.src = E; 7393 fill.type = "solid"; 7394 if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { 7395 a.fill = "none"; 7396 a.gradient = params.fill; 7397 fill.rotate = false; 7398 } 7399 } 7400 } 7401 if ("fill-opacity" in params || "opacity" in params) { 7402 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); 7403 opacity = mmin(mmax(opacity, 0), 1); 7404 fill.opacity = opacity; 7405 if (fill.src) { 7406 fill.color = "none"; 7407 } 7408 } 7409 node.appendChild(fill); 7410 var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), 7411 newstroke = false; 7412 !stroke && (newstroke = stroke = createNode("stroke")); 7413 if ((params.stroke && params.stroke != "none") || 7414 params["stroke-width"] || 7415 params["stroke-opacity"] != null || 7416 params["stroke-dasharray"] || 7417 params["stroke-miterlimit"] || 7418 params["stroke-linejoin"] || 7419 params["stroke-linecap"]) { 7420 stroke.on = true; 7421 } 7422 (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); 7423 var strokeColor = R.getRGB(params.stroke); 7424 stroke.on && params.stroke && (stroke.color = strokeColor.hex); 7425 opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); 7426 var width = (toFloat(params["stroke-width"]) || 1) * .75; 7427 opacity = mmin(mmax(opacity, 0), 1); 7428 params["stroke-width"] == null && (width = a["stroke-width"]); 7429 params["stroke-width"] && (stroke.weight = width); 7430 width && width < 1 && (opacity *= width) && (stroke.weight = 1); 7431 stroke.opacity = opacity; 7432 7433 params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); 7434 stroke.miterlimit = params["stroke-miterlimit"] || 8; 7435 params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); 7436 if (params["stroke-dasharray"]) { 7437 var dasharray = { 7438 "-": "shortdash", 7439 ".": "shortdot", 7440 "-.": "shortdashdot", 7441 "-..": "shortdashdotdot", 7442 ". ": "dot", 7443 "- ": "dash", 7444 "--": "longdash", 7445 "- .": "dashdot", 7446 "--.": "longdashdot", 7447 "--..": "longdashdotdot" 7448 }; 7449 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; 7450 } 7451 newstroke && node.appendChild(stroke); 7452 } 7453 if (res.type == "text") { 7454 res.paper.canvas.style.display = E; 7455 var span = res.paper.span, 7456 m = 100, 7457 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); 7458 s = span.style; 7459 a.font && (s.font = a.font); 7460 a["font-family"] && (s.fontFamily = a["font-family"]); 7461 a["font-weight"] && (s.fontWeight = a["font-weight"]); 7462 a["font-style"] && (s.fontStyle = a["font-style"]); 7463 fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10; 7464 s.fontSize = fontSize * m + "px"; 7465 res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "<").replace(/&/g, "&").replace(/\n/g, "<br>")); 7466 var brect = span.getBoundingClientRect(); 7467 res.W = a.w = (brect.right - brect.left) / m; 7468 res.H = a.h = (brect.bottom - brect.top) / m; 7469 // res.paper.canvas.style.display = "none"; 7470 res.X = a.x; 7471 res.Y = a.y + res.H / 2; 7472 7473 ("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)); 7474 var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; 7475 for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { 7476 res._.dirty = 1; 7477 break; 7478 } 7479 7480 // text-anchor emulation 7481 switch (a["text-anchor"]) { 7482 case "start": 7483 res.textpath.style["v-text-align"] = "left"; 7484 res.bbx = res.W / 2; 7485 break; 7486 case "end": 7487 res.textpath.style["v-text-align"] = "right"; 7488 res.bbx = -res.W / 2; 7489 break; 7490 default: 7491 res.textpath.style["v-text-align"] = "center"; 7492 res.bbx = 0; 7493 break; 7494 } 7495 res.textpath.style["v-text-kern"] = true; 7496 } 7497 // res.paper.canvas.style.display = E; 7498 }, 7499 addGradientFill = function (o, gradient, fill) { 7500 o.attrs = o.attrs || {}; 7501 var attrs = o.attrs, 7502 pow = Math.pow, 7503 opacity, 7504 oindex, 7505 type = "linear", 7506 fxfy = ".5 .5"; 7507 o.attrs.gradient = gradient; 7508 gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) { 7509 type = "radial"; 7510 if (fx && fy) { 7511 fx = toFloat(fx); 7512 fy = toFloat(fy); 7513 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); 7514 fxfy = fx + S + fy; 7515 } 7516 return E; 7517 }); 7518 gradient = gradient.split(/\s*\-\s*/); 7519 if (type == "linear") { 7520 var angle = gradient.shift(); 7521 angle = -toFloat(angle); 7522 if (isNaN(angle)) { 7523 return null; 7524 } 7525 } 7526 var dots = R._parseDots(gradient); 7527 if (!dots) { 7528 return null; 7529 } 7530 o = o.shape || o.node; 7531 if (dots.length) { 7532 o.removeChild(fill); 7533 fill.on = true; 7534 fill.method = "none"; 7535 fill.color = dots[0].color; 7536 fill.color2 = dots[dots.length - 1].color; 7537 var clrs = []; 7538 for (var i = 0, ii = dots.length; i < ii; i++) { 7539 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); 7540 } 7541 fill.colors = clrs.length ? clrs.join() : "0% " + fill.color; 7542 if (type == "radial") { 7543 fill.type = "gradientTitle"; 7544 fill.focus = "100%"; 7545 fill.focussize = "0 0"; 7546 fill.focusposition = fxfy; 7547 fill.angle = 0; 7548 } else { 7549 // fill.rotate= true; 7550 fill.type = "gradient"; 7551 fill.angle = (270 - angle) % 360; 7552 } 7553 o.appendChild(fill); 7554 } 7555 return 1; 7556 }, 7557 Element = function (node, vml) { 7558 this[0] = this.node = node; 7559 node.raphael = true; 7560 this.id = R._oid++; 7561 node.raphaelid = this.id; 7562 this.X = 0; 7563 this.Y = 0; 7564 this.attrs = {}; 7565 this.paper = vml; 7566 this.matrix = R.matrix(); 7567 this._ = { 7568 transform: [], 7569 sx: 1, 7570 sy: 1, 7571 dx: 0, 7572 dy: 0, 7573 deg: 0, 7574 dirty: 1, 7575 dirtyT: 1 7576 }; 7577 !vml.bottom && (vml.bottom = this); 7578 this.prev = vml.top; 7579 vml.top && (vml.top.next = this); 7580 vml.top = this; 7581 this.next = null; 7582 }; 7583 var elproto = R.el; 7584 7585 Element.prototype = elproto; 7586 elproto.constructor = Element; 7587 elproto.transform = function (tstr) { 7588 if (tstr == null) { 7589 return this._.transform; 7590 } 7591 var vbs = this.paper._viewBoxShift, 7592 vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E, 7593 oldt; 7594 if (vbs) { 7595 oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E); 7596 } 7597 R._extractTransform(this, vbt + tstr); 7598 var matrix = this.matrix.clone(), 7599 skew = this.skew, 7600 o = this.node, 7601 split, 7602 isGrad = ~Str(this.attrs.fill).indexOf("-"), 7603 isPatt = !Str(this.attrs.fill).indexOf("url("); 7604 matrix.translate(1, 1); 7605 if (isPatt || isGrad || this.type == "image") { 7606 skew.matrix = "1 0 0 1"; 7607 skew.offset = "0 0"; 7608 split = matrix.split(); 7609 if ((isGrad && split.noRotation) || !split.isSimple) { 7610 o.style.filter = matrix.toFilter(); 7611 var bb = this.getBBox(), 7612 bbt = this.getBBox(1), 7613 dx = bb.x - bbt.x, 7614 dy = bb.y - bbt.y; 7615 o.coordorigin = (dx * -zoom) + S + (dy * -zoom); 7616 setCoords(this, 1, 1, dx, dy, 0); 7617 } else { 7618 o.style.filter = E; 7619 setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate); 7620 } 7621 } else { 7622 o.style.filter = E; 7623 skew.matrix = Str(matrix); 7624 skew.offset = matrix.offset(); 7625 } 7626 oldt && (this._.transform = oldt); 7627 return this; 7628 }; 7629 elproto.rotate = function (deg, cx, cy) { 7630 if (this.removed) { 7631 return this; 7632 } 7633 if (deg == null) { 7634 return; 7635 } 7636 deg = Str(deg).split(separator); 7637 if (deg.length - 1) { 7638 cx = toFloat(deg[1]); 7639 cy = toFloat(deg[2]); 7640 } 7641 deg = toFloat(deg[0]); 7642 (cy == null) && (cx = cy); 7643 if (cx == null || cy == null) { 7644 var bbox = this.getBBox(1); 7645 cx = bbox.x + bbox.width / 2; 7646 cy = bbox.y + bbox.height / 2; 7647 } 7648 this._.dirtyT = 1; 7649 this.transform(this._.transform.concat([["r", deg, cx, cy]])); 7650 return this; 7651 }; 7652 elproto.translate = function (dx, dy) { 7653 if (this.removed) { 7654 return this; 7655 } 7656 dx = Str(dx).split(separator); 7657 if (dx.length - 1) { 7658 dy = toFloat(dx[1]); 7659 } 7660 dx = toFloat(dx[0]) || 0; 7661 dy = +dy || 0; 7662 if (this._.bbox) { 7663 this._.bbox.x += dx; 7664 this._.bbox.y += dy; 7665 } 7666 this.transform(this._.transform.concat([["t", dx, dy]])); 7667 return this; 7668 }; 7669 elproto.scale = function (sx, sy, cx, cy) { 7670 if (this.removed) { 7671 return this; 7672 } 7673 sx = Str(sx).split(separator); 7674 if (sx.length - 1) { 7675 sy = toFloat(sx[1]); 7676 cx = toFloat(sx[2]); 7677 cy = toFloat(sx[3]); 7678 isNaN(cx) && (cx = null); 7679 isNaN(cy) && (cy = null); 7680 } 7681 sx = toFloat(sx[0]); 7682 (sy == null) && (sy = sx); 7683 (cy == null) && (cx = cy); 7684 if (cx == null || cy == null) { 7685 var bbox = this.getBBox(1); 7686 } 7687 cx = cx == null ? bbox.x + bbox.width / 2 : cx; 7688 cy = cy == null ? bbox.y + bbox.height / 2 : cy; 7689 7690 this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); 7691 this._.dirtyT = 1; 7692 return this; 7693 }; 7694 elproto.hide = function () { 7695 !this.removed && (this.node.style.display = "none"); 7696 return this; 7697 }; 7698 elproto.show = function () { 7699 !this.removed && (this.node.style.display = E); 7700 return this; 7701 }; 7702 elproto._getBBox = function () { 7703 if (this.removed) { 7704 return {}; 7705 } 7706 return { 7707 x: this.X + (this.bbx || 0) - this.W / 2, 7708 y: this.Y - this.H, 7709 width: this.W, 7710 height: this.H 7711 }; 7712 }; 7713 elproto.remove = function () { 7714 if (this.removed || !this.node.parentNode) { 7715 return; 7716 } 7717 this.paper.__set__ && this.paper.__set__.exclude(this); 7718 R.eve.unbind("raphael.*.*." + this.id); 7719 R._tear(this, this.paper); 7720 this.node.parentNode.removeChild(this.node); 7721 this.shape && this.shape.parentNode.removeChild(this.shape); 7722 for (var i in this) { 7723 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 7724 } 7725 this.removed = true; 7726 }; 7727 elproto.attr = function (name, value) { 7728 if (this.removed) { 7729 return this; 7730 } 7731 if (name == null) { 7732 var res = {}; 7733 for (var a in this.attrs) if (this.attrs[has](a)) { 7734 res[a] = this.attrs[a]; 7735 } 7736 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; 7737 res.transform = this._.transform; 7738 return res; 7739 } 7740 if (value == null && R.is(name, "string")) { 7741 if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { 7742 return this.attrs.gradient; 7743 } 7744 var names = name.split(separator), 7745 out = {}; 7746 for (var i = 0, ii = names.length; i < ii; i++) { 7747 name = names[i]; 7748 if (name in this.attrs) { 7749 out[name] = this.attrs[name]; 7750 } else if (R.is(this.paper.customAttributes[name], "function")) { 7751 out[name] = this.paper.customAttributes[name].def; 7752 } else { 7753 out[name] = R._availableAttrs[name]; 7754 } 7755 } 7756 return ii - 1 ? out : out[names[0]]; 7757 } 7758 if (this.attrs && value == null && R.is(name, "array")) { 7759 out = {}; 7760 for (i = 0, ii = name.length; i < ii; i++) { 7761 out[name[i]] = this.attr(name[i]); 7762 } 7763 return out; 7764 } 7765 var params; 7766 if (value != null) { 7767 params = {}; 7768 params[name] = value; 7769 } 7770 value == null && R.is(name, "object") && (params = name); 7771 for (var key in params) { 7772 eve("raphael.attr." + key + "." + this.id, this, params[key]); 7773 } 7774 if (params) { 7775 for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { 7776 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); 7777 this.attrs[key] = params[key]; 7778 for (var subkey in par) if (par[has](subkey)) { 7779 params[subkey] = par[subkey]; 7780 } 7781 } 7782 // this.paper.canvas.style.display = "none"; 7783 if (params.text && this.type == "text") { 7784 this.textpath.string = params.text; 7785 } 7786 setFillAndStroke(this, params); 7787 // this.paper.canvas.style.display = E; 7788 } 7789 return this; 7790 }; 7791 elproto.toFront = function () { 7792 !this.removed && this.node.parentNode.appendChild(this.node); 7793 this.paper && this.paper.top != this && R._tofront(this, this.paper); 7794 return this; 7795 }; 7796 elproto.toBack = function () { 7797 if (this.removed) { 7798 return this; 7799 } 7800 if (this.node.parentNode.firstChild != this.node) { 7801 this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); 7802 R._toback(this, this.paper); 7803 } 7804 return this; 7805 }; 7806 elproto.insertAfter = function (element) { 7807 if (this.removed) { 7808 return this; 7809 } 7810 if (element.constructor == R.st.constructor) { 7811 element = element[element.length - 1]; 7812 } 7813 if (element.node.nextSibling) { 7814 element.node.parentNode.insertBefore(this.node, element.node.nextSibling); 7815 } else { 7816 element.node.parentNode.appendChild(this.node); 7817 } 7818 R._insertafter(this, element, this.paper); 7819 return this; 7820 }; 7821 elproto.insertBefore = function (element) { 7822 if (this.removed) { 7823 return this; 7824 } 7825 if (element.constructor == R.st.constructor) { 7826 element = element[0]; 7827 } 7828 element.node.parentNode.insertBefore(this.node, element.node); 7829 R._insertbefore(this, element, this.paper); 7830 return this; 7831 }; 7832 elproto.blur = function (size) { 7833 var s = this.node.runtimeStyle, 7834 f = s.filter; 7835 f = f.replace(blurregexp, E); 7836 if (+size !== 0) { 7837 this.attrs.blur = size; 7838 s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; 7839 s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); 7840 } else { 7841 s.filter = f; 7842 s.margin = 0; 7843 delete this.attrs.blur; 7844 } 7845 return this; 7846 }; 7847 7848 R._engine.path = function (pathString, vml) { 7849 var el = createNode("shape"); 7850 el.style.cssText = cssDot; 7851 el.coordsize = zoom + S + zoom; 7852 el.coordorigin = vml.coordorigin; 7853 var p = new Element(el, vml), 7854 attr = {fill: "none", stroke: "#000"}; 7855 pathString && (attr.path = pathString); 7856 p.type = "path"; 7857 p.path = []; 7858 p.Path = E; 7859 setFillAndStroke(p, attr); 7860 vml.canvas.appendChild(el); 7861 var skew = createNode("skew"); 7862 skew.on = true; 7863 el.appendChild(skew); 7864 p.skew = skew; 7865 p.transform(E); 7866 return p; 7867 }; 7868 R._engine.rect = function (vml, x, y, w, h, r) { 7869 var path = R._rectPath(x, y, w, h, r), 7870 res = vml.path(path), 7871 a = res.attrs; 7872 res.X = a.x = x; 7873 res.Y = a.y = y; 7874 res.W = a.width = w; 7875 res.H = a.height = h; 7876 a.r = r; 7877 a.path = path; 7878 res.type = "rect"; 7879 return res; 7880 }; 7881 R._engine.ellipse = function (vml, x, y, rx, ry) { 7882 var res = vml.path(), 7883 a = res.attrs; 7884 res.X = x - rx; 7885 res.Y = y - ry; 7886 res.W = rx * 2; 7887 res.H = ry * 2; 7888 res.type = "ellipse"; 7889 setFillAndStroke(res, { 7890 cx: x, 7891 cy: y, 7892 rx: rx, 7893 ry: ry 7894 }); 7895 return res; 7896 }; 7897 R._engine.circle = function (vml, x, y, r) { 7898 var res = vml.path(), 7899 a = res.attrs; 7900 res.X = x - r; 7901 res.Y = y - r; 7902 res.W = res.H = r * 2; 7903 res.type = "circle"; 7904 setFillAndStroke(res, { 7905 cx: x, 7906 cy: y, 7907 r: r 7908 }); 7909 return res; 7910 }; 7911 R._engine.image = function (vml, src, x, y, w, h) { 7912 var path = R._rectPath(x, y, w, h), 7913 res = vml.path(path).attr({stroke: "none"}), 7914 a = res.attrs, 7915 node = res.node, 7916 fill = node.getElementsByTagName(fillString)[0]; 7917 a.src = src; 7918 res.X = a.x = x; 7919 res.Y = a.y = y; 7920 res.W = a.width = w; 7921 res.H = a.height = h; 7922 a.path = path; 7923 res.type = "image"; 7924 fill.parentNode == node && node.removeChild(fill); 7925 fill.rotate = true; 7926 fill.src = src; 7927 fill.type = "tile"; 7928 res._.fillpos = [x, y]; 7929 res._.fillsize = [w, h]; 7930 node.appendChild(fill); 7931 setCoords(res, 1, 1, 0, 0, 0); 7932 return res; 7933 }; 7934 R._engine.text = function (vml, x, y, text) { 7935 var el = createNode("shape"), 7936 path = createNode("path"), 7937 o = createNode("textpath"); 7938 x = x || 0; 7939 y = y || 0; 7940 text = text || ""; 7941 path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); 7942 path.textpathok = true; 7943 o.string = Str(text); 7944 o.on = true; 7945 el.style.cssText = cssDot; 7946 el.coordsize = zoom + S + zoom; 7947 el.coordorigin = "0 0"; 7948 var p = new Element(el, vml), 7949 attr = { 7950 fill: "#000", 7951 stroke: "none", 7952 font: R._availableAttrs.font, 7953 text: text 7954 }; 7955 p.shape = el; 7956 p.path = path; 7957 p.textpath = o; 7958 p.type = "text"; 7959 p.attrs.text = Str(text); 7960 p.attrs.x = x; 7961 p.attrs.y = y; 7962 p.attrs.w = 1; 7963 p.attrs.h = 1; 7964 setFillAndStroke(p, attr); 7965 el.appendChild(o); 7966 el.appendChild(path); 7967 vml.canvas.appendChild(el); 7968 var skew = createNode("skew"); 7969 skew.on = true; 7970 el.appendChild(skew); 7971 p.skew = skew; 7972 p.transform(E); 7973 return p; 7974 }; 7975 R._engine.setSize = function (width, height) { 7976 var cs = this.canvas.style; 7977 this.width = width; 7978 this.height = height; 7979 width == +width && (width += "px"); 7980 height == +height && (height += "px"); 7981 cs.width = width; 7982 cs.height = height; 7983 cs.clip = "rect(0 " + width + " " + height + " 0)"; 7984 if (this._viewBox) { 7985 R._engine.setViewBox.apply(this, this._viewBox); 7986 } 7987 return this; 7988 }; 7989 R._engine.setViewBox = function (x, y, w, h, fit) { 7990 R.eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]); 7991 var width = this.width, 7992 height = this.height, 7993 size = 1 / mmax(w / width, h / height), 7994 H, W; 7995 if (fit) { 7996 H = height / h; 7997 W = width / w; 7998 if (w * H < width) { 7999 x -= (width - w * H) / 2 / H; 8000 } 8001 if (h * W < height) { 8002 y -= (height - h * W) / 2 / W; 8003 } 8004 } 8005 this._viewBox = [x, y, w, h, !!fit]; 8006 this._viewBoxShift = { 8007 dx: -x, 8008 dy: -y, 8009 scale: size 8010 }; 8011 this.forEach(function (el) { 8012 el.transform("..."); 8013 }); 8014 return this; 8015 }; 8016 var createNode; 8017 R._engine.initWin = function (win) { 8018 var doc = win.document; 8019 doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); 8020 try { 8021 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); 8022 createNode = function (tagName) { 8023 return doc.createElement('<rvml:' + tagName + ' class="rvml">'); 8024 }; 8025 } catch (e) { 8026 createNode = function (tagName) { 8027 return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); 8028 }; 8029 } 8030 }; 8031 R._engine.initWin(R._g.win); 8032 R._engine.create = function () { 8033 var con = R._getContainer.apply(0, arguments), 8034 container = con.container, 8035 height = con.height, 8036 s, 8037 width = con.width, 8038 x = con.x, 8039 y = con.y; 8040 if (!container) { 8041 throw new Error("VML container not found."); 8042 } 8043 var res = new R._Paper, 8044 c = res.canvas = R._g.doc.createElement("div"), 8045 cs = c.style; 8046 x = x || 0; 8047 y = y || 0; 8048 width = width || 512; 8049 height = height || 342; 8050 res.width = width; 8051 res.height = height; 8052 width == +width && (width += "px"); 8053 height == +height && (height += "px"); 8054 res.coordsize = zoom * 1e3 + S + zoom * 1e3; 8055 res.coordorigin = "0 0"; 8056 res.span = R._g.doc.createElement("span"); 8057 res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; 8058 c.appendChild(res.span); 8059 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); 8060 if (container == 1) { 8061 R._g.doc.body.appendChild(c); 8062 cs.left = x + "px"; 8063 cs.top = y + "px"; 8064 cs.position = "absolute"; 8065 } else { 8066 if (container.firstChild) { 8067 container.insertBefore(c, container.firstChild); 8068 } else { 8069 container.appendChild(c); 8070 } 8071 } 8072 res.renderfix = function () {}; 8073 return res; 8074 }; 8075 R.prototype.clear = function () { 8076 R.eve("raphael.clear", this); 8077 this.canvas.innerHTML = E; 8078 this.span = R._g.doc.createElement("span"); 8079 this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; 8080 this.canvas.appendChild(this.span); 8081 this.bottom = this.top = null; 8082 }; 8083 R.prototype.remove = function () { 8084 R.eve("raphael.remove", this); 8085 this.canvas.parentNode.removeChild(this.canvas); 8086 for (var i in this) { 8087 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 8088 } 8089 return true; 8090 }; 8091 8092 var setproto = R.st; 8093 for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { 8094 setproto[method] = (function (methodname) { 8095 return function () { 8096 var arg = arguments; 8097 return this.forEach(function (el) { 8098 el[methodname].apply(el, arg); 8099 }); 8100 }; 8101 })(method); 8102 } 8103})(); 8104 8105 // EXPOSE 8106 // SVG and VML are appended just before the EXPOSE line 8107 // Even with AMD, Raphael should be defined globally 8108 oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); 8109 8110 return R; 8111})); 8112