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

Main Function

-

- Raphael -

-

- Creates a canvas object on which to draw. You must do this first, as all future calls to drawing methods from this instance will be bound to this canvas. -

-

Parameters

-
    -
  1. container HTMLElement or string
  2. -
  3. width number
  4. -
  5. height number
  6. -
-

or

-
    -
  1. x number
  2. -
  3. y number
  4. -
  5. width number
  6. -
  7. height number
  8. -
-

or

-
    -
  1. 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>})
  2. -
-

Usage

-
// Each of the following examples create a canvas that is 320px wide by 200px high
-// Canvas is created at the viewport’s 10,50 coordinate
-var paper = Raphael(10, 50, 320, 200);
-// Canvas is created at the top left corner of the #notepad element
-// (or its top right corner in dir="rtl" elements)
-var paper = Raphael(document.getElementById("notepad"), 320, 200);
-// Same as above
-var paper = Raphael("notepad", 320, 200);
-// Image dump
-var set = Raphael(["notepad", 320, 200, {
-    type: "rect",
-    x: 10,
-    y: 10,
-    width: 25,
-    height: 25,
-    stroke: "#f00"
+
+Raphaël Reference
  1. Animation
  2. Animation.delay()
  3. Animation.repeat()
  4. Element
  5. Element.animate()
  6. Element.clone()
  7. Element.getBBox()
  8. Element.getPointAtLength()
  9. Element.getSubpath()
  10. Element.getTotalLength()
  11. Element.glow()
  12. Element.rotate()
  13. Element.scale()
  14. Element.setTime()
  15. Element.status()
  16. Element.transform()
  17. Element.translate()
  18. Paper
  19. Paper.bottom
  20. Paper.circle()
  21. Paper.ellipse()
  22. Paper.forEach()
  23. Paper.getById()
  24. Paper.getElementByPoint()
  25. Paper.image()
  26. Paper.path()
  27. Paper.raphael
  28. Paper.rect()
  29. Paper.set()
  30. Paper.setSize()
  31. Paper.text()
  32. Paper.top
  33. Raphael()
  34. Raphael.angle()
  35. Raphael.animation()
  36. Raphael.deg()
  37. Raphael.easing_formulas
  38. Raphael.findDotsAtSegment()
  39. Raphael.fn
  40. Raphael.getColor()
  41. Raphael.getColor.reset()
  42. Raphael.getPointAtLength()
  43. Raphael.getRGB()
  44. Raphael.getSubpath()
  45. Raphael.getTotalLength()
  46. Raphael.hsb()
  47. Raphael.hsb2rgb()
  48. Raphael.hsl()
  49. Raphael.hsl2rgb()
  50. Raphael.is()
  51. Raphael.parsePathString()
  52. Raphael.parseTransformString()
  53. Raphael.path2curve()
  54. Raphael.pathToRelative()
  55. Raphael.rad()
  56. Raphael.rgb()
  57. Raphael.rgb2hsb()
  58. Raphael.rgb2hsl()
  59. Raphael.setWindow()
  60. Raphael.snapTo()
  61. Raphael.svg
  62. Raphael.type
  63. Raphael.vml

Raphaël Reference

Check out the source: raphael.js

Animation

+

Animation.delay(delay)

+

Creates copy of existing animation object with given delay.

+

Parameters +

+
delay
+
number
+
number of ms to pass between animation start and actual animation
+
+

Returns: object new altered Animation object

+

Animation.repeat(repeat)

+

Creates copy of existing animation object with given repetition.

+

Parameters +

+
repeat
+
number
+
number iterations of animation. For infinite animation pass Infinity
+
+

Returns: object new altered Animation object

+

Element

+

Element.animate(…)

+

Creates and starts animation for given element.

+

Parameters +

+
params
+
object
+
final attributes for the element, see also Element.attr
+
ms
+
number
+
number of milliseconds for animation to run
+
easing
+
optional
+
string
+
easing type. Accept on of Raphael.easing_formulas or CSS format: cubic-bezier(XX, XX, XX, XX)
+
callback
+
optional
+
function
+
callback function. Will be called at the end of animation.
+
+

or

+
animation
+
object
+
animation object, see Raphael.animation
+
+

Returns: object original element

+

Element.clone()

+

Returns: object clone of a given element

+

Element.getBBox(isWithoutTransform)

+

Return bounding box for a given element

+

Parameters +

+
isWithoutTransform
+
boolean
+
flag, true if you want to have bounding box before transformations. Default is false.
+
+

Returns: object Bounding box object:

+
{
+    x: //top left corner x,
+    y: //top left corner y,
+    width: //width,
+    height: //height
+}
+
+

Element.getPointAtLength(length)

+

Return coordinates of the point located at the given length on the given path. Only works for element of “path” type.

+

Parameters +

+
length
+
number
+
 
+
+

Returns: object representation of the point:

+
{
+    x: //x coordinate,
+    y: //y coordinate,
+    alpha: //angle of derivative
+}
+
+

Element.getSubpath(from, to)

+

Return subpath of a given element from given length to given length. Only works for element of “path” type.

+

Parameters +

+
from
+
number
+
position of the start of the segment
+
to
+
number
+
position of the end of the segment
+
+

Returns: string pathstring for the segment

+

Element.getTotalLength()

+

Returns length of the path in pixels. Only works for element of “path” type.

+

Returns: number length.

+

Element.glow()

+

Return set of elements that create glow-like effect around given element. See Paper.set.

+

Note: Glow is not connected to the elment. If you change element attributes it won’t adjust itself.

+

Returns: object set of elements that represents glow

+

Element.rotate(deg, [cx], [cy])

+

Adds rotation by given angle around given point to the list oftransformations of the element.

+

Parameters +

+
deg
+
number
+
angle in degrees
+
cx
+
optional
+
number
+
x coordinate of the centre of rotation
+
cy
+
optional
+
number
+
y coordinate of the centre of rotation
+
+

If cx & cy aren’t specified centre of the shape is used as a point of rotation.

+

Returns: object Element

+

Element.scale(sx, sy, [cx], [cy])

+

Adds scale by given amount relative to given point to the list oftransformations of the element.

+

Parameters +

+
sx
+
number
+
horisontal scale amount
+
sy
+
number
+
vertical scale amount
+
cx
+
optional
+
number
+
x coordinate of the centre of scale
+
cy
+
optional
+
number
+
y coordinate of the centre of scale
+
+

If cx & cy aren’t specified centre of the shape is used instead.

+

Returns: object Element

+

Element.setTime(anim, value)

+

Sets the status of animation of the element in milliseconds. Similar to Element.status method.

+

Parameters +

+
anim
+
object
+
animation object
+
value
+
number
+
number of milliseconds from the beginning of the animation
+
+

Returns: object original element if value is specified

+

Element.status([anim], [value])

+

Gets or sets the status of animation of the element.

+

Parameters +

+
anim
+
optional
+
object
+
animation object
+
value
+
optional
+
number
+
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.
+
+

Returns: number status

+

or

+

Returns: array status if anim is not specified in format:

+
[{
+    anim: // animation object,
+    status: // status
 }, {
-    type: "text",
-    x: 30,
-    y: 40,
-    text: "Dump"
-}]);
-

- circle -

-
-

- Draws a circle. -

-

Parameters

-
    -
  1. x number X coordinate of the centre
  2. -
  3. y number Y coordinate of the centre
  4. -
  5. r number radius
  6. -
-

Usage

-
var c = paper.circle(50, 50, 40);
-

- rect -

-
-

- Draws a rectangle. -

-

Parameters

-
    -
  1. x number X coordinate of top left corner
  2. -
  3. y number Y coordinate of top left corner
  4. -
  5. width number
  6. -
  7. height number
  8. -
  9. r number [optional] radius for rounded corners, default is 0
  10. -
-

Usage

-
// regular rectangle
-var c = paper.rect(10, 10, 50, 50);
-// rectangle with rounded corners
-var c = paper.rect(40, 40, 50, 50, 10);
-

- ellipse -

-
-

- Draws an ellipse. -

-

Parameters

-
    -
  1. x number X coordinate of the centre
  2. -
  3. y number X coordinate of the centre
  4. -
  5. rx number Horisontal radius
  6. -
  7. ry number Vertical radius
  8. -
-

Usage

-
var c = paper.ellipse(50, 50, 40, 20);
-

- image -

-
-

- Embeds an image into the SVG/VML canvas. -

-

Parameters

-
    -
  1. src string URI of the source image
  2. -
  3. x number X coordinate position
  4. -
  5. y number Y coordinate position
  6. -
  7. width number Width of the image
  8. -
  9. height number Height of the image
  10. -
-

Usage

-
var c = paper.image("apple.png", 10, 10, 80, 80);
-

- set -

-
-

- Creates array-like object to keep and operate couple of elements at once. Warning: it doesn’t create any elements for itself in the page. -

-

Usage

-
var st = paper.set();
-st.push(
-    paper.circle(10, 10, 5),
-    paper.circle(30, 10, 5)
-);
-st.attr({fill: "red"});
-

- text -

-
-

- Draws a text string. If you need line breaks, put “\n” in the string. -

-

Parameters

-
    -
  1. x number X coordinate position.
  2. -
  3. y number Y coordinate position.
  4. -
  5. text string The text string to draw.
  6. -
-

Usage

-
var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!");
-

- path -

-
-

- Creates a path element by given path data string. -

-

Parameters

-
    -
  1. pathString string [optional] Path data in SVG path string format.
  2. -
-

Usage

-
var c = paper.path("M10 10L90 90");
-// draw a diagonal line:
-// move to 10,10, line to 90,90
-

- clear -

-

- Clears the canvas, i.e. removes all the elements. -

-

Usage

-
var c = paper.path("M10 10L90 90");
-paper.clear();
-

- Element’s generic methods -

-

- Each object created on the canvas shares these same generic methods: -

-

- node -

-

- Gives you a reference to the DOM object, so you can assign event handlers or just mess around. -

-

Usage

-
// draw a circle at coordinate 10,10 with radius of 10
-var c = paper.circle(10, 10, 10);
-c.node.onclick = function () {
-    c.attr("fill", "red");
-};
-

- paper -

-

- Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions. -

-

Usage

-
Raphael.el.cross = function () {
-    this.attr({fill: "red"});
-    this.paper.path("M10,10L50,50M50,10L10,50")
-        .attr({stroke: "red"});
-}
-

- remove -

-

- Removes element from the DOM. You can’t use it after this method call. -

-

Usage

-
var c = paper.circle(10, 10, 10);
-c.remove();
-

- hide -

-

- Makes element invisible. -

-

Usage

-
var c = paper.circle(10, 10, 10);
-c.hide();
-

- show -

-

- Makes element visible. -

-

Usage

-
var c = paper.circle(10, 10, 10);
-c.show();
-

- rotate -

-

- Rotates the element by the given degree from its center point. -

-

Parameters

-
    -
  1. degree number Degree of rotation (0 – 360°)
  2. -
  3. isAbsolute boolean [optional] Specifies is degree is relative to previous position (false) or is it absolute angle (true)
  4. -
-

or

-
    -
  1. degree number Degree of rotation (0 – 360°)
  2. -
  3. cx number [optional] X coordinate of the origin of rotation
  4. -
  5. cY number [optional] Y coordinate of the origin of rotation
  6. -
-

Usage

-
var c = paper.circle(10, 10, 10);
-c.rotate(45);        // rotation is relative
-c.rotate(45, true);  // rotation is absolute
-

- translate -

-

- Moves the element around the canvas by the given distances. -

-

Parameters

-
    -
  1. dx number Pixels of translation by X axis
  2. -
  3. dy number Pixels of translation by Y axis
  4. -
-

Usage

-
var c = paper.circle(10, 10, 10);
-// moves the circle 10 px to the right and down
-c.translate(10, 10);
-

- scale -

-

- Resizes the element by the given multiplier. -

-

Parameters

-
    -
  1. Xtimes number Amount to scale horizontally
  2. -
  3. Ytimes number Amount to scale vertically
  4. -
  5. centerX number [optional] X of the center of scaling, default is the center of the element
  6. -
  7. centerY number [optional] Y of the center of scaling, default is the center of the element
  8. -
-

Usage

-
var c = paper.circle(10, 10, 10);
-// makes the circle 1.5 times larger
-c.scale(1.5, 1.5);
-// makes the circle half as wide, and 75% as high
-c.scale(.5, .75);
-

- attr -

-

- Sets the attributes of elements directly. -

-

Parameters

-
    -
  1. attributeName string
  2. -
  3. value string
  4. -
-

or

-
    -
  1. params object
  2. -
-

or

-
    -
  1. attributeName string in this case method returns current value for given attribute name
  2. -
-

or

-
    -
  1. attributeNames array in this case method returns array of current values for given attribute names
  2. -
-

or

-

no parameters, in this case object containing all attributes will be returned

-

Possible parameters

-

Please refer to the SVG specification for an explanation of these parameters.

-
    -
  • clip-rect string comma or space separated values: x, y, width and height
  • -
  • cursor string CSS type of the cursor
  • -
  • cx number
  • -
  • cy number
  • -
  • - fill colour or gradient -
      -
    • linear gradient: “‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›”, example: “90-#fff-#000” – 90° gradient from white to black or “0-#fff-#f00:20-#000” – 0° gradient from white via red (at 20%) to black
    • -
    • radial gradient: “r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›”, example: “r#fff-#000” – gradient from white to black or “r(0.25, 0.75)#fff-#000” – gradient from white to black with focus point at 0.25, 0.75
    • -
    • Focus point coordinates are in 0..1 range
    • -
    • Radial gradients can only be applied to circles and ellipses
    • -
    -
  • -
  • fill-opacity number
  • -
  • font string
  • -
  • font-family string
  • -
  • font-size number
  • -
  • font-weight string
  • -
  • height number
  • -
  • href string URL, if specified element behaves as hyperlink
  • -
  • opacity number
  • -
  • path pathString SVG path string format
  • -
  • r number
  • -
  • rotation number
  • -
  • rx number
  • -
  • ry number
  • -
  • scale string comma or space separated values: xtimes, ytimes, cx, cy. See: scale
  • -
  • src string (URL)
  • -
  • stroke colour
  • -
  • stroke-dasharray string [“”, “-”, “.”, “-.”, “-..”, “. ”, “- ”, “--”, “- .”, “--.”, “--..”]
  • -
  • stroke-linecap string [“butt”, “square”, “round”]
  • -
  • stroke-linejoin string [“bevel”, “round”, “miter”]
  • -
  • stroke-miterlimit number
  • -
  • stroke-opacity number
  • -
  • stroke-width number
  • -
  • target string used with href
  • -
  • text-anchor string [“start”, “middle”, “end”], default is “middle”
  • -
  • title string will create tooltip with a given text
  • -
  • translation string comma or space separated values: x and y
  • -
  • width number
  • -
  • x number
  • -
  • y number
  • -
-

Usage

-
var c = paper.circle(10, 10, 10);
-// using strings
-c.attr("fill", "black");
-// using params object
-c.attr({fill: "#000", stroke: "#f00", opacity: 0.5});
-c.attr({
-    fill: "90-#fff-#000",
-    "stroke-dasharray": "-..",
-    "clip-rect": "10, 10, 100, 100"
-});
-

- animate -

-

- Changes an attribute from its current value to its specified value in the given amount of milliseconds. -

-

Parameters

-
    -
  1. newAttrs object A parameters object of the animation results. (Not all attributes can be animated.)
  2. -
  3. ms number The duration of the animation, given in milliseconds.
  4. -
  5. callback function [optional]
  6. -
-

or

-
    -
  1. newAttrs object A parameters object of the animation results. (Not all attributes can be animated.)
  2. -
  3. ms number The duration of the animation, given in milliseconds.
  4. -
  5. easing string [“>”, “<”, “<>”, “backIn”, “backOut”, “bounce”, “elastic”, “cubic-bezier(p1, p2, p3, p4)”] or function [optional], see explanation re cubic-bezier syntax
  6. -
  7. callback function [optional]
  8. -
-

or

-
    -
  1. keyFrames object Key-value map, where key represents keyframe timing: [“from”, “20%”, “to”, “35%”, etc] and value is the same as newAttrs from above, except it could also have easing and callback properties
  2. -
  3. ms number The duration of the animation, given in milliseconds.
  4. -
-

Look at the example of keyframes usage

-

Attributes that can be animated

-

The newAttrs parameter accepts an object whose properties are the attributes to animate. However, not all attributes listed in the attr method reference can be animated. The following is a list of those properties that can be animated:

-
    -
  • clip-rect string
  • -
  • cx number
  • -
  • cy number
  • -
  • fill colour
  • -
  • fill-opacity number
  • -
  • font-size number
  • -
  • height number
  • -
  • opacity number
  • -
  • path pathString
  • -
  • r number
  • -
  • rotation string
  • -
  • rx number
  • -
  • ry number
  • -
  • scale string
  • -
  • stroke colour
  • -
  • stroke-opacity number
  • -
  • stroke-width number
  • -
  • translation string
  • -
  • width number
  • -
  • x number
  • -
  • y number
  • -
-

Easing

-

- For easing use built in functions or add your own by adding new functions to Raphael.easing_formulas object. Look at the example of easing usage. -

-

Usage

-
var c = paper.circle(10, 10, 10);
-c.animate({cx: 20, r: 20}, 2000);
-c.animate({cx: 20, r: 20}, 2000, "bounce");
-c.animate({
-    "20%": {cx: 20, r: 20, easing: ">"},
-    "50%": {cx: 70, r: 120, callback: function () {…}},
-    "100%": {cx: 10, r: 10}
-}, 2000);
-

- animateWith -

-

- The same as animate method, but synchronise animation with another element. -

-

Parameters

-

The same as for animate method, but first argument is an element.

-

Usage

-
var c = paper.circle(10, 10, 10),
-    r = paper.rect(10, 10, 10, 10);
-c.animate({cx: 20, r: 20}, 2000);
-r.animateWith(c, {x: 20}, 2000);
-

- animateAlong -

-
-

- Animates element along the given path. As an option it could rotate element along the path. -

-

Parameters

-
    -
  1. path object or string path element or path string along which the element will be animated
  2. -
  3. ms number The duration of the animation, given in milliseconds.
  4. -
  5. rotate boolean [optional] if true, element will be rotated along the path
  6. -
  7. callback function [optional]
  8. -
-

Usage

-
var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z").attr({stroke: "#ddd"}),
-    e = r.ellipse(104, 100, 4, 4).attr({stroke: "none", fill: "#f00"}),
-    b = r.rect(0, 0, 620, 400).attr({stroke: "none", fill: "#000", opacity: 0}).click(function () {
-        e.attr({rx: 5, ry: 3}).animateAlong(p, 4000, true, function () {
-            e.attr({rx: 4, ry: 4});
-        });
-    });
-

- animateAlongBack -

-

- Similar to animateAlong. Animates element along the given path, starting from the end of it. -

-

- onAnimation -

-
-

- Sets or resets the function that will be called on each stage of the animation. -

-

Parameters

-
    -
  1. f function function that will be called on each stage of animation
  2. -
-

Usage

-
var p = r.path("M10,50c0,50,80-50,80,0c0,50-80-50-80,0z"),
-    p2 = r.path(),
-    e = r.ellipse(10, 50, 4, 4).attr({stroke: "none", fill: "#f00"}).onAnimation(function () {
-        p2.attr({path: "M50,10L" + e.attr("cx") + "," + e.attr("cy")});
-    }),
-    b = r.rect(0, 0, 620, 400).attr({stroke: "none", fill: "#000", opacity: 0}).click(function () {
-        e.attr({rx: 5, ry: 3}).animateAlong(p, 4000, true, function () {
-            e.attr({rx: 4, ry: 4});
-        });
-    });
-

- getBBox -

-

- Returns the dimensions of an element. -

-

Usage

-
var c = paper.circle(10, 10, 10);
-var width = c.getBBox().width;
-

- toFront -

-

- Moves the element so it is the closest to the viewer’s eyes, on top of other elements. -

-

Usage

-
var c = paper.circle(10, 10, 10);
-c.toFront();
-

- toBack -

-

- Moves the element so it is the furthest from the viewer’s eyes, behind other elements. -

-

Usage

-
var c = paper.circle(10, 10, 10);
-c.toBack();
-

- insertBefore -

-

- Inserts current object before the given one. -

-

Usage

-
var r = paper.rect(10, 10, 10, 10);
-var c = paper.circle(10, 10, 10);
-c.insertBefore(r);
-

- insertAfter -

-

- Inserts current object after the given one. -

-

Usage

-
var r = paper.rect(10, 10, 10, 10);
-var c = paper.circle(10, 10, 10);
-r.insertAfter(c);
-

- clone -

-

- Returns a clone of the current element. -

-

Usage

-
var r = paper.rect(10, 10, 10, 10);
-var c = r.clone();
-

Graphic Primitives

-

- Methods of “paper” object, created with Raphael function call. -

-

- raphael -

-

- Internal reference to Raphael object. In case it is not available. -

-

Usage

-
Raphael.el.red = function () {
-    var hsb = this.paper.raphael.rgb2hsb(this.attr("fill"));
-    hsb.h = 1;
-    this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex});
-}
-

