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

+Raphaël Reference
  1. Animation
  2. Animation.delay()
  3. Animation.repeat()
  4. Element
  5. Element.animate()
  6. Element.animateWith()
  7. Element.attr()
  8. Element.clone()
  9. Element.drag()
  10. Element.getBBox()
  11. Element.getPointAtLength()
  12. Element.getSubpath()
  13. Element.getTotalLength()
  14. Element.glow()
  15. Element.hide()
  16. Element.hover()
  17. Element.id
  18. Element.insertAfter()
  19. Element.insertBefore()
  20. Element.next
  21. Element.node
  22. Element.onDragOver()
  23. Element.paper
  24. Element.pause()
  25. Element.prev
  26. Element.raphael
  27. Element.remove()
  28. Element.resume()
  29. Element.rotate()
  30. Element.scale()
  31. Element.setTime()
  32. Element.show()
  33. Element.status()
  34. Element.stop()
  35. Element.toBack()
  36. Element.toFront()
  37. Element.transform()
  38. Element.translate()
  39. Element.undrag()
  40. Element.unhover()
  41. Paper
  42. Paper.bottom
  43. Paper.circle()
  44. Paper.clear()
  45. Paper.customAttributes
  46. Paper.ellipse()
  47. Paper.forEach()
  48. Paper.getById()
  49. Paper.getElementByPoint()
  50. Paper.image()
  51. Paper.path()
  52. Paper.raphael
  53. Paper.rect()
  54. Paper.remove()
  55. Paper.safari()
  56. Paper.set()
  57. Paper.setSize()
  58. Paper.setViewBox()
  59. Paper.text()
  60. Paper.top
  61. Raphael()
  62. Raphael.angle()
  63. Raphael.animation()
  64. Raphael.deg()
  65. Raphael.easing_formulas
  66. Raphael.el
  67. Raphael.findDotsAtSegment()
  68. Raphael.fn
  69. Raphael.getColor()
  70. Raphael.getColor.reset()
  71. Raphael.getPointAtLength()
  72. Raphael.getRGB()
  73. Raphael.getSubpath()
  74. Raphael.getTotalLength()
  75. Raphael.hsb()
  76. Raphael.hsb2rgb()
  77. Raphael.hsl()
  78. Raphael.hsl2rgb()
  79. Raphael.is()
  80. Raphael.parsePathString()
  81. Raphael.parseTransformString()
  82. Raphael.path2curve()
  83. Raphael.pathToRelative()
  84. Raphael.rad()
  85. Raphael.rgb()
  86. Raphael.rgb2hsb()
  87. Raphael.rgb2hsl()
  88. Raphael.setWindow()
  89. Raphael.snapTo()
  90. Raphael.svg
  91. Raphael.type
  92. Raphael.vml
  93. Set
  94. Set.forEach()
  95. Set.pop()
  96. Set.push()

Raphaël Reference

Check out the source: raphael.js

Animation

+

Animation.delay(delay)

+

Creates copy of existing animation object with given delay. +

Parameters

delay
@@ -10,8 +11,9 @@
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.

+

Animation.repeat(repeat)

+

Creates copy of existing animation object with given repetition. +

Parameters

repeat
@@ -20,8 +22,36 @@

Returns: object new altered Animation object

Element

-

Element.animate(…)

-

Creates and starts animation for given 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.animateWith(…)

+

Acts similar to Element.animate, but ensure that given animation runs in sync with another given element. +

Parameters

params
@@ -33,22 +63,175 @@
easing
optional
string
-
easing type. Accept on of Raphael.easing_formulas or CSS format: cubic-bezier(XX, XX, XX, XX)
+
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

+

or +

animation
object
animation object, see Raphael.animation

Returns: object original element

-

Element.clone()

+

Element.attr(…)

+

Sets the attributes of the element. +

+

Parameters +

+
attrName
+
string
+
attribute’s name
+
value
+
string
+
value
+
+

or +

+
params
+
object
+
object of name/value pairs
+
+

or +

+
attrName
+
string
+
attribute’s name
+
+

or +

+
attrNames
+
array
+
in this case method returns array of current values for given attribute names
+
+

Returns: object Element if attrsName & value or params are passed in.

