X-Git-Url: http://git.roojs.org/?p=raphael;a=blobdiff_plain;f=raphael.js;h=bf6e741fdf2c1bc4945ade5ee864f6493721a997;hp=7d56fad6eff45a22d006c6d2af2bde00b2919bff;hb=300aa589f5a0ba7fce667cd62c7cdda0bd5ad904;hpb=f032ff7a900cc06856c75904ceaba029c00b7936 diff --git a/raphael.js b/raphael.js index 7d56fad..bf6e741 100644 --- a/raphael.js +++ b/raphael.js @@ -1,229 +1,808 @@ -/*! - * Raphael 1.2.6 - JavaScript Vector Library - * - * Copyright (c) 2008 - 2009 Dmitry Baranovskiy (http://raphaeljs.com) - * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. - */ +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2.0.1 - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +// ┌──────────────────────────────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.4.0 - JavaScript Events Library │ \\ +// ├──────────────────────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// │ Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. │ \\ +// └──────────────────────────────────────────────────────────────────────────────────────┘ \\ -window.Raphael = (function () { - var separator = /[, ]+/, - doc = document, - win = window, - oldRaphael = { - was: "Raphael" in win, - is: win.Raphael +(function (glob) { + var version = "0.4.0", + has = "hasOwnProperty", + separator = /[\.\/]/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; }, - R = function () { - if (R.is(arguments[0], "array")) { - var a = arguments[0], - cnv = create[apply](R, a.splice(0, 3 + R.is(a[0], nu))), - res = cnv.set(); - for (var i = 0, ii = a[length]; i < ii; i++) { - var j = a[i] || {}; - ({circle:1, rect:1, path:1, ellipse:1, text:1, image:1})[has](j.type) && res[push](cnv[j.type]().attr(j)); + current_event, + stop, + events = {n: {}}, + + eve = function (name, scope) { + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + errors = []; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; } - return res; } - return create[apply](R, arguments); + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + } + stop = oldstop; + return out.length ? out : null; + }; + + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + + + eve.on = function (name, f) { + var names = name.split(separator), + e = events; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + !e[names[i]] && (e[names[i]] = {n: {}}); + e = e[names[i]]; + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + return fun; + } + e.f.push(f); + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + + eve.stop = function () { + stop = 1; + }; + + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + + eve.unbind = function (name, f) { + var names = name.split(separator), + e, + key, + splice, + i, ii, j, jj, + cur = [events]; + for (i = 0, ii = names.length; i < ii; i++) { + for (j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + + eve.once = function (name, f) { + var f2 = function () { + f.apply(this, arguments); + eve.unbind(name, f2); + }; + return eve.on(name, f2); + }; + + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (glob.eve = eve); +})(this); + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ "Raphaël 2.0.1" - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +(function () { + + function R(first) { + if (R.is(first, "function")) { + return loaded ? first() : eve.on("DOMload", first); + } else if (R.is(first, array)) { + return R._engine.create[apply](R, first.splice(0, 3 + R.is(first[0], nu))).add(first); + } else { + var args = Array.prototype.slice.call(arguments, 0); + if (R.is(args[args.length - 1], "function")) { + var f = args.pop(); + return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("DOMload", function () { + f.call(R._engine.create[apply](R, args)); + }); + } else { + return R._engine.create[apply](R, arguments); + } + } + } + R.version = "2.0.1"; + R.eve = eve; + var loaded, + separator = /[, ]+/, + elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1}, + formatrg = /\{(\d+)\}/g, + proto = "prototype", + has = "hasOwnProperty", + g = { + doc: document, + win: window + }, + oldRaphael = { + was: Object.prototype[has].call(g.win, "Raphael"), + is: g.win.Raphael }, + Paper = function () { + + + this.ca = this.customAttributes = {}; + }, + paperproto, appendChild = "appendChild", apply = "apply", concat = "concat", + supportsTouch = "createTouch" in g.doc, E = "", S = " ", - events = "click dblclick mousedown mousemove mouseout mouseover mouseup".split(S), - has = "hasOwnProperty", - isit = /^\[object\s+|\]$/gi, - join = "join", - length = "length", - proto = "prototype", - lowerCase = String[proto].toLowerCase, + Str = String, + split = "split", + events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S), + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + lowerCase = Str.prototype.toLowerCase, math = Math, mmax = math.max, mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, nu = "number", + string = "string", + array = "array", toString = "toString", - objectToString = Object[proto][toString], + fillString = "fill", + objectToString = Object.prototype.toString, paper = {}, - pow = math.pow, push = "push", - rg = /^(?=[\da-f]$)/, - ISURL = /^url\(['"]?([^\)]+)['"]?\)$/i, + ISURL = R._ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + 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, + isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1}, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, round = math.round, setAttribute = "setAttribute", - split = "split", toFloat = parseFloat, toInt = parseInt, - upperCase = String[proto].toUpperCase, - availableAttrs = {"clip-rect": "0 0 10e9 10e9", 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, rotation: 0, rx: 0, ry: 0, scale: "1 1", 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", translation: "0 0", width: 0, x: 0, y: 0}, - availableAnimAttrs = {"clip-rect": "csv", cx: nu, cy: nu, fill: "colour", "fill-opacity": nu, "font-size": nu, height: nu, opacity: nu, path: "path", r: nu, rotation: "csv", rx: nu, ry: nu, scale: "csv", stroke: "colour", "stroke-opacity": nu, "stroke-width": nu, translation: "csv", width: nu, x: nu, y: nu}, - rp = "replace"; - R.version = "1.2.6"; - R.type = (win.SVGAngle || doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); + upperCase = Str.prototype.toUpperCase, + availableAttrs = R._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/", + "letter-spacing": 0, + 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 + }, + availableAnimAttrs = R._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 + }, + commaSpaces = /\s*,\s*/, + hsrg = {hs: 1, rg: 1}, + p2s = /,?([achlmqrstvxz]),?/gi, + pathCommand = /([achlmrqstvz])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig, + tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)\s*,?\s*/ig, + radial_gradient = R._radial_gradient = /^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/, + eldata = {}, + sortByKey = function (a, b) { + return a.key - b.key; + }, + sortByNumber = function (a, b) { + return toFloat(a) - toFloat(b); + }, + fun = function () {}, + pipe = function (x) { + return x; + }, + rectPath = R._rectPath = function (x, y, w, h, r) { + if (r) { + return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]]; + } + return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + }, + ellipsePath = function (x, y, rx, ry) { + if (ry == null) { + ry = rx; + } + return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]]; + }, + getPath = R._getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var a = el.attrs; + return ellipsePath(a.cx, a.cy, a.r); + }, + ellipse: function (el) { + var a = el.attrs; + return ellipsePath(a.cx, a.cy, a.rx, a.ry); + }, + rect: function (el) { + var a = el.attrs; + return rectPath(a.x, a.y, a.width, a.height, a.r); + }, + image: function (el) { + var a = el.attrs; + return rectPath(a.x, a.y, a.width, a.height); + }, + text: function (el) { + var bbox = el._getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }, + mapPath = R.mapPath = function (path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, ii, jj, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + }; + + R._g = g; + + R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); + if (R.type == "VML") { + var d = g.doc.createElement("div"), + b; + d.innerHTML = ''; + b = d.firstChild; + b.style.behavior = "url(#default#VML)"; + if (!(b && typeof b.adj == "object")) { + return (R.type = E); + } + d = null; + } + + R.svg = !(R.vml = R.type == "VML"); + R._Paper = Paper; + + R.fn = paperproto = Paper.prototype = R.prototype; R._id = 0; R._oid = 0; - R.fn = {}; + R.is = function (o, type) { type = lowerCase.call(type); - return ((type == "object" || type == "undefined") && typeof o == type) || (o == null && type == "null") || lowerCase.call(objectToString.call(o)[rp](isit, E)) == type; + if (type == "finite") { + return !isnan[has](+o); + } + if (type == "array") { + return o instanceof Array; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + (type == "array" && Array.isArray && Array.isArray(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; }; + + R.angle = function (x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3); + } + }; + + R.rad = function (deg) { + return deg % 360 * PI / 180; + }; + + R.deg = function (rad) { + return rad * 180 / PI % 360; + }; + + R.snapTo = function (values, value, tolerance) { + tolerance = R.is(tolerance, "finite") ? tolerance : 10; + if (R.is(values, array)) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; + }; + + + var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { + return function () { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); + }; + })(/[xy]/g, function (c) { + var r = math.random() * 16 | 0, + v = c == "x" ? r : (r & 3 | 8); + return v.toString(16); + }); + + R.setWindow = function (newwin) { - win = newwin; - doc = win.document; + eve("setWindow", R, g.win, newwin); + g.win = newwin; + g.doc = g.win.document; + if (R._engine.initWin) { + R._engine.initWin(g.win); + } }; - // colour utilities var toHex = function (color) { if (R.vml) { // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ var trim = /^\s+|\s+$/g; + var bod; + try { + var docum = new ActiveXObject("htmlfile"); + docum.write(""); + docum.close(); + bod = docum.body; + } catch(e) { + bod = createPopup().document.body; + } + var range = bod.createTextRange(); toHex = cacher(function (color) { - var bod; - color = (color + E).replace(trim, E); - try { - var document = new ActiveXObject("htmlfile"); - document.write(""); - document.close(); - bod = document.body; - } catch(e) { - bod = createPopup().document.body; - } - var range = bod.createTextRange(); try { - bod.style.color = color; + bod.style.color = Str(color).replace(trim, E); var value = range.queryCommandValue("ForeColor"); value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); - return "#" + ("000000" + value[toString](16)).slice(-6); + return "#" + ("000000" + value.toString(16)).slice(-6); } catch(e) { return "none"; } }); } else { - var i = doc.createElement("i"); - i.className = "Rapha\xebl Colour Picker"; - i.style.cssText = "display:none"; - doc.body[appendChild](i); + var i = g.doc.createElement("i"); + i.title = "Rapha\xebl Colour Picker"; + i.style.display = "none"; + g.doc.body.appendChild(i); toHex = cacher(function (color) { i.style.color = color; - return doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); }); } return toHex(color); - }; - R.hsb2rgb = cacher(function (hue, saturation, brightness) { - if (R.is(hue, "object") && "h" in hue && "s" in hue && "b" in hue) { - brightness = hue.b; - saturation = hue.s; - hue = hue.h; + }, + hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; + }, + hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; + }, + rgbtoString = function () { + return this.hex; + }, + prepareRGB = function (r, g, b) { + if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; } - var red, - green, - blue; - if (brightness == 0) { - return {r: 0, g: 0, b: 0, hex: "#000"}; - } - if (hue > 1 || saturation > 1 || brightness > 1) { - hue /= 255; - saturation /= 255; - brightness /= 255; - } - var i = ~~(hue * 6), - f = (hue * 6) - i, - p = brightness * (1 - saturation), - q = brightness * (1 - (saturation * f)), - t = brightness * (1 - (saturation * (1 - f))); - red = [brightness, q, p, p, t, brightness, brightness][i]; - green = [t, brightness, brightness, q, p, p, t][i]; - blue = [p, p, t, brightness, brightness, q, p][i]; - red *= 255; - green *= 255; - blue *= 255; - var rgb = {r: red, g: green, b: blue}, - r = (~~red)[toString](16), - g = (~~green)[toString](16), - b = (~~blue)[toString](16); - r = r[rp](rg, "0"); - g = g[rp](rg, "0"); - b = b[rp](rg, "0"); - rgb.hex = "#" + r + g + b; + if (g == null && R.is(r, string)) { + var clr = R.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; + }, + packageRGB = function (r, g, b, o) { + r *= 255; + g *= 255; + b *= 255; + var rgb = { + r: r, + g: g, + b: b, + hex: R.rgb(r, g, b), + toString: rgbtoString + }; + R.is(o, "finite") && (rgb.opacity = o); return rgb; - }, R); - R.rgb2hsb = cacher(function (red, green, blue) { - if (R.is(red, "object") && "r" in red && "g" in red && "b" in red) { - blue = red.b; - green = red.g; - red = red.r; - } - if (R.is(red, "string")) { - var clr = R.getRGB(red); - red = clr.r; - green = clr.g; - blue = clr.b; - } - if (red > 1 || green > 1 || blue > 1) { - red /= 255; - green /= 255; - blue /= 255; - } - var max = mmax(red, green, blue), - min = mmin(red, green, blue), - hue, - saturation, - brightness = max; - if (min == max) { - return {h: 0, s: 0, b: max}; + }; + + + R.color = function (clr) { + var rgb; + if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = R.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.hex = rgb.hex; + } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = R.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.hex = rgb.hex; } else { - var delta = (max - min); - saturation = delta / max; - if (red == max) { - hue = (green - blue) / delta; - } else if (green == max) { - hue = 2 + ((blue - red) / delta); + if (R.is(clr, "string")) { + clr = R.getRGB(clr); + } + if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) { + rgb = R.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = R.rgb2hsb(clr); + clr.v = rgb.b; } else { - hue = 4 + ((red - green) / delta); + clr = {hex: "none"}; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; } - hue /= 6; - hue < 0 && hue++; - hue > 1 && hue--; } - return {h: hue, s: saturation, b: brightness}; - }, R); - var p2s = /,?([achlmqrstvxz]),?/gi; + clr.toString = rgbtoString; + return clr; + }; + + R.hsb2rgb = function (h, s, v, o) { + if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + h = h.h; + o = h.o; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); + }; + + R.hsl2rgb = function (h, s, l, o) { + if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); + }; + + R.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; + }; + + R.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; + }; R._path2string = function () { - return this.join(",")[rp](p2s, "$1"); + return this.join(",").replace(p2s, "$1"); }; + function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } + } function cacher(f, scope, postprocessor) { function newf() { - var arg = Array[proto].slice.call(arguments, 0), - args = arg[join]("\u25ba"), + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), cache = newf.cache = newf.cache || {}, count = newf.count = newf.count || []; if (cache[has](args)) { + repush(count, args); return postprocessor ? postprocessor(cache[args]) : cache[args]; } - count[length] >= 1e3 && delete cache[count.shift()]; - count[push](args); + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); cache[args] = f[apply](scope, arg); return postprocessor ? postprocessor(cache[args]) : cache[args]; } return newf; } + var preload = R._preload = function (src, f) { + var img = g.doc.createElement("img"); + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; + img.onload = function () { + f.call(this); + this.onload = null; + g.doc.body.removeChild(this); + }; + img.onerror = function () { + g.doc.body.removeChild(this); + }; + g.doc.body.appendChild(img); + img.src = src; + }; + + function clrToString() { + return this.hex; + } + + R.getRGB = cacher(function (colour) { - if (!colour || !!((colour + E).indexOf("-") + 1)) { - return {r: -1, g: -1, b: -1, hex: "none", error: 1}; + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; } - colour = colour + E; if (colour == "none") { - return {r: -1, g: -1, b: -1, hex: "none"}; + return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString}; } - !({hs: 1, rg: 1})[has](colour.substring(0, 2)) && (colour = toHex(colour)); + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); var res, red, green, blue, - rgb = colour.match(/^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgb\(\s*([\d\.]+\s*,\s*[\d\.]+\s*,\s*[\d\.]+)\s*\)|rgb\(\s*([\d\.]+%\s*,\s*[\d\.]+%\s*,\s*[\d\.]+%)\s*\)|hs[bl]\(\s*([\d\.]+\s*,\s*[\d\.]+\s*,\s*[\d\.]+)\s*\)|hs[bl]\(\s*([\d\.]+%\s*,\s*[\d\.]+%\s*,\s*[\d\.]+%)\s*\))\s*$/i); + opacity, + t, + values, + rgb = colour.match(colourRegExp); if (rgb) { if (rgb[2]) { blue = toInt(rgb[2].substring(5), 16); @@ -231,48 +810,67 @@ window.Raphael = (function () { red = toInt(rgb[2].substring(1, 3), 16); } if (rgb[3]) { - blue = toInt(rgb[3].substring(3) + rgb[3].substring(3), 16); - green = toInt(rgb[3].substring(2, 3) + rgb[3].substring(2, 3), 16); - red = toInt(rgb[3].substring(1, 2) + rgb[3].substring(1, 2), 16); + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); } if (rgb[4]) { - rgb = rgb[4][split](/\s*,\s*/); - red = toFloat(rgb[0]); - green = toFloat(rgb[1]); - blue = toFloat(rgb[2]); + values = rgb[4][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); } if (rgb[5]) { - rgb = rgb[5][split](/\s*,\s*/); - red = toFloat(rgb[0]) * 2.55; - green = toFloat(rgb[1]) * 2.55; - blue = toFloat(rgb[2]) * 2.55; + values = rgb[5][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return R.hsb2rgb(red, green, blue, opacity); } if (rgb[6]) { - rgb = rgb[6][split](/\s*,\s*/); - red = toFloat(rgb[0]); - green = toFloat(rgb[1]); - blue = toFloat(rgb[2]); - return R.hsb2rgb(red, green, blue); - } - if (rgb[7]) { - rgb = rgb[7][split](/\s*,\s*/); - red = toFloat(rgb[0]) * 2.55; - green = toFloat(rgb[1]) * 2.55; - blue = toFloat(rgb[2]) * 2.55; - return R.hsb2rgb(red, green, blue); - } - rgb = {r: red, g: green, b: blue}; - var r = (~~red)[toString](16), - g = (~~green)[toString](16), - b = (~~blue)[toString](16); - r = r[rp](rg, "0"); - g = g[rp](rg, "0"); - b = b[rp](rg, "0"); - rgb.hex = "#" + r + g + b; + values = rgb[6][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return R.hsl2rgb(red, green, blue, opacity); + } + rgb = {r: red, g: green, b: blue, toString: clrToString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + R.is(opacity, "finite") && (rgb.opacity = opacity); return rgb; } - return {r: -1, g: -1, b: -1, hex: "none", error: 1}; + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; }, R); + + R.hsb = cacher(function (h, s, b) { + return R.hsb2rgb(h, s, b).hex; + }); + + R.hsl = cacher(function (h, s, l) { + return R.hsl2rgb(h, s, l).hex; + }); + + R.rgb = cacher(function (r, g, b) { + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); + }); + R.getColor = function (value) { var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, rgb = this.hsb2rgb(start.h, start.s, start.b); @@ -284,37 +882,129 @@ window.Raphael = (function () { } return rgb.hex; }; + R.getColor.reset = function () { delete this.start; }; - // path utilities + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 > i; i += 2) { + var p = [{x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]}]; + if (iLen - 4 == i) { + p[0] = {x: +crp[i - 2], y: +crp[i - 1]}; + p[3] = p[2]; + } else if (i) { + p[0] = {x: +crp[i - 2], y: +crp[i - 1]}; + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + R.parsePathString = cacher(function (pathString) { if (!pathString) { return null; } - var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0}, + var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0}, data = []; - if (R.is(pathString, "array") && R.is(pathString[0], "array")) { // rough assumption + if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption data = pathClone(pathString); } - if (!data[length]) { - (pathString + E)[rp](/([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig, function (a, b, c) { + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { var params = [], - name = lowerCase.call(b); - c[rp](/(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig, function (a, b) { - b && params[push](+b); + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); }); - while (params[length] >= paramCounts[name]) { - data[push]([b][concat](params.splice(0, paramCounts[name]))); + if (name == "m" && params.length > 2) { + data.push([b][concat](params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "r") { + data.push([b][concat](params)); + } else while (params.length >= paramCounts[name]) { + data.push([b][concat](params.splice(0, paramCounts[name]))); if (!paramCounts[name]) { break; - }; + } } }); } - data[toString] = R._path2string; + data.toString = R._path2string; return data; }); + + R.parseTransformString = cacher(function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption + data = pathClone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = lowerCase.call(b); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b][concat](params)); + }); + } + data.toString = R._path2string; + return data; + }); + + R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + (mx > nx || my < ny) && (alpha += 180); + 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 + }; + }; + R._removedFactory = function (methodname) { + return function () { + throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object"); + }; + }; var pathDimensions = cacher(function (path) { if (!path) { return {x: 0, y: 0, width: 0, height: 0}; @@ -325,13 +1015,13 @@ window.Raphael = (function () { X = [], Y = [], p; - for (var i = 0, ii = path[length]; i < ii; i++) { + for (var i = 0, ii = path.length; i < ii; i++) { p = path[i]; if (p[0] == "M") { x = p[1]; y = p[2]; - X[push](x); - Y[push](y); + X.push(x); + Y.push(y); } else { var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); X = X[concat](dim.min.x, dim.max.x); @@ -348,23 +1038,30 @@ window.Raphael = (function () { width: mmax[apply](0, X) - xmin, height: mmax[apply](0, Y) - ymin }; + }, null, function (o) { + return { + x: o.x, + y: o.y, + width: o.width, + height: o.height + }; }), pathClone = function (pathArray) { var res = []; - if (!R.is(pathArray, "array") || !R.is(pathArray && pathArray[0], "array")) { // rough assumption + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption pathArray = R.parsePathString(pathArray); } - for (var i = 0, ii = pathArray[length]; i < ii; i++) { + for (var i = 0, ii = pathArray.length; i < ii; i++) { res[i] = []; - for (var j = 0, jj = pathArray[i][length]; j < jj; j++) { + for (var j = 0, jj = pathArray[i].length; j < jj; j++) { res[i][j] = pathArray[i][j]; } } - res[toString] = R._path2string; + res.toString = R._path2string; return res; }, - pathToRelative = cacher(function (pathArray) { - if (!R.is(pathArray, "array") || !R.is(pathArray && pathArray[0], "array")) { // rough assumption + pathToRelative = R._pathToRelative = cacher(function (pathArray) { + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption pathArray = R.parsePathString(pathArray); } var res = [], @@ -379,9 +1076,9 @@ window.Raphael = (function () { mx = x; my = y; start++; - res[push](["M", x, y]); + res.push(["M", x, y]); } - for (var i = start, ii = pathArray[length]; i < ii; i++) { + for (var i = start, ii = pathArray.length; i < ii; i++) { var r = res[i] = [], pa = pathArray[i]; if (pa[0] != lowerCase.call(pa[0])) { @@ -403,7 +1100,7 @@ window.Raphael = (function () { mx = pa[1]; my = pa[2]; default: - for (var j = 1, jj = pa[length]; j < jj; j++) { + for (var j = 1, jj = pa.length; j < jj; j++) { r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); } } @@ -413,11 +1110,11 @@ window.Raphael = (function () { mx = pa[1] + x; my = pa[2] + y; } - for (var k = 0, kk = pa[length]; k < kk; k++) { + for (var k = 0, kk = pa.length; k < kk; k++) { res[i][k] = pa[k]; } } - var len = res[i][length]; + var len = res[i].length; switch (res[i][0]) { case "z": x = mx; @@ -434,13 +1131,16 @@ window.Raphael = (function () { y += +res[i][len - 1]; } } - res[toString] = R._path2string; + res.toString = R._path2string; return res; }, 0, pathClone), - pathToAbsolute = cacher(function (pathArray) { - if (!R.is(pathArray, "array") || !R.is(pathArray && pathArray[0], "array")) { // rough assumption + pathToAbsolute = R._pathToAbsolute = cacher(function (pathArray) { + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption pathArray = R.parsePathString(pathArray); } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } var res = [], x = 0, y = 0, @@ -455,9 +1155,9 @@ window.Raphael = (function () { start++; res[0] = ["M", x, y]; } - for (var i = start, ii = pathArray[length]; i < ii; i++) { - var r = res[i] = [], - pa = pathArray[i]; + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; if (pa[0] != upperCase.call(pa[0])) { r[0] = upperCase.call(pa[0]); switch (r[0]) { @@ -476,17 +1176,31 @@ window.Raphael = (function () { case "H": r[1] = +pa[1] + x; break; + case "R": + var dots = [x, y][concat](pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res[concat](catmullRom2bezier(dots)); + break; case "M": mx = +pa[1] + x; my = +pa[2] + y; default: - for (var j = 1, jj = pa[length]; j < jj; j++) { + for (j = 1, jj = pa.length; j < jj; j++) { r[j] = +pa[j] + ((j % 2) ? x : y); } } + } else if (pa[0] == "R") { + dots = [x, y][concat](pa.slice(1)); + res.pop(); + res = res[concat](catmullRom2bezier(dots)); + r = ["R"][concat](pa.slice(-2)); } else { - for (var k = 0, kk = pa[length]; k < kk; k++) { - res[i][k] = pa[k]; + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; } } switch (r[0]) { @@ -500,12 +1214,15 @@ window.Raphael = (function () { case "V": y = r[1]; break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; default: - x = res[i][res[i][length] - 2]; - y = res[i][res[i][length] - 1]; + x = r[r.length - 2]; + y = r[r.length - 1]; } } - res[toString] = R._path2string; + res.toString = R._path2string; return res; }, null, pathClone), l2c = function (x1, y1, x2, y2) { @@ -526,8 +1243,7 @@ window.Raphael = (function () { a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { // for more information of where this math came from visit: // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - var PI = math.PI, - _120 = PI * 120 / 180, + var _120 = PI * 120 / 180, rad = PI / 180 * (+angle || 0), res = [], xy, @@ -547,16 +1263,20 @@ window.Raphael = (function () { sin = math.sin(PI / 180 * angle), x = (x1 - x2) / 2, y = (y1 - y2) / 2; - rx = mmax(rx, math.abs(x)); - ry = mmax(ry, math.abs(y)); + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } var rx2 = rx * rx, ry2 = ry * ry, k = (large_arc_flag == sweep_flag ? -1 : 1) * - math.sqrt(math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), cx = k * rx * y / ry + (x1 + x2) / 2, cy = k * -ry * x / rx + (y1 + y2) / 2, - f1 = math.asin((y1 - cy) / ry), - f2 = math.asin((y2 - cy) / ry); + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); f1 = x1 < cx ? PI - f1 : f1; f2 = x2 < cx ? PI - f2 : f2; @@ -575,7 +1295,7 @@ window.Raphael = (function () { cy = recursive[3]; } var df = f2 - f1; - if (math.abs(df) > _120) { + if (abs(df) > _120) { var f2old = f2, x2old = x2, y2old = y2; @@ -601,35 +1321,21 @@ window.Raphael = (function () { if (recursive) { return [m2, m3, m4][concat](res); } else { - res = [m2, m3, m4][concat](res)[join](",")[split](","); + res = [m2, m3, m4][concat](res).join()[split](","); var newres = []; - for (var i = 0, ii = res[length]; i < ii; i++) { + for (var i = 0, ii = res.length; i < ii; i++) { newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; } return newres; } }, - findDotAtSegment = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { var t1 = 1 - t; return { x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y }; - }), - findDotsAtSegment = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { - var t1 = 1 - t, - x = pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, - y = pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y, - mx = p1x + 2 * t * (c1x - p1x) + t * t * (c2x - 2 * c1x + p1x), - my = p1y + 2 * t * (c1y - p1y) + t * t * (c2y - 2 * c1y + p1y), - nx = c1x + 2 * t * (c2x - c1x) + t * t * (p2x - 2 * c2x + c1x), - ny = c1y + 2 * t * (c2y - c1y) + t * t * (p2y - 2 * c2y + c1y), - ax = (1 - t) * p1x + t * c1x, - ay = (1 - t) * p1y + t * c1y, - cx = (1 - t) * c2x + t * p2x, - cy = (1 - t) * c2y + t * p2y; - 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}}; - }), + }, curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), b = 2 * (c1x - p1x) - 2 * (c2x - c1x), @@ -639,41 +1345,41 @@ window.Raphael = (function () { y = [p1y, p2y], x = [p1x, p2x], dot; - math.abs(t1) > 1e12 && (t1 = .5); - math.abs(t2) > 1e12 && (t2 = .5); + abs(t1) > "1e12" && (t1 = .5); + abs(t2) > "1e12" && (t2 = .5); if (t1 > 0 && t1 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); - x[push](dot.x); - y[push](dot.y); + x.push(dot.x); + y.push(dot.y); } if (t2 > 0 && t2 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); - x[push](dot.x); - y[push](dot.y); + x.push(dot.x); + y.push(dot.y); } a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); b = 2 * (c1y - p1y) - 2 * (c2y - c1y); c = p1y - c1y; t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; - math.abs(t1) > 1e12 && (t1 = .5); - math.abs(t2) > 1e12 && (t2 = .5); + abs(t1) > "1e12" && (t1 = .5); + abs(t2) > "1e12" && (t2 = .5); if (t1 > 0 && t1 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); - x[push](dot.x); - y[push](dot.y); + x.push(dot.x); + y.push(dot.y); } if (t2 > 0 && t2 < 1) { dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); - x[push](dot.x); - y[push](dot.y); + x.push(dot.x); + y.push(dot.y); } return { min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} }; }), - path2curve = cacher(function (path, path2) { + path2curve = R._path2curve = cacher(function (path, path2) { var p = pathToAbsolute(path), p2 = path2 && pathToAbsolute(path2), attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, @@ -723,14 +1429,14 @@ window.Raphael = (function () { return path; }, fixArc = function (pp, i) { - if (pp[i][length] > 7) { + if (pp[i].length > 7) { pp[i].shift(); var pi = pp[i]; - while (pi[length]) { + while (pi.length) { pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); } pp.splice(i, 1); - ii = mmax(p[length], p2 && p2[length] || 0); + ii = mmax(p.length, p2 && p2.length || 0); } }, fixM = function (path1, path2, a1, a2, i) { @@ -740,10 +1446,10 @@ window.Raphael = (function () { a1.by = 0; a1.x = path1[i][1]; a1.y = path1[i][2]; - ii = mmax(p[length], p2 && p2[length] || 0); + ii = mmax(p.length, p2 && p2.length || 0); } }; - for (var i = 0, ii = mmax(p[length], p2 && p2[length] || 0); i < ii; i++) { + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { p[i] = processPath(p[i], attrs); fixArc(p, i); p2 && (p2[i] = processPath(p2[i], attrs2)); @@ -752,8 +1458,8 @@ window.Raphael = (function () { fixM(p2, p, attrs2, attrs, i); var seg = p[i], seg2 = p2 && p2[i], - seglen = seg[length], - seg2len = p2 && seg2[length]; + seglen = seg.length, + seg2len = p2 && seg2.length; attrs.x = seg[seglen - 2]; attrs.y = seg[seglen - 1]; attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; @@ -765,9 +1471,9 @@ window.Raphael = (function () { } return p2 ? [p, p2] : p; }, null, pathClone), - parseDots = cacher(function (gradient) { + parseDots = R._parseDots = cacher(function (gradient) { var dots = []; - for (var i = 0, ii = gradient[length]; i < ii; i++) { + for (var i = 0, ii = gradient.length; i < ii; i++) { var dot = {}, par = gradient[i].match(/^([^:]*):?([\d\.]*)/); dot.color = R.getRGB(par[1]); @@ -776,9 +1482,9 @@ window.Raphael = (function () { } dot.color = dot.color.hex; par[2] && (dot.offset = par[2] + "%"); - dots[push](dot); + dots.push(dot); } - for (var i = 1, ii = dots[length] - 1; i < ii; i++) { + for (i = 1, ii = dots.length - 1; i < ii; i++) { if (!dots[i].offset) { var start = toFloat(dots[i - 1].offset || 0), end = 0; @@ -802,59 +1508,13 @@ window.Raphael = (function () { } return dots; }), - getContainer = function () { - var container, - x, - y, - width, - height; - if (R.is(arguments[0], "string") || R.is(arguments[0], "object")) { - if (R.is(arguments[0], "string")) { - container = doc.getElementById(arguments[0]); - } else { - container = arguments[0]; - } - if (container.tagName) { - if (arguments[1] == null) { - return { - container: container, - width: container.style.pixelWidth || container.offsetWidth, - height: container.style.pixelHeight || container.offsetHeight - }; - } else { - return {container: container, width: arguments[1], height: arguments[2]}; - } - } - } else if (R.is(arguments[0], nu) && arguments[length] > 3) { - return {container: 1, x: arguments[0], y: arguments[1], width: arguments[2], height: arguments[3]}; - } - }, - plugins = function (con, add) { - var that = this; - for (var prop in add) if (add[has](prop) && !(prop in con)) { - switch (typeof add[prop]) { - case "function": - (function (f) { - con[prop] = con === that ? f : function () { return f[apply](that, arguments); }; - })(add[prop]); - break; - case "object": - con[prop] = con[prop] || {}; - plugins.call(this, con[prop], add[prop]); - break; - default: - con[prop] = add[prop]; - break; - } - } - }, - tear = function (el, paper) { + tear = R._tear = function (el, paper) { el == paper.top && (paper.top = el.prev); el == paper.bottom && (paper.bottom = el.next); el.next && (el.next.prev = el.prev); el.prev && (el.prev.next = el.next); }, - tofront = function (el, paper) { + tofront = R._tofront = function (el, paper) { if (paper.top === el) { return; } @@ -864,7 +1524,7 @@ window.Raphael = (function () { paper.top.next = el; paper.top = el; }, - toback = function (el, paper) { + toback = R._toback = function (el, paper) { if (paper.bottom === el) { return; } @@ -874,7 +1534,7 @@ window.Raphael = (function () { paper.bottom.prev = el; paper.bottom = el; }, - insertafter = function (el, el2, paper) { + insertafter = R._insertafter = function (el, el2, paper) { tear(el, paper); el2 == paper.top && (paper.top = el); el2.next && (el2.next.prev = el); @@ -882,2209 +1542,3921 @@ window.Raphael = (function () { el.prev = el2; el2.next = el; }, - insertbefore = function (el, el2, paper) { + insertbefore = R._insertbefore = function (el, el2, paper) { tear(el, paper); el2 == paper.bottom && (paper.bottom = el); el2.prev && (el2.prev.next = el); el.prev = el2.prev; el2.prev = el; el.next = el2; - }; - - // SVG - if (R.svg) { - paper.svgns = "http://www.w3.org/2000/svg"; - paper.xlink = "http://www.w3.org/1999/xlink"; - var round = function (num) { - return +num + (~~num === num) * .5; }, - roundPath = function (path) { - for (var i = 0, ii = path[length]; i < ii; i++) { - if (lowerCase.call(path[i][0]) != "a") { - for (var j = 1, jj = path[i][length]; j < jj; j++) { - path[i][j] = round(path[i][j]); + extractTransform = R._extractTransform = function (el, tstr) { + if (tstr == null) { + return el._.transform; + } + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E); + var tdata = R.parseTransformString(tstr), + deg = 0, + dx = 0, + dy = 0, + sx = 1, + sy = 1, + _ = el._, + m = new Matrix; + _.transform = tdata || []; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); } - } else { - path[i][6] = round(path[i][6]); - path[i][7] = round(path[i][7]); + } else if (command == "r") { + if (tlen == 2) { + bb = bb || el.getBBox(1); + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + deg += t[1]; + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + deg += t[1]; + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || el.getBBox(1); + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + sx *= t[1]; + sy *= t[tlen - 1]; + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + sx *= t[1]; + sy *= t[2]; + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); } + _.dirtyT = 1; + el.matrix = m; } - return path; - }, - $ = function (el, attr) { - if (attr) { - for (var key in attr) if (attr[has](key)) { - el[setAttribute](key, attr[key]); - } + } + + el.matrix = m; + + _.sx = sx; + _.sy = sy; + _.deg = deg; + _.dx = dx = m.e; + _.dy = dy = m.f; + + if (sx == 1 && sy == 1 && !deg && _.bbox) { + _.bbox.x += +dx; + _.bbox.y += +dy; + } else { + _.dirtyT = 1; + } + }, + getEmpty = function (item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; } else { - return doc.createElementNS(paper.svgns, el); - } - }; - R[toString] = function () { - return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; - }; - var thePath = function (pathString, SVG) { - var el = $("path"); - SVG.canvas && SVG.canvas[appendChild](el); - var p = new Element(el, SVG); - p.type = "path"; - setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString}); - return p; - }; - var addGradientFill = function (o, gradient, SVG) { - var type = "linear", - fx = .5, fy = .5, - s = o.style; - gradient = (gradient + E)[rp](/^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/, function (all, _fx, _fy) { - type = "radial"; - if (_fx && _fy) { - fx = toFloat(_fx); - fy = toFloat(_fy); - if (pow(fx - .5, 2) + pow(fy - .5, 2) > .25) { - fy = math.sqrt(.25 - pow(fx - .5, 2)) + .5; - } + return [l, 0]; } - return E; - }); - gradient = gradient[split](/\s*\-\s*/); - if (type == "linear") { - var angle = gradient.shift(); - angle = -toFloat(angle); - if (isNaN(angle)) { - return null; + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; } - var vector = [0, 0, math.cos(angle * math.PI / 180), math.sin(angle * math.PI / 180)], - max = 1 / (mmax(math.abs(vector[2]), math.abs(vector[3])) || 1); - vector[2] *= max; - vector[3] *= max; - if (vector[2] < 0) { - vector[0] = -vector[2]; - vector[2] = 0; + } + }, + equaliseTransform = R._equaliseTransform = function (t1, t2) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = R.parseTransformString(t1) || []; + t2 = R.parseTransformString(t2) || []; + var maxlength = mmax(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + return; } - if (vector[3] < 0) { - vector[1] = -vector[3]; - vector[3] = 0; + from[i] = []; + to[i] = []; + for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); } } - var dots = parseDots(gradient); - if (!dots) { - return null; - } - var el = $(type + "Gradient"); - el.id = "r" + (R._id++)[toString](36); - type == "radial" ? $(el, {fx: fx, fy: fy}) : $(el, {x1: vector[0], y1: vector[1], x2: vector[2], y2: vector[3]}); - SVG.defs[appendChild](el); - for (var i = 0, ii = dots[length]; i < ii; i++) { - var stop = $("stop"); - $(stop, { - offset: dots[i].offset ? dots[i].offset : !i ? "0%" : "100%", - "stop-color": dots[i].color || "#fff" - }); - el[appendChild](stop); + return { + from: from, + to: to }; - $(o, { - fill: "url(#" + el.id + ")", - opacity: 1, - "fill-opacity": 1 - }); - s.fill = E; - s.opacity = 1; - s.fillOpacity = 1; - return 1; - }; - var updatePosition = function (o) { - var bbox = o.getBBox(); - $(o.pattern, {patternTransform: R.format("translate({0},{1})", bbox.x, bbox.y)}); }; - var setFillAndStroke = function (o, params) { - var dasharray = { - "": [0], - "none": [0], - "-": [3, 1], - ".": [1, 1], - "-.": [3, 1, 1, 1], - "-..": [3, 1, 1, 1, 1, 1], - ". ": [1, 3], - "- ": [4, 3], - "--": [8, 3], - "- .": [4, 3, 1, 3], - "--.": [8, 3, 1, 3], - "--..": [8, 3, 1, 3, 1, 3] - }, - node = o.node, - attrs = o.attrs, - rot = o.rotate(), - addDashes = function (o, value) { - value = dasharray[lowerCase.call(value)]; - if (value) { - var width = o.attrs["stroke-width"] || "1", - butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, - dashes = []; - var i = value[length]; - while (i--) { - dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; - } - $(node, {"stroke-dasharray": dashes[join](",")}); - } + R._getContainer = function (x, y, w, h) { + var container; + container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x; + if (container == null) { + return; + } + if (container.tagName) { + if (y == null) { + return { + container: container, + width: container.style.pixelWidth || container.offsetWidth, + height: container.style.pixelHeight || container.offsetHeight }; - params[has]("rotation") && (rot = params.rotation); - var rotxy = (rot + E)[split](separator); - if (!(rotxy.length - 1)) { - rotxy = null; - } else { - rotxy[1] = +rotxy[1]; - rotxy[2] = +rotxy[2]; - } - toFloat(rot) && o.rotate(0, true); - for (var att in params) if (params[has](att)) { - if (!availableAttrs[has](att)) { - continue; - } - var value = params[att]; - attrs[att] = value; - switch (att) { - case "rotation": - o.rotate(value, true); - break; - // Hyperlink - case "href": - case "title": - case "target": - var pn = node.parentNode; - if (lowerCase.call(pn.tagName) != "a") { - var hl = $("a"); - pn.insertBefore(hl, node); - hl[appendChild](node); - pn = hl; - } - pn.setAttributeNS(o.paper.xlink, att, value); - break; - case "cursor": - node.style.cursor = value; - break; - case "clip-rect": - var rect = (value + E)[split](separator); - if (rect[length] == 4) { - o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); - var el = $("clipPath"), - rc = $("rect"); - el.id = "r" + (R._id++)[toString](36); - $(rc, { - x: rect[0], - y: rect[1], - width: rect[2], - height: rect[3] - }); - el[appendChild](rc); - o.paper.defs[appendChild](el); - $(node, {"clip-path": "url(#" + el.id + ")"}); - o.clip = rc; - } - if (!value) { - var clip = doc.getElementById(node.getAttribute("clip-path")[rp](/(^url\(#|\)$)/g, E)); - clip && clip.parentNode.removeChild(clip); - $(node, {"clip-path": E}); - delete o.clip; - } - break; - case "path": - if (value && o.type == "path") { - attrs.path = roundPath(pathToAbsolute(value)); - $(node, {d: attrs.path}); - } - break; - case "width": - node[setAttribute](att, value); - if (attrs.fx) { - att = "x"; - value = attrs.x; - } else { - break; - } - case "x": - if (attrs.fx) { - value = -attrs.x - (attrs.width || 0); - } - case "rx": - if (att == "rx" && o.type == "rect") { - break; - } - case "cx": - rotxy && (att == "x" || att == "cx") && (rotxy[1] += value - attrs[att]); - node[setAttribute](att, round(value)); - o.pattern && updatePosition(o); - break; - case "height": - node[setAttribute](att, value); - if (attrs.fy) { - att = "y"; - value = attrs.y; - } else { - break; - } - case "y": - if (attrs.fy) { - value = -attrs.y - (attrs.height || 0); - } - case "ry": - if (att == "ry" && o.type == "rect") { - break; - } - case "cy": - rotxy && (att == "y" || att == "cy") && (rotxy[2] += value - attrs[att]); - node[setAttribute](att, round(value)); - o.pattern && updatePosition(o); - break; - case "r": - if (o.type == "rect") { - $(node, {rx: value, ry: value}); - } else { - node[setAttribute](att, value); - } - break; - case "src": - if (o.type == "image") { - node.setAttributeNS(o.paper.xlink, "href", value); - } - break; - case "stroke-width": - node.style.strokeWidth = value; - // Need following line for Firefox - node[setAttribute](att, value); - if (attrs["stroke-dasharray"]) { - addDashes(o, attrs["stroke-dasharray"]); - } - break; - case "stroke-dasharray": - addDashes(o, value); - break; - case "translation": - var xy = (value + E)[split](separator); - xy[0] = +xy[0] || 0; - xy[1] = +xy[1] || 0; - if (rotxy) { - rotxy[1] += xy[0]; - rotxy[2] += xy[1]; - } - translate.call(o, xy[0], xy[1]); - break; - case "scale": - var xy = (value + E)[split](separator); - o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, +xy[2] || null, +xy[3] || null); - break; - case "fill": - var isURL = (value + E).match(ISURL); - if (isURL) { - var el = $("pattern"), - ig = $("image"); - el.id = "r" + (R._id++)[toString](36); - $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse"}); - $(ig, {x: 0, y: 0}); - ig.setAttributeNS(o.paper.xlink, "href", isURL[1]); - el[appendChild](ig); - - var img = doc.createElement("img"); - img.style.cssText = "position:absolute;left:-9999em;top-9999em"; - img.onload = function () { - $(el, {width: this.offsetWidth, height: this.offsetHeight}); - $(ig, {width: this.offsetWidth, height: this.offsetHeight}); - doc.body.removeChild(this); - paper.safari(); - }; - doc.body[appendChild](img); - img.src = isURL[1]; - o.paper.defs[appendChild](el); - node.style.fill = "url(#" + el.id + ")"; - $(node, {fill: "url(#" + el.id + ")"}); - o.pattern = el; - o.pattern && updatePosition(o); - break; - } - if (!R.getRGB(value).error) { - delete params.gradient; - delete attrs.gradient; - !R.is(attrs.opacity, "undefined") && - R.is(params.opacity, "undefined") && - $(node, {opacity: attrs.opacity}); - !R.is(attrs["fill-opacity"], "undefined") && - R.is(params["fill-opacity"], "undefined") && - $(node, {"fill-opacity": attrs["fill-opacity"]}); - } else if ((({circle: 1, ellipse: 1})[has](o.type) || (value + E).charAt() != "r") && addGradientFill(node, value, o.paper)) { - attrs.gradient = value; - attrs.fill = "none"; - break; - } - case "stroke": - node[setAttribute](att, R.getRGB(value).hex); - break; - case "gradient": - (({circle: 1, ellipse: 1})[has](o.type) || (value + E).charAt() != "r") && addGradientFill(node, value, o.paper); - break; - case "opacity": - case "fill-opacity": - if (attrs.gradient) { - var gradient = doc.getElementById(node.getAttribute("fill")[rp](/^url\(#|\)$/g, E)); - if (gradient) { - var stops = gradient.getElementsByTagName("stop"); - stops[stops[length] - 1][setAttribute]("stop-opacity", value); - } - break; - } - default: - att == "font-size" && (value = toInt(value, 10) + "px"); - var cssrule = att[rp](/(\-.)/g, function (w) { - return upperCase.call(w.substring(1)); - }); - node.style[cssrule] = value; - // Need following line for Firefox - node[setAttribute](att, value); - break; - } - } - - tuneText(o, params); - if (rotxy) { - o.rotate(rotxy.join(S)); } else { - toFloat(rot) && o.rotate(rot, true); + return { + container: container, + width: y, + height: w + }; } + } + return { + container: 1, + x: x, + y: y, + width: w, + height: h }; - var leading = 1.2; - var tuneText = function (el, params) { - if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { - return; - } - var a = el.attrs, - node = el.node, - fontSize = node.firstChild ? toInt(doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; + }; + + R.pathToRelative = pathToRelative; + R._engine = {}; + + R.path2curve = path2curve; + + R.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; + function Matrix(a, b, c, d, e, f) { + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; - if (params[has]("text")) { - a.text = params.text; - while (node.firstChild) { - node.removeChild(node.firstChild); - } - var texts = (params.text + E)[split]("\n"); - for (var i = 0, ii = texts[length]; i < ii; i++) if (texts[i]) { - var tspan = $("tspan"); - i && $(tspan, {dy: fontSize * leading, x: a.x}); - tspan[appendChild](doc.createTextNode(texts[i])); - node[appendChild](tspan); - } - } else { - var texts = node.getElementsByTagName("tspan"); - for (var i = 0, ii = texts[length]; i < ii; i++) { - i && $(texts[i], {dy: fontSize * leading, x: a.x}); - } - } - $(node, {y: a.y}); - var bb = el.getBBox(), - dif = a.y - (bb.y + bb.height / 2); - dif && isFinite(dif) && $(node, {y: a.y + dif}); - }; - var Element = function (node, svg) { - var X = 0, - Y = 0; - this[0] = node; - this.id = R._oid++; - this.node = node; - node.raphael = this; - this.paper = svg; - this.attrs = this.attrs || {}; - this.transformations = []; // rotate, translate, scale - this._ = { - tx: 0, - ty: 0, - rt: {deg: 0, cx: 0, cy: 0}, - sx: 1, - sy: 1 - }; - !svg.bottom && (svg.bottom = this); - this.prev = svg.top; - svg.top && (svg.top.next = this); - svg.top = this; - this.next = null; - }; - Element[proto].rotate = function (deg, cx, cy) { - if (this.removed) { - return this; - } - if (deg == null) { - if (this._.rt.cx) { - return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S); - } - return this._.rt.deg; - } - var bbox = this.getBBox(); - deg = (deg + E)[split](separator); - if (deg[length] - 1) { - cx = toFloat(deg[1]); - cy = toFloat(deg[2]); - } - deg = toFloat(deg[0]); - if (cx != null) { - this._.rt.deg = deg; - } else { - this._.rt.deg += deg; - } - (cy == null) && (cx = null); - this._.rt.cx = cx; - this._.rt.cy = cy; - cx = cx == null ? bbox.x + bbox.width / 2 : cx; - cy = cy == null ? bbox.y + bbox.height / 2 : cy; - if (this._.rt.deg) { - this.transformations[0] = R.format("rotate({0} {1} {2})", this._.rt.deg, cx, cy); - this.clip && $(this.clip, {transform: R.format("rotate({0} {1} {2})", -this._.rt.deg, cx, cy)}); - } else { - this.transformations[0] = E; - this.clip && $(this.clip, {transform: E}); - } - $(this.node, {transform: this.transformations[join](S)}); - return this; - }; - Element[proto].hide = function () { - !this.removed && (this.node.style.display = "none"); - return this; - }; - Element[proto].show = function () { - !this.removed && (this.node.style.display = ""); - return this; - }; - Element[proto].remove = function () { - if (this.removed) { - return; + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; } - tear(this, this.paper); - this.node.parentNode.removeChild(this.node); - for (var i in this) { - delete this[i]; - } - this.removed = true; - }; - Element[proto].getBBox = function () { - if (this.removed) { - return this; - } - if (this.type == "path") { - return pathDimensions(this.attrs.path); - } - if (this.node.style.display == "none") { - this.show(); - var hide = true; - } - var bbox = {}; - try { - bbox = this.node.getBBox(); - } catch(e) { - // Firefox 3.0.x plays badly here - } finally { - bbox = bbox || {}; - } - if (this.type == "text") { - bbox = {x: bbox.x, y: Infinity, width: 0, height: 0}; - for (var i = 0, ii = this.node.getNumberOfChars(); i < ii; i++) { - var bb = this.node.getExtentOfChar(i); - (bb.y < bbox.y) && (bbox.y = bb.y); - (bb.y + bb.height - bbox.y > bbox.height) && (bbox.height = bb.y + bb.height - bbox.y); - (bb.x + bb.width - bbox.x > bbox.width) && (bbox.width = bb.x + bb.width - bbox.x); + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; } } - hide && this.hide(); - return bbox; + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; }; - Element[proto].attr = function () { - if (this.removed) { - return this; - } - if (arguments[length] == 0) { - var res = {}; - for (var i in this.attrs) if (this.attrs[has](i)) { - res[i] = this.attrs[i]; - } - return res; - } - if (arguments[length] == 1 && R.is(arguments[0], "string")) { - if (arguments[0] == "translation") { - return translate.call(this); - } - if (arguments[0] == "rotation") { - return this.rotate(); - } - if (arguments[0] == "scale") { - return this.scale(); - } - if (arguments[0] == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { - return this.attrs.gradient; - } - return this.attrs[arguments[0]]; - } - if (arguments[length] == 1 && R.is(arguments[0], "array")) { - var values = {}; - for (var j in arguments[0]) if (arguments[0][has](j)) { - values[arguments[0][j]] = this.attrs[arguments[0][j]]; - } - return values; - } - if (arguments[length] == 2) { - var params = {}; - params[arguments[0]] = arguments[1]; - setFillAndStroke(this, params); - } else if (arguments[length] == 1 && R.is(arguments[0], "object")) { - setFillAndStroke(this, arguments[0]); - } - return this; + + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); }; - Element[proto].toFront = function () { - if (this.removed) { - return this; - } - this.node.parentNode[appendChild](this.node); - var svg = this.paper; - svg.top != this && tofront(this, svg); - return this; + + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); }; - Element[proto].toBack = function () { - if (this.removed) { - return this; - } - if (this.node.parentNode.firstChild != this.node) { - this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); - toback(this, this.paper); - var svg = this.paper; - } - return this; + + matrixproto.translate = function (x, y) { + this.add(1, 0, 0, 1, x, y); }; - Element[proto].insertAfter = function (element) { - if (this.removed) { - return this; - } - var svg = this.paper, - node = element.node; - if (node.nextSibling) { - node.parentNode.insertBefore(this.node, node.nextSibling); - } else { - node.parentNode[appendChild](this.node); - } - insertafter(this, element, this.paper); - return this; + + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); }; - Element[proto].insertBefore = function (element) { - if (this.removed) { - return this; - } - var node = element.node; - node.parentNode.insertBefore(this.node, node); - insertbefore(this, element, this.paper); - return this; + + matrixproto.rotate = function (a, x, y) { + a = R.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + this.add(1, 0, 0, 1, -x, -y); }; - var theCircle = function (svg, x, y, r) { - x = round(x); - y = round(y); - var el = $("circle"); - svg.canvas && svg.canvas[appendChild](el); - var res = new Element(el, svg); - res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; - res.type = "circle"; - $(el, res.attrs); - return res; + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; }; - var theRect = function (svg, x, y, w, h, r) { - x = round(x); - y = round(y); - var el = $("rect"); - svg.canvas && svg.canvas[appendChild](el); - var res = new Element(el, svg); - res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; - res.type = "rect"; - $(el, res.attrs); - return res; + + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; }; - var theEllipse = function (svg, x, y, rx, ry) { - x = round(x); - y = round(y); - var el = $("ellipse"); - svg.canvas && svg.canvas[appendChild](el); - var res = new Element(el, svg); - res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; - res.type = "ellipse"; - $(el, res.attrs); - return res; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); }; - var theImage = function (svg, src, x, y, w, h) { - var el = $("image"); - $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); - el.setAttributeNS(svg.xlink, "href", src); - svg.canvas && svg.canvas[appendChild](el); - var res = new Element(el, svg); - res.attrs = {x: x, y: y, width: w, height: h, src: src}; - res.type = "image"; - return res; + matrixproto.toString = function () { + return R.svg ? + "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" : + [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join(); }; - var theText = function (svg, x, y, text) { - var el = $("text"); - $(el, {x: x, y: y, "text-anchor": "middle"}); - svg.canvas && svg.canvas[appendChild](el); - var res = new Element(el, svg); - res.attrs = {x: x, y: y, "text-anchor": "middle", text: text, font: availableAttrs.font, stroke: "none", fill: "#000"}; - res.type = "text"; - setFillAndStroke(res, res.attrs); - return res; + matrixproto.toFilter = function () { + return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) + + ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) + + ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')"; }; - var setSize = function (width, height) { - this.width = width || this.width; - this.height = height || this.height; - this.canvas[setAttribute]("width", this.width); - this.canvas[setAttribute]("height", this.height); - return this; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; }; - var create = function () { - var con = getContainer[apply](null, arguments), - container = con && con.container, - x = con.x, - y = con.y, - width = con.width, - height = con.height; - if (!container) { - throw new Error("SVG container not found."); - } - paper.canvas = $("svg"); - var cnvs = paper.canvas; - paper.width = width || 512; - paper.height = height || 342; - $(cnvs, { - xmlns: "http://www.w3.org/2000/svg", - version: 1.1, - width: paper.width, - height: paper.height - }); - if (container == 1) { - cnvs.style.cssText = "position:absolute;left:" + x + "px;top:" + y + "px"; - doc.body[appendChild](cnvs); - } else { - if (container.firstChild) { - container.insertBefore(cnvs, container.firstChild); - } else { - container[appendChild](cnvs); + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = R.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; } + } else { + out.rotate = R.deg(math.asin(sin)); } - container = { canvas: cnvs }; - for (var prop in paper) if (paper[has](prop)) { - container[prop] = paper[prop]; - } - container.bottom = container.top = null; - plugins.call(container, container, R.fn); - container.clear(); - container.raphael = R; - return container; - }; - paper.clear = function () { - var c = this.canvas; - while (c.firstChild) { - c.removeChild(c.firstChild); - } - this.bottom = this.top = null; - (this.desc = $("desc"))[appendChild](doc.createTextNode("Created with Rapha\xebl")); - c[appendChild](this.desc); - c[appendChild](this.defs = $("defs")); + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; }; - paper.remove = function () { - this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); - for (var i in this) { - delete this[i]; + + matrixproto.toTransformString = function (shorter) { + var s = shorter || this[split](); + if (s.isSimple) { + s.scalex = +s.scalex.toFixed(4); + s.scaley = +s.scaley.toFixed(4); + s.rotate = +s.rotate.toFixed(4); + return (s.dx && s.dy ? "t" + [s.dx, s.dy] : E) + + (s.scalex != 1 || s.scaley != 1 ? "s" + [s.scalex, s.scaley, 0, 0] : E) + + (s.rotate ? "r" + [s.rotate, 0, 0] : E); + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; } }; - } + })(Matrix.prototype); - // VML - if (R.vml) { - var path2vml = function (path) { - var total = /[ahqtv]/ig, - command = pathToAbsolute; - (path + E).match(total) && (command = path2curve); - total = /[clmz]/g; - if (command == pathToAbsolute && !(path + E).match(total)) { - var map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, - bites = /([clmz]),?([^clmz]*)/gi, - val = /-?[^,\s-]+/g; - var res = (path + E)[rp](bites, function (all, command, args) { - var vals = []; - args[rp](val, function (value) { - vals[push](round(value)); - }); - return map[command] + vals; - }); - return res; - } - var pa = command(path), p, res = [], r; - for (var i = 0, ii = pa[length]; i < ii; i++) { - p = pa[i]; - r = lowerCase.call(pa[i][0]); - r == "z" && (r = "x"); - for (var j = 1, jj = p[length]; j < jj; j++) { - r += round(p[j]) + (j != jj - 1 ? "," : E); - } - res[push](r); - } - return res[join](S); - }; + // WebKit rendering bug workaround method + var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/); + if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") || + (navigator.vendor == "Google Inc." && version && version[1] < 8)) { - R[toString] = function () { - return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; - }; - var thePath = function (pathString, VML) { - var g = createNode("group"); - g.style.cssText = "position:absolute;left:0;top:0;width:" + VML.width + "px;height:" + VML.height + "px"; - g.coordsize = VML.coordsize; - g.coordorigin = VML.coordorigin; - var el = createNode("shape"), ol = el.style; - ol.width = VML.width + "px"; - ol.height = VML.height + "px"; - el.coordsize = this.coordsize; - el.coordorigin = this.coordorigin; - g[appendChild](el); - var p = new Element(el, g, VML); - p.isAbsolute = true; - p.type = "path"; - p.path = []; - p.Path = E; - pathString && setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString}); - VML.canvas[appendChild](g); - return p; + paperproto.safari = function () { + var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"}); + setTimeout(function () {rect.remove();}); }; - var setFillAndStroke = function (o, params) { - o.attrs = o.attrs || {}; - var node = o.node, - a = o.attrs, - s = node.style, - xy, - res = o; - for (var par in params) if (params[has](par)) { - a[par] = params[par]; - } - params.href && (node.href = params.href); - params.title && (node.title = params.title); - params.target && (node.target = params.target); - params.cursor && (s.cursor = params.cursor); - if (params.path && o.type == "path") { - a.path = params.path; - node.path = path2vml(a.path); - } - if (params.rotation != null) { - o.rotate(params.rotation, true); - } - if (params.translation) { - xy = (params.translation + E)[split](separator); - translate.call(o, xy[0], xy[1]); - if (o._.rt.cx != null) { - o._.rt.cx +=+ xy[0]; - o._.rt.cy +=+ xy[1]; - o.setBox(o.attrs, xy[0], xy[1]); - } - } - if (params.scale) { - xy = (params.scale + E)[split](separator); - o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, +xy[2] || null, +xy[3] || null); - } - if ("clip-rect" in params) { - var rect = (params["clip-rect"] + E)[split](separator); - if (rect[length] == 4) { - rect[2] = +rect[2] + (+rect[0]); - rect[3] = +rect[3] + (+rect[1]); - var div = node.clipRect || doc.createElement("div"), - dstyle = div.style, - group = node.parentNode; - dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); - if (!node.clipRect) { - dstyle.position = "absolute"; - dstyle.top = 0; - dstyle.left = 0; - dstyle.width = o.paper.width + "px"; - dstyle.height = o.paper.height + "px"; - group.parentNode.insertBefore(div, group); - div[appendChild](group); - node.clipRect = div; - } - } - if (!params["clip-rect"]) { - node.clipRect && (node.clipRect.style.clip = E); - } - } - if (o.type == "image" && params.src) { - node.src = params.src; - } - if (o.type == "image" && params.opacity) { - node.filterOpacity = " progid:DXImageTransform.Microsoft.Alpha(opacity=" + (params.opacity * 100) + ")"; - s.filter = (node.filterMatrix || E) + (node.filterOpacity || E); - } - params.font && (s.font = params.font); - params["font-family"] && (s.fontFamily = '"' + params["font-family"][split](",")[0][rp](/^['"]+|['"]+$/g, E) + '"'); - params["font-size"] && (s.fontSize = params["font-size"]); - params["font-weight"] && (s.fontWeight = params["font-weight"]); - params["font-style"] && (s.fontStyle = params["font-style"]); - if (params.opacity != null || - params["stroke-width"] != null || - params.fill != null || - params.stroke != null || - params["stroke-width"] != null || - params["stroke-opacity"] != null || - params["fill-opacity"] != null || - params["stroke-dasharray"] != null || - params["stroke-miterlimit"] != null || - params["stroke-linejoin"] != null || - params["stroke-linecap"] != null) { - node = o.shape || node; - var fill = (node.getElementsByTagName("fill") && node.getElementsByTagName("fill")[0]), - newfill = false; - !fill && (newfill = fill = createNode("fill")); - if ("fill-opacity" in params || "opacity" in params) { - var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1); - opacity < 0 && (opacity = 0); - opacity > 1 && (opacity = 1); - fill.opacity = opacity; - } - params.fill && (fill.on = true); - if (fill.on == null || params.fill == "none") { - fill.on = false; - } - if (fill.on && params.fill) { - var isURL = params.fill.match(ISURL); - if (isURL) { - fill.src = isURL[1]; - fill.type = "tile"; - } else { - fill.color = R.getRGB(params.fill).hex; - fill.src = E; - fill.type = "solid"; - if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || (params.fill + E).charAt() != "r") && addGradientFill(res, params.fill)) { - a.fill = "none"; - a.gradient = params.fill; + } else { + paperproto.safari = fun; + } + + var preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = (function () { + if (g.doc.addEventListener) { + return function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + x = e.clientX + scrollX, + y = e.clientY + scrollY; + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } } } - } - newfill && node[appendChild](fill); - var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), - newstroke = false; - !stroke && (newstroke = stroke = createNode("stroke")); - if ((params.stroke && params.stroke != "none") || - params["stroke-width"] || - params["stroke-opacity"] != null || - params["stroke-dasharray"] || - params["stroke-miterlimit"] || - params["stroke-linejoin"] || - params["stroke-linecap"]) { - stroke.on = true; - } - (params.stroke == "none" || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); - stroke.on && params.stroke && (stroke.color = R.getRGB(params.stroke).hex); - var opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1), - width = (toFloat(params["stroke-width"]) || 1) * .75; - opacity < 0 && (opacity = 0); - opacity > 1 && (opacity = 1); - params["stroke-width"] == null && (width = a["stroke-width"]); - params["stroke-width"] && (stroke.weight = width); - width && width < 1 && (opacity *= width) && (stroke.weight = 1); - stroke.opacity = opacity; - - params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); - stroke.miterlimit = params["stroke-miterlimit"] || 8; - params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); - if (params["stroke-dasharray"]) { - var dasharray = { - "-": "shortdash", - ".": "shortdot", - "-.": "shortdashdot", - "-..": "shortdashdotdot", - ". ": "dot", - "- ": "dash", - "--": "longdash", - "- .": "dashdot", - "--.": "longdashdot", - "--..": "longdashdotdot" - }; - stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; - } - newstroke && node[appendChild](stroke); - } - if (res.type == "text") { - var s = res.paper.span.style; - a.font && (s.font = a.font); - a["font-family"] && (s.fontFamily = a["font-family"]); - a["font-size"] && (s.fontSize = a["font-size"]); - a["font-weight"] && (s.fontWeight = a["font-weight"]); - a["font-style"] && (s.fontStyle = a["font-style"]); - res.node.string && (res.paper.span.innerHTML = (res.node.string + E)[rp](/")); - res.W = a.w = res.paper.span.offsetWidth; - res.H = a.h = res.paper.span.offsetHeight; - res.X = a.x; - res.Y = a.y + round(res.H / 2); - - // text-anchor emulationm - switch (a["text-anchor"]) { - case "start": - res.node.style["v-text-align"] = "left"; - res.bbx = round(res.W / 2); - break; - case "end": - res.node.style["v-text-align"] = "right"; - res.bbx = -round(res.W / 2); - break; - default: - res.node.style["v-text-align"] = "center"; - break; - } - } - }; - var addGradientFill = function (o, gradient) { - o.attrs = o.attrs || {}; - var attrs = o.attrs, - fill = o.node.getElementsByTagName("fill"), - type = "linear", - fxfy = ".5 .5"; - o.attrs.gradient = gradient; - gradient = (gradient + E)[rp](/^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/, function (all, fx, fy) { - type = "radial"; - if (fx && fy) { - fx = toFloat(fx); - fy = toFloat(fy); - if (pow(fx - .5, 2) + pow(fy - .5, 2) > .25) { - fy = math.sqrt(.25 - pow(fx - .5, 2)) + .5; + return fn.call(element, e, x, y); + }; + obj.addEventListener(realName, f, false); + return function () { + obj.removeEventListener(realName, f, false); + return true; + }; + }; + } else if (g.doc.attachEvent) { + return function (obj, type, fn, element) { + var f = function (e) { + e = e || g.win.event; + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + x = e.clientX + scrollX, + y = e.clientY + scrollY; + e.preventDefault = e.preventDefault || preventDefault; + e.stopPropagation = e.stopPropagation || stopPropagation; + return fn.call(element, e, x, y); + }; + obj.attachEvent("on" + type, f); + var detacher = function () { + obj.detachEvent("on" + type, f); + return true; + }; + return detacher; + }; + } + })(), + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; } - fxfy = fx + S + fy; - } - return E; - }); - gradient = gradient[split](/\s*\-\s*/); - if (type == "linear") { - var angle = gradient.shift(); - angle = -toFloat(angle); - if (isNaN(angle)) { - return null; } + } else { + e.preventDefault(); } - var dots = parseDots(gradient); - if (!dots) { - return null; - } - o = o.shape || o.node; - fill = fill[0] || createNode("fill"); - if (dots[length]) { - fill.on = true; - fill.method = "none"; - fill.type = (type == "radial") ? "gradientradial" : "gradient"; - fill.color = dots[0].color; - fill.color2 = dots[dots[length] - 1].color; - var clrs = []; - for (var i = 0, ii = dots[length]; i < ii; i++) { - dots[i].offset && clrs[push](dots[i].offset + S + dots[i].color); - } - fill.colors.value = clrs[length] ? clrs[join](",") : "0% " + fill.color; - if (type == "radial") { - fill.focus = "100%"; - fill.focussize = fxfy; - fill.focusposition = fxfy; - } else { - fill.angle = (270 - angle) % 360; + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + g.win.opera && parent.removeChild(node); + node.style.display = "none"; + o = dragi.el.paper.getElementByPoint(x, y); + node.style.display = display; + g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + o && eve("drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + R.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + } + drag = []; + }, + + elproto = R.el = {}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for (var i = events.length; i--;) { + (function (eventName) { + R[eventName] = elproto[eventName] = function (fn, scope) { + if (R.is(fn, "function")) { + this.events = this.events || []; + this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)}); } - } - return 1; - }; - var Element = function (node, group, vml) { - var Rotation = 0, - RotX = 0, - RotY = 0, - Scale = 1; - this[0] = node; - this.id = R._oid++; - this.node = node; - node.raphael = this; - this.X = 0; - this.Y = 0; - this.attrs = {}; - this.Group = group; - this.paper = vml; - this._ = { - tx: 0, - ty: 0, - rt: {deg:0}, - sx: 1, - sy: 1 - }; - !vml.bottom && (vml.bottom = this); - this.prev = vml.top; - vml.top && (vml.top.next = this); - vml.top = this; - this.next = null; - }; - Element[proto].rotate = function (deg, cx, cy) { - if (this.removed) { return this; - } - if (deg == null) { - if (this._.rt.cx) { - return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S); + }; + R["un" + eventName] = elproto["un" + eventName] = function (fn) { + var events = this.events, + l = events.length; + while (l--) if (events[l].name == eventName && events[l].f == fn) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; } - return this._.rt.deg; - } - deg = (deg + E)[split](separator); - if (deg[length] - 1) { - cx = toFloat(deg[1]); - cy = toFloat(deg[2]); - } - deg = toFloat(deg[0]); - if (cx != null) { - this._.rt.deg = deg; - } else { - this._.rt.deg += deg; - } - cy == null && (cx = null); - this._.rt.cx = cx; - this._.rt.cy = cy; - this.setBox(this.attrs, cx, cy); - this.Group.style.rotation = this._.rt.deg; - // gradient fix for rotation. TODO - // var fill = (this.shape || this.node).getElementsByTagName("fill"); - // fill = fill[0] || {}; - // var b = ((360 - this._.rt.deg) - 270) % 360; - // !R.is(fill.angle, "undefined") && (fill.angle = b); - return this; - }; - Element[proto].setBox = function (params, cx, cy) { - if (this.removed) { return this; - } - var gs = this.Group.style, - os = (this.shape && this.shape.style) || this.node.style; - params = params || {}; - for (var i in params) if (params[has](i)) { - this.attrs[i] = params[i]; - } - cx = cx || this._.rt.cx; - cy = cy || this._.rt.cy; - var attr = this.attrs, - x, - y, - w, - h; - switch (this.type) { - case "circle": - x = attr.cx - attr.r; - y = attr.cy - attr.r; - w = h = attr.r * 2; - break; - case "ellipse": - x = attr.cx - attr.rx; - y = attr.cy - attr.ry; - w = attr.rx * 2; - h = attr.ry * 2; - break; - case "rect": - case "image": - x = +attr.x; - y = +attr.y; - w = attr.width || 0; - h = attr.height || 0; - break; - case "text": - this.textpath.v = ["m", round(attr.x), ", ", round(attr.y - 2), "l", round(attr.x) + 1, ", ", round(attr.y - 2)][join](E); - x = attr.x - round(this.W / 2); - y = attr.y - this.H / 2; - w = this.W; - h = this.H; - break; - case "path": - if (!this.attrs.path) { - x = 0; - y = 0; - w = this.paper.width; - h = this.paper.height; - } else { - var dim = pathDimensions(this.attrs.path); - x = dim.x; - y = dim.y; - w = dim.width; - h = dim.height; - } - break; - default: - x = 0; - y = 0; - w = this.paper.width; - h = this.paper.height; - break; - } - cx = (cx == null) ? x + w / 2 : cx; - cy = (cy == null) ? y + h / 2 : cy; - var left = cx - this.paper.width / 2, - top = cy - this.paper.height / 2; - if (this.type == "path" || this.type == "text") { - (gs.left != left + "px") && (gs.left = left + "px"); - (gs.top != top + "px") && (gs.top = top + "px"); - this.X = this.type == "text" ? x : -left; - this.Y = this.type == "text" ? y : -top; - this.W = w; - this.H = h; - (os.left != -left + "px") && (os.left = -left + "px"); - (os.top != -top + "px") && (os.top = -top + "px"); - } else { - (gs.left != left + "px") && (gs.left = left + "px"); - (gs.top != top + "px") && (gs.top = top + "px"); - this.X = x; - this.Y = y; - this.W = w; - this.H = h; - (gs.width != this.paper.width + "px") && (gs.width = this.paper.width + "px"); - (gs.height != this.paper.height + "px") && (gs.height = this.paper.height + "px"); - (os.left != x - left + "px") && (os.left = x - left + "px"); - (os.top != y - top + "px") && (os.top = y - top + "px"); - (os.width != w + "px") && (os.width = w + "px"); - (os.height != h + "px") && (os.height = h + "px"); - var arcsize = (+params.r || 0) / mmin(w, h); - if (this.type == "rect" && this.arcsize.toFixed(4) != arcsize.toFixed(4) && (arcsize || this.arcsize)) { - // We should replace element with the new one - var o = createNode("roundrect"), - a = {}, - i = 0, - ii = this.events[length]; - o.arcsize = arcsize; - o.raphael = this; - this.Group[appendChild](o); - this.Group.removeChild(this.node); - this[0] = this.node = o; - this.arcsize = arcsize; - for (var i in attr) { - a[i] = attr[i]; - } - delete a.scale; - this.attr(a); - if (this.events) for (; i < ii; i++) { - this.events[i].unbind = addEvent(this.node, this.events[i].name, this.events[i].f, this); - } + }; + })(events[i]); + } + + + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 1) { + if (R.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); } - } - }; - Element[proto].hide = function () { - !this.removed && (this.Group.style.display = "none"); - return this; - }; - Element[proto].show = function () { - !this.removed && (this.Group.style.display = "block"); - return this; - }; - Element[proto].getBBox = function () { - if (this.removed) { return this; } - if (this.type == "path") { - return pathDimensions(this.attrs.path); - } - return { - x: this.X + (this.bbx || 0), - y: this.Y, - width: this.W, - height: this.H - }; + eve("data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("data.set." + this.id, this, value, key); + return this; + }; + + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + var draggable = []; + + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + function start(e) { + (e.originalEvent || e).preventDefault(); + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; + this._drag.x = e.clientX + scrollX; + this._drag.y = e.clientY + scrollY; + this._drag.id = e.identifier; + !drag.length && R.mousemove(dragMove).mouseup(dragUp); + drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("drag.start." + this.id, onstart); + onmove && eve.on("drag.move." + this.id, onmove); + onend && eve.on("drag.end." + this.id, onend); + eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e); + } + this._drag = {}; + draggable.push({el: this, start: start}); + this.mousedown(start); + return this; + }; + + elproto.onDragOver = function (f) { + f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id); + }; + + elproto.undrag = function () { + var i = draggable.length; + while (i--) if (draggable[i].el == this) { + this.unmousedown(draggable[i].start); + draggable.splice(i, 1); + eve.unbind("drag.*." + this.id); + } + !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp); + }; + + paperproto.circle = function (x, y, r) { + var out = R._engine.circle(this, x || 0, y || 0, r || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.rect = function (x, y, w, h, r) { + var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.ellipse = function (x, y, rx, ry) { + var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.path = function (pathString) { + pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E); + var out = R._engine.path(R.format[apply](R, arguments), this); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.image = function (src, x, y, w, h) { + var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.text = function (x, y, text) { + var out = R._engine.text(this, x || 0, y || 0, Str(text)); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.set = function (itemsArray) { + !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length)); + var out = new Set(itemsArray); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.setStart = function (set) { + this.__set__ = set || this.set(); + }; + + paperproto.setFinish = function (set) { + var out = this.__set__; + delete this.__set__; + return out; + }; + + paperproto.setSize = function (width, height) { + return R._engine.setSize.call(this, width, height); + }; + + paperproto.setViewBox = function (x, y, w, h, fit) { + return R._engine.setViewBox.call(this, x, y, w, h, fit); + }; + + + paperproto.top = paperproto.bottom = null; + + paperproto.raphael = R; + var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left }; - Element[proto].remove = function () { - if (this.removed) { - return; + }; + + paperproto.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = g.doc.elementFromPoint(x, y); + if (g.win.opera && target.tagName == "svg") { + var so = getOffset(svg), + sr = svg.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = svg.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; } - tear(this, this.paper); - this.node.parentNode.removeChild(this.node); - this.Group.parentNode.removeChild(this.Group); - this.shape && this.shape.parentNode.removeChild(this.shape); - for (var i in this) { - delete this[i]; + } + if (!target) { + return null; + } + while (target.parentNode && target != svg.parentNode && !target.raphael) { + target = target.parentNode; + } + target == paper.canvas.parentNode && (target = svg); + target = target && target.raphael ? paper.getById(target.raphaelid) : null; + return target; + }; + + paperproto.getById = function (id) { + var bot = this.bottom; + while (bot) { + if (bot.id == id) { + return bot; } - this.removed = true; - }; - Element[proto].attr = function () { - if (this.removed) { + bot = bot.next; + } + return null; + }; + + paperproto.forEach = function (callback, thisArg) { + var bot = this.bottom; + while (bot) { + if (callback.call(thisArg, bot) === false) { return this; } - if (arguments[length] == 0) { - var res = {}; - for (var i in this.attrs) if (this.attrs[has](i)) { - res[i] = this.attrs[i]; - } - return res; + bot = bot.next; + } + return this; + }; + function x_y() { + return this.x + S + this.y; + } + function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; + } + + elproto.getBBox = function (isWithoutTransform) { + if (this.removed) { + return {}; + } + var _ = this._; + if (isWithoutTransform) { + if (_.dirty || !_.bboxwt) { + this.realPath = getPath[this.type](this); + _.bboxwt = pathDimensions(this.realPath); + _.bboxwt.toString = x_y_w_h; + _.dirty = 0; } - if (arguments[length] == 1 && R.is(arguments[0], "string")) { - if (arguments[0] == "translation") { - return translate.call(this); - } - if (arguments[0] == "rotation") { - return this.rotate(); - } - if (arguments[0] == "scale") { - return this.scale(); - } - if (arguments[0] == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { - return this.attrs.gradient; - } - return this.attrs[arguments[0]]; + return _.bboxwt; + } + if (_.dirty || _.dirtyT || !_.bbox) { + if (_.dirty || !this.realPath) { + _.bboxwt = 0; + this.realPath = getPath[this.type](this); } - if (this.attrs && arguments[length] == 1 && R.is(arguments[0], "array")) { - var values = {}; - for (var i = 0, ii = arguments[0][length]; i < ii; i++) { - values[arguments[0][i]] = this.attrs[arguments[0][i]]; - }; - return values; + _.bbox = pathDimensions(mapPath(this.realPath, this.matrix)); + _.bbox.toString = x_y_w_h; + _.dirty = _.dirtyT = 0; + } + return _.bbox; + }; + + elproto.clone = function () { + if (this.removed) { + return null; + } + var out = this.paper[this.type]().attr(this.attr()); + this.__set__ && this.__set__.push(out); + return out; + }; + + elproto.glow = function (glow) { + if (this.type == "text") { + return null; + } + glow = glow || {}; + var s = { + width: (glow.width || 10) + (+this.attr("stroke-width") || 1), + fill: glow.fill || false, + opacity: glow.opacity || .5, + offsetx: glow.offsetx || 0, + offsety: glow.offsety || 0, + color: glow.color || "#000" + }, + c = s.width / 2, + r = this.paper, + out = r.set(), + path = this.realPath || getPath[this.type](this); + path = this.matrix ? mapPath(path, this.matrix) : path; + for (var i = 1; i < c + 1; i++) { + 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) + })); + } + return out.insertBefore(this).translate(s.offsetx, s.offsety); + }; + var curveslengths = {}, + getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + var len = 0, + precision = 100, + name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(), + cache = curveslengths[name], + old, dot; + !cache && (curveslengths[name] = cache = {data: []}); + cache.timer && clearTimeout(cache.timer); + cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3); + if (length != null && !cache.precision) { + var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + cache.precision = ~~total * 10; + cache.data = []; + } + precision = cache.precision || precision; + for (var i = 0; i < precision + 1; i++) { + if (cache.data[i * precision]) { + dot = cache.data[i * precision]; + } else { + dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision); + cache.data[i * precision] = dot; } - var params; - if (arguments[length] == 2) { - params = {}; - params[arguments[0]] = arguments[1]; + i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5)); + if (length != null && len >= length) { + return dot; } - arguments[length] == 1 && R.is(arguments[0], "object") && (params = arguments[0]); - if (params) { - if (params.text && this.type == "text") { - this.node.string = params.text; - } - setFillAndStroke(this, params); - if (params.gradient && (({circle: 1, ellipse: 1})[has](this.type) || (params.gradient + E).charAt() != "r")) { - addGradientFill(this, params.gradient); + old = dot; + } + if (length == null) { + return len; + } + }, + getLengthFactory = function (istotal, subpath) { + return function (path, length, onlystart) { + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return {x: point.x, y: point.y, alpha: point.alpha}; + } + } + len += l; + x = +p[5]; + y = +p[6]; } - (this.type != "path" || this._.rt.deg) && this.setBox(this.attrs); - } - return this; - }; - Element[proto].toFront = function () { - !this.removed && this.Group.parentNode[appendChild](this.Group); - this.paper.top != this && tofront(this, this.paper); - return this; - }; - Element[proto].toBack = function () { - if (this.removed) { - return this; - } - if (this.Group.parentNode.firstChild != this.Group) { - this.Group.parentNode.insertBefore(this.Group, this.Group.parentNode.firstChild); - toback(this, this.paper); + sp += p.shift() + p; } - return this; + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); + return point; }; - Element[proto].insertAfter = function (element) { - if (this.removed) { - return this; + }; + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + + R.getTotalLength = getTotalLength; + + R.getPointAtLength = getPointAtLength; + + R.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + + elproto.getTotalLength = function () { + if (this.type != "path") {return;} + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + return getTotalLength(this.attrs.path); + }; + + elproto.getPointAtLength = function (length) { + if (this.type != "path") {return;} + return getPointAtLength(this.attrs.path, length); + }; + + elproto.getSubpath = function (from, to) { + if (this.type != "path") {return;} + return R.getSubpath(this.attrs.path, from, to); + }; + + var ef = R.easing_formulas = { + linear: function (n) { + return n; + }, + "<": function (n) { + return pow(n, 1.7); + }, + ">": function (n) { + return pow(n, .48); + }, + "<>": function (n) { + var q = .48 - n / 1.04, + Q = math.sqrt(.1734 + q * q), + x = Q - q, + X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }, + backIn: function (n) { + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }, + backOut: function (n) { + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }, + elastic: function (n) { + if (n == !!n) { + return n; } - if (element.Group.nextSibling) { - element.Group.parentNode.insertBefore(this.Group, element.Group.nextSibling); + return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1; + }, + bounce: function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; } else { - element.Group.parentNode[appendChild](this.Group); - } - insertafter(this, element, this.paper); - return this; - }; - Element[proto].insertBefore = function (element) { - if (this.removed) { - return this; + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } } - element.Group.parentNode.insertBefore(this.Group, element.Group); - insertbefore(this, element, this.paper); - return this; - }; + return l; + } + }; + ef.easeIn = ef["ease-in"] = ef["<"]; + ef.easeOut = ef["ease-out"] = ef[">"]; + ef.easeInOut = ef["ease-in-out"] = ef["<>"]; + ef["back-in"] = ef.backIn; + ef["back-out"] = ef.backOut; - var theCircle = function (vml, x, y, r) { - var g = createNode("group"), - o = createNode("oval"), - ol = o.style; - g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; - g.coordsize = vml.coordsize; - g.coordorigin = vml.coordorigin; - g[appendChild](o); - var res = new Element(o, g, vml); - res.type = "circle"; - setFillAndStroke(res, {stroke: "#000", fill: "none"}); - res.attrs.cx = x; - res.attrs.cy = y; - res.attrs.r = r; - res.setBox({x: x - r, y: y - r, width: r * 2, height: r * 2}); - vml.canvas[appendChild](g); - return res; - }; - var theRect = function (vml, x, y, w, h, r) { - var g = createNode("group"), - o = createNode("roundrect"), - arcsize = (+r || 0) / (mmin(w, h)); - g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; - g.coordsize = vml.coordsize; - g.coordorigin = vml.coordorigin; - g[appendChild](o); - o.arcsize = arcsize; - var res = new Element(o, g, vml); - res.type = "rect"; - setFillAndStroke(res, {stroke: "#000"}); - res.arcsize = arcsize; - res.setBox({x: x, y: y, width: w, height: h, r: r}); - vml.canvas[appendChild](g); - return res; - }; - var theEllipse = function (vml, x, y, rx, ry) { - var g = createNode("group"), - o = createNode("oval"), - ol = o.style; - g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; - g.coordsize = vml.coordsize; - g.coordorigin = vml.coordorigin; - g[appendChild](o); - var res = new Element(o, g, vml); - res.type = "ellipse"; - setFillAndStroke(res, {stroke: "#000"}); - res.attrs.cx = x; - res.attrs.cy = y; - res.attrs.rx = rx; - res.attrs.ry = ry; - res.setBox({x: x - rx, y: y - ry, width: rx * 2, height: ry * 2}); - vml.canvas[appendChild](g); - return res; - }; - var theImage = function (vml, src, x, y, w, h) { - var g = createNode("group"), - o = createNode("image"), - ol = o.style; - g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; - g.coordsize = vml.coordsize; - g.coordorigin = vml.coordorigin; - o.src = src; - g[appendChild](o); - var res = new Element(o, g, vml); - res.type = "image"; - res.attrs.src = src; - res.attrs.x = x; - res.attrs.y = y; - res.attrs.w = w; - res.attrs.h = h; - res.setBox({x: x, y: y, width: w, height: h}); - vml.canvas[appendChild](g); - return res; - }; - var theText = function (vml, x, y, text) { - var g = createNode("group"), - el = createNode("shape"), - ol = el.style, - path = createNode("path"), - ps = path.style, - o = createNode("textpath"); - g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px"; - g.coordsize = vml.coordsize; - g.coordorigin = vml.coordorigin; - path.v = R.format("m{0},{1}l{2},{1}", round(x), round(y), round(x) + 1); - path.textpathok = true; - ol.width = vml.width; - ol.height = vml.height; - o.string = text + E; - o.on = true; - el[appendChild](o); - el[appendChild](path); - g[appendChild](el); - var res = new Element(o, g, vml); - res.shape = el; - res.textpath = path; - res.type = "text"; - res.attrs.text = text; - res.attrs.x = x; - res.attrs.y = y; - res.attrs.w = 1; - res.attrs.h = 1; - setFillAndStroke(res, {font: availableAttrs.font, stroke: "none", fill: "#000"}); - res.setBox(); - vml.canvas[appendChild](g); - return res; + var animationElements = [], + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + animation = function () { + var Now = +new Date, + l = 0; + for (; l < animationElements.length; l++) { + var e = animationElements[l]; + if (e.el.removed || e.paused) { + continue; + } + var time = Now - e.start, + ms = e.ms, + easing = e.easing, + from = e.from, + diff = e.diff, + to = e.to, + t = e.t, + that = e.el, + set = {}, + now, + init = {}, + key; + if (e.initstatus) { + time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; + e.status = e.initstatus; + delete e.initstatus; + e.stop && animationElements.splice(l--, 1); + } else { + e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top; + } + if (time < 0) { + continue; + } + if (time < ms) { + var pos = easing(time / ms); + for (var attr in from) if (from[has](attr)) { + switch (availableAnimAttrs[attr]) { + case nu: + now = +from[attr] + pos * ms * diff[attr]; + break; + case "colour": + now = "rgb(" + [ + upto255(round(from[attr].r + pos * ms * diff[attr].r)), + upto255(round(from[attr].g + pos * ms * diff[attr].g)), + upto255(round(from[attr].b + pos * ms * diff[attr].b)) + ].join(",") + ")"; + break; + case "path": + now = []; + for (var i = 0, ii = from[attr].length; i < ii; i++) { + now[i] = [from[attr][i][0]]; + for (var j = 1, jj = from[attr][i].length; j < jj; j++) { + now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; + } + now[i] = now[i].join(S); + } + now = now.join(S); + break; + case "transform": + if (diff[attr].real) { + now = []; + for (i = 0, ii = from[attr].length; i < ii; i++) { + now[i] = [from[attr][i][0]]; + for (j = 1, jj = from[attr][i].length; j < jj; j++) { + now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j]; + } + } + } else { + var get = function (i) { + return +from[attr][i] + pos * ms * diff[attr][i]; + }; + // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]]; + now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]]; + } + break; + case "csv": + if (attr == "clip-rect") { + now = []; + i = 4; + while (i--) { + now[i] = +from[attr][i] + pos * ms * diff[attr][i]; + } + } + break; + default: + var from2 = [][concat](from[attr]); + now = []; + i = that.paper.customAttributes[attr].length; + while (i--) { + now[i] = +from2[i] + pos * ms * diff[attr][i]; + } + break; + } + set[attr] = now; + } + that.attr(set); + (function (id, that, anim) { + setTimeout(function () { + eve("anim.frame." + id, that, anim); + }); + })(that.id, that, e.anim); + } else { + (function(f, el, a) { + setTimeout(function() { + eve("anim.frame." + el.id, el, a); + eve("anim.finish." + el.id, el, a); + R.is(f, "function") && f.call(el); + }); + })(e.callback, that, e.anim); + that.attr(to); + animationElements.splice(l--, 1); + if (e.repeat > 1 && !e.next) { + for (key in to) if (to[has](key)) { + init[key] = e.totalOrigin[key]; + } + e.el.attr(init); + runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1); + } + if (e.next && !e.stop) { + runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat); + } + } + } + R.svg && that && that.paper && that.paper.safari(); + animationElements.length && requestAnimFrame(animation); + }, + upto255 = function (color) { + return color > 255 ? 255 : color < 0 ? 0 : color; }; - var setSize = function (width, height) { - var cs = this.canvas.style; - width == +width && (width += "px"); - height == +height && (height += "px"); - cs.width = width; - cs.height = height; - cs.clip = "rect(0 " + width + " " + height + " 0)"; + + elproto.animateWith = function (element, anim, params, ms, easing, callback) { + var a = params ? R.animation(params, ms, easing, callback) : anim, + status = element.status(anim); + return this.animate(a).status(a, status * anim.ms / a.ms); + }; + function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { + var cx = 3 * p1x, + bx = 3 * (p2x - p1x) - cx, + ax = 1 - cx - bx, + cy = 3 * p1y, + by = 3 * (p2y - p1y) - cy, + ay = 1 - cy - by; + function sampleCurveX(t) { + return ((ax * t + bx) * t + cx) * t; + } + function solve(x, epsilon) { + var t = solveCurveX(x, epsilon); + return ((ay * t + by) * t + cy) * t; + } + function solveCurveX(x, epsilon) { + var t0, t1, t2, x2, d2, i; + for(t2 = x, i = 0; i < 8; i++) { + x2 = sampleCurveX(t2) - x; + if (abs(x2) < epsilon) { + return t2; + } + d2 = (3 * ax * t2 + 2 * bx) * t2 + cx; + if (abs(d2) < 1e-6) { + break; + } + t2 = t2 - x2 / d2; + } + t0 = 0; + t1 = 1; + t2 = x; + if (t2 < t0) { + return t0; + } + if (t2 > t1) { + return t1; + } + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (abs(x2 - x) < epsilon) { + return t2; + } + if (x > x2) { + t0 = t2; + } else { + t1 = t2; + } + t2 = (t1 - t0) / 2 + t0; + } + return t2; + } + return solve(t, 1 / (200 * duration)); + } + elproto.onAnimation = function (f) { + f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id); + return this; + }; + function Animation(anim, ms) { + var percents = [], + newAnim = {}; + this.ms = ms; + this.times = 1; + if (anim) { + for (var attr in anim) if (anim[has](attr)) { + newAnim[toFloat(attr)] = anim[attr]; + percents.push(toFloat(attr)); + } + percents.sort(sortByNumber); + } + this.anim = newAnim; + this.top = percents[percents.length - 1]; + this.percents = percents; + } + + Animation.prototype.delay = function (delay) { + var a = new Animation(this.anim, this.ms); + a.times = this.times; + a.del = +delay || 0; + return a; + }; + + Animation.prototype.repeat = function (times) { + var a = new Animation(this.anim, this.ms); + a.del = this.del; + a.times = math.floor(mmax(times, 0)) || 1; + return a; + }; + function runAnimation(anim, element, percent, status, totalOrigin, times) { + percent = toFloat(percent); + var params, + isInAnim, + isInAnimSet, + percents = [], + next, + prev, + timestamp, + ms = anim.ms, + from = {}, + to = {}, + diff = {}; + if (status) { + for (i = 0, ii = animationElements.length; i < ii; i++) { + var e = animationElements[i]; + if (e.el.id == element.id && e.anim == anim) { + if (e.percent != percent) { + animationElements.splice(i, 1); + isInAnimSet = 1; + } else { + isInAnim = e; + } + element.attr(e.totalOrigin); + break; + } + } + } else { + status = +to; // NaN + } + for (var i = 0, ii = anim.percents.length; i < ii; i++) { + if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) { + percent = anim.percents[i]; + prev = anim.percents[i - 1] || 0; + ms = ms / anim.top * (percent - prev); + next = anim.percents[i + 1]; + params = anim.anim[percent]; + break; + } else if (status) { + element.attr(anim.anim[anim.percents[i]]); + } + } + if (!params) { + return; + } + if (!isInAnim) { + for (var attr in params) if (params[has](attr)) { + if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) { + from[attr] = element.attr(attr); + (from[attr] == null) && (from[attr] = availableAttrs[attr]); + to[attr] = params[attr]; + switch (availableAnimAttrs[attr]) { + case nu: + diff[attr] = (to[attr] - from[attr]) / ms; + break; + case "colour": + from[attr] = R.getRGB(from[attr]); + var toColour = R.getRGB(to[attr]); + diff[attr] = { + r: (toColour.r - from[attr].r) / ms, + g: (toColour.g - from[attr].g) / ms, + b: (toColour.b - from[attr].b) / ms + }; + break; + case "path": + var pathes = path2curve(from[attr], to[attr]), + toPath = pathes[1]; + from[attr] = pathes[0]; + diff[attr] = []; + for (i = 0, ii = from[attr].length; i < ii; i++) { + diff[attr][i] = [0]; + for (var j = 1, jj = from[attr][i].length; j < jj; j++) { + diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; + } + } + break; + case "transform": + var _ = element._, + eq = equaliseTransform(_[attr], to[attr]); + if (eq) { + from[attr] = eq.from; + to[attr] = eq.to; + diff[attr] = []; + diff[attr].real = true; + for (i = 0, ii = from[attr].length; i < ii; i++) { + diff[attr][i] = [from[attr][i][0]]; + for (j = 1, jj = from[attr][i].length; j < jj; j++) { + diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; + } + } + } else { + var m = (element.matrix || new Matrix), + to2 = { + _: {transform: _.transform}, + getBBox: function () { + return element.getBBox(1); + } + }; + from[attr] = [ + m.a, + m.b, + m.c, + m.d, + m.e, + m.f + ]; + extractTransform(to2, to[attr]); + to[attr] = to2._.transform; + diff[attr] = [ + (to2.matrix.a - m.a) / ms, + (to2.matrix.b - m.b) / ms, + (to2.matrix.c - m.c) / ms, + (to2.matrix.d - m.d) / ms, + (to2.matrix.e - m.e) / ms, + (to2.matrix.e - m.f) / ms + ]; + // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy]; + // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }}; + // extractTransform(to2, to[attr]); + // diff[attr] = [ + // (to2._.sx - _.sx) / ms, + // (to2._.sy - _.sy) / ms, + // (to2._.deg - _.deg) / ms, + // (to2._.dx - _.dx) / ms, + // (to2._.dy - _.dy) / ms + // ]; + } + break; + case "csv": + var values = Str(params[attr])[split](separator), + from2 = Str(from[attr])[split](separator); + if (attr == "clip-rect") { + from[attr] = from2; + diff[attr] = []; + i = from2.length; + while (i--) { + diff[attr][i] = (values[i] - from[attr][i]) / ms; + } + } + to[attr] = values; + break; + default: + values = [][concat](params[attr]); + from2 = [][concat](from[attr]); + diff[attr] = []; + i = element.paper.customAttributes[attr].length; + while (i--) { + diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms; + } + break; + } + } + } + var easing = params.easing, + easyeasy = R.easing_formulas[easing]; + if (!easyeasy) { + easyeasy = Str(easing).match(bezierrg); + if (easyeasy && easyeasy.length == 5) { + var curve = easyeasy; + easyeasy = function (t) { + return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms); + }; + } else { + easyeasy = pipe; + } + } + timestamp = params.start || anim.start || +new Date; + e = { + anim: anim, + percent: percent, + timestamp: timestamp, + start: timestamp + (anim.del || 0), + status: 0, + initstatus: status || 0, + stop: false, + ms: ms, + easing: easyeasy, + from: from, + diff: diff, + to: to, + el: element, + callback: params.callback, + prev: prev, + next: next, + repeat: times || anim.times, + origin: element.attr(), + totalOrigin: totalOrigin + }; + animationElements.push(e); + if (status && !isInAnim && !isInAnimSet) { + e.stop = true; + e.start = new Date - ms * status; + if (animationElements.length == 1) { + return animation(); + } + } + if (isInAnimSet) { + e.start = new Date - e.ms * status; + } + animationElements.length == 1 && requestAnimFrame(animation); + } else { + isInAnim.initstatus = status; + isInAnim.start = new Date - isInAnim.ms * status; + } + eve("anim.start." + element.id, element, anim); + } + + R.animation = function (params, ms, easing, callback) { + if (params instanceof Animation) { + return params; + } + if (R.is(easing, "function") || !easing) { + callback = callback || easing || null; + easing = null; + } + params = Object(params); + ms = +ms || 0; + var p = {}, + json, + attr; + for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) { + json = true; + p[attr] = params[attr]; + } + if (!json) { + return new Animation(params, ms); + } else { + easing && (p.easing = easing); + callback && (p.callback = callback); + return new Animation({100: p}, ms); + } + }; + + elproto.animate = function (params, ms, easing, callback) { + var element = this; + if (element.removed) { + callback && callback.call(element); + return element; + } + var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback); + runAnimation(anim, element, anim.percents[0], null, element.attr()); + return element; + }; + + elproto.setTime = function (anim, value) { + if (anim && value != null) { + this.status(anim, mmin(value, anim.ms) / anim.ms); + } + return this; + }; + + elproto.status = function (anim, value) { + var out = [], + i = 0, + len, + e; + if (value != null) { + runAnimation(anim, this, -1, mmin(value, 1)); + return this; + } else { + len = animationElements.length; + for (; i < len; i++) { + e = animationElements[i]; + if (e.el.id == this.id && (!anim || e.anim == anim)) { + if (anim) { + return e.status; + } + out.push({ + anim: e.anim, + status: e.status + }); + } + } + if (anim) { + return 0; + } + return out; + } + }; + + elproto.pause = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) { + animationElements[i].paused = true; + } + } + return this; + }; + + elproto.resume = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + var e = animationElements[i]; + if (eve("anim.resume." + this.id, this, e.anim) !== false) { + delete e.paused; + this.status(e.anim, e.status); + } + } + return this; + }; + + elproto.stop = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) { + animationElements.splice(i--, 1); + } + } + return this; + }; + elproto.toString = function () { + return "Rapha\xebl\u2019s object"; + }; + + // Set + var Set = function (items) { + this.items = []; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item && (item.constructor == elproto.constructor || item.constructor == Set)) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + for (var method in elproto) if (elproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname][apply](el, arg); + }); + }; + })(method); + } + setproto.attr = function (name, value) { + if (name && R.is(name, array) && R.is(name[0], "object")) { + for (var j = 0, jj = name.length; j < jj; j++) { + this.items[j].attr(name[j]); + } + } else { + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(name, value); + } + } + return this; + }; + + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + }; + setproto.animate = function (params, ms, easing, callback) { + (R.is(easing, "function") || !easing) && (callback = easing || null); + var len = this.items.length, + i = len, + item, + set = this, + collector; + if (!len) { return this; + } + callback && (collector = function () { + !--len && callback.call(set); + }); + easing = R.is(easing, string) ? easing : collector; + var anim = R.animation(params, ms, easing, collector); + item = this.items[--i].animate(anim); + while (i--) { + this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim); + } + return this; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + w = [], + h = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + w.push(box.x + box.width); + h.push(box.y + box.height); + } + x = mmin[apply](0, x); + y = mmin[apply](0, y); + return { + x: x, + y: y, + width: mmax[apply](0, w) - x, + height: mmax[apply](0, h) - y }; - doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Rapha\xebl\u2018s set"; + }; + + + R.registerFont = function (font) { + if (!font.face) { + return font; + } + this.fonts = this.fonts || {}; + var fontcopy = { + w: font.w, + face: {}, + glyphs: {} + }, + family = font.face["font-family"]; + for (var prop in font.face) if (font.face[has](prop)) { + fontcopy.face[prop] = font.face[prop]; + } + if (this.fonts[family]) { + this.fonts[family].push(fontcopy); + } else { + this.fonts[family] = [fontcopy]; + } + if (!font.svg) { + fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); + for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { + var path = font.glyphs[glyph]; + fontcopy.glyphs[glyph] = { + w: path.w, + k: {}, + d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { + return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; + }) + "z" + }; + if (path.k) { + for (var k in path.k) if (path[has](k)) { + fontcopy.glyphs[glyph].k[k] = path.k[k]; + } + } + } + } + return font; + }; + + paperproto.getFont = function (family, weight, style, stretch) { + stretch = stretch || "normal"; + style = style || "normal"; + weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; + if (!R.fonts) { + return; + } + var font = R.fonts[family]; + if (!font) { + var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); + for (var fontName in R.fonts) if (R.fonts[has](fontName)) { + if (name.test(fontName)) { + font = R.fonts[fontName]; + break; + } + } + } + var thefont; + if (font) { + for (var i = 0, ii = font.length; i < ii; i++) { + thefont = font[i]; + if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { + break; + } + } + } + return thefont; + }; + + paperproto.print = function (x, y, string, font, size, origin, letter_spacing) { + origin = origin || "middle"; // baseline|middle + letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); + var out = this.set(), + letters = Str(string)[split](E), + shift = 0, + path = E, + scale; + R.is(font, string) && (font = this.getFont(font)); + if (font) { + scale = (size || 16) / font.face["units-per-em"]; + var bb = font.face.bbox[split](separator), + top = +bb[0], + height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2); + for (var i = 0, ii = letters.length; i < ii; i++) { + var prev = i && font.glyphs[letters[i - 1]] || {}, + curr = font.glyphs[letters[i]]; + shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; + curr && curr.d && out.push(this.path(curr.d).attr({ + fill: "#000", + stroke: "none", + transform: [["t", shift * scale, 0]] + })); + } + out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]); + } + return out; + }; + + + paperproto.add = function (json) { + if (R.is(json, "array")) { + var res = this.set(), + i = 0, + ii = json.length, + j; + for (; i < ii; i++) { + j = json[i] || {}; + elements[has](j.type) && res.push(this[j.type]().attr(j)); + } + } + return res; + }; + + + R.format = function (token, params) { + var args = R.is(params, array) ? [0][concat](params) : arguments; + token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { + return args[++i] == null ? E : args[i]; + })); + return token || E; + }; + + R.fullfill = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return String(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; + })(); + + R.ninja = function () { + oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; + return R; + }; + + R.st = setproto; + // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + (function (doc, loaded, f) { + if (doc.readyState == null && doc.addEventListener){ + doc.addEventListener(loaded, f = function () { + doc.removeEventListener(loaded, f, false); + doc.readyState = "complete"; + }, false); + doc.readyState = "loading"; + } + function isLoaded() { + (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload"); + } + isLoaded(); + })(document, "DOMContentLoaded"); + + oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); + + eve.on("DOMload", function () { + loaded = true; + }); +})(); + + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ SVG Module │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +window.Raphael.svg && function (R) { + var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + abs = math.abs, + pow = math.pow, + separator = /[, ]+/, + eve = R.eve, + E = "", + S = " "; + var xlink = "http://www.w3.org/1999/xlink", + markers = { + block: "M5,0 0,2.5 5,5z", + classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", + diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", + open: "M6,1 1,3.5 6,6", + oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" + }, + markerCounter = {}; + R.toString = function () { + return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; + }; + var $ = function (el, attr) { + if (attr) { + if (typeof el == "string") { + el = $(el); + } + for (var key in attr) if (attr[has](key)) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); + } else { + el.setAttribute(key, Str(attr[key])); + } + } + } else { + el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el); + el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); + } + return el; + }, + addGradientFill = function (element, gradient) { + var type = "linear", + id = element.id + gradient, + fx = .5, fy = .5, + o = element.node, + SVG = element.paper, + s = o.style, + el = R._g.doc.getElementById(id); + if (!el) { + gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) { + type = "radial"; + if (_fx && _fy) { + fx = toFloat(_fx); + fy = toFloat(_fy); + var dir = ((fy > .5) * 2 - 1); + pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && + (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && + fy != .5 && + (fy = fy.toFixed(5) - 1e-5 * dir); + } + return E; + }); + gradient = gradient.split(/\s*\-\s*/); + if (type == "linear") { + var angle = gradient.shift(); + angle = -toFloat(angle); + if (isNaN(angle)) { + return null; + } + var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], + max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); + vector[2] *= max; + vector[3] *= max; + if (vector[2] < 0) { + vector[0] = -vector[2]; + vector[2] = 0; + } + if (vector[3] < 0) { + vector[1] = -vector[3]; + vector[3] = 0; + } + } + var dots = R._parseDots(gradient); + if (!dots) { + return null; + } + id = id.replace(/[\(\)\s,\xb0#]/g, "_"); + + if (element.gradient && id != element.gradient.id) { + SVG.defs.removeChild(element.gradient); + delete element.gradient; + } + + if (!element.gradient) { + el = $(type + "Gradient", {id: id}); + element.gradient = el; + $(el, type == "radial" ? { + fx: fx, + fy: fy + } : { + x1: vector[0], + y1: vector[1], + x2: vector[2], + y2: vector[3], + gradientTransform: element.matrix.invert() + }); + SVG.defs.appendChild(el); + for (var i = 0, ii = dots.length; i < ii; i++) { + el.appendChild($("stop", { + offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", + "stop-color": dots[i].color || "#fff" + })); + } + } + } + $(o, { + fill: "url(#" + id + ")", + opacity: 1, + "fill-opacity": 1 + }); + s.fill = E; + s.opacity = 1; + s.fillOpacity = 1; + return 1; + }, + updatePosition = function (o) { + var bbox = o.getBBox(1); + $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); + }, + addArrow = function (o, value, isEnd) { + if (o.type == "path") { + var values = Str(value).toLowerCase().split("-"), + p = o.paper, + se = isEnd ? "end" : "start", + node = o.node, + attrs = o.attrs, + stroke = attrs["stroke-width"], + i = values.length, + type = "classic", + from, + to, + dx, + refX, + attr, + w = 3, + h = 3, + t = 5; + while (i--) { + switch (values[i]) { + case "block": + case "classic": + case "oval": + case "diamond": + case "open": + case "none": + type = values[i]; + break; + case "wide": h = 5; break; + case "narrow": h = 2; break; + case "long": w = 5; break; + case "short": w = 2; break; + } + } + if (type == "open") { + w += 2; + h += 2; + t += 2; + dx = 1; + refX = isEnd ? 4 : 1; + attr = { + fill: "none", + stroke: attrs.stroke + }; + } else { + refX = dx = w / 2; + attr = { + fill: attrs.stroke, + stroke: "none" + }; + } + if (o._.arrows) { + if (isEnd) { + o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; + o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; + } else { + o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; + o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; + } + } else { + o._.arrows = {}; + } + if (type != "none") { + var pathId = "raphael-marker-" + type, + markerId = "raphael-marker-" + se + type + w + h; + if (!R._g.doc.getElementById(pathId)) { + p.defs.appendChild($($("path"), { + "stroke-linecap": "round", + d: markers[type], + id: pathId + })); + markerCounter[pathId] = 1; + } else { + markerCounter[pathId]++; + } + var marker = R._g.doc.getElementById(markerId), + use; + if (!marker) { + marker = $($("marker"), { + id: markerId, + markerHeight: h, + markerWidth: w, + orient: "auto", + refX: refX, + refY: h / 2 + }); + use = $($("use"), { + "xlink:href": "#" + pathId, + transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")", + "stroke-width": 1 / ((w / t + h / t) / 2) + }); + marker.appendChild(use); + p.defs.appendChild(marker); + markerCounter[markerId] = 1; + } else { + markerCounter[markerId]++; + use = marker.getElementsByTagName("use")[0]; + } + $(use, attr); + var delta = dx * (type != "diamond" && type != "oval"); + if (isEnd) { + from = o._.arrows.startdx * stroke || 0; + to = R.getTotalLength(attrs.path) - delta * stroke; + } else { + from = delta * stroke; + to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); + } + attr = {}; + attr["marker-" + se] = "url(#" + markerId + ")"; + if (to || from) { + attr.d = Raphael.getSubpath(attrs.path, from, to); + } + $(node, attr); + o._.arrows[se + "Path"] = pathId; + o._.arrows[se + "Marker"] = markerId; + o._.arrows[se + "dx"] = delta; + o._.arrows[se + "Type"] = type; + o._.arrows[se + "String"] = value; + } else { + if (isEnd) { + from = o._.arrows.startdx * stroke || 0; + to = R.getTotalLength(attrs.path) - from; + } else { + from = 0; + to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); + } + o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)}); + delete o._.arrows[se + "Path"]; + delete o._.arrows[se + "Marker"]; + delete o._.arrows[se + "dx"]; + delete o._.arrows[se + "Type"]; + delete o._.arrows[se + "String"]; + } + for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { + var item = R._g.doc.getElementById(attr); + item && item.parentNode.removeChild(item); + } + } + }, + dasharray = { + "": [0], + "none": [0], + "-": [3, 1], + ".": [1, 1], + "-.": [3, 1, 1, 1], + "-..": [3, 1, 1, 1, 1, 1], + ". ": [1, 3], + "- ": [4, 3], + "--": [8, 3], + "- .": [4, 3, 1, 3], + "--.": [8, 3, 1, 3], + "--..": [8, 3, 1, 3, 1, 3] + }, + addDashes = function (o, value, params) { + value = dasharray[Str(value).toLowerCase()]; + if (value) { + var width = o.attrs["stroke-width"] || "1", + butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, + dashes = [], + i = value.length; + while (i--) { + dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; + } + $(o.node, {"stroke-dasharray": dashes.join(",")}); + } + }, + setFillAndStroke = function (o, params) { + var node = o.node, + attrs = o.attrs, + vis = node.style.visibility; + node.style.visibility = "hidden"; + for (var att in params) { + if (params[has](att)) { + if (!R._availableAttrs[has](att)) { + continue; + } + var value = params[att]; + attrs[att] = value; + switch (att) { + case "blur": + o.blur(value); + break; + case "href": + case "title": + case "target": + var pn = node.parentNode; + if (pn.tagName.toLowerCase() != "a") { + var hl = $("a"); + pn.insertBefore(hl, node); + hl.appendChild(node); + pn = hl; + } + if (att == "target" && value == "blank") { + pn.setAttributeNS(xlink, "show", "new"); + } else { + pn.setAttributeNS(xlink, att, value); + } + break; + case "cursor": + node.style.cursor = value; + break; + case "transform": + o.transform(value); + break; + case "arrow-start": + addArrow(o, value); + break; + case "arrow-end": + addArrow(o, value, 1); + break; + case "clip-rect": + var rect = Str(value).split(separator); + if (rect.length == 4) { + o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); + var el = $("clipPath"), + rc = $("rect"); + el.id = R.createUUID(); + $(rc, { + x: rect[0], + y: rect[1], + width: rect[2], + height: rect[3] + }); + el.appendChild(rc); + o.paper.defs.appendChild(el); + $(node, {"clip-path": "url(#" + el.id + ")"}); + o.clip = rc; + } + if (!value) { + var path = node.getAttribute("clip-path"); + if (path) { + var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E)); + clip && clip.parentNode.removeChild(clip); + $(node, {"clip-path": E}); + delete o.clip; + } + } + break; + case "path": + if (o.type == "path") { + $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"}); + o._.dirty = 1; + if (o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + } + break; + case "width": + node.setAttribute(att, value); + o._.dirty = 1; + if (attrs.fx) { + att = "x"; + value = attrs.x; + } else { + break; + } + case "x": + if (attrs.fx) { + value = -attrs.x - (attrs.width || 0); + } + case "rx": + if (att == "rx" && o.type == "rect") { + break; + } + case "cx": + node.setAttribute(att, value); + o.pattern && updatePosition(o); + o._.dirty = 1; + break; + case "height": + node.setAttribute(att, value); + o._.dirty = 1; + if (attrs.fy) { + att = "y"; + value = attrs.y; + } else { + break; + } + case "y": + if (attrs.fy) { + value = -attrs.y - (attrs.height || 0); + } + case "ry": + if (att == "ry" && o.type == "rect") { + break; + } + case "cy": + node.setAttribute(att, value); + o.pattern && updatePosition(o); + o._.dirty = 1; + break; + case "r": + if (o.type == "rect") { + $(node, {rx: value, ry: value}); + } else { + node.setAttribute(att, value); + } + o._.dirty = 1; + break; + case "src": + if (o.type == "image") { + node.setAttributeNS(xlink, "href", value); + } + break; + case "stroke-width": + if (o._.sx != 1 || o._.sy != 1) { + value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; + } + if (o.paper._vbSize) { + value *= o.paper._vbSize; + } + node.setAttribute(att, value); + if (attrs["stroke-dasharray"]) { + addDashes(o, attrs["stroke-dasharray"], params); + } + if (o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + break; + case "stroke-dasharray": + addDashes(o, value, params); + break; + case "fill": + var isURL = Str(value).match(R._ISURL); + if (isURL) { + el = $("pattern"); + var ig = $("image"); + el.id = R.createUUID(); + $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); + $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); + el.appendChild(ig); + + (function (el) { + R._preload(isURL[1], function () { + var w = this.offsetWidth, + h = this.offsetHeight; + $(el, {width: w, height: h}); + $(ig, {width: w, height: h}); + o.paper.safari(); + }); + })(el); + o.paper.defs.appendChild(el); + node.style.fill = "url(#" + el.id + ")"; + $(node, {fill: "url(#" + el.id + ")"}); + o.pattern = el; + o.pattern && updatePosition(o); + break; + } + var clr = R.getRGB(value); + if (!clr.error) { + delete params.gradient; + delete attrs.gradient; + !R.is(attrs.opacity, "undefined") && + R.is(params.opacity, "undefined") && + $(node, {opacity: attrs.opacity}); + !R.is(attrs["fill-opacity"], "undefined") && + R.is(params["fill-opacity"], "undefined") && + $(node, {"fill-opacity": attrs["fill-opacity"]}); + } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { + if ("opacity" in attrs || "fill-opacity" in attrs) { + var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + if (gradient) { + var stops = gradient.getElementsByTagName("stop"); + $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); + } + } + attrs.gradient = value; + attrs.fill = "none"; + break; + } + clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); + case "stroke": + clr = R.getRGB(value); + node.setAttribute(att, clr.hex); + att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); + if (att == "stroke" && o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + break; + case "gradient": + (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); + break; + case "opacity": + if (attrs.gradient && !attrs[has]("stroke-opacity")) { + $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); + } + // fall + case "fill-opacity": + if (attrs.gradient) { + gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + if (gradient) { + stops = gradient.getElementsByTagName("stop"); + $(stops[stops.length - 1], {"stop-opacity": value}); + } + break; + } + default: + att == "font-size" && (value = toInt(value, 10) + "px"); + var cssrule = att.replace(/(\-.)/g, function (w) { + return w.substring(1).toUpperCase(); + }); + node.style[cssrule] = value; + o._.dirty = 1; + node.setAttribute(att, value); + break; + } + } + } + + tuneText(o, params); + node.style.visibility = vis; + }, + leading = 1.2, + tuneText = function (el, params) { + if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { + return; + } + var a = el.attrs, + node = el.node, + fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; + + if (params[has]("text")) { + a.text = params.text; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var texts = Str(params.text).split("\n"), + tspans = [], + tspan; + for (var i = 0, ii = texts.length; i < ii; i++) { + tspan = $("tspan"); + i && $(tspan, {dy: fontSize * leading, x: a.x}); + tspan.appendChild(R._g.doc.createTextNode(texts[i])); + node.appendChild(tspan); + tspans[i] = tspan; + } + } else { + tspans = node.getElementsByTagName("tspan"); + for (i = 0, ii = tspans.length; i < ii; i++) if (i) { + $(tspans[i], {dy: fontSize * leading, x: a.x}); + } else { + $(tspans[0], {dy: 0}); + } + } + $(node, {x: a.x, y: a.y}); + el._.dirty = 1; + var bb = el._getBBox(), + dif = a.y - (bb.y + bb.height / 2); + dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); + }, + Element = function (node, svg) { + var X = 0, + Y = 0; + + this[0] = this.node = node; + + node.raphael = true; + + this.id = R._oid++; + node.raphaelid = this.id; + this.matrix = R.matrix(); + this.realPath = null; + + this.paper = svg; + this.attrs = this.attrs || {}; + this._ = { + transform: [], + sx: 1, + sy: 1, + deg: 0, + dx: 0, + dy: 0, + dirty: 1 + }; + !svg.bottom && (svg.bottom = this); + + this.prev = svg.top; + svg.top && (svg.top.next = this); + svg.top = this; + + this.next = null; + }, + elproto = R.el; + + Element.prototype = elproto; + elproto.constructor = Element; + + R._engine.path = function (pathString, SVG) { + var el = $("path"); + SVG.canvas && SVG.canvas.appendChild(el); + var p = new Element(el, SVG); + p.type = "path"; + setFillAndStroke(p, { + fill: "none", + stroke: "#000", + path: pathString + }); + return p; + }; + + elproto.rotate = function (deg, cx, cy) { + if (this.removed) { + return this; + } + deg = Str(deg).split(separator); + if (deg.length - 1) { + cx = toFloat(deg[1]); + cy = toFloat(deg[2]); + } + deg = toFloat(deg[0]); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + cx = bbox.x + bbox.width / 2; + cy = bbox.y + bbox.height / 2; + } + this.transform(this._.transform.concat([["r", deg, cx, cy]])); + return this; + }; + + elproto.scale = function (sx, sy, cx, cy) { + if (this.removed) { + return this; + } + sx = Str(sx).split(separator); + if (sx.length - 1) { + sy = toFloat(sx[1]); + cx = toFloat(sx[2]); + cy = toFloat(sx[3]); + } + sx = toFloat(sx[0]); + (sy == null) && (sy = sx); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + } + cx = cx == null ? bbox.x + bbox.width / 2 : cx; + cy = cy == null ? bbox.y + bbox.height / 2 : cy; + this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); + return this; + }; + + elproto.translate = function (dx, dy) { + if (this.removed) { + return this; + } + dx = Str(dx).split(separator); + if (dx.length - 1) { + dy = toFloat(dx[1]); + } + dx = toFloat(dx[0]) || 0; + dy = +dy || 0; + this.transform(this._.transform.concat([["t", dx, dy]])); + return this; + }; + + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + return _.transform; + } + R._extractTransform(this, tstr); + + this.clip && $(this.clip, {transform: this.matrix.invert()}); + this.pattern && updatePosition(this); + this.node && $(this.node, {transform: this.matrix}); + + if (_.sx != 1 || _.sy != 1) { + var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; + this.attr({"stroke-width": sw}); + } + + return this; + }; + + elproto.hide = function () { + !this.removed && this.paper.safari(this.node.style.display = "none"); + return this; + }; + + elproto.show = function () { + !this.removed && this.paper.safari(this.node.style.display = ""); + return this; + }; + + elproto.remove = function () { + if (this.removed) { + return; + } + var paper = this.paper; + paper.__set__ && paper.__set__.exclude(this); + eve.unbind("*.*." + this.id); + if (this.gradient) { + paper.defs.removeChild(this.gradient); + } + R._tear(this, paper); + this.node.parentNode.removeChild(this.node); + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + this.removed = true; + }; + elproto._getBBox = function () { + if (this.node.style.display == "none") { + this.show(); + var hide = true; + } + var bbox = {}; try { - !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); - var createNode = function (tagName) { - return doc.createElement(''); - }; - } catch (e) { - var createNode = function (tagName) { - return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); - }; + bbox = this.node.getBBox(); + } catch(e) { + // Firefox 3.0.x plays badly here + } finally { + bbox = bbox || {}; } - var create = function () { - var con = getContainer[apply](null, arguments), - container = con.container, - height = con.height, - s, - width = con.width, - x = con.x, - y = con.y; - if (!container) { - throw new Error("VML container not found."); - } - var res = {}, - c = res.canvas = doc.createElement("div"), - cs = c.style; - width = width || 512; - height = height || 342; - width == +width && (width += "px"); - height == +height && (height += "px"); - res.width = 1e3; - res.height = 1e3; - res.coordsize = "1000 1000"; - res.coordorigin = "0 0"; - res.span = doc.createElement("span"); - res.span.style.cssText = "position:absolute;left:-9999px;top:-9999px;padding:0;margin:0;line-height:1;display:inline;"; - c[appendChild](res.span); - cs.cssText = R.format("width:{0};height:{1};position:absolute;clip:rect(0 {0} {1} 0);overflow:hidden", width, height); - if (container == 1) { - doc.body[appendChild](c); - cs.left = x + "px"; - cs.top = y + "px"; - container = { - style: { - width: width, - height: height - } - }; - } else { - container.style.width = width; - container.style.height = height; - if (container.firstChild) { - container.insertBefore(c, container.firstChild); + hide && this.hide(); + return bbox; + }; + + elproto.attr = function (name, value) { + if (this.removed) { + return this; + } + if (name == null) { + var res = {}; + for (var a in this.attrs) if (this.attrs[has](a)) { + res[a] = this.attrs[a]; + } + res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; + res.transform = this._.transform; + return res; + } + if (value == null && R.is(name, "string")) { + if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { + return this.attrs.gradient; + } + if (name == "transform") { + return this._.transform; + } + var names = name.split(separator), + out = {}; + for (var i = 0, ii = names.length; i < ii; i++) { + name = names[i]; + if (name in this.attrs) { + out[name] = this.attrs[name]; + } else if (R.is(this.paper.customAttributes[name], "function")) { + out[name] = this.paper.customAttributes[name].def; } else { - container[appendChild](c); + out[name] = R._availableAttrs[name]; } } - for (var prop in paper) if (paper[has](prop)) { - res[prop] = paper[prop]; + return ii - 1 ? out : out[names[0]]; + } + if (value == null && R.is(name, "array")) { + out = {}; + for (i = 0, ii = name.length; i < ii; i++) { + out[name[i]] = this.attr(name[i]); } - plugins.call(res, res, R.fn); - res.top = res.bottom = null; - res.raphael = R; - return res; - }; - paper.clear = function () { - this.canvas.innerHTML = E; - this.bottom = this.top = null; - }; - paper.remove = function () { - this.canvas.parentNode.removeChild(this.canvas); - for (var i in this) { - delete this[i]; + return out; + } + if (value != null) { + var params = {}; + params[name] = value; + } else if (name != null && R.is(name, "object")) { + params = name; + } + for (var key in params) { + eve("attr." + key + "." + this.id, this, params[key]); + } + for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { + var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); + this.attrs[key] = params[key]; + for (var subkey in par) if (par[has](subkey)) { + params[subkey] = par[subkey]; } - }; - } - - // rest - // Safari or Chrome (WebKit) rendering bug workaround method - if ((/^Apple|^Google/).test(navigator.vendor) && !(navigator.userAgent.indexOf("Version/4.0") + 1)) { - paper.safari = function () { - var rect = this.rect(-99, -99, this.width + 99, this.height + 99); - setTimeout(function () {rect.remove();}); - }; - } else { - paper.safari = function () {}; - } - - // Events - var addEvent = (function () { - if (doc.addEventListener) { - return function (obj, type, fn, element) { - var f = function (e) { - return fn.call(element, e); - }; - obj.addEventListener(type, f, false); - return function () { - obj.removeEventListener(type, f, false); - return true; - }; - }; - } else if (doc.attachEvent) { - return function (obj, type, fn, element) { - var f = function (e) { - return fn.call(element, e || win.event); - }; - obj.attachEvent("on" + type, f); - var detacher = function () { - obj.detachEvent("on" + type, f); - return true; - }; - return detacher; - }; } - })(); - for (var i = events[length]; i--;) { - (function (eventName) { - Element[proto][eventName] = function (fn) { - if (R.is(fn, "function")) { - this.events = this.events || []; - this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node, eventName, fn, this)}); - } - return this; - }; - Element[proto]["un" + eventName] = function (fn) { - var events = this.events, - l = events[length]; - while (l--) if (events[l].name == eventName && events[l].f == fn) { - events[l].unbind(); - events.splice(l, 1); - !events.length && delete this.events; - return this; - } - return this; - }; - })(events[i]); - } - Element[proto].hover = function (f_in, f_out) { - return this.mouseover(f_in).mouseout(f_out); + setFillAndStroke(this, params); + return this; }; - Element[proto].unhover = function (f_in, f_out) { - return this.unmouseover(f_in).unmouseout(f_out); + + elproto.toFront = function () { + if (this.removed) { + return this; + } + if (this.node.parentNode.tagName.toLowerCase() == "a") { + this.node.parentNode.parentNode.appendChild(this.node.parentNode); + } else { + this.node.parentNode.appendChild(this.node); + } + var svg = this.paper; + svg.top != this && R._tofront(this, svg); + return this; }; - paper.circle = function (x, y, r) { - return theCircle(this, x || 0, y || 0, r || 0); + + elproto.toBack = function () { + if (this.removed) { + return this; + } + var parent = this.node.parentNode; + if (parent.tagName.toLowerCase() == "a") { + parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild); + } else if (parent.firstChild != this.node) { + parent.insertBefore(this.node, this.node.parentNode.firstChild); + } + R._toback(this, this.paper); + var svg = this.paper; + return this; }; - paper.rect = function (x, y, w, h, r) { - return theRect(this, x || 0, y || 0, w || 0, h || 0, r || 0); + + elproto.insertAfter = function (element) { + if (this.removed) { + return this; + } + var node = element.node || element[element.length - 1].node; + if (node.nextSibling) { + node.parentNode.insertBefore(this.node, node.nextSibling); + } else { + node.parentNode.appendChild(this.node); + } + R._insertafter(this, element, this.paper); + return this; }; - paper.ellipse = function (x, y, rx, ry) { - return theEllipse(this, x || 0, y || 0, rx || 0, ry || 0); + + elproto.insertBefore = function (element) { + if (this.removed) { + return this; + } + var node = element.node || element[0].node; + node.parentNode.insertBefore(this.node, node); + R._insertbefore(this, element, this.paper); + return this; }; - paper.path = function (pathString) { - pathString && !R.is(pathString, "string") && !R.is(pathString[0], "array") && (pathString += E); - return thePath(R.format[apply](R, arguments), this); + elproto.blur = function (size) { + // Experimental. No Safari support. Use it on your own risk. + var t = this; + if (+size !== 0) { + var fltr = $("filter"), + blur = $("feGaussianBlur"); + t.attrs.blur = size; + fltr.id = R.createUUID(); + $(blur, {stdDeviation: +size || 1.5}); + fltr.appendChild(blur); + t.paper.defs.appendChild(fltr); + t._blur = fltr; + $(t.node, {filter: "url(#" + fltr.id + ")"}); + } else { + if (t._blur) { + t._blur.parentNode.removeChild(t._blur); + delete t._blur; + delete t.attrs.blur; + } + t.node.removeAttribute("filter"); + } }; - paper.image = function (src, x, y, w, h) { - return theImage(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); + R._engine.circle = function (svg, x, y, r) { + var el = $("circle"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; + res.type = "circle"; + $(el, res.attrs); + return res; }; - paper.text = function (x, y, text) { - return theText(this, x || 0, y || 0, text || E); + R._engine.rect = function (svg, x, y, w, h, r) { + var el = $("rect"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; + res.type = "rect"; + $(el, res.attrs); + return res; }; - paper.set = function (itemsArray) { - arguments[length] > 1 && (itemsArray = Array[proto].splice.call(arguments, 0, arguments[length])); - return new Set(itemsArray); + R._engine.ellipse = function (svg, x, y, rx, ry) { + var el = $("ellipse"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; + res.type = "ellipse"; + $(el, res.attrs); + return res; }; - paper.setSize = setSize; - function scaleToString() { - return this.x + S + this.y; + R._engine.image = function (svg, src, x, y, w, h) { + var el = $("image"); + $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); + el.setAttributeNS(xlink, "href", src); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {x: x, y: y, width: w, height: h, src: src}; + res.type = "image"; + return res; }; - Element[proto].scale = function (x, y, cx, cy) { - if (x == null && y == null) { - return { - x: this._.sx, - y: this._.sy, - toString: scaleToString - }; + R._engine.text = function (svg, x, y, text) { + var el = $("text"); + // $(el, {x: x, y: y, "text-anchor": "middle"}); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = { + x: x, + y: y, + "text-anchor": "middle", + text: text, + font: R._availableAttrs.font, + stroke: "none", + fill: "#000" + }; + res.type = "text"; + setFillAndStroke(res, res.attrs); + return res; + }; + R._engine.setSize = function (width, height) { + this.width = width || this.width; + this.height = height || this.height; + this.canvas.setAttribute("width", this.width); + this.canvas.setAttribute("height", this.height); + if (this._viewBox) { + this.setViewBox.apply(this, this._viewBox); } - y = y || x; - !+y && (y = x); - var dx, - dy, - dcx, - dcy, - a = this.attrs; - if (x != 0) { - var bb = this.getBBox(), - rcx = bb.x + bb.width / 2, - rcy = bb.y + bb.height / 2, - kx = x / this._.sx, - ky = y / this._.sy; - cx = (+cx || cx == 0) ? cx : rcx; - cy = (+cy || cy == 0) ? cy : rcy; - var dirx = ~~(x / math.abs(x)), - diry = ~~(y / math.abs(y)), - s = this.node.style, - ncx = cx + (rcx - cx) * kx, - ncy = cy + (rcy - cy) * ky; - switch (this.type) { - case "rect": - case "image": - var neww = a.width * dirx * kx, - newh = a.height * diry * ky, - newr = a.r * mmin(kx, ky), - newx = ncx - neww / 2, - newy = ncy - newh / 2; - this.attr({ - height: newh, - r: newr, - width: neww, - x: newx, - y: newy - }); - break; - case "circle": - case "ellipse": - this.attr({ - rx: a.rx * dirx * kx, - ry: a.ry * diry * ky, - r: a.r * mmin(dirx * kx, diry * ky), - cx: ncx, - cy: ncy - }); - break; - case "path": - var path = pathToRelative(a.path), - skip = true; - for (var i = 0, ii = path[length]; i < ii; i++) { - var p = path[i], - j, - P0 = upperCase.call(p[0]); - if (P0 == "M" && skip) { - continue; - } else { - skip = false; - } - if (P0 == "A") { - p[path[i][length] - 2] *= kx; - p[path[i][length] - 1] *= ky; - p[1] *= dirx * kx; - p[2] *= diry * ky; - p[5] = +(dirx + diry ? !!+p[5] : !+p[5]); - } else if (P0 == "H") { - for (j = 1, jj = p[length]; j < jj; j++) { - p[j] *= kx; - } - } else if (P0 == "V") { - for (j = 1, jj = p[length]; j < jj; j++) { - p[j] *= ky; - } - } else { - for (j = 1, jj = p[length]; j < jj; j++) { - p[j] *= (j % 2) ? kx : ky; - } - } - } - var dim2 = pathDimensions(path), - dx = ncx - dim2.x - dim2.width / 2, - dy = ncy - dim2.y - dim2.height / 2; - path[0][1] += dx; - path[0][2] += dy; - - this.attr({path: path}); - break; - } - if (this.type in {text: 1, image:1} && (dirx != 1 || diry != 1)) { - if (this.transformations) { - this.transformations[2] = "scale("[concat](dirx, ",", diry, ")"); - this.node[setAttribute]("transform", this.transformations[join](S)); - dx = (dirx == -1) ? -a.x - (neww || 0) : a.x; - dy = (diry == -1) ? -a.y - (newh || 0) : a.y; - this.attr({x: dx, y: dy}); - a.fx = dirx - 1; - a.fy = diry - 1; - } else { - this.node.filterMatrix = " progid:DXImageTransform.Microsoft.Matrix(M11="[concat](dirx, - ", M12=0, M21=0, M22=", diry, - ", Dx=0, Dy=0, sizingmethod='auto expand', filtertype='bilinear')"); - s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E); - } + return this; + }; + R._engine.create = function () { + var con = R._getContainer.apply(0, arguments), + container = con && con.container, + x = con.x, + y = con.y, + width = con.width, + height = con.height; + if (!container) { + throw new Error("SVG container not found."); + } + var cnvs = $("svg"), + css = "overflow:hidden;", + isFloating; + x = x || 0; + y = y || 0; + width = width || 512; + height = height || 342; + $(cnvs, { + height: height, + version: 1.1, + width: width, + xmlns: "http://www.w3.org/2000/svg" + }); + if (container == 1) { + cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; + R._g.doc.body.appendChild(cnvs); + isFloating = 1; + } else { + cnvs.style.cssText = css + "position:relative"; + if (container.firstChild) { + container.insertBefore(cnvs, container.firstChild); } else { - if (this.transformations) { - this.transformations[2] = E; - this.node[setAttribute]("transform", this.transformations[join](S)); - a.fx = 0; - a.fy = 0; - } else { - this.node.filterMatrix = E; - s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E); - } + container.appendChild(cnvs); } - a.scale = [x, y, cx, cy][join](S); - this._.sx = x; - this._.sy = y; } + container = new R._Paper; + container.width = width; + container.height = height; + container.canvas = cnvs; + // plugins.call(container, container, R.fn); + container.clear(); + container._left = container._top = 0; + isFloating && (container.renderfix = function () {}); + container.renderfix(); + return container; + }; + R._engine.setViewBox = function (x, y, w, h, fit) { + eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); + var size = mmax(w / this.width, h / this.height), + top = this.top, + aspectRatio = fit ? "meet" : "xMinYMin", + vb, + sw; + if (x == null) { + if (this._vbSize) { + size = 1; + } + delete this._vbSize; + vb = "0 0 " + this.width + S + this.height; + } else { + this._vbSize = size; + vb = x + S + y + S + w + S + h; + } + $(this.canvas, { + viewBox: vb, + preserveAspectRatio: aspectRatio + }); + while (size && top) { + sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; + top.attr({"stroke-width": sw}); + top._.dirty = 1; + top._.dirtyT = 1; + top = top.prev; + } + this._viewBox = [x, y, w, h, !!fit]; return this; }; + + R.prototype.renderfix = function () { + var cnvs = this.canvas, + s = cnvs.style, + pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(), + left = -pos.e % 1, + top = -pos.f % 1; + if (left || top) { + if (left) { + this._left = (this._left + left) % 1; + s.left = this._left + "px"; + } + if (top) { + this._top = (this._top + top) % 1; + s.top = this._top + "px"; + } + } + }; + + R.prototype.clear = function () { + R.eve("clear", this); + var c = this.canvas; + while (c.firstChild) { + c.removeChild(c.firstChild); + } + this.bottom = this.top = null; + (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version)); + c.appendChild(this.desc); + c.appendChild(this.defs = $("defs")); + }; + + R.prototype.remove = function () { + eve("remove", this); + this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + }; + var setproto = R.st; + for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname].apply(el, arg); + }); + }; + })(method); + } +}(window.Raphael); - // animation easing formulas - R.easing_formulas = { - linear: function (n) { - return n; - }, - "<": function (n) { - return pow(n, 3); - }, - ">": function (n) { - return pow(n - 1, 3) + 1; - }, - "<>": function (n) { - n = n * 2; - if (n < 1) { - return pow(n, 3) / 2; +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ VML Module │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +window.Raphael.vml && function (R) { + var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + math = Math, + round = math.round, + mmax = math.max, + mmin = math.min, + abs = math.abs, + fillString = "fill", + separator = /[, ]+/, + eve = R.eve, + ms = " progid:DXImageTransform.Microsoft", + S = " ", + E = "", + map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, + bites = /([clmz]),?([^clmz]*)/gi, + blurregexp = / progid:\S+Blur\([^\)]+\)/g, + val = /-?[^,\s-]+/g, + cssDot = "position:absolute;left:0;top:0;width:1px;height:1px", + zoom = 21600, + pathTypes = {path: 1, rect: 1, image: 1}, + ovalTypes = {circle: 1, ellipse: 1}, + path2vml = function (path) { + var total = /[ahqstv]/ig, + command = R._pathToAbsolute; + Str(path).match(total) && (command = R._path2curve); + total = /[clmz]/g; + if (command == R._pathToAbsolute && !Str(path).match(total)) { + var res = Str(path).replace(bites, function (all, command, args) { + var vals = [], + isMove = command.toLowerCase() == "m", + res = map[command]; + args.replace(val, function (value) { + if (isMove && vals.length == 2) { + res += vals + map[command == "m" ? "l" : "L"]; + vals = []; + } + vals.push(round(value * zoom)); + }); + return res + vals; + }); + return res; } - n -= 2; - return (pow(n, 3) + 2) / 2; - }, - backIn: function (n) { - var s = 1.70158; - return n * n * ((s + 1) * n - s); + var pa = command(path), p, r; + res = []; + for (var i = 0, ii = pa.length; i < ii; i++) { + p = pa[i]; + r = pa[i][0].toLowerCase(); + r == "z" && (r = "x"); + for (var j = 1, jj = p.length; j < jj; j++) { + r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); + } + res.push(r); + } + return res.join(S); }, - backOut: function (n) { - n = n - 1; - var s = 1.70158; - return n * n * ((s + 1) * n + s) + 1; + compensation = function (deg, dx, dy) { + var m = R.matrix(); + m.rotate(-deg, .5, .5); + return { + dx: m.x(dx, dy), + dy: m.y(dx, dy) + }; }, - elastic: function (n) { - if (n == 0 || n == 1) { - return n; + setCoords = function (p, sx, sy, dx, dy, deg) { + var _ = p._, + m = p.matrix, + fillpos = _.fillpos, + o = p.node, + s = o.style, + y = 1, + flip = "", + dxdy, + kx = zoom / sx, + ky = zoom / sy; + s.visibility = "hidden"; + if (!sx || !sy) { + return; } - var p = .3, - s = p / 4; - return pow(2, -10 * n) * math.sin((n - s) * (2 * math.PI) / p) + 1; - }, - bounce: function (n) { - var s = 7.5625, - p = 2.75, - l; - if (n < (1 / p)) { - l = s * n * n; - } else { - if (n < (2 / p)) { - n -= (1.5 / p); - l = s * n * n + .75; - } else { - if (n < (2.5 / p)) { - n -= (2.25 / p); - l = s * n * n + .9375; - } else { - n -= (2.625 / p); - l = s * n * n + .984375; - } + o.coordsize = abs(kx) + S + abs(ky); + s.rotation = deg * (sx * sy < 0 ? -1 : 1); + if (deg) { + var c = compensation(deg, dx, dy); + dx = c.dx; + dy = c.dy; + } + sx < 0 && (flip += "x"); + sy < 0 && (flip += " y") && (y = -1); + s.flip = flip; + o.coordorigin = (dx * -kx) + S + (dy * -ky); + if (fillpos || _.fillsize) { + var fill = o.getElementsByTagName(fillString); + fill = fill && fill[0]; + o.removeChild(fill); + if (fillpos) { + c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); + fill.position = c.dx * y + S + c.dy * y; + } + if (_.fillsize) { + fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); } + o.appendChild(fill); } - return l; - } + s.visibility = "visible"; + }; + R.toString = function () { + return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; }; + var addArrow = function (o, value, isEnd) { + var values = Str(value).toLowerCase().split("-"), + se = isEnd ? "end" : "start", + i = values.length, + type = "classic", + w = "medium", + h = "medium"; + while (i--) { + switch (values[i]) { + case "block": + case "classic": + case "oval": + case "diamond": + case "open": + case "none": + type = values[i]; + break; + case "wide": + case "narrow": h = values[i]; break; + case "long": + case "short": w = values[i]; break; + } + } + var stroke = o.node.getElementsByTagName("stroke")[0]; + stroke[se + "arrow"] = type; + stroke[se + "arrowlength"] = w; + stroke[se + "arrowwidth"] = h; + }, + setFillAndStroke = function (o, params) { + // o.paper.canvas.style.display = "none"; + o.attrs = o.attrs || {}; + var node = o.node, + a = o.attrs, + s = node.style, + xy, + 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), + isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), + res = o; - var animationElements = {length : 0}, - animation = function () { - var Now = +new Date; - for (var l in animationElements) if (l != "length" && animationElements[has](l)) { - var e = animationElements[l]; - if (e.stop) { - delete animationElements[l]; - animationElements[length]--; - continue; + + for (var par in params) if (params[has](par)) { + a[par] = params[par]; + } + if (newpath) { + a.path = R._getPath[o.type](o); + o._.dirty = 1; + } + params.href && (node.href = params.href); + params.title && (node.title = params.title); + params.target && (node.target = params.target); + params.cursor && (s.cursor = params.cursor); + "blur" in params && o.blur(params.blur); + if (params.path && o.type == "path" || newpath) { + node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path); + if (o.type == "image") { + o._.fillpos = [a.x, a.y]; + o._.fillsize = [a.width, a.height]; + setCoords(o, 1, 1, 0, 0, 0); + } + } + "transform" in params && o.transform(params.transform); + if (isOval) { + var cx = +a.cx, + cy = +a.cy, + rx = +a.rx || +a.r || 0, + ry = +a.ry || +a.r || 0; + 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)); + } + if ("clip-rect" in params) { + var rect = Str(params["clip-rect"]).split(separator); + if (rect.length == 4) { + rect[2] = +rect[2] + (+rect[0]); + rect[3] = +rect[3] + (+rect[1]); + var div = node.clipRect || R._g.doc.createElement("div"), + dstyle = div.style; + dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); + if (!node.clipRect) { + dstyle.position = "absolute"; + dstyle.top = 0; + dstyle.left = 0; + dstyle.width = o.paper.width + "px"; + dstyle.height = o.paper.height + "px"; + node.parentNode.insertBefore(div, node); + div.appendChild(node); + node.clipRect = div; } - var time = Now - e.start, - ms = e.ms, - easing = e.easing, - from = e.from, - diff = e.diff, - to = e.to, - t = e.t, - prev = e.prev || 0, - that = e.el, - callback = e.callback, - set = {}, - now; - if (time < ms) { - var pos = R.easing_formulas[easing] ? R.easing_formulas[easing](time / ms) : time / ms; - for (var attr in from) if (from[has](attr)) { - switch (availableAnimAttrs[attr]) { - case "number": - now = +from[attr] + pos * ms * diff[attr]; - break; - case "colour": - now = "rgb(" + [ - upto255(round(from[attr].r + pos * ms * diff[attr].r)), - upto255(round(from[attr].g + pos * ms * diff[attr].g)), - upto255(round(from[attr].b + pos * ms * diff[attr].b)) - ][join](",") + ")"; - break; - case "path": - now = []; - for (var i = 0, ii = from[attr][length]; i < ii; i++) { - now[i] = [from[attr][i][0]]; - for (var j = 1, jj = from[attr][i][length]; j < jj; j++) { - now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; - } - now[i] = now[i][join](S); - } - now = now[join](S); - break; - case "csv": - switch (attr) { - case "translation": - var x = diff[attr][0] * (time - prev), - y = diff[attr][1] * (time - prev); - t.x += x; - t.y += y; - now = x + S + y; - break; - case "rotation": - now = +from[attr][0] + pos * ms * diff[attr][0]; - from[attr][1] && (now += "," + from[attr][1] + "," + from[attr][2]); - break; - case "scale": - now = [+from[attr][0] + pos * ms * diff[attr][0], +from[attr][1] + pos * ms * diff[attr][1], (2 in to[attr] ? to[attr][2] : E), (3 in to[attr] ? to[attr][3] : E)][join](S); - break; - case "clip-rect": - now = []; - var i = 4; - while (i--) { - now[i] = +from[attr][i] + pos * ms * diff[attr][i]; - } - break; - } - break; - } - set[attr] = now; - } - that.attr(set); - that._run && that._run.call(that); + } + if (!params["clip-rect"]) { + node.clipRect && (node.clipRect.style.clip = "auto"); + } + } + if (o.textpath) { + var textpathStyle = o.textpath.style; + params.font && (textpathStyle.font = params.font); + params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); + params["font-size"] && (textpathStyle.fontSize = params["font-size"]); + params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); + params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); + } + if ("arrow-start" in params) { + addArrow(res, params["arrow-start"]); + } + if ("arrow-end" in params) { + addArrow(res, params["arrow-end"], 1); + } + if (params.opacity != null || + params["stroke-width"] != null || + params.fill != null || + params.src != null || + params.stroke != null || + params["stroke-width"] != null || + params["stroke-opacity"] != null || + params["fill-opacity"] != null || + params["stroke-dasharray"] != null || + params["stroke-miterlimit"] != null || + params["stroke-linejoin"] != null || + params["stroke-linecap"] != null) { + var fill = node.getElementsByTagName(fillString), + newfill = false; + fill = fill && fill[0]; + !fill && (newfill = fill = createNode(fillString)); + if (o.type == "image" && params.src) { + fill.src = params.src; + } + params.fill && (fill.on = true); + if (fill.on == null || params.fill == "none" || params.fill === null) { + fill.on = false; + } + if (fill.on && params.fill) { + var isURL = Str(params.fill).match(R._ISURL); + if (isURL) { + fill.parentNode == node && node.removeChild(fill); + fill.rotate = true; + fill.src = isURL[1]; + fill.type = "tile"; + var bbox = o.getBBox(1); + fill.position = bbox.x + S + bbox.y; + o._.fillpos = [bbox.x, bbox.y]; + + R._preload(isURL[1], function () { + o._.fillsize = [this.offsetWidth, this.offsetHeight]; + }); } else { - (t.x || t.y) && that.translate(-t.x, -t.y); - to.scale && (to.scale = to.scale + E); - that.attr(to); - delete animationElements[l]; - animationElements[length]--; - that.in_animation = null; - R.is(callback, "function") && callback.call(that); + fill.color = R.getRGB(params.fill).hex; + fill.src = E; + fill.type = "solid"; + if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { + a.fill = "none"; + a.gradient = params.fill; + fill.rotate = false; + } } - e.prev = time; } - R.svg && paper.safari(); - animationElements[length] && setTimeout(animation); - }, - upto255 = function (color) { - return color > 255 ? 255 : (color < 0 ? 0 : color); - }, - translate = function (x, y) { - if (x == null) { - return {x: this._.tx, y: this._.ty}; - } - this._.tx += +x; - this._.ty += +y; - switch (this.type) { - case "circle": - case "ellipse": - this.attr({cx: +x + this.attrs.cx, cy: +y + this.attrs.cy}); - break; - case "rect": - case "image": - case "text": - this.attr({x: +x + this.attrs.x, y: +y + this.attrs.y}); - break; - case "path": - var path = pathToRelative(this.attrs.path); - path[0][1] += +x; - path[0][2] += +y; - this.attr({path: path}); + if ("fill-opacity" in params || "opacity" in params) { + var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); + opacity = mmin(mmax(opacity, 0), 1); + fill.opacity = opacity; + if (fill.src) { + fill.color = "none"; + } + } + node.appendChild(fill); + var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), + newstroke = false; + !stroke && (newstroke = stroke = createNode("stroke")); + if ((params.stroke && params.stroke != "none") || + params["stroke-width"] || + params["stroke-opacity"] != null || + params["stroke-dasharray"] || + params["stroke-miterlimit"] || + params["stroke-linejoin"] || + params["stroke-linecap"]) { + stroke.on = true; + } + (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); + var strokeColor = R.getRGB(params.stroke); + stroke.on && params.stroke && (stroke.color = strokeColor.hex); + opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); + var width = (toFloat(params["stroke-width"]) || 1) * .75; + opacity = mmin(mmax(opacity, 0), 1); + params["stroke-width"] == null && (width = a["stroke-width"]); + params["stroke-width"] && (stroke.weight = width); + width && width < 1 && (opacity *= width) && (stroke.weight = 1); + stroke.opacity = opacity; + + params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); + stroke.miterlimit = params["stroke-miterlimit"] || 8; + params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); + if (params["stroke-dasharray"]) { + var dasharray = { + "-": "shortdash", + ".": "shortdot", + "-.": "shortdashdot", + "-..": "shortdashdotdot", + ". ": "dot", + "- ": "dash", + "--": "longdash", + "- .": "dashdot", + "--.": "longdashdot", + "--..": "longdashdotdot" + }; + stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; + } + newstroke && node.appendChild(stroke); + } + if (res.type == "text") { + res.paper.canvas.style.display = E; + var span = res.paper.span, + m = 100, + fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); + s = span.style; + a.font && (s.font = a.font); + a["font-family"] && (s.fontFamily = a["font-family"]); + a["font-weight"] && (s.fontWeight = a["font-weight"]); + a["font-style"] && (s.fontStyle = a["font-style"]); + fontSize = toFloat(a["font-size"] || fontSize && fontSize[0]) || 10; + s.fontSize = fontSize * m + "px"; + res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/")); + var brect = span.getBoundingClientRect(); + res.W = a.w = (brect.right - brect.left) / m; + res.H = a.h = (brect.bottom - brect.top) / m; + // res.paper.canvas.style.display = "none"; + res.X = a.x; + res.Y = a.y + res.H / 2; + + ("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)); + var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; + for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { + res._.dirty = 1; break; } - return this; + + // text-anchor emulation + switch (a["text-anchor"]) { + case "start": + res.textpath.style["v-text-align"] = "left"; + res.bbx = res.W / 2; + break; + case "end": + res.textpath.style["v-text-align"] = "right"; + res.bbx = -res.W / 2; + break; + default: + res.textpath.style["v-text-align"] = "center"; + res.bbx = 0; + break; + } + res.textpath.style["v-text-kern"] = true; + } + // res.paper.canvas.style.display = E; + }, + addGradientFill = function (o, gradient, fill) { + o.attrs = o.attrs || {}; + var attrs = o.attrs, + pow = Math.pow, + opacity, + oindex, + type = "linear", + fxfy = ".5 .5"; + o.attrs.gradient = gradient; + gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) { + type = "radial"; + if (fx && fy) { + fx = toFloat(fx); + fy = toFloat(fy); + pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); + fxfy = fx + S + fy; + } + return E; + }); + gradient = gradient.split(/\s*\-\s*/); + if (type == "linear") { + var angle = gradient.shift(); + angle = -toFloat(angle); + if (isNaN(angle)) { + return null; + } + } + var dots = R._parseDots(gradient); + if (!dots) { + return null; + } + o = o.shape || o.node; + if (dots.length) { + o.removeChild(fill); + fill.on = true; + fill.method = "none"; + fill.color = dots[0].color; + fill.color2 = dots[dots.length - 1].color; + var clrs = []; + for (var i = 0, ii = dots.length; i < ii; i++) { + dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); + } + fill.colors = clrs.length ? clrs.join() : "0% " + fill.color; + if (type == "radial") { + fill.type = "gradientTitle"; + fill.focus = "100%"; + fill.focussize = "0 0"; + fill.focusposition = fxfy; + fill.angle = 0; + } else { + // fill.rotate= true; + fill.type = "gradient"; + fill.angle = (270 - angle) % 360; + } + o.appendChild(fill); + } + return 1; + }, + Element = function (node, vml) { + this[0] = this.node = node; + node.raphael = true; + this.id = R._oid++; + node.raphaelid = this.id; + this.X = 0; + this.Y = 0; + this.attrs = {}; + this.paper = vml; + this.matrix = R.matrix(); + this._ = { + transform: [], + sx: 1, + sy: 1, + dx: 0, + dy: 0, + deg: 0, + dirty: 1, + dirtyT: 1 }; - Element[proto].animateWith = function (element, params, ms, easing, callback) { - animationElements[element.id] && (params.start = animationElements[element.id].start); - return this.animate(params, ms, easing, callback); + !vml.bottom && (vml.bottom = this); + this.prev = vml.top; + vml.top && (vml.top.next = this); + vml.top = this; + this.next = null; }; - Element[proto].onAnimation = function (f) { - this._run = f || null; + var elproto = R.el; + + Element.prototype = elproto; + elproto.constructor = Element; + elproto.transform = function (tstr) { + if (tstr == null) { + return this._.transform; + } + var vbs = this.paper._viewBoxShift, + vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E, + oldt; + if (vbs) { + oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E); + } + R._extractTransform(this, vbt + tstr); + var matrix = this.matrix.clone(), + skew = this.skew, + o = this.node, + split, + isGrad = ~Str(this.attrs.fill).indexOf("-"), + isPatt = !Str(this.attrs.fill).indexOf("url("); + matrix.translate(-.5, -.5); + if (isPatt || isGrad || this.type == "image") { + skew.matrix = "1 0 0 1"; + skew.offset = "0 0"; + split = matrix.split(); + if ((isGrad && split.noRotation) || !split.isSimple) { + o.style.filter = matrix.toFilter(); + var bb = this.getBBox(), + bbt = this.getBBox(1), + dx = bb.x - bbt.x, + dy = bb.y - bbt.y; + o.coordorigin = (dx * -zoom) + S + (dy * -zoom); + setCoords(this, 1, 1, dx, dy, 0); + } else { + o.style.filter = E; + setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate); + } + } else { + o.style.filter = E; + skew.matrix = Str(matrix); + skew.offset = matrix.offset(); + } + oldt && (this._.transform = oldt); return this; }; - Element[proto].animate = function (params, ms, easing, callback) { - if (R.is(easing, "function") || !easing) { - callback = easing || null; + elproto.rotate = function (deg, cx, cy) { + if (this.removed) { + return this; } - var from = {}, - to = {}, - diff = {}; - for (var attr in params) if (params[has](attr)) { - if (availableAnimAttrs[has](attr)) { - from[attr] = this.attr(attr); - (from[attr] == null) && (from[attr] = availableAttrs[attr]); - to[attr] = params[attr]; - switch (availableAnimAttrs[attr]) { - case "number": - diff[attr] = (to[attr] - from[attr]) / ms; - break; - case "colour": - from[attr] = R.getRGB(from[attr]); - var toColour = R.getRGB(to[attr]); - diff[attr] = { - r: (toColour.r - from[attr].r) / ms, - g: (toColour.g - from[attr].g) / ms, - b: (toColour.b - from[attr].b) / ms - }; - break; - case "path": - var pathes = path2curve(from[attr], to[attr]); - from[attr] = pathes[0]; - to[attr] = pathes[1]; - diff[attr] = []; - for (var i = 0, ii = from[attr][length]; i < ii; i++) { - diff[attr][i] = [0]; - for (var j = 1, jj = from[attr][i][length]; j < jj; j++) { - diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; - } - } - break; - case "csv": - var values = (params[attr] + E)[split](separator), - from2 = (from[attr] + E)[split](separator); - switch (attr) { - case "translation": - from[attr] = [0, 0]; - diff[attr] = [values[0] / ms, values[1] / ms]; - break; - case "rotation": - from[attr] = (from2[1] == values[1] && from2[2] == values[2]) ? from2 : [0, values[1], values[2]]; - diff[attr] = [(values[0] - from[attr][0]) / ms, 0, 0]; - break; - case "scale": - params[attr] = values; - from[attr] = (from[attr] + E)[split](separator); - diff[attr] = [(values[0] - from[attr][0]) / ms, (values[1] - from[attr][1]) / ms, 0, 0]; - break; - case "clip-rect": - from[attr] = (from[attr] + E)[split](separator); - diff[attr] = []; - var i = 4; - while (i--) { - diff[attr][i] = (values[i] - from[attr][i]) / ms; - } - break; - } - to[attr] = values; - } - } - } - this.stop(); - this.in_animation = 1; - animationElements[this.id] = { - start: params.start || +new Date, - ms: ms, - easing: easing, - from: from, - diff: diff, - to: to, - el: this, - callback: callback, - t: {x: 0, y: 0} - }; - ++animationElements[length] == 1 && animation(); + if (deg == null) { + return; + } + deg = Str(deg).split(separator); + if (deg.length - 1) { + cx = toFloat(deg[1]); + cy = toFloat(deg[2]); + } + deg = toFloat(deg[0]); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + cx = bbox.x + bbox.width / 2; + cy = bbox.y + bbox.height / 2; + } + this._.dirtyT = 1; + this.transform(this._.transform.concat([["r", deg, cx, cy]])); + return this; + }; + elproto.translate = function (dx, dy) { + if (this.removed) { + return this; + } + dx = Str(dx).split(separator); + if (dx.length - 1) { + dy = toFloat(dx[1]); + } + dx = toFloat(dx[0]) || 0; + dy = +dy || 0; + if (this._.bbox) { + this._.bbox.x += dx; + this._.bbox.y += dy; + } + this.transform(this._.transform.concat([["t", dx, dy]])); + return this; + }; + elproto.scale = function (sx, sy, cx, cy) { + if (this.removed) { + return this; + } + sx = Str(sx).split(separator); + if (sx.length - 1) { + sy = toFloat(sx[1]); + cx = toFloat(sx[2]); + cy = toFloat(sx[3]); + isNaN(cx) && (cx = null); + isNaN(cy) && (cy = null); + } + sx = toFloat(sx[0]); + (sy == null) && (sy = sx); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + } + cx = cx == null ? bbox.x + bbox.width / 2 : cx; + cy = cy == null ? bbox.y + bbox.height / 2 : cy; + + this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); + this._.dirtyT = 1; return this; }; - Element[proto].stop = function () { - animationElements[this.id] && animationElements[length]--; - delete animationElements[this.id]; + elproto.hide = function () { + !this.removed && (this.node.style.display = "none"); return this; }; - Element[proto].translate = function (x, y) { - return this.attr({translation: x + " " + y}); + elproto.show = function () { + !this.removed && (this.node.style.display = E); + return this; }; - Element[proto][toString] = function () { - return "Rapha\xebl\u2019s object"; + elproto._getBBox = function () { + if (this.removed) { + return {}; + } + return { + x: this.X + (this.bbx || 0) - this.W / 2, + y: this.Y - this.H, + width: this.W, + height: this.H + }; }; - R.ae = animationElements; - - // Set - var Set = function (items) { - this.items = []; - this[length] = 0; - if (items) { - for (var i = 0, ii = items[length]; i < ii; i++) { - if (items[i] && (items[i].constructor == Element || items[i].constructor == Set)) { - this[this.items[length]] = this.items[this.items[length]] = items[i]; - this[length]++; + elproto.remove = function () { + if (this.removed) { + return; + } + this.paper.__set__ && this.paper.__set__.exclude(this); + R.eve.unbind("*.*." + this.id); + R._tear(this, this.paper); + this.node.parentNode.removeChild(this.node); + this.shape && this.shape.parentNode.removeChild(this.shape); + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + this.removed = true; + }; + elproto.attr = function (name, value) { + if (this.removed) { + return this; + } + if (name == null) { + var res = {}; + for (var a in this.attrs) if (this.attrs[has](a)) { + res[a] = this.attrs[a]; + } + res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; + res.transform = this._.transform; + return res; + } + if (value == null && R.is(name, "string")) { + if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { + return this.attrs.gradient; + } + var names = name.split(separator), + out = {}; + for (var i = 0, ii = names.length; i < ii; i++) { + name = names[i]; + if (name in this.attrs) { + out[name] = this.attrs[name]; + } else if (R.is(this.paper.customAttributes[name], "function")) { + out[name] = this.paper.customAttributes[name].def; + } else { + out[name] = R._availableAttrs[name]; } } + return ii - 1 ? out : out[names[0]]; } - }; - Set[proto][push] = function () { - var item, - len; - for (var i = 0, ii = arguments[length]; i < ii; i++) { - item = arguments[i]; - if (item && (item.constructor == Element || item.constructor == Set)) { - len = this.items[length]; - this[len] = this.items[len] = item; - this[length]++; + if (this.attrs && value == null && R.is(name, "array")) { + out = {}; + for (i = 0, ii = name.length; i < ii; i++) { + out[name[i]] = this.attr(name[i]); } + return out; } - return this; - }; - Set[proto].pop = function () { - delete this[this[length]--]; - return this.items.pop(); - }; - for (var method in Element[proto]) if (Element[proto][has](method)) { - Set[proto][method] = (function (methodname) { - return function () { - for (var i = 0, ii = this.items[length]; i < ii; i++) { - this.items[i][methodname][apply](this.items[i], arguments); + var params; + if (value != null) { + params = {}; + params[name] = value; + } + value == null && R.is(name, "object") && (params = name); + for (var key in params) { + eve("attr." + key + "." + this.id, this, params[key]); + } + if (params) { + for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { + var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); + this.attrs[key] = params[key]; + for (var subkey in par) if (par[has](subkey)) { + params[subkey] = par[subkey]; } - return this; - }; - })(method); - } - Set[proto].attr = function (name, value) { - if (name && R.is(name, "array") && R.is(name[0], "object")) { - for (var j = 0, jj = name[length]; j < jj; j++) { - this.items[j].attr(name[j]); } - } else { - for (var i = 0, ii = this.items[length]; i < ii; i++) { - this.items[i].attr[apply](this.items[i], arguments); + // this.paper.canvas.style.display = "none"; + if (params.text && this.type == "text") { + this.textpath.string = params.text; } + setFillAndStroke(this, params); + // this.paper.canvas.style.display = E; } return this; }; - Set[proto].animate = function (params, ms, easing, callback) { - (R.is(easing, "function") || !easing) && (callback = easing || null); - var len = this.items[length], - i = len, - set = this, - collector; - callback && (collector = function () { - !--len && callback.call(set); - }); - this.items[--i].animate(params, ms, easing || collector, collector); - while (i--) { - this.items[i].animateWith(this.items[len - 1], params, ms, easing || collector, collector); - } + elproto.toFront = function () { + !this.removed && this.node.parentNode.appendChild(this.node); + this.paper && this.paper.top != this && R._tofront(this, this.paper); return this; }; - Set[proto].insertAfter = function (el) { - var i = this.items[length]; - while (i--) { - this.items[i].insertAfter(el); + elproto.toBack = function () { + if (this.removed) { + return this; + } + if (this.node.parentNode.firstChild != this.node) { + this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); + R._toback(this, this.paper); } return this; }; - Set[proto].getBBox = function () { - var x = [], - y = [], - w = [], - h = []; - for (var i = this.items[length]; i--;) { - var box = this.items[i].getBBox(); - x[push](box.x); - y[push](box.y); - w[push](box.x + box.width); - h[push](box.y + box.height); + elproto.insertAfter = function (element) { + if (this.removed) { + return this; } - x = mmin[apply](0, x); - y = mmin[apply](0, y); - return { - x: x, - y: y, - width: mmax[apply](0, w) - x, - height: mmax[apply](0, h) - y - }; + if (element.constructor == R.st.constructor) { + element = element[element.length - 1]; + } + if (element.node.nextSibling) { + element.node.parentNode.insertBefore(this.node, element.node.nextSibling); + } else { + element.node.parentNode.appendChild(this.node); + } + R._insertafter(this, element, this.paper); + return this; }; - - R.registerFont = function (font) { - if (!font.face) { - return font; + elproto.insertBefore = function (element) { + if (this.removed) { + return this; } - this.fonts = this.fonts || {}; - var fontcopy = { - w: font.w, - face: {}, - glyphs: {} - }, - family = font.face["font-family"]; - for (var prop in font.face) if (font.face[has](prop)) { - fontcopy.face[prop] = font.face[prop]; + if (element.constructor == R.st.constructor) { + element = element[0]; } - if (this.fonts[family]) { - this.fonts[family][push](fontcopy); + element.node.parentNode.insertBefore(this.node, element.node); + R._insertbefore(this, element, this.paper); + return this; + }; + elproto.blur = function (size) { + var s = this.node.runtimeStyle, + f = s.filter; + f = f.replace(blurregexp, E); + if (+size !== 0) { + this.attrs.blur = size; + s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; + s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); } else { - this.fonts[family] = [fontcopy]; + s.filter = f; + s.margin = 0; + delete this.attrs.blur; } - if (!font.svg) { - fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); - for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { - var path = font.glyphs[glyph]; - fontcopy.glyphs[glyph] = { - w: path.w, - k: {}, - d: path.d && "M" + path.d[rp](/[mlcxtrv]/g, function (command) { - return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; - }) + "z" - }; - if (path.k) { - for (var k in path.k) if (path[has](k)) { - fontcopy.glyphs[glyph].k[k] = path.k[k]; - } - } - } + }; + + R._engine.path = function (pathString, vml) { + var el = createNode("shape"); + el.style.cssText = cssDot; + el.coordsize = zoom + S + zoom; + el.coordorigin = vml.coordorigin; + var p = new Element(el, vml), + attr = {fill: "none", stroke: "#000"}; + pathString && (attr.path = pathString); + p.type = "path"; + p.path = []; + p.Path = E; + setFillAndStroke(p, attr); + vml.canvas.appendChild(el); + var skew = createNode("skew"); + skew.on = true; + el.appendChild(skew); + p.skew = skew; + p.transform(E); + return p; + }; + R._engine.rect = function (vml, x, y, w, h, r) { + var path = R._rectPath(x, y, w, h, r), + res = vml.path(path), + a = res.attrs; + res.X = a.x = x; + res.Y = a.y = y; + res.W = a.width = w; + res.H = a.height = h; + a.r = r; + a.path = path; + res.type = "rect"; + return res; + }; + R._engine.ellipse = function (vml, x, y, rx, ry) { + var res = vml.path(), + a = res.attrs; + res.X = x - rx; + res.Y = y - ry; + res.W = rx * 2; + res.H = ry * 2; + res.type = "ellipse"; + setFillAndStroke(res, { + cx: x, + cy: y, + rx: rx, + ry: ry + }); + return res; + }; + R._engine.circle = function (vml, x, y, r) { + var res = vml.path(), + a = res.attrs; + res.X = x - r; + res.Y = y - r; + res.W = res.H = r * 2; + res.type = "circle"; + setFillAndStroke(res, { + cx: x, + cy: y, + r: r + }); + return res; + }; + R._engine.image = function (vml, src, x, y, w, h) { + var path = R._rectPath(x, y, w, h), + res = vml.path(path).attr({stroke: "none"}), + a = res.attrs, + node = res.node, + fill = node.getElementsByTagName(fillString)[0]; + a.src = src; + res.X = a.x = x; + res.Y = a.y = y; + res.W = a.width = w; + res.H = a.height = h; + a.path = path; + res.type = "image"; + fill.parentNode == node && node.removeChild(fill); + fill.rotate = true; + fill.src = src; + fill.type = "tile"; + res._.fillpos = [x, y]; + res._.fillsize = [w, h]; + node.appendChild(fill); + setCoords(res, 1, 1, 0, 0, 0); + return res; + }; + R._engine.text = function (vml, x, y, text) { + var el = createNode("shape"), + path = createNode("path"), + o = createNode("textpath"); + x = x || 0; + y = y || 0; + text = text || ""; + path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); + path.textpathok = true; + o.string = Str(text); + o.on = true; + el.style.cssText = cssDot; + el.coordsize = zoom + S + zoom; + el.coordorigin = "0 0"; + var p = new Element(el, vml), + attr = { + fill: "#000", + stroke: "none", + font: R._availableAttrs.font, + text: text + }; + p.shape = el; + p.path = path; + p.textpath = o; + p.type = "text"; + p.attrs.text = Str(text); + p.attrs.x = x; + p.attrs.y = y; + p.attrs.w = 1; + p.attrs.h = 1; + setFillAndStroke(p, attr); + el.appendChild(o); + el.appendChild(path); + vml.canvas.appendChild(el); + var skew = createNode("skew"); + skew.on = true; + el.appendChild(skew); + p.skew = skew; + p.transform(E); + return p; + }; + R._engine.setSize = function (width, height) { + var cs = this.canvas.style; + this.width = width; + this.height = height; + width == +width && (width += "px"); + height == +height && (height += "px"); + cs.width = width; + cs.height = height; + cs.clip = "rect(0 " + width + " " + height + " 0)"; + if (this._viewBox) { + R._engine.setViewBox.apply(this, this._viewBox); } - return font; + return this; }; - paper.getFont = function (family, weight, style, stretch) { - stretch = stretch || "normal"; - style = style || "normal"; - weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; - var font = R.fonts[family]; - if (!font) { - var name = new RegExp("(^|\\s)" + family[rp](/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); - for (var fontName in R.fonts) if (R.fonts[has](fontName)) { - if (name.test(fontName)) { - font = R.fonts[fontName]; - break; - } + R._engine.setViewBox = function (x, y, w, h, fit) { + R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); + var width = this.width, + height = this.height, + size = 1 / mmax(w / width, h / height), + H, W; + if (fit) { + H = height / h; + W = width / w; + if (w * H < width) { + x -= (width - w * H) / 2 / H; } - } - var thefont; - if (font) { - for (var i = 0, ii = font[length]; i < ii; i++) { - thefont = font[i]; - if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { - break; - } + if (h * W < height) { + y -= (height - h * W) / 2 / W; } } - return thefont; + this._viewBox = [x, y, w, h, !!fit]; + this._viewBoxShift = { + dx: -x, + dy: -y, + scale: size + }; + this.forEach(function (el) { + el.transform("..."); + }); + return this; }; - paper.print = function (x, y, string, font, size, origin) { - origin = origin || "middle"; // baseline|middle - var out = this.set(), - letters = (string + E)[split](E), - shift = 0, - path = E, - scale; - R.is(font, "string") && (font = this.getFont(font)); - if (font) { - scale = (size || 16) / font.face["units-per-em"]; - var bb = font.face.bbox.split(separator), - top = +bb[0], - height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2); - for (var i = 0, ii = letters[length]; i < ii; i++) { - var prev = i && font.glyphs[letters[i - 1]] || {}, - curr = font.glyphs[letters[i]]; - shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) : 0; - curr && curr.d && out[push](this.path(curr.d).attr({fill: "#000", stroke: "none", translation: [shift, 0]})); + var createNode; + R._engine.initWin = function (win) { + var doc = win.document; + doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); + try { + !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); + createNode = function (tagName) { + return doc.createElement(''); + }; + } catch (e) { + createNode = function (tagName) { + return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); + }; } - out.scale(scale, scale, top, height).translate(x - top, y - height); + }; + R._engine.initWin(R._g.win); + R._engine.create = function () { + var con = R._getContainer.apply(0, arguments), + container = con.container, + height = con.height, + s, + width = con.width, + x = con.x, + y = con.y; + if (!container) { + throw new Error("VML container not found."); } - return out; - }; - - R.format = function (token) { - var args = R.is(arguments[1], "array") ? [0][concat](arguments[1]) : arguments, - rg = /\{(\d+)\}/g; - token && R.is(token, "string") && args[length] - 1 && (token = token[rp](rg, function (str, i) { - return args[++i] == null ? E : args[i]; - })); - return token || E; - }; - R.ninja = function () { - var r = win.Raphael, u; - if (oldRaphael.was) { - win.Raphael = oldRaphael.is; + var res = new R._Paper, + c = res.canvas = R._g.doc.createElement("div"), + cs = c.style; + x = x || 0; + y = y || 0; + width = width || 512; + height = height || 342; + res.width = width; + res.height = height; + width == +width && (width += "px"); + height == +height && (height += "px"); + res.coordsize = zoom * 1e3 + S + zoom * 1e3; + res.coordorigin = "0 0"; + res.span = R._g.doc.createElement("span"); + res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; + c.appendChild(res.span); + 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); + if (container == 1) { + R._g.doc.body.appendChild(c); + cs.left = x + "px"; + cs.top = y + "px"; + cs.position = "absolute"; } else { - try { - delete win.Raphael; - } catch (e) { - win.Raphael = u; + if (container.firstChild) { + container.insertBefore(c, container.firstChild); + } else { + container.appendChild(c); } } - return r; + // plugins.call(res, res, R.fn); + res.renderfix = function () {}; + return res; + }; + R.prototype.clear = function () { + R.eve("clear", this); + this.canvas.innerHTML = E; + this.span = R._g.doc.createElement("span"); + this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; + this.canvas.appendChild(this.span); + this.bottom = this.top = null; + }; + R.prototype.remove = function () { + R.eve("remove", this); + this.canvas.parentNode.removeChild(this.canvas); + for (var i in this) { + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; + } + return true; }; - R.el = Element[proto]; - return R; -})(); \ No newline at end of file + + var setproto = R.st; + for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname].apply(el, arg); + }); + }; + })(method); + } +}(window.Raphael); \ No newline at end of file