- getTotalLength -

-

- Path specific method. Returns length of the path in pixels. -

-

Usage

-
var p = r.path("M100,100c0,50 100-50 100,0c0,50 -100-50 -100,0z");
-    alert(p.getTotalLength());
-

- getPointAtLength -

-
-

- Path specific method. Returns point description at given length. -

-

Parameters

-
    -
  1. length number length in pixels from the beginining of the path to the point
  2. -
-

Usage

-
var p = r.path("M10,50c0,50,80-50,80,0c0,50-80-50-80,0z");
-    var point = p.getPointAtLength(30);
-    r.circle(point.x, point.y, 3);
-

Returned object format:

-
    -
  • x – x coordinate of the point
  • -
  • y – y coordinate of the point
  • -
  • alpha – angle of the path at the point
  • -
-

- getSubpath -

-
-

- Path specific method. Returns the subpath string of a given path. -

-

Parameters

-
    -
  1. from number length in pixels from the beginning of the path to the beginning of the subpath
  2. -
  3. to number length in pixels from the beginning of the path to the end of the subpath
  4. -
-

Usage

-
var p = r.path("M10,50c0,50,80-50,80,0c0,50-80-50-80,0z");
-    var path = p.getSubpath(10, 60);
-    r.path(path).attr({stroke: "#f00"});
-