+

Returns: ... value of the attribute if only attrsName is passed in.

+

Returns: array array of values of the attribute if attrsNames is passed in.

+

Returns: object object of attributes if nothing is passed in.

+

Possible parameters +

+

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

+
  1. arrow-endstringarrowhead on the end of the path. The format for string is <type>[-<width>[-<length>]]. Possible types: classic, block, open, oval, diamond, none, width: wide, narrow, midium, length: long, short, midium. +
  2. clip-rectstringcomma or space separated values: x, y, width and height +
  3. cursorstringCSS type of the cursor +
  4. cxnumber  +
  5. cynumber  +
  6. fillstringcolour, gradient or image +
  7. fill-opacitynumber  +
  8. fontstring  +
  9. font-familystring  +
  10. font-sizenumberfont size in pixels +
  11. font-weightstring  +
  12. heightnumber  +
  13. hrefstringURL, if specified element behaves as hyperlink +
  14. opacitynumber  +
  15. pathstringSVG path string format +
  16. rnumber  +
  17. rxnumber  +
  18. rynumber  +
  19. srcstringimage URL, only works for Element.image element +
  20. strokestringstroke colour +
  21. stroke-dasharraystring[“”, “-”, “.”, “-.”, “-..”, “. ”, “- ”, “--”, “- .”, “--.”, “--..”] +
  22. stroke-linecapstring[“butt”, “square”, “round”] +
  23. stroke-linejoinstring[“bevel”, “round”, “miter”] +
  24. stroke-miterlimitnumber  +
  25. stroke-opacitynumber  +
  26. stroke-widthnumberstroke width in pixels, default is '1' +
  27. targetstringused with href +
  28. textstringcontents of the text element. Use \n for multiline text +
  29. text-anchorstring[“start”, “middle”, “end”], default is “middle” +
  30. titlestringwill create tooltip with a given text +
  31. transformstringsee Element.transform +
  32. widthnumber  +
  33. xnumber  +
  34. ynumber  +
+

Gradients +

Linear gradient format: “‹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. +

+

Path String +

+

Please refer to SVG documentation regarding path string. Raphaël fully supports it.

+

Colour Parsing +

+
    +
  • 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)”
  • +
+

Element.clone()

Returns: object clone of a given element

-

Element.getBBox(isWithoutTransform)

-

Return bounding box for a given element

+

Element.drag(onmove, onstart, onend, [mcontext], [scontext], [econtext])

+

Adds event handlers for drag of the element. +

+

Parameters +

+
onmove
+
function
+
handler for moving
+
onstart
+
function
+
handler for drag start
+
onend
+
function
+
handler for drag end
+
mcontext
+
optional
+
object
+
context for moving handler
+
scontext
+
optional
+
object
+
context for drag start handler
+
econtext
+
optional
+
object
+
context for drag end handler
+
+

Additionaly following drag events will be triggered: drag.start.<id> on start, +drag.end.<id> on end and drag.move.<id> on every move. When element will be dragged over another element +drag.over.<id> will be fired as well. +

+

Start event and start handler will be called in specified context or in context of the element with following parameters: +

+
  1. xnumberx position of the mouse +
  2. ynumbery position of the mouse +
  3. eventobjectDOM event object +
+

Move event and move handler will be called in specified context or in context of the element with following parameters: +

+
  1. dxnumbershift by x from the start point +
  2. dynumbershift by y from the start point +
  3. xnumberx position of the mouse +
  4. ynumbery position of the mouse +
  5. eventobjectDOM event object +
+

End event and end handler will be called in specified context or in context of the element with following parameters: +

+
  1. eventobjectDOM event object +
+

Returns: object Element

+

Element.getBBox(isWithoutTransform)

+

Return bounding box for a given element +

Parameters

isWithoutTransform
@@ -56,15 +239,14 @@
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.

+
  1. {
    1. x:numbertop left corner x +
    2. y:numbertop left corner y +
    3. width:numberwidth +
    4. height:numberheight +
  2. }
+

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
@@ -72,14 +254,13 @@
 

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.

+
  1. {
    1. x:numberx coordinate +
    2. y:numbery coordinate +
    3. alpha:numberangle of derivative +
  2. }
