1// ┌────────────────────────────────────────────────────────────────────┐ \\ 2// │ Raphaël 2.1.2 - 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})(window || this); 380// ┌─────────────────────────────────────────────────────────────────────┐ \\ 381// │ "Raphaël 2.1.2" - 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(["eve"], 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.2"; 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 (typeof obj == "function" || 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 = mmax(~~(l1 / 5), 1), 1799 n2 = mmax(~~(l2 / 5), 1), 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.001 && t2 >= 0 && t2 <= 1.001) { 1829 if (justCount) { 1830 res++; 1831 } else { 1832 res.push({ 1833 x: is.x, 1834 y: is.y, 1835 t1: mmin(t1, 1), 1836 t2: mmin(t2, 1) 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, pcom) { 2365 var nx, ny, tq = {T:1, Q:1}; 2366 if (!path) { 2367 return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; 2368 } 2369 !(path[0] in tq) && (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 isPointInside = true; 5416 return false; // stop loop 5417 } 5418 }); 5419 return isPointInside; 5420 }; 5421 5422 /*\ 5423 * Raphael.registerFont 5424 [ method ] 5425 ** 5426 * 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. 5427 * Returns original parameter, so it could be used with chaining. 5428 # <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> 5429 ** 5430 > Parameters 5431 ** 5432 - font (object) the font to register 5433 = (object) the font you passed in 5434 > Usage 5435 | Cufon.registerFont(Raphael.registerFont({…})); 5436 \*/ 5437 R.registerFont = function (font) { 5438 if (!font.face) { 5439 return font; 5440 } 5441 this.fonts = this.fonts || {}; 5442 var fontcopy = { 5443 w: font.w, 5444 face: {}, 5445 glyphs: {} 5446 }, 5447 family = font.face["font-family"]; 5448 for (var prop in font.face) if (font.face[has](prop)) { 5449 fontcopy.face[prop] = font.face[prop]; 5450 } 5451 if (this.fonts[family]) { 5452 this.fonts[family].push(fontcopy); 5453 } else { 5454 this.fonts[family] = [fontcopy]; 5455 } 5456 if (!font.svg) { 5457 fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); 5458 for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { 5459 var path = font.glyphs[glyph]; 5460 fontcopy.glyphs[glyph] = { 5461 w: path.w, 5462 k: {}, 5463 d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { 5464 return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; 5465 }) + "z" 5466 }; 5467 if (path.k) { 5468 for (var k in path.k) if (path[has](k)) { 5469 fontcopy.glyphs[glyph].k[k] = path.k[k]; 5470 } 5471 } 5472 } 5473 } 5474 return font; 5475 }; 5476 /*\ 5477 * Paper.getFont 5478 [ method ] 5479 ** 5480 * 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”. 5481 ** 5482 > Parameters 5483 ** 5484 - family (string) font family name or any word from it 5485 - weight (string) #optional font weight 5486 - style (string) #optional font style 5487 - stretch (string) #optional font stretch 5488 = (object) the font object 5489 > Usage 5490 | paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30); 5491 \*/ 5492 paperproto.getFont = function (family, weight, style, stretch) { 5493 stretch = stretch || "normal"; 5494 style = style || "normal"; 5495 weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; 5496 if (!R.fonts) { 5497 return; 5498 } 5499 var font = R.fonts[family]; 5500 if (!font) { 5501 var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); 5502 for (var fontName in R.fonts) if (R.fonts[has](fontName)) { 5503 if (name.test(fontName)) { 5504 font = R.fonts[fontName]; 5505 break; 5506 } 5507 } 5508 } 5509 var thefont; 5510 if (font) { 5511 for (var i = 0, ii = font.length; i < ii; i++) { 5512 thefont = font[i]; 5513 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { 5514 break; 5515 } 5516 } 5517 } 5518 return thefont; 5519 }; 5520 /*\ 5521 * Paper.print 5522 [ method ] 5523 ** 5524 * Creates path that represent given text written using given font at given position with given size. 5525 * Result of the method is path element that contains whole text as a separate path. 5526 ** 5527 > Parameters 5528 ** 5529 - x (number) x position of the text 5530 - y (number) y position of the text 5531 - string (string) text to print 5532 - font (object) font object, see @Paper.getFont 5533 - size (number) #optional size of the font, default is `16` 5534 - origin (string) #optional could be `"baseline"` or `"middle"`, default is `"middle"` 5535 - letter_spacing (number) #optional number in range `-1..1`, default is `0` 5536 - line_spacing (number) #optional number in range `1..3`, default is `1` 5537 = (object) resulting path element, which consist of all letters 5538 > Usage 5539 | var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"}); 5540 \*/ 5541 paperproto.print = function (x, y, string, font, size, origin, letter_spacing, line_spacing) { 5542 origin = origin || "middle"; // baseline|middle 5543 letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); 5544 line_spacing = mmax(mmin(line_spacing || 1, 3), 1); 5545 var letters = Str(string)[split](E), 5546 shift = 0, 5547 notfirst = 0, 5548 path = E, 5549 scale; 5550 R.is(font, "string") && (font = this.getFont(font)); 5551 if (font) { 5552 scale = (size || 16) / font.face["units-per-em"]; 5553 var bb = font.face.bbox[split](separator), 5554 top = +bb[0], 5555 lineHeight = bb[3] - bb[1], 5556 shifty = 0, 5557 height = +bb[1] + (origin == "baseline" ? lineHeight + (+font.face.descent) : lineHeight / 2); 5558 for (var i = 0, ii = letters.length; i < ii; i++) { 5559 if (letters[i] == "\n") { 5560 shift = 0; 5561 curr = 0; 5562 notfirst = 0; 5563 shifty += lineHeight * line_spacing; 5564 } else { 5565 var prev = notfirst && font.glyphs[letters[i - 1]] || {}, 5566 curr = font.glyphs[letters[i]]; 5567 shift += notfirst ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; 5568 notfirst = 1; 5569 } 5570 if (curr && curr.d) { 5571 path += R.transformPath(curr.d, ["t", shift * scale, shifty * scale, "s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]); 5572 } 5573 } 5574 } 5575 return this.path(path).attr({ 5576 fill: "#000", 5577 stroke: "none" 5578 }); 5579 }; 5580 5581 /*\ 5582 * Paper.add 5583 [ method ] 5584 ** 5585 * Imports elements in JSON array in format `{type: type, <attributes>}` 5586 ** 5587 > Parameters 5588 ** 5589 - json (array) 5590 = (object) resulting set of imported elements 5591 > Usage 5592 | paper.add([ 5593 | { 5594 | type: "circle", 5595 | cx: 10, 5596 | cy: 10, 5597 | r: 5 5598 | }, 5599 | { 5600 | type: "rect", 5601 | x: 10, 5602 | y: 10, 5603 | width: 10, 5604 | height: 10, 5605 | fill: "#fc0" 5606 | } 5607 | ]); 5608 \*/ 5609 paperproto.add = function (json) { 5610 if (R.is(json, "array")) { 5611 var res = this.set(), 5612 i = 0, 5613 ii = json.length, 5614 j; 5615 for (; i < ii; i++) { 5616 j = json[i] || {}; 5617 elements[has](j.type) && res.push(this[j.type]().attr(j)); 5618 } 5619 } 5620 return res; 5621 }; 5622 5623 /*\ 5624 * Raphael.format 5625 [ method ] 5626 ** 5627 * Simple format function. Replaces construction of type “`{<number>}`” to the corresponding argument. 5628 ** 5629 > Parameters 5630 ** 5631 - token (string) string to format 5632 - … (string) rest of arguments will be treated as parameters for replacement 5633 = (string) formated string 5634 > Usage 5635 | var x = 10, 5636 | y = 20, 5637 | width = 40, 5638 | height = 50; 5639 | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z" 5640 | paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width)); 5641 \*/ 5642 R.format = function (token, params) { 5643 var args = R.is(params, array) ? [0][concat](params) : arguments; 5644 token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { 5645 return args[++i] == null ? E : args[i]; 5646 })); 5647 return token || E; 5648 }; 5649 /*\ 5650 * Raphael.fullfill 5651 [ method ] 5652 ** 5653 * A little bit more advanced format function than @Raphael.format. Replaces construction of type “`{<name>}`” to the corresponding argument. 5654 ** 5655 > Parameters 5656 ** 5657 - token (string) string to format 5658 - json (object) object which properties will be used as a replacement 5659 = (string) formated string 5660 > Usage 5661 | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z" 5662 | paper.path(Raphael.fullfill("M{x},{y}h{dim.width}v{dim.height}h{dim['negative width']}z", { 5663 | x: 10, 5664 | y: 20, 5665 | dim: { 5666 | width: 40, 5667 | height: 50, 5668 | "negative width": -40 5669 | } 5670 | })); 5671 \*/ 5672 R.fullfill = (function () { 5673 var tokenRegex = /\{([^\}]+)\}/g, 5674 objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties 5675 replacer = function (all, key, obj) { 5676 var res = obj; 5677 key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { 5678 name = name || quotedName; 5679 if (res) { 5680 if (name in res) { 5681 res = res[name]; 5682 } 5683 typeof res == "function" && isFunc && (res = res()); 5684 } 5685 }); 5686 res = (res == null || res == obj ? all : res) + ""; 5687 return res; 5688 }; 5689 return function (str, obj) { 5690 return String(str).replace(tokenRegex, function (all, key) { 5691 return replacer(all, key, obj); 5692 }); 5693 }; 5694 })(); 5695 /*\ 5696 * Raphael.ninja 5697 [ method ] 5698 ** 5699 * 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. 5700 * Beware, that in this case plugins could stop working, because they are depending on global variable existance. 5701 ** 5702 = (object) Raphael object 5703 > Usage 5704 | (function (local_raphael) { 5705 | var paper = local_raphael(10, 10, 320, 200); 5706 | … 5707 | })(Raphael.ninja()); 5708 \*/ 5709 R.ninja = function () { 5710 oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; 5711 return R; 5712 }; 5713 /*\ 5714 * Raphael.st 5715 [ property (object) ] 5716 ** 5717 * You can add your own method to elements and sets. It is wise to add a set method for each element method 5718 * you added, so you will be able to call the same method on sets too. 5719 ** 5720 * See also @Raphael.el. 5721 > Usage 5722 | Raphael.el.red = function () { 5723 | this.attr({fill: "#f00"}); 5724 | }; 5725 | Raphael.st.red = function () { 5726 | this.forEach(function (el) { 5727 | el.red(); 5728 | }); 5729 | }; 5730 | // then use it 5731 | paper.set(paper.circle(100, 100, 20), paper.circle(110, 100, 20)).red(); 5732 \*/ 5733 R.st = setproto; 5734 // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html 5735 (function (doc, loaded, f) { 5736 if (doc.readyState == null && doc.addEventListener){ 5737 doc.addEventListener(loaded, f = function () { 5738 doc.removeEventListener(loaded, f, false); 5739 doc.readyState = "complete"; 5740 }, false); 5741 doc.readyState = "loading"; 5742 } 5743 function isLoaded() { 5744 (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("raphael.DOMload"); 5745 } 5746 isLoaded(); 5747 })(document, "DOMContentLoaded"); 5748 5749 eve.on("raphael.DOMload", function () { 5750 loaded = true; 5751 }); 5752 5753// ┌─────────────────────────────────────────────────────────────────────┐ \\ 5754// │ Raphaël - JavaScript Vector Library │ \\ 5755// ├─────────────────────────────────────────────────────────────────────┤ \\ 5756// │ SVG Module │ \\ 5757// ├─────────────────────────────────────────────────────────────────────┤ \\ 5758// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ 5759// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ 5760// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ 5761// └─────────────────────────────────────────────────────────────────────┘ \\ 5762 5763(function(){ 5764 if (!R.svg) { 5765 return; 5766 } 5767 var has = "hasOwnProperty", 5768 Str = String, 5769 toFloat = parseFloat, 5770 toInt = parseInt, 5771 math = Math, 5772 mmax = math.max, 5773 abs = math.abs, 5774 pow = math.pow, 5775 separator = /[, ]+/, 5776 eve = R.eve, 5777 E = "", 5778 S = " "; 5779 var xlink = "http://www.w3.org/1999/xlink", 5780 markers = { 5781 block: "M5,0 0,2.5 5,5z", 5782 classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", 5783 diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", 5784 open: "M6,1 1,3.5 6,6", 5785 oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" 5786 }, 5787 markerCounter = {}; 5788 R.toString = function () { 5789 return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; 5790 }; 5791 var $ = function (el, attr) { 5792 if (attr) { 5793 if (typeof el == "string") { 5794 el = $(el); 5795 } 5796 for (var key in attr) if (attr[has](key)) { 5797 if (key.substring(0, 6) == "xlink:") { 5798 el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); 5799 } else { 5800 el.setAttribute(key, Str(attr[key])); 5801 } 5802 } 5803 } else { 5804 el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el); 5805 el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); 5806 } 5807 return el; 5808 }, 5809 addGradientFill = function (element, gradient) { 5810 var type = "linear", 5811 id = element.id + gradient, 5812 fx = .5, fy = .5, 5813 o = element.node, 5814 SVG = element.paper, 5815 s = o.style, 5816 el = R._g.doc.getElementById(id); 5817 if (!el) { 5818 gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) { 5819 type = "radial"; 5820 if (_fx && _fy) { 5821 fx = toFloat(_fx); 5822 fy = toFloat(_fy); 5823 var dir = ((fy > .5) * 2 - 1); 5824 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && 5825 (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && 5826 fy != .5 && 5827 (fy = fy.toFixed(5) - 1e-5 * dir); 5828 } 5829 return E; 5830 }); 5831 gradient = gradient.split(/\s*\-\s*/); 5832 if (type == "linear") { 5833 var angle = gradient.shift(); 5834 angle = -toFloat(angle); 5835 if (isNaN(angle)) { 5836 return null; 5837 } 5838 var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], 5839 max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); 5840 vector[2] *= max; 5841 vector[3] *= max; 5842 if (vector[2] < 0) { 5843 vector[0] = -vector[2]; 5844 vector[2] = 0; 5845 } 5846 if (vector[3] < 0) { 5847 vector[1] = -vector[3]; 5848 vector[3] = 0; 5849 } 5850 } 5851 var dots = R._parseDots(gradient); 5852 if (!dots) { 5853 return null; 5854 } 5855 id = id.replace(/[\(\)\s,\xb0#]/g, "_"); 5856 5857 if (element.gradient && id != element.gradient.id) { 5858 SVG.defs.removeChild(element.gradient); 5859 delete element.gradient; 5860 } 5861 5862 if (!element.gradient) { 5863 el = $(type + "Gradient", {id: id}); 5864 element.gradient = el; 5865 $(el, type == "radial" ? { 5866 fx: fx, 5867 fy: fy 5868 } : { 5869 x1: vector[0], 5870 y1: vector[1], 5871 x2: vector[2], 5872 y2: vector[3], 5873 gradientTransform: element.matrix.invert() 5874 }); 5875 SVG.defs.appendChild(el); 5876 for (var i = 0, ii = dots.length; i < ii; i++) { 5877 el.appendChild($("stop", { 5878 offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", 5879 "stop-color": dots[i].color || "#fff" 5880 })); 5881 } 5882 } 5883 } 5884 $(o, { 5885 fill: "url(#" + id + ")", 5886 opacity: 1, 5887 "fill-opacity": 1 5888 }); 5889 s.fill = E; 5890 s.opacity = 1; 5891 s.fillOpacity = 1; 5892 return 1; 5893 }, 5894 updatePosition = function (o) { 5895 var bbox = o.getBBox(1); 5896 $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); 5897 }, 5898 addArrow = function (o, value, isEnd) { 5899 if (o.type == "path") { 5900 var values = Str(value).toLowerCase().split("-"), 5901 p = o.paper, 5902 se = isEnd ? "end" : "start", 5903 node = o.node, 5904 attrs = o.attrs, 5905 stroke = attrs["stroke-width"], 5906 i = values.length, 5907 type = "classic", 5908 from, 5909 to, 5910 dx, 5911 refX, 5912 attr, 5913 w = 3, 5914 h = 3, 5915 t = 5; 5916 while (i--) { 5917 switch (values[i]) { 5918 case "block": 5919 case "classic": 5920 case "oval": 5921 case "diamond": 5922 case "open": 5923 case "none": 5924 type = values[i]; 5925 break; 5926 case "wide": h = 5; break; 5927 case "narrow": h = 2; break; 5928 case "long": w = 5; break; 5929 case "short": w = 2; break; 5930 } 5931 } 5932 if (type == "open") { 5933 w += 2; 5934 h += 2; 5935 t += 2; 5936 dx = 1; 5937 refX = isEnd ? 4 : 1; 5938 attr = { 5939 fill: "none", 5940 stroke: attrs.stroke 5941 }; 5942 } else { 5943 refX = dx = w / 2; 5944 attr = { 5945 fill: attrs.stroke, 5946 stroke: "none" 5947 }; 5948 } 5949 if (o._.arrows) { 5950 if (isEnd) { 5951 o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; 5952 o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; 5953 } else { 5954 o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; 5955 o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; 5956 } 5957 } else { 5958 o._.arrows = {}; 5959 } 5960 if (type != "none") { 5961 var pathId = "raphael-marker-" + type, 5962 markerId = "raphael-marker-" + se + type + w + h; 5963 if (!R._g.doc.getElementById(pathId)) { 5964 p.defs.appendChild($($("path"), { 5965 "stroke-linecap": "round", 5966 d: markers[type], 5967 id: pathId 5968 })); 5969 markerCounter[pathId] = 1; 5970 } else { 5971 markerCounter[pathId]++; 5972 } 5973 var marker = R._g.doc.getElementById(markerId), 5974 use; 5975 if (!marker) { 5976 marker = $($("marker"), { 5977 id: markerId, 5978 markerHeight: h, 5979 markerWidth: w, 5980 orient: "auto", 5981 refX: refX, 5982 refY: h / 2 5983 }); 5984 use = $($("use"), { 5985 "xlink:href": "#" + pathId, 5986 transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")", 5987 "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4) 5988 }); 5989 marker.appendChild(use); 5990 p.defs.appendChild(marker); 5991 markerCounter[markerId] = 1; 5992 } else { 5993 markerCounter[markerId]++; 5994 use = marker.getElementsByTagName("use")[0]; 5995 } 5996 $(use, attr); 5997 var delta = dx * (type != "diamond" && type != "oval"); 5998 if (isEnd) { 5999 from = o._.arrows.startdx * stroke || 0; 6000 to = R.getTotalLength(attrs.path) - delta * stroke; 6001 } else { 6002 from = delta * stroke; 6003 to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); 6004 } 6005 attr = {}; 6006 attr["marker-" + se] = "url(#" + markerId + ")"; 6007 if (to || from) { 6008 attr.d = R.getSubpath(attrs.path, from, to); 6009 } 6010 $(node, attr); 6011 o._.arrows[se + "Path"] = pathId; 6012 o._.arrows[se + "Marker"] = markerId; 6013 o._.arrows[se + "dx"] = delta; 6014 o._.arrows[se + "Type"] = type; 6015 o._.arrows[se + "String"] = value; 6016 } else { 6017 if (isEnd) { 6018 from = o._.arrows.startdx * stroke || 0; 6019 to = R.getTotalLength(attrs.path) - from; 6020 } else { 6021 from = 0; 6022 to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); 6023 } 6024 o._.arrows[se + "Path"] && $(node, {d: R.getSubpath(attrs.path, from, to)}); 6025 delete o._.arrows[se + "Path"]; 6026 delete o._.arrows[se + "Marker"]; 6027 delete o._.arrows[se + "dx"]; 6028 delete o._.arrows[se + "Type"]; 6029 delete o._.arrows[se + "String"]; 6030 } 6031 for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { 6032 var item = R._g.doc.getElementById(attr); 6033 item && item.parentNode.removeChild(item); 6034 } 6035 } 6036 }, 6037 dasharray = { 6038 "": [0], 6039 "none": [0], 6040 "-": [3, 1], 6041 ".": [1, 1], 6042 "-.": [3, 1, 1, 1], 6043 "-..": [3, 1, 1, 1, 1, 1], 6044 ". ": [1, 3], 6045 "- ": [4, 3], 6046 "--": [8, 3], 6047 "- .": [4, 3, 1, 3], 6048 "--.": [8, 3, 1, 3], 6049 "--..": [8, 3, 1, 3, 1, 3] 6050 }, 6051 addDashes = function (o, value, params) { 6052 value = dasharray[Str(value).toLowerCase()]; 6053 if (value) { 6054 var width = o.attrs["stroke-width"] || "1", 6055 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, 6056 dashes = [], 6057 i = value.length; 6058 while (i--) { 6059 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; 6060 } 6061 $(o.node, {"stroke-dasharray": dashes.join(",")}); 6062 } 6063 }, 6064 setFillAndStroke = function (o, params) { 6065 var node = o.node, 6066 attrs = o.attrs, 6067 vis = node.style.visibility; 6068 node.style.visibility = "hidden"; 6069 for (var att in params) { 6070 if (params[has](att)) { 6071 if (!R._availableAttrs[has](att)) { 6072 continue; 6073 } 6074 var value = params[att]; 6075 attrs[att] = value; 6076 switch (att) { 6077 case "blur": 6078 o.blur(value); 6079 break; 6080 case "title": 6081 var title = node.getElementsByTagName("title"); 6082 6083 // Use the existing <title>. 6084 if (title.length && (title = title[0])) { 6085 title.firstChild.nodeValue = value; 6086 } else { 6087 title = $("title"); 6088 var val = R._g.doc.createTextNode(value); 6089 title.appendChild(val); 6090 node.appendChild(title); 6091 } 6092 break; 6093 case "href": 6094 case "target": 6095 var pn = node.parentNode; 6096 if (pn.tagName.toLowerCase() != "a") { 6097 var hl = $("a"); 6098 pn.insertBefore(hl, node); 6099 hl.appendChild(node); 6100 pn = hl; 6101 } 6102 if (att == "target") { 6103 pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value); 6104 } else { 6105 pn.setAttributeNS(xlink, att, value); 6106 } 6107 break; 6108 case "cursor": 6109 node.style.cursor = value; 6110 break; 6111 case "transform": 6112 o.transform(value); 6113 break; 6114 case "arrow-start": 6115 addArrow(o, value); 6116 break; 6117 case "arrow-end": 6118 addArrow(o, value, 1); 6119 break; 6120 case "clip-rect": 6121 var rect = Str(value).split(separator); 6122 if (rect.length == 4) { 6123 o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); 6124 var el = $("clipPath"), 6125 rc = $("rect"); 6126 el.id = R.createUUID(); 6127 $(rc, { 6128 x: rect[0], 6129 y: rect[1], 6130 width: rect[2], 6131 height: rect[3] 6132 }); 6133 el.appendChild(rc); 6134 o.paper.defs.appendChild(el); 6135 $(node, {"clip-path": "url(#" + el.id + ")"}); 6136 o.clip = rc; 6137 } 6138 if (!value) { 6139 var path = node.getAttribute("clip-path"); 6140 if (path) { 6141 var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E)); 6142 clip && clip.parentNode.removeChild(clip); 6143 $(node, {"clip-path": E}); 6144 delete o.clip; 6145 } 6146 } 6147 break; 6148 case "path": 6149 if (o.type == "path") { 6150 $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"}); 6151 o._.dirty = 1; 6152 if (o._.arrows) { 6153 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 6154 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 6155 } 6156 } 6157 break; 6158 case "width": 6159 node.setAttribute(att, value); 6160 o._.dirty = 1; 6161 if (attrs.fx) { 6162 att = "x"; 6163 value = attrs.x; 6164 } else { 6165 break; 6166 } 6167 case "x": 6168 if (attrs.fx) { 6169 value = -attrs.x - (attrs.width || 0); 6170 } 6171 case "rx": 6172 if (att == "rx" && o.type == "rect") { 6173 break; 6174 } 6175 case "cx": 6176 node.setAttribute(att, value); 6177 o.pattern && updatePosition(o); 6178 o._.dirty = 1; 6179 break; 6180 case "height": 6181 node.setAttribute(att, value); 6182 o._.dirty = 1; 6183 if (attrs.fy) { 6184 att = "y"; 6185 value = attrs.y; 6186 } else { 6187 break; 6188 } 6189 case "y": 6190 if (attrs.fy) { 6191 value = -attrs.y - (attrs.height || 0); 6192 } 6193 case "ry": 6194 if (att == "ry" && o.type == "rect") { 6195 break; 6196 } 6197 case "cy": 6198 node.setAttribute(att, value); 6199 o.pattern && updatePosition(o); 6200 o._.dirty = 1; 6201 break; 6202 case "r": 6203 if (o.type == "rect") { 6204 $(node, {rx: value, ry: value}); 6205 } else { 6206 node.setAttribute(att, value); 6207 } 6208 o._.dirty = 1; 6209 break; 6210 case "src": 6211 if (o.type == "image") { 6212 node.setAttributeNS(xlink, "href", value); 6213 } 6214 break; 6215 case "stroke-width": 6216 if (o._.sx != 1 || o._.sy != 1) { 6217 value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; 6218 } 6219 if (o.paper._vbSize) { 6220 value *= o.paper._vbSize; 6221 } 6222 node.setAttribute(att, value); 6223 if (attrs["stroke-dasharray"]) { 6224 addDashes(o, attrs["stroke-dasharray"], params); 6225 } 6226 if (o._.arrows) { 6227 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 6228 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 6229 } 6230 break; 6231 case "stroke-dasharray": 6232 addDashes(o, value, params); 6233 break; 6234 case "fill": 6235 var isURL = Str(value).match(R._ISURL); 6236 if (isURL) { 6237 el = $("pattern"); 6238 var ig = $("image"); 6239 el.id = R.createUUID(); 6240 $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); 6241 $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); 6242 el.appendChild(ig); 6243 6244 (function (el) { 6245 R._preload(isURL[1], function () { 6246 var w = this.offsetWidth, 6247 h = this.offsetHeight; 6248 $(el, {width: w, height: h}); 6249 $(ig, {width: w, height: h}); 6250 o.paper.safari(); 6251 }); 6252 })(el); 6253 o.paper.defs.appendChild(el); 6254 $(node, {fill: "url(#" + el.id + ")"}); 6255 o.pattern = el; 6256 o.pattern && updatePosition(o); 6257 break; 6258 } 6259 var clr = R.getRGB(value); 6260 if (!clr.error) { 6261 delete params.gradient; 6262 delete attrs.gradient; 6263 !R.is(attrs.opacity, "undefined") && 6264 R.is(params.opacity, "undefined") && 6265 $(node, {opacity: attrs.opacity}); 6266 !R.is(attrs["fill-opacity"], "undefined") && 6267 R.is(params["fill-opacity"], "undefined") && 6268 $(node, {"fill-opacity": attrs["fill-opacity"]}); 6269 } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { 6270 if ("opacity" in attrs || "fill-opacity" in attrs) { 6271 var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); 6272 if (gradient) { 6273 var stops = gradient.getElementsByTagName("stop"); 6274 $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); 6275 } 6276 } 6277 attrs.gradient = value; 6278 attrs.fill = "none"; 6279 break; 6280 } 6281 clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); 6282 case "stroke": 6283 clr = R.getRGB(value); 6284 node.setAttribute(att, clr.hex); 6285 att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); 6286 if (att == "stroke" && o._.arrows) { 6287 "startString" in o._.arrows && addArrow(o, o._.arrows.startString); 6288 "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); 6289 } 6290 break; 6291 case "gradient": 6292 (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); 6293 break; 6294 case "opacity": 6295 if (attrs.gradient && !attrs[has]("stroke-opacity")) { 6296 $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); 6297 } 6298 // fall 6299 case "fill-opacity": 6300 if (attrs.gradient) { 6301 gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); 6302 if (gradient) { 6303 stops = gradient.getElementsByTagName("stop"); 6304 $(stops[stops.length - 1], {"stop-opacity": value}); 6305 } 6306 break; 6307 } 6308 default: 6309 att == "font-size" && (value = toInt(value, 10) + "px"); 6310 var cssrule = att.replace(/(\-.)/g, function (w) { 6311 return w.substring(1).toUpperCase(); 6312 }); 6313 node.style[cssrule] = value; 6314 o._.dirty = 1; 6315 node.setAttribute(att, value); 6316 break; 6317 } 6318 } 6319 } 6320 6321 tuneText(o, params); 6322 node.style.visibility = vis; 6323 }, 6324 leading = 1.2, 6325 tuneText = function (el, params) { 6326 if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { 6327 return; 6328 } 6329 var a = el.attrs, 6330 node = el.node, 6331 fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; 6332 6333 if (params[has]("text")) { 6334 a.text = params.text; 6335 while (node.firstChild) { 6336 node.removeChild(node.firstChild); 6337 } 6338 var texts = Str(params.text).split("\n"), 6339 tspans = [], 6340 tspan; 6341 for (var i = 0, ii = texts.length; i < ii; i++) { 6342 tspan = $("tspan"); 6343 i && $(tspan, {dy: fontSize * leading, x: a.x}); 6344 tspan.appendChild(R._g.doc.createTextNode(texts[i])); 6345 node.appendChild(tspan); 6346 tspans[i] = tspan; 6347 } 6348 } else { 6349 tspans = node.getElementsByTagName("tspan"); 6350 for (i = 0, ii = tspans.length; i < ii; i++) if (i) { 6351 $(tspans[i], {dy: fontSize * leading, x: a.x}); 6352 } else { 6353 $(tspans[0], {dy: 0}); 6354 } 6355 } 6356 $(node, {x: a.x, y: a.y}); 6357 el._.dirty = 1; 6358 var bb = el._getBBox(), 6359 dif = a.y - (bb.y + bb.height / 2); 6360 dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); 6361 }, 6362 Element = function (node, svg) { 6363 var X = 0, 6364 Y = 0; 6365 /*\ 6366 * Element.node 6367 [ property (object) ] 6368 ** 6369 * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. 6370 ** 6371 * Note: Don’t mess with it. 6372 > Usage 6373 | // draw a circle at coordinate 10,10 with radius of 10 6374 | var c = paper.circle(10, 10, 10); 6375 | c.node.onclick = function () { 6376 | c.attr("fill", "red"); 6377 | }; 6378 \*/ 6379 this[0] = this.node = node; 6380 /*\ 6381 * Element.raphael 6382 [ property (object) ] 6383 ** 6384 * Internal reference to @Raphael object. In case it is not available. 6385 > Usage 6386 | Raphael.el.red = function () { 6387 | var hsb = this.paper.raphael.rgb2hsb(this.attr("fill")); 6388 | hsb.h = 1; 6389 | this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex}); 6390 | } 6391 \*/ 6392 node.raphael = true; 6393 /*\ 6394 * Element.id 6395 [ property (number) ] 6396 ** 6397 * Unique id of the element. Especially usesful when you want to listen to events of the element, 6398 * because all events are fired in format `<module>.<action>.<id>`. Also useful for @Paper.getById method. 6399 \*/ 6400 this.id = R._oid++; 6401 node.raphaelid = this.id; 6402 this.matrix = R.matrix(); 6403 this.realPath = null; 6404 /*\ 6405 * Element.paper 6406 [ property (object) ] 6407 ** 6408 * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions. 6409 > Usage 6410 | Raphael.el.cross = function () { 6411 | this.attr({fill: "red"}); 6412 | this.paper.path("M10,10L50,50M50,10L10,50") 6413 | .attr({stroke: "red"}); 6414 | } 6415 \*/ 6416 this.paper = svg; 6417 this.attrs = this.attrs || {}; 6418 this._ = { 6419 transform: [], 6420 sx: 1, 6421 sy: 1, 6422 deg: 0, 6423 dx: 0, 6424 dy: 0, 6425 dirty: 1 6426 }; 6427 !svg.bottom && (svg.bottom = this); 6428 /*\ 6429 * Element.prev 6430 [ property (object) ] 6431 ** 6432 * Reference to the previous element in the hierarchy. 6433 \*/ 6434 this.prev = svg.top; 6435 svg.top && (svg.top.next = this); 6436 svg.top = this; 6437 /*\ 6438 * Element.next 6439 [ property (object) ] 6440 ** 6441 * Reference to the next element in the hierarchy. 6442 \*/ 6443 this.next = null; 6444 }, 6445 elproto = R.el; 6446 6447 Element.prototype = elproto; 6448 elproto.constructor = Element; 6449 6450 R._engine.path = function (pathString, SVG) { 6451 var el = $("path"); 6452 SVG.canvas && SVG.canvas.appendChild(el); 6453 var p = new Element(el, SVG); 6454 p.type = "path"; 6455 setFillAndStroke(p, { 6456 fill: "none", 6457 stroke: "#000", 6458 path: pathString 6459 }); 6460 return p; 6461 }; 6462 /*\ 6463 * Element.rotate 6464 [ method ] 6465 ** 6466 * Deprecated! Use @Element.transform instead. 6467 * Adds rotation by given angle around given point to the list of 6468 * transformations of the element. 6469 > Parameters 6470 - deg (number) angle in degrees 6471 - cx (number) #optional x coordinate of the centre of rotation 6472 - cy (number) #optional y coordinate of the centre of rotation 6473 * If cx & cy aren’t specified centre of the shape is used as a point of rotation. 6474 = (object) @Element 6475 \*/ 6476 elproto.rotate = function (deg, cx, cy) { 6477 if (this.removed) { 6478 return this; 6479 } 6480 deg = Str(deg).split(separator); 6481 if (deg.length - 1) { 6482 cx = toFloat(deg[1]); 6483 cy = toFloat(deg[2]); 6484 } 6485 deg = toFloat(deg[0]); 6486 (cy == null) && (cx = cy); 6487 if (cx == null || cy == null) { 6488 var bbox = this.getBBox(1); 6489 cx = bbox.x + bbox.width / 2; 6490 cy = bbox.y + bbox.height / 2; 6491 } 6492 this.transform(this._.transform.concat([["r", deg, cx, cy]])); 6493 return this; 6494 }; 6495 /*\ 6496 * Element.scale 6497 [ method ] 6498 ** 6499 * Deprecated! Use @Element.transform instead. 6500 * Adds scale by given amount relative to given point to the list of 6501 * transformations of the element. 6502 > Parameters 6503 - sx (number) horisontal scale amount 6504 - sy (number) vertical scale amount 6505 - cx (number) #optional x coordinate of the centre of scale 6506 - cy (number) #optional y coordinate of the centre of scale 6507 * If cx & cy aren’t specified centre of the shape is used instead. 6508 = (object) @Element 6509 \*/ 6510 elproto.scale = function (sx, sy, cx, cy) { 6511 if (this.removed) { 6512 return this; 6513 } 6514 sx = Str(sx).split(separator); 6515 if (sx.length - 1) { 6516 sy = toFloat(sx[1]); 6517 cx = toFloat(sx[2]); 6518 cy = toFloat(sx[3]); 6519 } 6520 sx = toFloat(sx[0]); 6521 (sy == null) && (sy = sx); 6522 (cy == null) && (cx = cy); 6523 if (cx == null || cy == null) { 6524 var bbox = this.getBBox(1); 6525 } 6526 cx = cx == null ? bbox.x + bbox.width / 2 : cx; 6527 cy = cy == null ? bbox.y + bbox.height / 2 : cy; 6528 this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); 6529 return this; 6530 }; 6531 /*\ 6532 * Element.translate 6533 [ method ] 6534 ** 6535 * Deprecated! Use @Element.transform instead. 6536 * Adds translation by given amount to the list of transformations of the element. 6537 > Parameters 6538 - dx (number) horisontal shift 6539 - dy (number) vertical shift 6540 = (object) @Element 6541 \*/ 6542 elproto.translate = function (dx, dy) { 6543 if (this.removed) { 6544 return this; 6545 } 6546 dx = Str(dx).split(separator); 6547 if (dx.length - 1) { 6548 dy = toFloat(dx[1]); 6549 } 6550 dx = toFloat(dx[0]) || 0; 6551 dy = +dy || 0; 6552 this.transform(this._.transform.concat([["t", dx, dy]])); 6553 return this; 6554 }; 6555 /*\ 6556 * Element.transform 6557 [ method ] 6558 ** 6559 * Adds transformation to the element which is separate to other attributes, 6560 * i.e. translation doesn’t change `x` or `y` of the rectange. The format 6561 * of transformation string is similar to the path string syntax: 6562 | "t100,100r30,100,100s2,2,100,100r45s1.5" 6563 * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for 6564 * scale and `m` is for matrix. 6565 * 6566 * 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`. 6567 * 6568 * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100; 6569 * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin 6570 * coordinates as optional parameters, the default is the centre point of the element. 6571 * Matrix accepts six parameters. 6572 > Usage 6573 | var el = paper.rect(10, 20, 300, 200); 6574 | // translate 100, 100, rotate 45°, translate -100, 0 6575 | el.transform("t100,100r45t-100,0"); 6576 | // if you want you can append or prepend transformations 6577 | el.transform("...t50,50"); 6578 | el.transform("s2..."); 6579 | // or even wrap 6580 | el.transform("t50,50...t-50-50"); 6581 | // to reset transformation call method with empty string 6582 | el.transform(""); 6583 | // to get current value call it without parameters 6584 | console.log(el.transform()); 6585 > Parameters 6586 - tstr (string) #optional transformation string 6587 * If tstr isn’t specified 6588 = (string) current transformation string 6589 * else 6590 = (object) @Element 6591 \*/ 6592 elproto.transform = function (tstr) { 6593 var _ = this._; 6594 if (tstr == null) { 6595 return _.transform; 6596 } 6597 R._extractTransform(this, tstr); 6598 6599 this.clip && $(this.clip, {transform: this.matrix.invert()}); 6600 this.pattern && updatePosition(this); 6601 this.node && $(this.node, {transform: this.matrix}); 6602 6603 if (_.sx != 1 || _.sy != 1) { 6604 var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; 6605 this.attr({"stroke-width": sw}); 6606 } 6607 6608 return this; 6609 }; 6610 /*\ 6611 * Element.hide 6612 [ method ] 6613 ** 6614 * Makes element invisible. See @Element.show. 6615 = (object) @Element 6616 \*/ 6617 elproto.hide = function () { 6618 !this.removed && this.paper.safari(this.node.style.display = "none"); 6619 return this; 6620 }; 6621 /*\ 6622 * Element.show 6623 [ method ] 6624 ** 6625 * Makes element visible. See @Element.hide. 6626 = (object) @Element 6627 \*/ 6628 elproto.show = function () { 6629 !this.removed && this.paper.safari(this.node.style.display = ""); 6630 return this; 6631 }; 6632 /*\ 6633 * Element.remove 6634 [ method ] 6635 ** 6636 * Removes element from the paper. 6637 \*/ 6638 elproto.remove = function () { 6639 if (this.removed || !this.node.parentNode) { 6640 return; 6641 } 6642 var paper = this.paper; 6643 paper.__set__ && paper.__set__.exclude(this); 6644 eve.unbind("raphael.*.*." + this.id); 6645 if (this.gradient) { 6646 paper.defs.removeChild(this.gradient); 6647 } 6648 R._tear(this, paper); 6649 if (this.node.parentNode.tagName.toLowerCase() == "a") { 6650 this.node.parentNode.parentNode.removeChild(this.node.parentNode); 6651 } else { 6652 this.node.parentNode.removeChild(this.node); 6653 } 6654 for (var i in this) { 6655 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 6656 } 6657 this.removed = true; 6658 }; 6659 elproto._getBBox = function () { 6660 if (this.node.style.display == "none") { 6661 this.show(); 6662 var hide = true; 6663 } 6664 var bbox = {}; 6665 try { 6666 bbox = this.node.getBBox(); 6667 } catch(e) { 6668 // Firefox 3.0.x plays badly here 6669 } finally { 6670 bbox = bbox || {}; 6671 } 6672 hide && this.hide(); 6673 return bbox; 6674 }; 6675 /*\ 6676 * Element.attr 6677 [ method ] 6678 ** 6679 * Sets the attributes of the element. 6680 > Parameters 6681 - attrName (string) attribute’s name 6682 - value (string) value 6683 * or 6684 - params (object) object of name/value pairs 6685 * or 6686 - attrName (string) attribute’s name 6687 * or 6688 - attrNames (array) in this case method returns array of current values for given attribute names 6689 = (object) @Element if attrsName & value or params are passed in. 6690 = (...) value of the attribute if only attrsName is passed in. 6691 = (array) array of values of the attribute if attrsNames is passed in. 6692 = (object) object of attributes if nothing is passed in. 6693 > Possible parameters 6694 # <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> 6695 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`. 6696 o clip-rect (string) comma or space separated values: x, y, width and height 6697 o cursor (string) CSS type of the cursor 6698 o cx (number) the x-axis coordinate of the center of the circle, or ellipse 6699 o cy (number) the y-axis coordinate of the center of the circle, or ellipse 6700 o fill (string) colour, gradient or image 6701 o fill-opacity (number) 6702 o font (string) 6703 o font-family (string) 6704 o font-size (number) font size in pixels 6705 o font-weight (string) 6706 o height (number) 6707 o href (string) URL, if specified element behaves as hyperlink 6708 o opacity (number) 6709 o path (string) SVG path string format 6710 o r (number) radius of the circle, ellipse or rounded corner on the rect 6711 o rx (number) horisontal radius of the ellipse 6712 o ry (number) vertical radius of the ellipse 6713 o src (string) image URL, only works for @Element.image element 6714 o stroke (string) stroke colour 6715 o stroke-dasharray (string) [“”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”] 6716 o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”] 6717 o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”] 6718 o stroke-miterlimit (number) 6719 o stroke-opacity (number) 6720 o stroke-width (number) stroke width in pixels, default is '1' 6721 o target (string) used with href 6722 o text (string) contents of the text element. Use `\n` for multiline text 6723 o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`” 6724 o title (string) will create tooltip with a given text 6725 o transform (string) see @Element.transform 6726 o width (number) 6727 o x (number) 6728 o y (number) 6729 > Gradients 6730 * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90° 6731 * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black. 6732 * 6733 * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” – 6734 * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point 6735 * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses. 6736 > Path String 6737 # <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> 6738 > Colour Parsing 6739 # <ul> 6740 # <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li> 6741 # <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li> 6742 # <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li> 6743 # <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200, 100, 0)</code>”)</li> 6744 # <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%, 175%, 0%)</code>”)</li> 6745 # <li>rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“<code>rgba(200, 100, 0, .5)</code>”)</li> 6746 # <li>rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“<code>rgba(100%, 175%, 0%, 50%)</code>”)</li> 6747 # <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5, 0.25, 1)</code>”)</li> 6748 # <li>hsb(•••%, •••%, •••%) — same as above, but in %</li> 6749 # <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li> 6750 # <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> 6751 # <li>hsl(•••%, •••%, •••%) — same as above, but in %</li> 6752 # <li>hsla(•••, •••, •••, •••) — same as above, but with opacity</li> 6753 # <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> 6754 # </ul> 6755 \*/ 6756 elproto.attr = function (name, value) { 6757 if (this.removed) { 6758 return this; 6759 } 6760 if (name == null) { 6761 var res = {}; 6762 for (var a in this.attrs) if (this.attrs[has](a)) { 6763 res[a] = this.attrs[a]; 6764 } 6765 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; 6766 res.transform = this._.transform; 6767 return res; 6768 } 6769 if (value == null && R.is(name, "string")) { 6770 if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { 6771 return this.attrs.gradient; 6772 } 6773 if (name == "transform") { 6774 return this._.transform; 6775 } 6776 var names = name.split(separator), 6777 out = {}; 6778 for (var i = 0, ii = names.length; i < ii; i++) { 6779 name = names[i]; 6780 if (name in this.attrs) { 6781 out[name] = this.attrs[name]; 6782 } else if (R.is(this.paper.customAttributes[name], "function")) { 6783 out[name] = this.paper.customAttributes[name].def; 6784 } else { 6785 out[name] = R._availableAttrs[name]; 6786 } 6787 } 6788 return ii - 1 ? out : out[names[0]]; 6789 } 6790 if (value == null && R.is(name, "array")) { 6791 out = {}; 6792 for (i = 0, ii = name.length; i < ii; i++) { 6793 out[name[i]] = this.attr(name[i]); 6794 } 6795 return out; 6796 } 6797 if (value != null) { 6798 var params = {}; 6799 params[name] = value; 6800 } else if (name != null && R.is(name, "object")) { 6801 params = name; 6802 } 6803 for (var key in params) { 6804 eve("raphael.attr." + key + "." + this.id, this, params[key]); 6805 } 6806 for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { 6807 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); 6808 this.attrs[key] = params[key]; 6809 for (var subkey in par) if (par[has](subkey)) { 6810 params[subkey] = par[subkey]; 6811 } 6812 } 6813 setFillAndStroke(this, params); 6814 return this; 6815 }; 6816 /*\ 6817 * Element.toFront 6818 [ method ] 6819 ** 6820 * Moves the element so it is the closest to the viewer’s eyes, on top of other elements. 6821 = (object) @Element 6822 \*/ 6823 elproto.toFront = function () { 6824 if (this.removed) { 6825 return this; 6826 } 6827 if (this.node.parentNode.tagName.toLowerCase() == "a") { 6828 this.node.parentNode.parentNode.appendChild(this.node.parentNode); 6829 } else { 6830 this.node.parentNode.appendChild(this.node); 6831 } 6832 var svg = this.paper; 6833 svg.top != this && R._tofront(this, svg); 6834 return this; 6835 }; 6836 /*\ 6837 * Element.toBack 6838 [ method ] 6839 ** 6840 * Moves the element so it is the furthest from the viewer’s eyes, behind other elements. 6841 = (object) @Element 6842 \*/ 6843 elproto.toBack = function () { 6844 if (this.removed) { 6845 return this; 6846 } 6847 var parent = this.node.parentNode; 6848 if (parent.tagName.toLowerCase() == "a") { 6849 parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild); 6850 } else if (parent.firstChild != this.node) { 6851 parent.insertBefore(this.node, this.node.parentNode.firstChild); 6852 } 6853 R._toback(this, this.paper); 6854 var svg = this.paper; 6855 return this; 6856 }; 6857 /*\ 6858 * Element.insertAfter 6859 [ method ] 6860 ** 6861 * Inserts current object after the given one. 6862 = (object) @Element 6863 \*/ 6864 elproto.insertAfter = function (element) { 6865 if (this.removed) { 6866 return this; 6867 } 6868 var node = element.node || element[element.length - 1].node; 6869 if (node.nextSibling) { 6870 node.parentNode.insertBefore(this.node, node.nextSibling); 6871 } else { 6872 node.parentNode.appendChild(this.node); 6873 } 6874 R._insertafter(this, element, this.paper); 6875 return this; 6876 }; 6877 /*\ 6878 * Element.insertBefore 6879 [ method ] 6880 ** 6881 * Inserts current object before the given one. 6882 = (object) @Element 6883 \*/ 6884 elproto.insertBefore = function (element) { 6885 if (this.removed) { 6886 return this; 6887 } 6888 var node = element.node || element[0].node; 6889 node.parentNode.insertBefore(this.node, node); 6890 R._insertbefore(this, element, this.paper); 6891 return this; 6892 }; 6893 elproto.blur = function (size) { 6894 // Experimental. No Safari support. Use it on your own risk. 6895 var t = this; 6896 if (+size !== 0) { 6897 var fltr = $("filter"), 6898 blur = $("feGaussianBlur"); 6899 t.attrs.blur = size; 6900 fltr.id = R.createUUID(); 6901 $(blur, {stdDeviation: +size || 1.5}); 6902 fltr.appendChild(blur); 6903 t.paper.defs.appendChild(fltr); 6904 t._blur = fltr; 6905 $(t.node, {filter: "url(#" + fltr.id + ")"}); 6906 } else { 6907 if (t._blur) { 6908 t._blur.parentNode.removeChild(t._blur); 6909 delete t._blur; 6910 delete t.attrs.blur; 6911 } 6912 t.node.removeAttribute("filter"); 6913 } 6914 return t; 6915 }; 6916 R._engine.circle = function (svg, x, y, r) { 6917 var el = $("circle"); 6918 svg.canvas && svg.canvas.appendChild(el); 6919 var res = new Element(el, svg); 6920 res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; 6921 res.type = "circle"; 6922 $(el, res.attrs); 6923 return res; 6924 }; 6925 R._engine.rect = function (svg, x, y, w, h, r) { 6926 var el = $("rect"); 6927 svg.canvas && svg.canvas.appendChild(el); 6928 var res = new Element(el, svg); 6929 res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; 6930 res.type = "rect"; 6931 $(el, res.attrs); 6932 return res; 6933 }; 6934 R._engine.ellipse = function (svg, x, y, rx, ry) { 6935 var el = $("ellipse"); 6936 svg.canvas && svg.canvas.appendChild(el); 6937 var res = new Element(el, svg); 6938 res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; 6939 res.type = "ellipse"; 6940 $(el, res.attrs); 6941 return res; 6942 }; 6943 R._engine.image = function (svg, src, x, y, w, h) { 6944 var el = $("image"); 6945 $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); 6946 el.setAttributeNS(xlink, "href", src); 6947 svg.canvas && svg.canvas.appendChild(el); 6948 var res = new Element(el, svg); 6949 res.attrs = {x: x, y: y, width: w, height: h, src: src}; 6950 res.type = "image"; 6951 return res; 6952 }; 6953 R._engine.text = function (svg, x, y, text) { 6954 var el = $("text"); 6955 svg.canvas && svg.canvas.appendChild(el); 6956 var res = new Element(el, svg); 6957 res.attrs = { 6958 x: x, 6959 y: y, 6960 "text-anchor": "middle", 6961 text: text, 6962 font: R._availableAttrs.font, 6963 stroke: "none", 6964 fill: "#000" 6965 }; 6966 res.type = "text"; 6967 setFillAndStroke(res, res.attrs); 6968 return res; 6969 }; 6970 R._engine.setSize = function (width, height) { 6971 this.width = width || this.width; 6972 this.height = height || this.height; 6973 this.canvas.setAttribute("width", this.width); 6974 this.canvas.setAttribute("height", this.height); 6975 if (this._viewBox) { 6976 this.setViewBox.apply(this, this._viewBox); 6977 } 6978 return this; 6979 }; 6980 R._engine.create = function () { 6981 var con = R._getContainer.apply(0, arguments), 6982 container = con && con.container, 6983 x = con.x, 6984 y = con.y, 6985 width = con.width, 6986 height = con.height; 6987 if (!container) { 6988 throw new Error("SVG container not found."); 6989 } 6990 var cnvs = $("svg"), 6991 css = "overflow:hidden;", 6992 isFloating; 6993 x = x || 0; 6994 y = y || 0; 6995 width = width || 512; 6996 height = height || 342; 6997 $(cnvs, { 6998 height: height, 6999 version: 1.1, 7000 width: width, 7001 xmlns: "http://www.w3.org/2000/svg" 7002 }); 7003 if (container == 1) { 7004 cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; 7005 R._g.doc.body.appendChild(cnvs); 7006 isFloating = 1; 7007 } else { 7008 cnvs.style.cssText = css + "position:relative"; 7009 if (container.firstChild) { 7010 container.insertBefore(cnvs, container.firstChild); 7011 } else { 7012 container.appendChild(cnvs); 7013 } 7014 } 7015 container = new R._Paper; 7016 container.width = width; 7017 container.height = height; 7018 container.canvas = cnvs; 7019 container.clear(); 7020 container._left = container._top = 0; 7021 isFloating && (container.renderfix = function () {}); 7022 container.renderfix(); 7023 return container; 7024 }; 7025 R._engine.setViewBox = function (x, y, w, h, fit) { 7026 eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]); 7027 var size = mmax(w / this.width, h / this.height), 7028 top = this.top, 7029 aspectRatio = fit ? "xMidYMid meet" : "xMinYMin", 7030 vb, 7031 sw; 7032 if (x == null) { 7033 if (this._vbSize) { 7034 size = 1; 7035 } 7036 delete this._vbSize; 7037 vb = "0 0 " + this.width + S + this.height; 7038 } else { 7039 this._vbSize = size; 7040 vb = x + S + y + S + w + S + h; 7041 } 7042 $(this.canvas, { 7043 viewBox: vb, 7044 preserveAspectRatio: aspectRatio 7045 }); 7046 while (size && top) { 7047 sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; 7048 top.attr({"stroke-width": sw}); 7049 top._.dirty = 1; 7050 top._.dirtyT = 1; 7051 top = top.prev; 7052 } 7053 this._viewBox = [x, y, w, h, !!fit]; 7054 return this; 7055 }; 7056 /*\ 7057 * Paper.renderfix 7058 [ method ] 7059 ** 7060 * Fixes the issue of Firefox and IE9 regarding subpixel rendering. If paper is dependant 7061 * on other elements after reflow it could shift half pixel which cause for lines to lost their crispness. 7062 * This method fixes the issue. 7063 ** 7064 Special thanks to Mariusz Nowak (http://www.medikoo.com/) for this method. 7065 \*/ 7066 R.prototype.renderfix = function () { 7067 var cnvs = this.canvas, 7068 s = cnvs.style, 7069 pos; 7070 try { 7071 pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(); 7072 } catch (e) { 7073 pos = cnvs.createSVGMatrix(); 7074 } 7075 var left = -pos.e % 1, 7076 top = -pos.f % 1; 7077 if (left || top) { 7078 if (left) { 7079 this._left = (this._left + left) % 1; 7080 s.left = this._left + "px"; 7081 } 7082 if (top) { 7083 this._top = (this._top + top) % 1; 7084 s.top = this._top + "px"; 7085 } 7086 } 7087 }; 7088 /*\ 7089 * Paper.clear 7090 [ method ] 7091 ** 7092 * Clears the paper, i.e. removes all the elements. 7093 \*/ 7094 R.prototype.clear = function () { 7095 R.eve("raphael.clear", this); 7096 var c = this.canvas; 7097 while (c.firstChild) { 7098 c.removeChild(c.firstChild); 7099 } 7100 this.bottom = this.top = null; 7101 (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version)); 7102 c.appendChild(this.desc); 7103 c.appendChild(this.defs = $("defs")); 7104 }; 7105 /*\ 7106 * Paper.remove 7107 [ method ] 7108 ** 7109 * Removes the paper from the DOM. 7110 \*/ 7111 R.prototype.remove = function () { 7112 eve("raphael.remove", this); 7113 this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); 7114 for (var i in this) { 7115 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 7116 } 7117 }; 7118 var setproto = R.st; 7119 for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { 7120 setproto[method] = (function (methodname) { 7121 return function () { 7122 var arg = arguments; 7123 return this.forEach(function (el) { 7124 el[methodname].apply(el, arg); 7125 }); 7126 }; 7127 })(method); 7128 } 7129})(); 7130 7131// ┌─────────────────────────────────────────────────────────────────────┐ \\ 7132// │ Raphaël - JavaScript Vector Library │ \\ 7133// ├─────────────────────────────────────────────────────────────────────┤ \\ 7134// │ VML Module │ \\ 7135// ├─────────────────────────────────────────────────────────────────────┤ \\ 7136// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ 7137// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ 7138// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ 7139// └─────────────────────────────────────────────────────────────────────┘ \\ 7140 7141(function(){ 7142 if (!R.vml) { 7143 return; 7144 } 7145 var has = "hasOwnProperty", 7146 Str = String, 7147 toFloat = parseFloat, 7148 math = Math, 7149 round = math.round, 7150 mmax = math.max, 7151 mmin = math.min, 7152 abs = math.abs, 7153 fillString = "fill", 7154 separator = /[, ]+/, 7155 eve = R.eve, 7156 ms = " progid:DXImageTransform.Microsoft", 7157 S = " ", 7158 E = "", 7159 map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, 7160 bites = /([clmz]),?([^clmz]*)/gi, 7161 blurregexp = / progid:\S+Blur\([^\)]+\)/g, 7162 val = /-?[^,\s-]+/g, 7163 cssDot = "position:absolute;left:0;top:0;width:1px;height:1px", 7164 zoom = 21600, 7165 pathTypes = {path: 1, rect: 1, image: 1}, 7166 ovalTypes = {circle: 1, ellipse: 1}, 7167 path2vml = function (path) { 7168 var total = /[ahqstv]/ig, 7169 command = R._pathToAbsolute; 7170 Str(path).match(total) && (command = R._path2curve); 7171 total = /[clmz]/g; 7172 if (command == R._pathToAbsolute && !Str(path).match(total)) { 7173 var res = Str(path).replace(bites, function (all, command, args) { 7174 var vals = [], 7175 isMove = command.toLowerCase() == "m", 7176 res = map[command]; 7177 args.replace(val, function (value) { 7178 if (isMove && vals.length == 2) { 7179 res += vals + map[command == "m" ? "l" : "L"]; 7180 vals = []; 7181 } 7182 vals.push(round(value * zoom)); 7183 }); 7184 return res + vals; 7185 }); 7186 return res; 7187 } 7188 var pa = command(path), p, r; 7189 res = []; 7190 for (var i = 0, ii = pa.length; i < ii; i++) { 7191 p = pa[i]; 7192 r = pa[i][0].toLowerCase(); 7193 r == "z" && (r = "x"); 7194 for (var j = 1, jj = p.length; j < jj; j++) { 7195 r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); 7196 } 7197 res.push(r); 7198 } 7199 return res.join(S); 7200 }, 7201 compensation = function (deg, dx, dy) { 7202 var m = R.matrix(); 7203 m.rotate(-deg, .5, .5); 7204 return { 7205 dx: m.x(dx, dy), 7206 dy: m.y(dx, dy) 7207 }; 7208 }, 7209 setCoords = function (p, sx, sy, dx, dy, deg) { 7210 var _ = p._, 7211 m = p.matrix, 7212 fillpos = _.fillpos, 7213 o = p.node, 7214 s = o.style, 7215 y = 1, 7216 flip = "", 7217 dxdy, 7218 kx = zoom / sx, 7219 ky = zoom / sy; 7220 s.visibility = "hidden"; 7221 if (!sx || !sy) { 7222 return; 7223 } 7224 o.coordsize = abs(kx) + S + abs(ky); 7225 s.rotation = deg * (sx * sy < 0 ? -1 : 1); 7226 if (deg) { 7227 var c = compensation(deg, dx, dy); 7228 dx = c.dx; 7229 dy = c.dy; 7230 } 7231 sx < 0 && (flip += "x"); 7232 sy < 0 && (flip += " y") && (y = -1); 7233 s.flip = flip; 7234 o.coordorigin = (dx * -kx) + S + (dy * -ky); 7235 if (fillpos || _.fillsize) { 7236 var fill = o.getElementsByTagName(fillString); 7237 fill = fill && fill[0]; 7238 o.removeChild(fill); 7239 if (fillpos) { 7240 c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); 7241 fill.position = c.dx * y + S + c.dy * y; 7242 } 7243 if (_.fillsize) { 7244 fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); 7245 } 7246 o.appendChild(fill); 7247 } 7248 s.visibility = "visible"; 7249 }; 7250 R.toString = function () { 7251 return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; 7252 }; 7253 var addArrow = function (o, value, isEnd) { 7254 var values = Str(value).toLowerCase().split("-"), 7255 se = isEnd ? "end" : "start", 7256 i = values.length, 7257 type = "classic", 7258 w = "medium", 7259 h = "medium"; 7260 while (i--) { 7261 switch (values[i]) { 7262 case "block": 7263 case "classic": 7264 case "oval": 7265 case "diamond": 7266 case "open": 7267 case "none": 7268 type = values[i]; 7269 break; 7270 case "wide": 7271 case "narrow": h = values[i]; break; 7272 case "long": 7273 case "short": w = values[i]; break; 7274 } 7275 } 7276 var stroke = o.node.getElementsByTagName("stroke")[0]; 7277 stroke[se + "arrow"] = type; 7278 stroke[se + "arrowlength"] = w; 7279 stroke[se + "arrowwidth"] = h; 7280 }, 7281 setFillAndStroke = function (o, params) { 7282 // o.paper.canvas.style.display = "none"; 7283 o.attrs = o.attrs || {}; 7284 var node = o.node, 7285 a = o.attrs, 7286 s = node.style, 7287 xy, 7288 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), 7289 isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), 7290 res = o; 7291 7292 7293 for (var par in params) if (params[has](par)) { 7294 a[par] = params[par]; 7295 } 7296 if (newpath) { 7297 a.path = R._getPath[o.type](o); 7298 o._.dirty = 1; 7299 } 7300 params.href && (node.href = params.href); 7301 params.title && (node.title = params.title); 7302 params.target && (node.target = params.target); 7303 params.cursor && (s.cursor = params.cursor); 7304 "blur" in params && o.blur(params.blur); 7305 if (params.path && o.type == "path" || newpath) { 7306 node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path); 7307 if (o.type == "image") { 7308 o._.fillpos = [a.x, a.y]; 7309 o._.fillsize = [a.width, a.height]; 7310 setCoords(o, 1, 1, 0, 0, 0); 7311 } 7312 } 7313 "transform" in params && o.transform(params.transform); 7314 if (isOval) { 7315 var cx = +a.cx, 7316 cy = +a.cy, 7317 rx = +a.rx || +a.r || 0, 7318 ry = +a.ry || +a.r || 0; 7319 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)); 7320 o._.dirty = 1; 7321 } 7322 if ("clip-rect" in params) { 7323 var rect = Str(params["clip-rect"]).split(separator); 7324 if (rect.length == 4) { 7325 rect[2] = +rect[2] + (+rect[0]); 7326 rect[3] = +rect[3] + (+rect[1]); 7327 var div = node.clipRect || R._g.doc.createElement("div"), 7328 dstyle = div.style; 7329 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); 7330 if (!node.clipRect) { 7331 dstyle.position = "absolute"; 7332 dstyle.top = 0; 7333 dstyle.left = 0; 7334 dstyle.width = o.paper.width + "px"; 7335 dstyle.height = o.paper.height + "px"; 7336 node.parentNode.insertBefore(div, node); 7337 div.appendChild(node); 7338 node.clipRect = div; 7339 } 7340 } 7341 if (!params["clip-rect"]) { 7342 node.clipRect && (node.clipRect.style.clip = "auto"); 7343 } 7344 } 7345 if (o.textpath) { 7346 var textpathStyle = o.textpath.style; 7347 params.font && (textpathStyle.font = params.font); 7348 params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); 7349 params["font-size"] && (textpathStyle.fontSize = params["font-size"]); 7350 params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); 7351 params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); 7352 } 7353 if ("arrow-start" in params) { 7354 addArrow(res, params["arrow-start"]); 7355 } 7356 if ("arrow-end" in params) { 7357 addArrow(res, params["arrow-end"], 1); 7358 } 7359 if (params.opacity != null || 7360 params["stroke-width"] != null || 7361 params.fill != null || 7362 params.src != null || 7363 params.stroke != null || 7364 params["stroke-width"] != null || 7365 params["stroke-opacity"] != null || 7366 params["fill-opacity"] != null || 7367 params["stroke-dasharray"] != null || 7368 params["stroke-miterlimit"] != null || 7369 params["stroke-linejoin"] != null || 7370 params["stroke-linecap"] != null) { 7371 var fill = node.getElementsByTagName(fillString), 7372 newfill = false; 7373 fill = fill && fill[0]; 7374 !fill && (newfill = fill = createNode(fillString)); 7375 if (o.type == "image" && params.src) { 7376 fill.src = params.src; 7377 } 7378 params.fill && (fill.on = true); 7379 if (fill.on == null || params.fill == "none" || params.fill === null) { 7380 fill.on = false; 7381 } 7382 if (fill.on && params.fill) { 7383 var isURL = Str(params.fill).match(R._ISURL); 7384 if (isURL) { 7385 fill.parentNode == node && node.removeChild(fill); 7386 fill.rotate = true; 7387 fill.src = isURL[1]; 7388 fill.type = "tile"; 7389 var bbox = o.getBBox(1); 7390 fill.position = bbox.x + S + bbox.y; 7391 o._.fillpos = [bbox.x, bbox.y]; 7392 7393 R._preload(isURL[1], function () { 7394 o._.fillsize = [this.offsetWidth, this.offsetHeight]; 7395 }); 7396 } else { 7397 fill.color = R.getRGB(params.fill).hex; 7398 fill.src = E; 7399 fill.type = "solid"; 7400 if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { 7401 a.fill = "none"; 7402 a.gradient = params.fill; 7403 fill.rotate = false; 7404 } 7405 } 7406 } 7407 if ("fill-opacity" in params || "opacity" in params) { 7408 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); 7409 opacity = mmin(mmax(opacity, 0), 1); 7410 fill.opacity = opacity; 7411 if (fill.src) { 7412 fill.color = "none"; 7413 } 7414 } 7415 node.appendChild(fill); 7416 var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), 7417 newstroke = false; 7418 !stroke && (newstroke = stroke = createNode("stroke")); 7419 if ((params.stroke && params.stroke != "none") || 7420 params["stroke-width"] || 7421 params["stroke-opacity"] != null || 7422 params["stroke-dasharray"] || 7423 params["stroke-miterlimit"] || 7424 params["stroke-linejoin"] || 7425 params["stroke-linecap"]) { 7426 stroke.on = true; 7427 } 7428 (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); 7429 var strokeColor = R.getRGB(params.stroke); 7430 stroke.on && params.stroke && (stroke.color = strokeColor.hex); 7431 opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); 7432 var width = (toFloat(params["stroke-width"]) || 1) * .75; 7433 opacity = mmin(mmax(opacity, 0), 1); 7434 params["stroke-width"] == null && (width = a["stroke-width"]); 7435 params["stroke-width"] && (stroke.weight = width); 7436 width && width < 1 && (opacity *= width) && (stroke.weight = 1); 7437 stroke.opacity = opacity; 7438 7439 params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); 7440 stroke.miterlimit = params["stroke-miterlimit"] || 8; 7441 params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); 7442 if ("stroke-dasharray" in params) { 7443 var dasharray = { 7444 "-": "shortdash", 7445 ".": "shortdot", 7446 "-.": "shortdashdot", 7447 "-..": "shortdashdotdot", 7448 ". ": "dot", 7449 "- ": "dash", 7450 "--": "longdash", 7451 "- .": "dashdot", 7452 "--.": "longdashdot", 7453 "--..": "longdashdotdot" 7454 }; 7455 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; 7456 } 7457 newstroke && node.appendChild(stroke); 7458 } 7459 if (res.type == "text") { 7460 res.paper.canvas.style.display = E; 7461 var span = res.paper.span, 7462 m = 100, 7463 fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); 7464 s = span.style; 7465 a.font && (s.font = a.font); 7466 a["font-family"] && (s.fontFamily = a["font-family"]); 7467 a["font-weight"] && (s.fontWeight = a["font-weight"]); 7468 a["font-style"] && (s.fontStyle = a["font-style"]); 7469 fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10; 7470 s.fontSize = fontSize * m + "px"; 7471 res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/</g, "<").replace(/&/g, "&").replace(/\n/g, "<br>")); 7472 var brect = span.getBoundingClientRect(); 7473 res.W = a.w = (brect.right - brect.left) / m; 7474 res.H = a.h = (brect.bottom - brect.top) / m; 7475 // res.paper.canvas.style.display = "none"; 7476 res.X = a.x; 7477 res.Y = a.y + res.H / 2; 7478 7479 ("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)); 7480 var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; 7481 for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { 7482 res._.dirty = 1; 7483 break; 7484 } 7485 7486 // text-anchor emulation 7487 switch (a["text-anchor"]) { 7488 case "start": 7489 res.textpath.style["v-text-align"] = "left"; 7490 res.bbx = res.W / 2; 7491 break; 7492 case "end": 7493 res.textpath.style["v-text-align"] = "right"; 7494 res.bbx = -res.W / 2; 7495 break; 7496 default: 7497 res.textpath.style["v-text-align"] = "center"; 7498 res.bbx = 0; 7499 break; 7500 } 7501 res.textpath.style["v-text-kern"] = true; 7502 } 7503 // res.paper.canvas.style.display = E; 7504 }, 7505 addGradientFill = function (o, gradient, fill) { 7506 o.attrs = o.attrs || {}; 7507 var attrs = o.attrs, 7508 pow = Math.pow, 7509 opacity, 7510 oindex, 7511 type = "linear", 7512 fxfy = ".5 .5"; 7513 o.attrs.gradient = gradient; 7514 gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) { 7515 type = "radial"; 7516 if (fx && fy) { 7517 fx = toFloat(fx); 7518 fy = toFloat(fy); 7519 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); 7520 fxfy = fx + S + fy; 7521 } 7522 return E; 7523 }); 7524 gradient = gradient.split(/\s*\-\s*/); 7525 if (type == "linear") { 7526 var angle = gradient.shift(); 7527 angle = -toFloat(angle); 7528 if (isNaN(angle)) { 7529 return null; 7530 } 7531 } 7532 var dots = R._parseDots(gradient); 7533 if (!dots) { 7534 return null; 7535 } 7536 o = o.shape || o.node; 7537 if (dots.length) { 7538 o.removeChild(fill); 7539 fill.on = true; 7540 fill.method = "none"; 7541 fill.color = dots[0].color; 7542 fill.color2 = dots[dots.length - 1].color; 7543 var clrs = []; 7544 for (var i = 0, ii = dots.length; i < ii; i++) { 7545 dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); 7546 } 7547 fill.colors = clrs.length ? clrs.join() : "0% " + fill.color; 7548 if (type == "radial") { 7549 fill.type = "gradientTitle"; 7550 fill.focus = "100%"; 7551 fill.focussize = "0 0"; 7552 fill.focusposition = fxfy; 7553 fill.angle = 0; 7554 } else { 7555 // fill.rotate= true; 7556 fill.type = "gradient"; 7557 fill.angle = (270 - angle) % 360; 7558 } 7559 o.appendChild(fill); 7560 } 7561 return 1; 7562 }, 7563 Element = function (node, vml) { 7564 this[0] = this.node = node; 7565 node.raphael = true; 7566 this.id = R._oid++; 7567 node.raphaelid = this.id; 7568 this.X = 0; 7569 this.Y = 0; 7570 this.attrs = {}; 7571 this.paper = vml; 7572 this.matrix = R.matrix(); 7573 this._ = { 7574 transform: [], 7575 sx: 1, 7576 sy: 1, 7577 dx: 0, 7578 dy: 0, 7579 deg: 0, 7580 dirty: 1, 7581 dirtyT: 1 7582 }; 7583 !vml.bottom && (vml.bottom = this); 7584 this.prev = vml.top; 7585 vml.top && (vml.top.next = this); 7586 vml.top = this; 7587 this.next = null; 7588 }; 7589 var elproto = R.el; 7590 7591 Element.prototype = elproto; 7592 elproto.constructor = Element; 7593 elproto.transform = function (tstr) { 7594 if (tstr == null) { 7595 return this._.transform; 7596 } 7597 var vbs = this.paper._viewBoxShift, 7598 vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E, 7599 oldt; 7600 if (vbs) { 7601 oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E); 7602 } 7603 R._extractTransform(this, vbt + tstr); 7604 var matrix = this.matrix.clone(), 7605 skew = this.skew, 7606 o = this.node, 7607 split, 7608 isGrad = ~Str(this.attrs.fill).indexOf("-"), 7609 isPatt = !Str(this.attrs.fill).indexOf("url("); 7610 matrix.translate(1, 1); 7611 if (isPatt || isGrad || this.type == "image") { 7612 skew.matrix = "1 0 0 1"; 7613 skew.offset = "0 0"; 7614 split = matrix.split(); 7615 if ((isGrad && split.noRotation) || !split.isSimple) { 7616 o.style.filter = matrix.toFilter(); 7617 var bb = this.getBBox(), 7618 bbt = this.getBBox(1), 7619 dx = bb.x - bbt.x, 7620 dy = bb.y - bbt.y; 7621 o.coordorigin = (dx * -zoom) + S + (dy * -zoom); 7622 setCoords(this, 1, 1, dx, dy, 0); 7623 } else { 7624 o.style.filter = E; 7625 setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate); 7626 } 7627 } else { 7628 o.style.filter = E; 7629 skew.matrix = Str(matrix); 7630 skew.offset = matrix.offset(); 7631 } 7632 oldt && (this._.transform = oldt); 7633 return this; 7634 }; 7635 elproto.rotate = function (deg, cx, cy) { 7636 if (this.removed) { 7637 return this; 7638 } 7639 if (deg == null) { 7640 return; 7641 } 7642 deg = Str(deg).split(separator); 7643 if (deg.length - 1) { 7644 cx = toFloat(deg[1]); 7645 cy = toFloat(deg[2]); 7646 } 7647 deg = toFloat(deg[0]); 7648 (cy == null) && (cx = cy); 7649 if (cx == null || cy == null) { 7650 var bbox = this.getBBox(1); 7651 cx = bbox.x + bbox.width / 2; 7652 cy = bbox.y + bbox.height / 2; 7653 } 7654 this._.dirtyT = 1; 7655 this.transform(this._.transform.concat([["r", deg, cx, cy]])); 7656 return this; 7657 }; 7658 elproto.translate = function (dx, dy) { 7659 if (this.removed) { 7660 return this; 7661 } 7662 dx = Str(dx).split(separator); 7663 if (dx.length - 1) { 7664 dy = toFloat(dx[1]); 7665 } 7666 dx = toFloat(dx[0]) || 0; 7667 dy = +dy || 0; 7668 if (this._.bbox) { 7669 this._.bbox.x += dx; 7670 this._.bbox.y += dy; 7671 } 7672 this.transform(this._.transform.concat([["t", dx, dy]])); 7673 return this; 7674 }; 7675 elproto.scale = function (sx, sy, cx, cy) { 7676 if (this.removed) { 7677 return this; 7678 } 7679 sx = Str(sx).split(separator); 7680 if (sx.length - 1) { 7681 sy = toFloat(sx[1]); 7682 cx = toFloat(sx[2]); 7683 cy = toFloat(sx[3]); 7684 isNaN(cx) && (cx = null); 7685 isNaN(cy) && (cy = null); 7686 } 7687 sx = toFloat(sx[0]); 7688 (sy == null) && (sy = sx); 7689 (cy == null) && (cx = cy); 7690 if (cx == null || cy == null) { 7691 var bbox = this.getBBox(1); 7692 } 7693 cx = cx == null ? bbox.x + bbox.width / 2 : cx; 7694 cy = cy == null ? bbox.y + bbox.height / 2 : cy; 7695 7696 this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); 7697 this._.dirtyT = 1; 7698 return this; 7699 }; 7700 elproto.hide = function () { 7701 !this.removed && (this.node.style.display = "none"); 7702 return this; 7703 }; 7704 elproto.show = function () { 7705 !this.removed && (this.node.style.display = E); 7706 return this; 7707 }; 7708 elproto._getBBox = function () { 7709 if (this.removed) { 7710 return {}; 7711 } 7712 return { 7713 x: this.X + (this.bbx || 0) - this.W / 2, 7714 y: this.Y - this.H, 7715 width: this.W, 7716 height: this.H 7717 }; 7718 }; 7719 elproto.remove = function () { 7720 if (this.removed || !this.node.parentNode) { 7721 return; 7722 } 7723 this.paper.__set__ && this.paper.__set__.exclude(this); 7724 R.eve.unbind("raphael.*.*." + this.id); 7725 R._tear(this, this.paper); 7726 this.node.parentNode.removeChild(this.node); 7727 this.shape && this.shape.parentNode.removeChild(this.shape); 7728 for (var i in this) { 7729 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 7730 } 7731 this.removed = true; 7732 }; 7733 elproto.attr = function (name, value) { 7734 if (this.removed) { 7735 return this; 7736 } 7737 if (name == null) { 7738 var res = {}; 7739 for (var a in this.attrs) if (this.attrs[has](a)) { 7740 res[a] = this.attrs[a]; 7741 } 7742 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; 7743 res.transform = this._.transform; 7744 return res; 7745 } 7746 if (value == null && R.is(name, "string")) { 7747 if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { 7748 return this.attrs.gradient; 7749 } 7750 var names = name.split(separator), 7751 out = {}; 7752 for (var i = 0, ii = names.length; i < ii; i++) { 7753 name = names[i]; 7754 if (name in this.attrs) { 7755 out[name] = this.attrs[name]; 7756 } else if (R.is(this.paper.customAttributes[name], "function")) { 7757 out[name] = this.paper.customAttributes[name].def; 7758 } else { 7759 out[name] = R._availableAttrs[name]; 7760 } 7761 } 7762 return ii - 1 ? out : out[names[0]]; 7763 } 7764 if (this.attrs && value == null && R.is(name, "array")) { 7765 out = {}; 7766 for (i = 0, ii = name.length; i < ii; i++) { 7767 out[name[i]] = this.attr(name[i]); 7768 } 7769 return out; 7770 } 7771 var params; 7772 if (value != null) { 7773 params = {}; 7774 params[name] = value; 7775 } 7776 value == null && R.is(name, "object") && (params = name); 7777 for (var key in params) { 7778 eve("raphael.attr." + key + "." + this.id, this, params[key]); 7779 } 7780 if (params) { 7781 for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { 7782 var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); 7783 this.attrs[key] = params[key]; 7784 for (var subkey in par) if (par[has](subkey)) { 7785 params[subkey] = par[subkey]; 7786 } 7787 } 7788 // this.paper.canvas.style.display = "none"; 7789 if (params.text && this.type == "text") { 7790 this.textpath.string = params.text; 7791 } 7792 setFillAndStroke(this, params); 7793 // this.paper.canvas.style.display = E; 7794 } 7795 return this; 7796 }; 7797 elproto.toFront = function () { 7798 !this.removed && this.node.parentNode.appendChild(this.node); 7799 this.paper && this.paper.top != this && R._tofront(this, this.paper); 7800 return this; 7801 }; 7802 elproto.toBack = function () { 7803 if (this.removed) { 7804 return this; 7805 } 7806 if (this.node.parentNode.firstChild != this.node) { 7807 this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); 7808 R._toback(this, this.paper); 7809 } 7810 return this; 7811 }; 7812 elproto.insertAfter = function (element) { 7813 if (this.removed) { 7814 return this; 7815 } 7816 if (element.constructor == R.st.constructor) { 7817 element = element[element.length - 1]; 7818 } 7819 if (element.node.nextSibling) { 7820 element.node.parentNode.insertBefore(this.node, element.node.nextSibling); 7821 } else { 7822 element.node.parentNode.appendChild(this.node); 7823 } 7824 R._insertafter(this, element, this.paper); 7825 return this; 7826 }; 7827 elproto.insertBefore = function (element) { 7828 if (this.removed) { 7829 return this; 7830 } 7831 if (element.constructor == R.st.constructor) { 7832 element = element[0]; 7833 } 7834 element.node.parentNode.insertBefore(this.node, element.node); 7835 R._insertbefore(this, element, this.paper); 7836 return this; 7837 }; 7838 elproto.blur = function (size) { 7839 var s = this.node.runtimeStyle, 7840 f = s.filter; 7841 f = f.replace(blurregexp, E); 7842 if (+size !== 0) { 7843 this.attrs.blur = size; 7844 s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; 7845 s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); 7846 } else { 7847 s.filter = f; 7848 s.margin = 0; 7849 delete this.attrs.blur; 7850 } 7851 return this; 7852 }; 7853 7854 R._engine.path = function (pathString, vml) { 7855 var el = createNode("shape"); 7856 el.style.cssText = cssDot; 7857 el.coordsize = zoom + S + zoom; 7858 el.coordorigin = vml.coordorigin; 7859 var p = new Element(el, vml), 7860 attr = {fill: "none", stroke: "#000"}; 7861 pathString && (attr.path = pathString); 7862 p.type = "path"; 7863 p.path = []; 7864 p.Path = E; 7865 setFillAndStroke(p, attr); 7866 vml.canvas.appendChild(el); 7867 var skew = createNode("skew"); 7868 skew.on = true; 7869 el.appendChild(skew); 7870 p.skew = skew; 7871 p.transform(E); 7872 return p; 7873 }; 7874 R._engine.rect = function (vml, x, y, w, h, r) { 7875 var path = R._rectPath(x, y, w, h, r), 7876 res = vml.path(path), 7877 a = res.attrs; 7878 res.X = a.x = x; 7879 res.Y = a.y = y; 7880 res.W = a.width = w; 7881 res.H = a.height = h; 7882 a.r = r; 7883 a.path = path; 7884 res.type = "rect"; 7885 return res; 7886 }; 7887 R._engine.ellipse = function (vml, x, y, rx, ry) { 7888 var res = vml.path(), 7889 a = res.attrs; 7890 res.X = x - rx; 7891 res.Y = y - ry; 7892 res.W = rx * 2; 7893 res.H = ry * 2; 7894 res.type = "ellipse"; 7895 setFillAndStroke(res, { 7896 cx: x, 7897 cy: y, 7898 rx: rx, 7899 ry: ry 7900 }); 7901 return res; 7902 }; 7903 R._engine.circle = function (vml, x, y, r) { 7904 var res = vml.path(), 7905 a = res.attrs; 7906 res.X = x - r; 7907 res.Y = y - r; 7908 res.W = res.H = r * 2; 7909 res.type = "circle"; 7910 setFillAndStroke(res, { 7911 cx: x, 7912 cy: y, 7913 r: r 7914 }); 7915 return res; 7916 }; 7917 R._engine.image = function (vml, src, x, y, w, h) { 7918 var path = R._rectPath(x, y, w, h), 7919 res = vml.path(path).attr({stroke: "none"}), 7920 a = res.attrs, 7921 node = res.node, 7922 fill = node.getElementsByTagName(fillString)[0]; 7923 a.src = src; 7924 res.X = a.x = x; 7925 res.Y = a.y = y; 7926 res.W = a.width = w; 7927 res.H = a.height = h; 7928 a.path = path; 7929 res.type = "image"; 7930 fill.parentNode == node && node.removeChild(fill); 7931 fill.rotate = true; 7932 fill.src = src; 7933 fill.type = "tile"; 7934 res._.fillpos = [x, y]; 7935 res._.fillsize = [w, h]; 7936 node.appendChild(fill); 7937 setCoords(res, 1, 1, 0, 0, 0); 7938 return res; 7939 }; 7940 R._engine.text = function (vml, x, y, text) { 7941 var el = createNode("shape"), 7942 path = createNode("path"), 7943 o = createNode("textpath"); 7944 x = x || 0; 7945 y = y || 0; 7946 text = text || ""; 7947 path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); 7948 path.textpathok = true; 7949 o.string = Str(text); 7950 o.on = true; 7951 el.style.cssText = cssDot; 7952 el.coordsize = zoom + S + zoom; 7953 el.coordorigin = "0 0"; 7954 var p = new Element(el, vml), 7955 attr = { 7956 fill: "#000", 7957 stroke: "none", 7958 font: R._availableAttrs.font, 7959 text: text 7960 }; 7961 p.shape = el; 7962 p.path = path; 7963 p.textpath = o; 7964 p.type = "text"; 7965 p.attrs.text = Str(text); 7966 p.attrs.x = x; 7967 p.attrs.y = y; 7968 p.attrs.w = 1; 7969 p.attrs.h = 1; 7970 setFillAndStroke(p, attr); 7971 el.appendChild(o); 7972 el.appendChild(path); 7973 vml.canvas.appendChild(el); 7974 var skew = createNode("skew"); 7975 skew.on = true; 7976 el.appendChild(skew); 7977 p.skew = skew; 7978 p.transform(E); 7979 return p; 7980 }; 7981 R._engine.setSize = function (width, height) { 7982 var cs = this.canvas.style; 7983 this.width = width; 7984 this.height = height; 7985 width == +width && (width += "px"); 7986 height == +height && (height += "px"); 7987 cs.width = width; 7988 cs.height = height; 7989 cs.clip = "rect(0 " + width + " " + height + " 0)"; 7990 if (this._viewBox) { 7991 R._engine.setViewBox.apply(this, this._viewBox); 7992 } 7993 return this; 7994 }; 7995 R._engine.setViewBox = function (x, y, w, h, fit) { 7996 R.eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]); 7997 var width = this.width, 7998 height = this.height, 7999 size = 1 / mmax(w / width, h / height), 8000 H, W; 8001 if (fit) { 8002 H = height / h; 8003 W = width / w; 8004 if (w * H < width) { 8005 x -= (width - w * H) / 2 / H; 8006 } 8007 if (h * W < height) { 8008 y -= (height - h * W) / 2 / W; 8009 } 8010 } 8011 this._viewBox = [x, y, w, h, !!fit]; 8012 this._viewBoxShift = { 8013 dx: -x, 8014 dy: -y, 8015 scale: size 8016 }; 8017 this.forEach(function (el) { 8018 el.transform("..."); 8019 }); 8020 return this; 8021 }; 8022 var createNode; 8023 R._engine.initWin = function (win) { 8024 var doc = win.document; 8025 doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); 8026 try { 8027 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); 8028 createNode = function (tagName) { 8029 return doc.createElement('<rvml:' + tagName + ' class="rvml">'); 8030 }; 8031 } catch (e) { 8032 createNode = function (tagName) { 8033 return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); 8034 }; 8035 } 8036 }; 8037 R._engine.initWin(R._g.win); 8038 R._engine.create = function () { 8039 var con = R._getContainer.apply(0, arguments), 8040 container = con.container, 8041 height = con.height, 8042 s, 8043 width = con.width, 8044 x = con.x, 8045 y = con.y; 8046 if (!container) { 8047 throw new Error("VML container not found."); 8048 } 8049 var res = new R._Paper, 8050 c = res.canvas = R._g.doc.createElement("div"), 8051 cs = c.style; 8052 x = x || 0; 8053 y = y || 0; 8054 width = width || 512; 8055 height = height || 342; 8056 res.width = width; 8057 res.height = height; 8058 width == +width && (width += "px"); 8059 height == +height && (height += "px"); 8060 res.coordsize = zoom * 1e3 + S + zoom * 1e3; 8061 res.coordorigin = "0 0"; 8062 res.span = R._g.doc.createElement("span"); 8063 res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; 8064 c.appendChild(res.span); 8065 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); 8066 if (container == 1) { 8067 R._g.doc.body.appendChild(c); 8068 cs.left = x + "px"; 8069 cs.top = y + "px"; 8070 cs.position = "absolute"; 8071 } else { 8072 if (container.firstChild) { 8073 container.insertBefore(c, container.firstChild); 8074 } else { 8075 container.appendChild(c); 8076 } 8077 } 8078 res.renderfix = function () {}; 8079 return res; 8080 }; 8081 R.prototype.clear = function () { 8082 R.eve("raphael.clear", this); 8083 this.canvas.innerHTML = E; 8084 this.span = R._g.doc.createElement("span"); 8085 this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; 8086 this.canvas.appendChild(this.span); 8087 this.bottom = this.top = null; 8088 }; 8089 R.prototype.remove = function () { 8090 R.eve("raphael.remove", this); 8091 this.canvas.parentNode.removeChild(this.canvas); 8092 for (var i in this) { 8093 this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; 8094 } 8095 return true; 8096 }; 8097 8098 var setproto = R.st; 8099 for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { 8100 setproto[method] = (function (methodname) { 8101 return function () { 8102 var arg = arguments; 8103 return this.forEach(function (el) { 8104 el[methodname].apply(el, arg); 8105 }); 8106 }; 8107 })(method); 8108 } 8109})(); 8110 8111 // EXPOSE 8112 // SVG and VML are appended just before the EXPOSE line 8113 // Even with AMD, Raphael should be defined globally 8114 oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); 8115 8116 return R; 8117})); 8118