- setSize -

-

- If you need to change dimensions of the canvas call this method -

-

Parameters

-
    -
  1. width number new width of the canvas
  2. -
  3. height number new height of the canvas
  4. -
-

- setWindow -

-

- Should be called before main Raphael method. Sets which window should be used for drawing. Default is the current one. You need to use it if you want to draw inside iframe -

-

Parameters

-
    -
  1. window object
  2. -
-

- getRGB -

-

- Parses passes string and returns an colour object. Especially useful for plug-in developers. -

-

Parameters

-
    -
  1. color string Colour in form acceptable by library
  2. -
-

Usage

-
var stroke = Raphael.getRGB(circle.attr("stroke")).hex;
-

- angle -

-

- Gives you an angle of the line formed by two points or angle between two lines formed by three points. -

-

Parameters

-
    -
  1. x1 number X of the first point
  2. -
  3. y1 number Y of the first point
  4. -
  5. x2 number X of the second point
  6. -
  7. y2 number Y of the second point
  8. -
  9. x3 number X of the third point [optional]
  10. -
  11. y3 number Y of the third point [optional]
  12. -
-

Usage

-
var angle = Raphael.angle(10, 10, 50, 50);
-

- rad -

-

- Converts angle to radians. -

-

Parameters

-
    -
  1. deg number value of an angle in degrees
  2. -