+

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
@@ -90,15 +271,130 @@
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.

+

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.

+

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 Paper.set of elements that represents glow

+

Element.hide()

+

Makes element invisible. See Element.show. +

+

Returns: object Element

+

Element.hover(f_in, f_out, [icontext], [ocontext])

+

Adds event handlers for hover for the element. +

+

Parameters +

+
f_in
+
function
+
handler for hover in
+
f_out
+
function
+
handler for hover out
+
icontext
+
optional
+
object
+
context for hover in handler
+
ocontext
+
optional
+
object
+
context for hover out handler
+
+

Returns: object Element

+

Element.id

+
number

Unique id of the element. Especially usesful when you want to listen to events of the element, +because all events are fired in format <module>.<action>.<id>. Also useful for Paper.getById method. +

+

Element.insertAfter()

+

Inserts current object after the given one. +

+

Returns: object Element

+

Element.insertBefore()

+

Inserts current object before the given one. +

+

Returns: object Element

+

Element.next

+
object

Reference to the next element in the hierarchy. +

+

Element.node

+
object

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

Element.onDragOver(f)

+

Shortcut for assigning event handler for drag.over.<id> event, where id is id of the element (see Element.id). +

+

Parameters +

+
f
+
function
+
handler for event
+
+

Element.paper

+
object

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

Element.pause([anim])

+

Stops animation of the element with ability to resume it later on. +

+

Parameters +

+
anim
+
optional
+
object
+
animation object
+
+

Returns: object original element

+

Element.prev

+
object

Reference to the previous element in the hierarchy. +

+

Element.raphael

+
object

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

Element.remove()

+

Removes element form the paper. +

+

Element.resume([anim])

+

Resumes animation if it was paused with Element.pause method. +

+

Parameters +

+
anim
+
optional
+
object
+
animation object
+
+

Returns: object original element

+

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

+

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

Parameters

deg
@@ -113,10 +409,13 @@
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.

+

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.

+

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

+

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

Parameters

sx
@@ -134,10 +433,12 @@
number
y coordinate of the centre of scale
-

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

+

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.

+

Element.setTime(anim, value)

+

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

Parameters

anim
@@ -148,8 +449,17 @@
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.

+

Note, that during animation following events are triggered: +

+

On each animation frame event anim.frame.<id>, on start anim.start.<id> and on end anim.finish.<id>. +

+

Element.show()

+

Makes element visible. See Element.hide. +

+

Returns: object Element

+

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

+

Gets or sets the status of animation of the element. +

Parameters

anim
@@ -162,24 +472,64 @@
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
-}, {
-    anim: // animation object,
-    status: // status
-}, ...]
-
-

or

+

or +

+

Returns: array status if anim is not specified. Array of objects in format:

+
  1. {
    1. anim:objectanimation object +
    2. status:numberstatus +
  2. }
+

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:

+

Element.stop([anim])

+

Stops animation of the element. +

+

Parameters +

+
anim
+
optional
+
object
+
animation object
+
+

Returns: object original element

+

Element.toBack()

+

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

+

Returns: object Element

+

Element.toFront()

+

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

+

Returns: object Element

+

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

+

Each letter is a command. There are four commands: t is for translate, r is for rotate, s is for +scale 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, 100 +rotate 45° around centre and scale 1.5 times relative to centre”. As you see rotate and scale commands has origin +coordinates as a optional parameters. +Matrix accepts six parameters. +

+

Usage +

+
var el = paper.rect(10, 20, 300, 200);
+// translate 100, 100, rotate 45°, translate -100, 0
+el.transform("t100,100r45t-100,0");
+// if you want you can append or prepend transformations
+el.transform("...t50,50");
+el.transform("s2...");
+// or even wrap
+el.transform("t50,50...t-50-50");
+// to reset transformation call method with empty string
+el.transform("");
+// to get current value call it without parameters
+console.log(el.transform());
+

Parameters

tstr
@@ -187,12 +537,15 @@
string
transformation string
-

If tstr isn’t specified

+

If tstr isn’t specified +

Returns: string current transformation string

-

else

+

else +

Returns: object Element

-

Element.translate(dx, dy)

-

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

+