-

Usage

-
var Sin = Math.sin(Raphael.rad(45));
-

- deg -

-

- Converts angle to degree. -

-

Parameters

-
    -
  1. rad number value of an angle in radians
  2. -
-

- snapTo -

-

- Returns a number adjusted to one of various values, if it’s close enough. -

-

Parameters

-
    -
  1. values number or array If values is a number, the value will be snapped to any multiple. If an array, the value will be snapped to the first element that’s within tolerance.
  2. -
  3. value number The value to adjust
  4. -
  5. tolerance number The value must be within tolerance of one of the snap values, or it will be returned unchanged [optional, default 10]
  6. -
-

Usage

-
// adjust -10..10 to 0, 40..60 to 50, 90-110 to 100, etc
-x = Raphael.snapTo(50, x);
-// adjust 5..35 to 20, 45..75 to 60, otherwise no change
-x = Raphael.snapTo([20, 60], x, 15);
-

- getColor -

-

- Returns a colour object for the next colour in spectrum -

-

Parameters

-
    -
  1. value number brightness [optional]
  2. -
-

Usage

-
var c = paper.path("M10,10L100,100").attr({stroke: Raphael.getColor()});
-

- getColor.reset -

-

- Resets getColor function, so it will start from the beginning -

-

- registerFont -

-

- 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. More about Cufón and how to convert your font form TTF, OTF, etc to JavaScript file. Returns original parameter, so it could be used with chaining. -

-

Parameters

-
    -
  1. font object the font to register
  2. -
-

Usage

-
Cufon.registerFont(Raphael.registerFont({…}))
-

- getFont -

-

- 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”. -

-

Parameters

-
    -
  1. family string font family name or any word from it
  2. -
  3. weight string weight of the font [optional]
  4. -
  5. style string style of the font [optional]
  6. -
  7. stretch string stretch of the font [optional]
  8. -
-

Usage

-
paper.print(100, 100, "Test string", paper.getFont("Times", 800), 30);
-

- print -

- -

- Creates set of shapes to represent given font at given position with given size. Result of the method is set object (see set) which contains each letter as separate path object. -

-

Parameters

-
    -
  1. x number x position of the text
  2. -
  3. y number y position of the text
  4. -
  5. text string text to print
  6. -
  7. font object font object (see getFont)
  8. -
  9. font_size number size of the font
  10. -
-

Usage

-
var txt = r.print(10, 50, "print", r.getFont("Museo"), 30).attr({fill: "#fff"});
-// following line will paint first letter in red
-txt[0].attr({fill: "#f00"});
-

- Adding your own methods to canvas -

-

- You can add your own method to the canvas. For example if you want to draw pie chart, you can create your own pie chart function and ship it as a Raphaël plugin. To do this you need to extend Raphael.fn object. Please note that you can create your own namespaces inside fn object. Methods will be run in context of canvas anyway. You should alter fn object before Raphaël instance was created, otherwise it will take no effect. -

-

Usage

-
Raphael.fn.arrow = function (x1, y1, x2, y2, size) {
-    return this.path( ... );
+    anim: // animation object,
+    status: // status
+}, ...]
+
+

or

+

Returns: object original element if value is specified

+

Element.transform([tstr])

+

Adds transformation to the element which is separate to other attributes,i.e. translation doesn’t change x or y of the rectange. The formatof transformation string is similar to the path string syntax:

+
"t100,100r30,100,100s2,2,100,100r45s1.5"
+
+

Each letter is a command. There are four commands: t is for translate, r is for rotate, s is forscale and m is for matrix.

+

So, example line could be read like “translate by 100, 100, rotate 30° around 100, 100, scale twice around 100, 100rotate 45° around centre and scale 1.5 times relative to centre”. As you see rotate and scale commands has origincoordinates as a optional parameters.Matrix accepts six parameters.

+

Parameters +

+
tstr
+
optional
+
string
+
transformation string
+
+

If tstr isn’t specified

+

Returns: string current transformation string

+

else

+

Returns: object Element

+

Element.translate(dx, dy)

+

Adds translation by given amount to the list of transformations of the element.

+

Parameters +

+
dx
+
number
+
horisontal shift
+
dy
+
number
+
vertical shift
+
+

Returns: object Element

+

Paper

+

Paper.bottom

+

Points to the bottom element on the paper

+

Paper.circle(x, y, r)

+

Draws a circle.

+

Parameters +

+
x
+
number
+
x coordinate of the centre
+
y
+
number
+
y coordinate of the centre
+
r
+
number
+
radius
+
+

Returns: object Raphaël element object with type “circle”

+

Usage +

+
var c = paper.circle(50, 50, 40);
+
+

Paper.ellipse(x, y, rx, ry)

+

Draws an ellipse.

+

Parameters +

+
x
+
number
+
x coordinate of the centre
+
y
+
number
+
y coordinate of the centre
+
rx
+
number
+
horisontal radius
+
ry
+
number
+
vertical radius
+
+

Returns: object Raphaël element object with type “ellipse”

+

Usage +

+
var c = paper.ellipse(50, 50, 40, 20);
+
+

Paper.forEach(callback, thisArg)

+

Executes given function for each element on the paper

+

If function returns false it will stop loop running.

+

Parameters +

+
callback
+
function
+
function to run
+
thisArg
+
object
+
context object for the callback
+
+

Returns: object Paper object

+

Paper.getById(id)

+

Returns you element by it’s internal ID.

+

Parameters +

+
id
+
number
+
id
+
+

Returns: object Raphaël element object

+

Paper.getElementByPoint(x, y)

+

Returns you topmost element under given point.

+

Returns: object Raphaël element object

+

Parameters +

+
x
+
number
+
x coordinate from the top left corner of the window
+
y
+
number
+
y coordinate from the top left corner of the window
+
+

Usage +

+
paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"});
+
+

Paper.image(src, x, y, width, height)

+

Embeds an image into the surface.

+

Parameters +

+
src
+
string
+
URI of the source image
+
x
+
number
+
x coordinate position
+
y
+
number
+
y coordinate position
+
width
+
number
+
width of the image
+
height
+
number
+
height of the image
+
+

Returns: object Raphaël element object with type “image”

+

Usage +

+
var c = paper.image("apple.png", 10, 10, 80, 80);
+
+

Paper.path(pathString)

+

Creates a path element by given path data string.

+

Parameters +

+
pathString
+
string
+
path data in SVG path string format.
+
+

Returns: object Raphaël element object with type “ellipse”

+Details of a path's data attribute's format are described in the SVG specification. +

Usage +

+
var c = paper.path("M10 10L90 90");
+// draw a diagonal line:
+// move to 10,10, line to 90,90
+
+