Element.translate(dx, dy)

+

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

Parameters

dx
@@ -203,11 +556,29 @@
vertical shift

Returns: object Element

+

Element.undrag()

+

Removes all drag event handlers from given element. +

+

Element.unhover(f_in, f_out)

+

Removes event handlers for hover for the element. +

+

Parameters +

+
f_in
+
function
+
handler for hover in
+
f_out
+
function
+
handler for hover out
+
+

Returns: object Element

Paper

-

Paper.bottom

-

Points to the bottom element on the paper

-

Paper.circle(x, y, r)

-

Draws a circle.

+

Paper.bottom

+

Points to the bottom element on the paper +

+

Paper.circle(x, y, r)

+

Draws a circle. +

Parameters

x
@@ -225,8 +596,37 @@

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

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

-

Draws an ellipse.

+

Paper.clear()

+

Clears the paper, i.e. removes all the elements. +

+

Paper.customAttributes

+
object

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

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

+

Draws an ellipse. +

Parameters

x
@@ -247,9 +647,11 @@

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.

+

Paper.forEach(callback, thisArg)

+

Executes given function for each element on the paper +

+

If function returns false it will stop loop running. +

Parameters

callback
@@ -260,8 +662,9 @@
context object for the callback

Returns: object Paper object

-

Paper.getById(id)

-

Returns you element by it’s internal ID.

+

Paper.getById(id)

+

Returns you element by it’s internal ID. +

Parameters

id
@@ -269,8 +672,9 @@
id

Returns: object Raphaël element object

-

Paper.getElementByPoint(x, y)

-

Returns you topmost element under given point.

+

Paper.getElementByPoint(x, y)

+

Returns you topmost element under given point. +

Returns: object Raphaël element object

Parameters

@@ -285,8 +689,9 @@

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

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

-

Embeds an image into the surface.

+

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

+

Embeds an image into the surface. +

Parameters

src
@@ -310,8 +715,9 @@

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

Paper.path(pathString)

-

Creates a path element by given path data string.

+

Paper.path(pathString)

+

Creates a path element by given path data string. +

Parameters

pathString
@@ -326,11 +732,13 @@ Details of a path's data attribute's format are described in the // 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)

+

Paper.raphael

+

Points to the Raphael object/function +

+

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

-

Draws a rectangle.

+

Draws a rectangle. +

Parameters

x
@@ -357,8 +765,34 @@ Details of a path's data attribute's format are described in the // 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.

+

Paper.remove()

+

Removes the paper from the DOM. +

+

Paper.safari(f_in, f_out, [icontext], [ocontext])

+

Adds event handlers for hover for the element. +

+

Parameters +

+
f_in
+
function
+
handler for hover in
+
f_out
+
function
+
handler for hover out
+
icontext
+
optional
+
object
+
context for hover in handler
+
ocontext
+
optional
+
object
+
context for hover out handler
+
+

Returns: object Element

+

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

@@ -369,8 +803,9 @@ st.push( ); st.attr({fill: "red"}); -

Paper.setSize(width, height)

-

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

+

Paper.setSize(width, height)

+

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

Parameters

width
@@ -389,8 +824,31 @@ st.push( ); st.attr({fill: "red"}); -

Paper.text(x, y, text)

-

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

+

Paper.setViewBox(x, y, w, h, fit)

+

Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by +specifying new boundaries. +

+

Parameters +

+
x
+
number
+
new x position, default is 0
+
y
+
number
+
new y position, default is 0
+
w
+
number
+
new width of the canvas
+
h
+
number
+
new height of the canvas
+
fit
+
boolean
+
true if you want graphics to fit into new boundary box
+
+

Paper.text(x, y, text)

+

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

Parameters

x
@@ -408,10 +866,14 @@ st.attr({fill: "red"});

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

Paper.top

-

Points to the topmost element on the paper

+

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.

+

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

container
@@ -424,7 +886,8 @@ st.attr({fill: "red"});
number
 
-

or

+

or +

x
number
 
@@ -438,12 +901,14 @@ st.attr({fill: "red"});
number
 
-

or

+

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

+

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.
@@ -474,8 +939,9 @@ st.attr({fill: "red"}); text: "Dump" }]); -

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