Paper.raphael

+

Points to the Raphael object/function

+

Paper.rect(x, y, width, height, r)

+

+

Draws a rectangle.

+

Parameters +

+
x
+
number
+
x coordinate of the top left corner
+
y
+
number
+
y coordinate of the top left corner
+
width
+
number
+
width
+
height
+
number
+
height
+
r
+
number
+
optional radius for rounded corners, default is 0
+
+

Returns: object Raphaël element object with type “rect”

+

Usage +

+
// regular rectangle
+var c = paper.rect(10, 10, 50, 50);
+// rectangle with rounded corners
+var c = paper.rect(40, 40, 50, 50, 10);
+
+

Paper.set()

+

Creates array-like object to keep and operate couple of elements at once.Warning: it doesn’t create any elements for itself in the page.

+

Returns: object array-like object that represents set of elements

+

Usage +

+
var st = paper.set();
+st.push(
+    paper.circle(10, 10, 5),
+    paper.circle(30, 10, 5)
+);
+st.attr({fill: "red"});
+
+

Paper.setSize(width, height)

+

If you need to change dimensions of the canvas call this method

+

Parameters +

+
width
+
number
+
new width of the canvas
+
height
+
number
+
new height of the canvas
+
+

Usage +

+
var st = paper.set();
+st.push(
+    paper.circle(10, 10, 5),
+    paper.circle(30, 10, 5)
+);
+st.attr({fill: "red"});
+
+

Paper.text(x, y, text)

+

Draws a text string. If you need line breaks, put “\n” in the string.

+

Parameters +

+
x
+
number
+
x coordinate position
+
y
+
number
+
y coordinate position
+
text
+
string
+
The text string to draw
+
+

Returns: object Raphaël element object with type “text”

+

Usage +

+
var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!");
+
+

Paper.top

+

Points to the topmost element on the paper

+

Raphael(…)

+

Creates a canvas object on which to draw.You must do this first, as all future calls to drawing methodsfrom this instance will be bound to this canvas.

+

Parameters +

+
container
+
HTMLElement string
+
DOM element or it’s id which is going to be a parent for drawing surface
+
width
+
number
+
 
+
height
+
number
+
 
+
+

or

+
x
+
number
+
 
+
y
+
number
+
 
+
width
+
number
+
 
+
height
+
number
+
 
+
+

or

+
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>})
+
+

or

+
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.
+
+

Returns: object Paper

+

Usage +

+
// Each of the following examples create a canvas that is 320px wide by 200px high
+// Canvas is created at the viewport’s 10,50 coordinate
+var paper = Raphael(10, 50, 320, 200);
+// Canvas is created at the top left corner of the #notepad element
+// (or its top right corner in dir="rtl" elements)
+var paper = Raphael(document.getElementById("notepad"), 320, 200);
+// Same as above
+var paper = Raphael("notepad", 320, 200);
+// Image dump
+var set = Raphael(["notepad", 320, 200, {
+    type: "rect",
+    x: 10,
+    y: 10,
+    width: 25,
+    height: 25,
+    stroke: "#f00"
+}, {
+    type: "text",
+    x: 30,
+    y: 40,
+    text: "Dump"
+}]);
+
+

Raphael.angle(x1, y1, x2, y2, [x3], [y3])

+

Returns angle between two or three points

+

Parameters +

+
x1
+
number
+
x coord of first point
+
y1
+
number
+
y coord of first point
+
x2
+
number
+
x coord of second point
+
y2
+
number
+
y coord of second point
+
x3
+
optional
+
number
+
x coord of third point
+
y3
+
optional
+
number
+
y coord of third point
+
+

Returns: number angle in degrees.

+

Raphael.animation(params, ms, [easing], [callback])

+

Creates animation object. That later could be used for Element.animate or Element.animateWith methods.See also Animation.delay and Animation.repeat methods.

+

Parameters +

+
params
+
object
+
final attributes for the element, see also Element.attr
+
ms
+
number
+
number of milliseconds for animation to run
+
easing
+
optional
+
string
+
easing type. Accept one of Raphael.easing_formulas or CSS format: cubic-bezier(XX, XX, XX, XX)
+
callback
+
optional
+
function
+
callback function. Will be called at the end of animation.
+
+

Returns: object Animation

+

Raphael.deg(deg)

+

Transform angle to degrees

+

Parameters +

+
deg
+
number
+
angle in radians
+
+

Returns: number angle in degrees.

+

Raphael.easing_formulas

+

Object that contains easing formulas for animation. You could extend it with your owns. By default it has following list of easing:

+
    +
  • “linear”
  • +
  • “<” or “easeIn” or “ease-in”
  • +
  • “>” or “easeOut” or “ease-out”
  • +
  • “<>” or “easeInOut” or “ease-in-out”
  • +
  • “backIn” or “back-in”
  • +
  • “backOut” or “back-out”
  • +
  • “elastic”
  • +
  • “bounce”
  • +
+

See also Easing demo.

+

Raphael.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t)

+

Utility methodFind dot coordinates on the given cubic bezier curve at the given t.

+

Parameters +

+
p1x
+
number
+
x of the first point of the curve
+
p1y
+
number
+
y of the first point of the curve
+
c1x
+
number
+
x of the first anchor of the curve
+
c1y
+
number
+
y of the first anchor of the curve
+
c2x
+
number
+
x of the second anchor of the curve
+
c2y
+
number
+
y of the second anchor of the curve
+
p2x
+
number
+
x of the second point of the curve
+
p2y
+
number
+
y of the second point of the curve
+
t
+
number
+
position on the curve (0..1)
+
+

Returns: object point information in format:

+
{
+    x: // x coordinate of the point,
+    y: // y coordinate of the point,
+    m: {
+        x: // x coordinate of the left anchor,
+        y: // y coordinate of the left anchor
+    },
+    n: {
+        x: // x coordinate of the right anchor,
+        y: // y coordinate of the right anchor
+    },
+    start: {
+        x: // x coordinate of the start of the curve,
+        y: // y coordinate of the start of the curve
+    },
+    end: {
+        x: // x coordinate of the end of the curve,
+        y: // y coordinate of the end of the curve
+    },
+    alpha: // angle of the curve derivative at the point.
+}
+
+

Raphael.fn

+
object

You can add your own method to the canvas. For example if you want to draw pie chart,you can create your own pie chart function and ship it as a Raphaël plugin. To do thisyou need to extend Raphael.fn object. Please note that you can create your own namespacesinside fn object. Methods will be run in context of canvas anyway. You should alter fnobject before Raphaël instance was created, otherwise it will take no effect.

+

Usage +

+
Raphael.fn.arrow = function (x1, y1, x2, y2, size) {
+    return this.path( ... );
 };
-// or create namespace
-Raphael.fn.mystuff = {
-    arrow: function () {…},
-    star: function () {…},
-    // etc…
+// or create namespace
+Raphael.fn.mystuff = {
+    arrow: function () {…},
+    star: function () {…},
+    // etc…
 };
-var paper = Raphael(10, 10, 630, 480);
-// then use it
-paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"});
+var paper = Raphael(10, 10, 630, 480);
+// then use it
+paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"});
 paper.mystuff.arrow();
 paper.mystuff.star();
 
-

- Adding your own methods to elements -

-

- You can add your own method to elements. This is usefull when you want to hack default functionality or want to wrap some common transformation or attributes in one method. In difference to canvas mathods, you can redefine element method at any time. -

-

Usage

-
Raphael.el.red = function () {
-    this.attr({fill: "#f00"});
-};
-// then use it
-paper.circle(100, 100, 20).red();
+

Raphael.getColor([value])

+

On each call returns next colour in the spectrum. To reset it back to red call Raphael.getColor.reset

+

Parameters +

+
value
+
optional
+
number
+
brightness, default is 0.75
+
+

Returns: string hex representation of the colour.

+

Raphael.getColor.reset()

+

Resets spectrum position for Raphael.getColor back to red.

+

Raphael.getPointAtLength(path, length)

+

Return coordinates of the point located at the given length on the given path.

+

Parameters +

+
path
+
string
+
SVG path string
+
length
+
number
+
 
+
+

Returns: object representation of the point:

+
{
+    x: //x coordinate,
+    y: //y coordinate,
+    alpha: //angle of derivative
+}
 
-

- Custom Attributes -

-

- If you have a set of attributes that you would like to represent as a function of some number you can do it easily with custom attributes: -

-

Usage

-
paper.customAttributes.hue = function (num) {
-    num = num % 1;
-    return {fill: "hsb(" + num + ", .75, 1)"};
-};
-// Custom attribute “hue” will change fill
-// to be given hue with fixed saturation and brightness.
-// Now you can use it like this:
-var c = paper.circle(10, 10, 10).attr({hue: .45});
-// or even like this:
-c.animate({hue: 1}, 1e3);
-
-// You could also create custom attribute
-// with multiple parameters:
-paper.customAttributes.hsb = function (h, s, b) {
-    return {fill: "hsb(" + [h, s, b].join(",") + ")"};
-};
-c.attr({hsb: ".5 .8 1"});
-c.animate({hsb: "1 0 .5"}, 1e3);
+

Raphael.getRGB(colour)

+

Parses colour string as RGB object

+

Parameters +

+
colour
+
string
+
colour string in one of formats:
+
+

Returns: object RGB object in format:

+
{
+    r: // red,
+    g: // green,
+    b: // blue
+    hex: // color in HTML/CSS format: #••••••,
+    error: // true if string can’t be parsed
+}
 
-

- Supported colour formats -

-

- You could specify colour in this formats: -

-
    -
  • Colour name (“red”, “green”, “cornflowerblue”, etc)
  • -
  • #••• — shortened HTML colour: (“#000”, “#fc0”, etc)
  • -
  • #•••••• — full length HTML colour: (“#000000”, “#bd2300”)
  • -
  • rgb(•••, •••, •••) — red, green and blue channels’ values: (“rgb(200, 100, 0)”)
  • -
  • rgb(•••%, •••%, •••%) — same as above, but in %: (“rgb(100%, 175%, 0%)”)
  • -
  • rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“rgba(200, 100, 0, .5)”)
  • -
  • rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“rgba(100%, 175%, 0%, 50%)”)
  • -
  • hsb(•••, •••, •••) — hue, saturation and brightness values: (“hsb(0.5, 0.25, 1)”)
  • -
  • hsb(•••%, •••%, •••%) — same as above, but in %
  • -
  • hsba(•••, •••, •••, •••) — same as above, but with opacity
  • -
  • hsl(•••, •••, •••) — almost the same as hsb, see Wikipedia page
  • -
  • hsl(•••%, •••%, •••%) — same as above, but in %
  • -
  • hsla(•••, •••, •••) — same as above, but with opacity
  • -
  • Optionally for hsb and hsl you could specify hue as a degree: “hsl(240deg, 1, .5)” or, if you want to go fancy, “hsl(240°, 1, .5)”
  • -
-

Usage

-
paper.circle(100, 100, 20).attr({
-    fill: "hsb(0.6, 1, 0.75)",
-    stroke: "red"
-});
-

- safari -

-

- There is an inconvenient rendering bug is Safari (WebKit): sometimes the rendering should be forced. This method should help with dealing with this bug. -

-

Usage

-
paper.safari();
-

- “Ninja Mode” -

-

- 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. Beware, that in this case plugins could stop working, because they are depending on global variable existance. -

-

Usage

-
(function (local_raphael) {
-    var paper = local_raphael(10, 10, 320, 200);
-    …
-})(Raphael.ninja());
+

Raphael.getSubpath(path, from, to)

+

Return subpath of a given path from given length to given length.

+

Parameters +

+
path
+
string
+
SVG path string
+
from
+
number
+
position of the start of the segment
+
to
+
number
+
position of the end of the segment
+
+

Returns: string pathstring for the segment

+

Raphael.getTotalLength(path)

+

Returns length of the given path in pixels.

+

Parameters +

+
path
+
string
+
SVG path string.
+
+

Returns: number length.

+

Raphael.hsb(h, s, b)

+

Converts HSB values to hex representation of the colour.

+

Parameters +

+
h
+
number
+
hue
+
s
+
number
+
saturation
+
b
+
number
+
value or brightness
+
+

Returns: string hex representation of the colour.