-

Returns angle between two or three points

+

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

+

Returns angle between two or three points +

Parameters

x1
@@ -500,8 +966,10 @@ st.attr({fill: "red"});
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.

+

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
@@ -513,15 +981,16 @@ st.attr({fill: "red"});
easing
optional
string
-
easing type. Accept one of Raphael.easing_formulas or CSS format: cubic-bezier(XX, XX, XX, XX)
+
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

+

Raphael.deg(deg)

+

Transform angle to degrees +

Parameters

deg
@@ -529,8 +998,9 @@ st.attr({fill: "red"});
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:

+

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”
  • @@ -542,8 +1012,23 @@ st.attr({fill: "red"});
  • “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.

+

Raphael.el

+
object

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 methods, +you can redefine element method at any time. Expending element methods wouldn’t affect set +

+

Usage +

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

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

+

Utility method +Find dot coordinates on the given cubic bezier curve at the given t. +

Parameters

p1x
@@ -575,30 +1060,25 @@ st.attr({fill: "red"});
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.

+
  1. {
    1. x:numberx coordinate of the point +
    2. y:numbery coordinate of the point +
    3. m: {
      1. x:numberx coordinate of the left anchor +
      2. y:numbery coordinate of the left anchor +
    4. }
    5. n: {
      1. x:numberx coordinate of the right anchor +
      2. y:numbery coordinate of the right anchor +
    6. }
    7. start: {
      1. x:numberx coordinate of the start of the curve +
      2. y:numbery coordinate of the start of the curve +
    8. }
    9. end: {
      1. x:numberx coordinate of the end of the curve +
      2. y:numbery coordinate of the end of the curve +
    10. }
    11. alpha:numberangle of the curve derivative at the point +
  2. }