+

Raphael.hsb2rgb(h, s, v)

+

Converts HSB values to RGB object.

+

Parameters +

+
h
+
number
+
hue
+
s
+
number
+
saturation
+
v
+
number
+
value or brightness
+
+

Returns: object RGB object in format:

+
{
+    r: // red,
+    g: // green,
+    b: // blue
+    hex: // color in HTML/CSS format: #••••••
+}
 
-

- Events -

-

- You can attach events to elements by using element.node and your favourite library ($(circle.node).click(…)) or you can use built-in methods: -

-

Usage

-
element.click(function (event) {
-    this.attr({fill: "red"});
-});
-element.dblclick(function (event) {
-    this.attr({fill: "red"});
-});
-element.mousedown(function (event) {
-    this.attr({fill: "red"});
-});
-element.mousemove(function (event) {
-    this.attr({fill: "red"});
-});
-element.mouseout(function (event) {
-    this.attr({fill: "red"});
-});
-element.mouseover(function (event) {
-    this.attr({fill: "red"});
-});
-element.mouseup(function (event) {
-    this.attr({fill: "red"});
-});
-element.hover(function (event) {
-    this.attr({fill: "red"});
-}, function (event) {
-    this.attr({fill: "black"});
-}, overScope, outScope);
-

- Second parameter is optional scope. By default handlers are run in the scope of the element. To unbind events use the same method names with “un” prefix, i.e. element.unclick(f); -

-

- Drag ’n’ Drop -

-

- To make element “draggable” you need to call method drag on element. -

-

Parameters

-
    -
  1. onmove function event handler for moving
  2. -
  3. onstart function event handler for start
  4. -
  5. onend function event handler for end of the drag
  6. -
-

Usage

-
var c = R.circle(100, 100, 50).attr({
-    fill: "hsb(.8, 1, 1)",
-    stroke: "none",
-    opacity: .5
-});
-var start = function () {
-    // storing original coordinates
-    this.ox = this.attr("cx");
-    this.oy = this.attr("cy");
-    this.attr({opacity: 1});
-},
-move = function (dx, dy) {
-    // move will be called with dx and dy
-    this.attr({cx: this.ox + dx, cy: this.oy + dy});
-},
-up = function () {
-    // restoring state
-    this.attr({opacity: .5});
-};
-c.drag(move, start, up);
-

- To unbind drag use the undrag method. -

-
-
-

- Home -

-

- Contents -

- -
- -
- - - - - - - - +

Raphael.hsl(h, s, l)

+

Converts HSL values to hex representation of the colour.

+

Parameters +

+
h
+
number
+
hue
+
s
+
number
+
saturation
+
l
+
number
+
luminosity
+
+

Returns: string hex representation of the colour.

+

Raphael.hsl2rgb(h, s, l)

+

Converts HSL values to RGB object.

+

Parameters +

+
h
+
number
+
hue
+
s
+
number
+
saturation
+
l
+
number
+
luminosity
+
+

Returns: object RGB object in format:

+
{
+    r: // red,
+    g: // green,
+    b: // blue
+    hex: // color in HTML/CSS format: #••••••
+}
+
+

Raphael.is(o, type)

+

Handfull replacement for typeof operator.

+

Parameters +

+
o
+
…
+
any object or primitive
+
type
+
string
+
name of the type, i.e. “string”, “function”, “number”, etc.
+
+

Returns: boolean is given value is of given type

+

Raphael.parsePathString(pathString)

+

Utility methodParses given path string into an array of arrays of path segments.

+

Parameters +

+
pathString
+
string array
+
path string or array of segments (in the last case it will be returned stright away)
+
+

Returns: array array of segments.

+

Raphael.parseTransformString(TString)

+

Utility methodParses given path string into an array of transformations.

+

Parameters +

+
TString
+
string array
+
transform string or array of transformations (in the last case it will be returned stright away)
+
+

Returns: array array of transformations.

+

Raphael.path2curve(pathString)

+

Utility methodConverts path to path where all segments are cubic bezier curves.

+

Parameters +

+
pathString
+
string array
+
path string or array of segments
+
+

Returns: array array of segments.

+

Raphael.pathToRelative(pathString)

+

Utility methodConverts path to relative form

+

Parameters +

+
pathString
+
string array
+
path string or array of segments
+
+

Returns: array array of segments.

+

Raphael.rad(deg)

+

Transform angle to radians

+

Parameters +

+
deg
+
number
+
angle in degrees
+
+

Returns: number angle in radians.

+

Raphael.rgb(r, g, b)

+

Converts RGB values to hex representation of the colour.

+

Parameters +

+
r
+
number
+
red
+
g
+
number
+
green
+
b
+
number
+
blue
+
+

Returns: string hex representation of the colour.

+

Raphael.rgb2hsb(r, g, b)

+

Converts RGB values to HSB object.

+

Parameters +

+
r
+
number
+
red
+
g
+
number
+
green
+
b
+
number
+
blue
+
+

Returns: object HSB object in format:

+
{
+    h: // hue,
+    s: // saturation,
+    b: // brightness
+}
+
+

Raphael.rgb2hsl(r, g, b)

+

Converts RGB values to HSL object.

+

Parameters +

+
r
+
number
+
red
+
g
+
number
+
green
+
b
+
number
+
blue
+
+

Returns: object HSL object in format:

+
{
+    h: // hue,
+    s: // saturation,
+    l: // luminosity
+}
+
+

Raphael.setWindow(newwin)

+

Used when you need to draw in <iframe>. Switched window to the iframe one.

+

Parameters +

+
newwin
+
window
+
new window object
+
+

Raphael.snapTo(values, value, [tolerance])

+

Snaps given value to given grid.

+

Parameters +

+
values
+
array number
+
given array of values or step of the grid
+
value
+
number
+
value to adjust
+
tolerance
+
optional
+
number
+
tolerance for snapping. Default is 10.
+
+

Returns: number adjusted value.

+

Raphael.svg

+
boolean

true if browser supports SVG.

+

Raphael.type

+
string

Can be “SVG”, “VML” or empty, depending on browser support.

+

Raphael.vml

+
boolean

true if browser supports VML.

+
\ No newline at end of file -- 2.39.2