+

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 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) {
@@ -616,8 +1096,9 @@ paper.arrow(10, 10, Raphael.getColor([value])
-

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

+

Raphael.getColor([value])

+

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

Parameters

value
@@ -626,10 +1107,12 @@ paper.mystuff.star();
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.

+

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
@@ -640,14 +1123,13 @@ paper.mystuff.star();
 

Returns: object representation of the point:

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

Raphael.getRGB(colour)

-

Parses colour string as RGB object

+
  1. {
    1. x:numberx coordinate +
    2. y:numbery coordinate +
    3. alpha:numberangle of derivative +
  2. }
+

Raphael.getRGB(colour)

+

Parses colour string as RGB object +

Parameters

colour
@@ -655,16 +1137,15 @@ paper.mystuff.star();
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
-}
-
-

Raphael.getSubpath(path, from, to)

-

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

+
  1. {
    1. rnumberred, +
    2. gnumbergreen, +
    3. bnumberblue +
    4. hexstringcolor in HTML/CSS format: #••••••, +
    5. errorbooleantrue if string can’t be parsed +
  2. }
+

Raphael.getSubpath(path, from, to)

+

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

Parameters

path
@@ -678,8 +1159,9 @@ paper.mystuff.star();
position of the end of the segment

Returns: string pathstring for the segment

-

Raphael.getTotalLength(path)

-

Returns length of the given path in pixels.

+

Raphael.getTotalLength(path)

+

Returns length of the given path in pixels. +

Parameters

path
@@ -687,8 +1169,9 @@ paper.mystuff.star();
SVG path string.

Returns: number length.

-

Raphael.hsb(h, s, b)

-

Converts HSB values to hex representation of the colour.

+

Raphael.hsb(h, s, b)

+

Converts HSB values to hex representation of the colour. +

Parameters

h
@@ -702,8 +1185,9 @@ paper.mystuff.star();
value or brightness

Returns: string hex representation of the colour.

-

Raphael.hsb2rgb(h, s, v)

-

Converts HSB values to RGB object.

+

Raphael.hsb2rgb(h, s, v)

+

Converts HSB values to RGB object. +

Parameters

h
@@ -717,15 +1201,14 @@ paper.mystuff.star();
value or brightness

Returns: object RGB object in format:

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

Raphael.hsl(h, s, l)

-

Converts HSL values to hex representation of the colour.

+
  1. {
    1. rnumberred, +
    2. gnumbergreen, +
    3. bnumberblue, +
    4. hexstringcolor in HTML/CSS format: #•••••• +
  2. }
+

Raphael.hsl(h, s, l)

+

Converts HSL values to hex representation of the colour. +

Parameters

h
@@ -739,8 +1222,9 @@ paper.mystuff.star();
luminosity

Returns: string hex representation of the colour.

-

Raphael.hsl2rgb(h, s, l)

-

Converts HSL values to RGB object.

+

Raphael.hsl2rgb(h, s, l)

+

Converts HSL values to RGB object. +

Parameters

h
@@ -754,15 +1238,14 @@ paper.mystuff.star();
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.

+
  1. {
    1. rnumberred, +
    2. gnumbergreen, +
    3. bnumberblue, +
    4. hexstringcolor in HTML/CSS format: #•••••• +
  2. }
+

Raphael.is(o, type)

+

Handfull replacement for typeof operator. +

Parameters

o
@@ -773,8 +1256,10 @@ paper.mystuff.star();
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.

+

Raphael.parsePathString(pathString)

+

Utility method +Parses given path string into an array of arrays of path segments. +

Parameters

pathString
@@ -782,8 +1267,10 @@ paper.mystuff.star();
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.

+

Raphael.parseTransformString(TString)

+

Utility method +Parses given path string into an array of transformations. +

Parameters

TString
@@ -791,8 +1278,10 @@ paper.mystuff.star();
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.

+

Raphael.path2curve(pathString)

+

Utility method +Converts path to path where all segments are cubic bezier curves. +

Parameters

pathString
@@ -800,8 +1289,10 @@ paper.mystuff.star();
path string or array of segments

Returns: array array of segments.

-

Raphael.pathToRelative(pathString)

-

Utility methodConverts path to relative form

+

Raphael.pathToRelative(pathString)

+

Utility method +Converts path to relative form +

Parameters

pathString
@@ -809,8 +1300,9 @@ paper.mystuff.star();
path string or array of segments

Returns: array array of segments.

-

Raphael.rad(deg)

-

Transform angle to radians

+

Raphael.rad(deg)

+

Transform angle to radians +

Parameters

deg
@@ -818,8 +1310,9 @@ paper.mystuff.star();
angle in degrees

Returns: number angle in radians.

-

Raphael.rgb(r, g, b)

-

Converts RGB values to hex representation of the colour.

+

Raphael.rgb(r, g, b)

+

Converts RGB values to hex representation of the colour. +

Parameters

r
@@ -833,8 +1326,9 @@ paper.mystuff.star();
blue

Returns: string hex representation of the colour.

-

Raphael.rgb2hsb(r, g, b)

-

Converts RGB values to HSB object.

+

Raphael.rgb2hsb(r, g, b)

+

Converts RGB values to HSB object. +

Parameters

r
@@ -848,14 +1342,13 @@ paper.mystuff.star();
blue

Returns: object HSB object in format:

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

Raphael.rgb2hsl(r, g, b)

-

Converts RGB values to HSL object.

+
  1. {
    1. hnumberhue +
    2. snumbersaturation +
    3. bnumberbrightness +
  2. }
+

Raphael.rgb2hsl(r, g, b)

+

Converts RGB values to HSL object. +

Parameters

r
@@ -869,22 +1362,22 @@ paper.mystuff.star();
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.

+
  1. {
    1. hnumberhue +
    2. snumbersaturation +
    3. lnumberluminosity +
  2. }
+

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.

+

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

+

Snaps given value to given grid. +

Parameters

values
@@ -900,9 +1393,36 @@ paper.mystuff.star();

Returns: number adjusted value.

Raphael.svg

-
boolean

true if browser supports SVG.

+
boolean

true if browser supports SVG. +

Raphael.type

-
string

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

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

true if browser supports VML. +

+

Set

+

Set.forEach(callback, thisArg)

+

Executes given function for each element in the set. +

+

If function returns false it will stop loop running. +

+

Parameters +

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

Returns: object Set object

+

Set.pop()

+

Removes last element and returns it. +

+

Returns: object element

+

Set.push()

+

Adds each argument to the current set. +

+

Returns: object original element

+
\ No newline at end of file -- 2.39.2