X-Git-Url: http://git.roojs.org/?a=blobdiff_plain;f=raphael.js;h=491bbba049fd454dc8c5e9423ccd79311ddcc80e;hb=51fbd073d70031550bade816d876f498e1ff3aa1;hp=91e8ee6ddb17eb1fe7f59bd14255ecb9eeacaf93;hpb=f7cbfd3ddb54c2f5fd8962e85168b023d87be025;p=raphael diff --git a/raphael.js b/raphael.js index 91e8ee6..491bbba 100644 --- a/raphael.js +++ b/raphael.js @@ -1,76 +1,240 @@ // ┌─────────────────────────────────────────────────────────────────────┐ \\ -// │ Raphaël 2 - JavaScript Vector Library │ \\ +// │ 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. │ \\ +// └──────────────────────────────────────────────────────────────────────────────────────┘ \\ + +(function (glob) { + var version = "0.4.0", + has = "hasOwnProperty", + separator = /[\.\/]/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + 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]; + } + } + 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 () { - /*\ - * Raphael - [ method ] - ** - * Creates a canvas object on which to draw. - * You must do this first, as all future calls to drawing methods - * from this instance will be bound to this canvas. - > Parameters - ** - - container (HTMLElement|string) DOM element or its ID which is going to be a parent for drawing surface - - width (number) - - height (number) - - callback (function) #optional callback function which is going to be executed in the context of newly created paper - * or - - x (number) - - y (number) - - width (number) - - height (number) - - callback (function) #optional callback function which is going to be executed in the context of newly created paper - * or - - all (array) (first 3 or 4 elements in the array are equal to [containerID, width, height] or [x, y, width, height]. The rest are element descriptions in format {type: type, }) - - callback (function) #optional callback function which is going to be executed in the context of newly created paper - * or - - onReadyCallback (function) function that is going to be called on DOM ready event. You can also subscribe to this event via Eve’s “DOMLoad” event. In this case method returns `undefined`. - = (object) @Paper - > Usage - | // Each of the following examples create a canvas - | // that is 320px wide by 200px high. - | // Canvas is created at the viewport’s 10,50 coordinate. - | var paper = Raphael(10, 50, 320, 200); - | // Canvas is created at the top left corner of the #notepad element - | // (or its top right corner in dir="rtl" elements) - | var paper = Raphael(document.getElementById("notepad"), 320, 200); - | // Same as above - | var paper = Raphael("notepad", 320, 200); - | // Image dump - | var set = Raphael(["notepad", 320, 200, { - | type: "rect", - | x: 10, - | y: 10, - | width: 25, - | height: 25, - | stroke: "#f00" - | }, { - | type: "text", - | x: 30, - | y: 40, - | text: "Dump" - | }]); - \*/ + function R(first) { if (R.is(first, "function")) { return loaded ? first() : eve.on("DOMload", first); } else if (R.is(first, array)) { - var a = first, - cnv = R._engine.create[apply](R, a.splice(0, 3 + R.is(a[0], nu))), - res = cnv.set(), - i = 0, - ii = a.length, - j; - for (; i < ii; i++) { - j = a[i] || {}; - elements[has](j.type) && res.push(cnv[j.type]().attr(j)); - } - return res; + 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")) { @@ -83,7 +247,8 @@ } } } - R.version = "2.0.0"; + R.version = "2.0.1"; + R.eve = eve; var loaded, separator = /[, ]+/, elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1}, @@ -98,7 +263,11 @@ was: Object.prototype[has].call(g.win, "Raphael"), is: g.win.Raphael }, - Paper = function () {}, + Paper = function () { + + + this.ca = this.customAttributes = {}; + }, paperproto, appendChild = "appendChild", apply = "apply", @@ -108,7 +277,7 @@ S = " ", Str = String, split = "split", - events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend orientationchange touchcancel gesturestart gesturechange gestureend".split(S), + events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S), touchMap = { mousedown: "touchstart", mousemove: "touchmove", @@ -130,14 +299,13 @@ paper = {}, push = "push", 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, + 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", toFloat = parseFloat, toInt = parseInt, - ms = " progid:DXImageTransform.Microsoft", upperCase = Str.prototype.toUpperCase, availableAttrs = R._availableAttrs = { "arrow-end": "none", @@ -157,6 +325,7 @@ gradient: 0, height: 0, href: "http://raphaeljs.com/", + "letter-spacing": 0, opacity: 1, path: "M0,0", r: 0, @@ -203,15 +372,16 @@ commaSpaces = /\s*,\s*/, hsrg = {hs: 1, rg: 1}, p2s = /,?([achlmqrstvxz]),?/gi, - pathCommand = /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig, + 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 a - b; + return toFloat(a) - toFloat(b); }, fun = function () {}, pipe = function (x) { @@ -254,11 +424,11 @@ return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); } }, - mapPath = function (path, matrix) { + mapPath = R.mapPath = function (path, matrix) { if (!matrix) { return path; } - var x, y, i, j, pathi; + var x, y, i, j, ii, jj, pathi; path = path2curve(path); for (i = 0, ii = path.length; i < ii; i++) { pathi = path[i]; @@ -273,12 +443,7 @@ }; R._g = g; - /*\ - * Raphael.type - [ property (string) ] - ** - * Can be “SVG”, “VML” or empty, depending on browser support. - \*/ + 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"), @@ -291,85 +456,15 @@ } d = null; } - /*\ - * Raphael.svg - [ property (boolean) ] - ** - * `true` if browser supports SVG. - \*/ - /*\ - * Raphael.vml - [ property (boolean) ] - ** - * `true` if browser supports VML. - \*/ + + R.svg = !(R.vml = R.type == "VML"); R._Paper = Paper; - /*\ - * Raphael.fn - [ property (object) ] - ** - * You can add your own method to the canvas. For example if you want to draw a pie chart, - * you can create your own pie chart function and ship it as a Raphaël plugin. To do this - * you need to extend the `Raphael.fn` object. Please note that you can create your own namespaces - * inside the `fn` object — methods will be run in the context of canvas anyway. You should alter - * the `fn` object before a Raphaël instance is created, otherwise it will take no effect. - > Usage - | Raphael.fn.arrow = function (x1, y1, x2, y2, size) { - | return this.path( ... ); - | }; - | // or create namespace - | Raphael.fn.mystuff = { - | arrow: function () {…}, - | star: function () {…}, - | // etc… - | }; - | var paper = Raphael(10, 10, 630, 480); - | // then use it - | paper.arrow(10, 10, 30, 30, 5).attr({fill: "#f00"}); - | paper.mystuff.arrow(); - | paper.mystuff.star(); - \*/ + R.fn = paperproto = Paper.prototype = R.prototype; - /*\ - * Paper.customAttributes - [ property (object) ] - ** - * If you have a set of attributes that you would like to represent - * as a function of some number you can do it easily with custom attributes: - > Usage - | paper.customAttributes.hue = function (num) { - | num = num % 1; - | return {fill: "hsb(" + num + ", .75, 1)"}; - | }; - | // Custom attribute “hue” will change fill - | // to be given hue with fixed saturation and brightness. - | // Now you can use it like this: - | var c = paper.circle(10, 10, 10).attr({hue: .45}); - | // or even like this: - | c.animate({hue: 1}, 1e3); - | - | // You could also create custom attribute - | // with multiple parameters: - | paper.customAttributes.hsb = function (h, s, b) { - | return {fill: "hsb(" + [h, s, b].join(",") + ")"}; - | }; - | c.attr({hsb: ".5 .8 1"}); - | c.animate({hsb: "1 0 .5"}, 1e3); - \*/ - paperproto.customAttributes = {}; R._id = 0; R._oid = 0; - /*\ - * Raphael.is - [ method ] - ** - * Handfull replacement for `typeof` operator. - > Parameters - - o (…) any object or primitive - - type (string) name of the type, i.e. “string”, “function”, “number”, etc. - = (boolean) is given value is of given type - \*/ + R.is = function (o, type) { type = lowerCase.call(type); if (type == "finite") { @@ -379,25 +474,12 @@ return o instanceof Array; } return (type == "null" && o === null) || - (type == typeof o) || + (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; }; - /*\ - * Raphael.angle - [ method ] - ** - * Returns angle between two or three points - > Parameters - - x1 (number) x coord of first point - - y1 (number) y coord of first point - - x2 (number) x coord of second point - - y2 (number) y coord of second point - - x3 (number) #optional x coord of third point - - y3 (number) #optional y coord of third point - = (number) angle in degrees. - \*/ + R.angle = function (x1, y1, x2, y2, x3, y3) { if (x3 == null) { var x = x1 - x2, @@ -410,41 +492,15 @@ return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3); } }; - /*\ - * Raphael.rad - [ method ] - ** - * Transform angle to radians - > Parameters - - deg (number) angle in degrees - = (number) angle in radians. - \*/ + R.rad = function (deg) { return deg % 360 * PI / 180; }; - /*\ - * Raphael.deg - [ method ] - ** - * Transform angle to degrees - > Parameters - - deg (number) angle in radians - = (number) angle in degrees. - \*/ + R.deg = function (rad) { return rad * 180 / PI % 360; }; - /*\ - * Raphael.snapTo - [ method ] - ** - * Snaps given value to given grid. - > Parameters - - values (array|number) given array of values or step of the grid - - value (number) value to adjust - - tolerance (number) #optional tolerance for snapping. Default is `10`. - = (number) adjusted value. - \*/ + R.snapTo = function (values, value, tolerance) { tolerance = R.is(tolerance, "finite") ? tolerance : 10; if (R.is(values, array)) { @@ -465,7 +521,8 @@ return value; }; - var createUUID = R._createUUID = (function (uuidRegEx, uuidReplacer) { + + var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { return function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); }; @@ -475,23 +532,15 @@ return v.toString(16); }); - /*\ - * Raphael.setWindow - [ method ] - ** - * Used when you need to draw in `<iframe>`. Switched window to the iframe one. - > Parameters - - newwin (window) new window object - \*/ + R.setWindow = function (newwin) { eve("setWindow", R, g.win, newwin); g.win = newwin; g.doc = g.win.document; - if (initWin) { - initWin(g.win); + 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/ @@ -572,26 +621,7 @@ return rgb; }; - /*\ - * Raphael.color - [ method ] - ** - * Parses the color string and returns object with all values for the given color. - > Parameters - - clr (string) color string in one of the supported formats (see @Raphael.getRGB) - = (object) Combined RGB & HSB object in format: - o { - o r (number) red, - o g (number) green, - o b (number) blue, - o hex (string) color in HTML/CSS format: #••••••, - o error (boolean) `true` if string can’t be parsed, - o h (number) hue, - o s (number) saturation, - o v (number) value (brightness), - o l (number) lightness - o } - \*/ + R.color = function (clr) { var rgb; if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { @@ -619,29 +649,13 @@ clr.v = rgb.b; } else { clr = {hex: "none"}; - crl.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + clr.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; } } clr.toString = rgbtoString; return clr; }; - /*\ - * Raphael.hsb2rgb - [ method ] - ** - * Converts HSB values to RGB object. - > Parameters - - h (number) hue - - s (number) saturation - - v (number) value or brightness - = (object) RGB object in format: - o { - o r (number) red, - o g (number) green, - o b (number) blue, - o hex (string) color in HTML/CSS format: #•••••• - o } - \*/ + R.hsb2rgb = function (h, s, v, o) { if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { v = h.b; @@ -662,23 +676,7 @@ B += [0, 0, X, C, C, X][h]; return packageRGB(R, G, B, o); }; - /*\ - * Raphael.hsl2rgb - [ method ] - ** - * Converts HSL values to RGB object. - > Parameters - - h (number) hue - - s (number) saturation - - l (number) luminosity - = (object) RGB object in format: - o { - o r (number) red, - o g (number) green, - o b (number) blue, - o hex (string) color in HTML/CSS format: #•••••• - 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; @@ -703,22 +701,7 @@ B += [0, 0, X, C, C, X][h]; return packageRGB(R, G, B, o); }; - /*\ - * Raphael.rgb2hsb - [ method ] - ** - * Converts RGB values to HSB object. - > Parameters - - r (number) red - - g (number) green - - b (number) blue - = (object) HSB object in format: - o { - o h (number) hue - o s (number) saturation - o b (number) brightness - o } - \*/ + R.rgb2hsb = function (r, g, b) { b = prepareRGB(r, g, b); r = b[0]; @@ -737,22 +720,7 @@ S = C == 0 ? 0 : C / V; return {h: H, s: S, b: V, toString: hsbtoString}; }; - /*\ - * Raphael.rgb2hsl - [ method ] - ** - * Converts RGB values to HSL object. - > Parameters - - r (number) red - - g (number) green - - b (number) blue - = (object) HSL object in format: - o { - o h (number) hue - o s (number) saturation - o l (number) luminosity - o } - \*/ + R.rgb2hsl = function (r, g, b) { b = prepareRGB(r, g, b); r = b[0]; @@ -802,7 +770,7 @@ var preload = R._preload = function (src, f) { var img = g.doc.createElement("img"); - img.style.cssText = "position:absolute;left:-9999em;top-9999em"; + img.style.cssText = "position:absolute;left:-9999em;top:-9999em"; img.onload = function () { f.call(this); this.onload = null; @@ -819,33 +787,7 @@ return this.hex; } - /*\ - * Raphael.getRGB - [ method ] - ** - * Parses colour string as RGB object - > Parameters - - colour (string) colour string in one of formats: - # - = (object) RGB object in format: - o { - o r (number) red, - o g (number) green, - o b (number) blue - o hex (string) color in HTML/CSS format: #••••••, - o error (boolean) true if string can’t be parsed - o } - \*/ + R.getRGB = cacher(function (colour) { if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; @@ -874,7 +816,7 @@ red = toInt((t = rgb[3].charAt(1)) + t, 16); } if (rgb[4]) { - values = rgb[4].split(commaSpaces); + values = rgb[4][split](commaSpaces); red = toFloat(values[0]); values[0].slice(-1) == "%" && (red *= 2.55); green = toFloat(values[1]); @@ -885,7 +827,7 @@ values[3] && values[3].slice(-1) == "%" && (opacity /= 100); } if (rgb[5]) { - values = rgb[5].split(commaSpaces); + values = rgb[5][split](commaSpaces); red = toFloat(values[0]); values[0].slice(-1) == "%" && (red *= 2.55); green = toFloat(values[1]); @@ -898,7 +840,7 @@ return R.hsb2rgb(red, green, blue, opacity); } if (rgb[6]) { - values = rgb[6].split(commaSpaces); + values = rgb[6][split](commaSpaces); red = toFloat(values[0]); values[0].slice(-1) == "%" && (red *= 2.55); green = toFloat(values[1]); @@ -917,57 +859,19 @@ } return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; }, R); - /*\ - * Raphael.hsb - [ method ] - ** - * Converts HSB values to hex representation of the colour. - > Parameters - - h (number) hue - - s (number) saturation - - b (number) value or brightness - = (string) hex representation of the colour. - \*/ + R.hsb = cacher(function (h, s, b) { return R.hsb2rgb(h, s, b).hex; }); - /*\ - * Raphael.hsl - [ method ] - ** - * Converts HSL values to hex representation of the colour. - > Parameters - - h (number) hue - - s (number) saturation - - l (number) luminosity - = (string) hex representation of the colour. - \*/ + R.hsl = cacher(function (h, s, l) { return R.hsl2rgb(h, s, l).hex; }); - /*\ - * Raphael.rgb - [ method ] - ** - * Converts RGB values to hex representation of the colour. - > Parameters - - r (number) red - - g (number) green - - b (number) blue - = (string) hex representation of the colour. - \*/ + R.rgb = cacher(function (r, g, b) { return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); }); - /*\ - * Raphael.getColor - [ method ] - ** - * On each call returns next colour in the spectrum. To reset it back to red call @Raphael.getColor.reset - > Parameters - - value (number) #optional brightness, default is `0.75` - = (string) hex representation of the colour. - \*/ + 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); @@ -979,32 +883,43 @@ } return rgb.hex; }; - /*\ - * Raphael.getColor.reset - [ method ] - ** - * Resets spectrum position for @Raphael.getColor back to red. - \*/ + R.getColor.reset = function () { delete this.start; }; - /*\ - * Raphael.parsePathString - [ method ] - ** - * Utility method - ** - * Parses given path string into an array of arrays of path segments. - > Parameters - - pathString (string|array) path string or array of segments (in the last case it will be returned straight away) - = (array) array of segments. - \*/ + // 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 data = pathClone(pathString); @@ -1012,7 +927,7 @@ if (!data.length) { Str(pathString).replace(pathCommand, function (a, b, c) { var params = [], - name = lowerCase.call(b); + name = b.toLowerCase(); c.replace(pathValues, function (a, b) { b && params.push(+b); }); @@ -1021,7 +936,9 @@ name = "l"; b = b == "m" ? "l" : "L"; } - while (params.length >= paramCounts[name]) { + 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; @@ -1032,17 +949,7 @@ data.toString = R._path2string; return data; }); - /*\ - * Raphael.parseTransformString - [ method ] - ** - * Utility method - ** - * Parses given path string into an array of transformations. - > Parameters - - TString (string|array) transform string or array of transformations (in the last case it will be returned straight away) - = (array) array of transformations. - \*/ + R.parseTransformString = cacher(function (TString) { if (!TString) { return null; @@ -1059,64 +966,29 @@ c.replace(pathValues, function (a, b) { b && params.push(+b); }); - data.push([name][concat](params)); + data.push([b][concat](params)); }); } data.toString = R._path2string; return data; }); - /*\ - * Raphael.findDotsAtSegment - [ method ] - ** - * Utility method - ** - * Find dot coordinates on the given cubic bezier curve at the given t. - > Parameters - - p1x (number) x of the first point of the curve - - p1y (number) y of the first point of the curve - - c1x (number) x of the first anchor of the curve - - c1y (number) y of the first anchor of the curve - - c2x (number) x of the second anchor of the curve - - c2y (number) y of the second anchor of the curve - - p2x (number) x of the second point of the curve - - p2y (number) y of the second point of the curve - - t (number) position on the curve (0..1) - = (object) point information in format: - o { - o x: (number) x coordinate of the point - o y: (number) y coordinate of the point - o m: { - o x: (number) x coordinate of the left anchor - o y: (number) y coordinate of the left anchor - o } - o n: { - o x: (number) x coordinate of the right anchor - o y: (number) y coordinate of the right anchor - o } - o start: { - o x: (number) x coordinate of the start of the curve - o y: (number) y coordinate of the start of the curve - o } - o end: { - o x: (number) x coordinate of the end of the curve - o y: (number) y coordinate of the end of the curve - o } - o alpha: (number) angle of the curve derivative at the point - o } - \*/ + R.findDotsAtSegment = 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, + 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 { @@ -1129,6 +1001,11 @@ 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}; @@ -1279,9 +1156,9 @@ 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]) { @@ -1300,17 +1177,31 @@ 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]; + r[k] = pa[k]; } } switch (r[0]) { @@ -1325,11 +1216,11 @@ y = r[1]; break; case "M": - mx = res[i][res[i].length - 2]; - my = res[i][res[i].length - 1]; + 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; @@ -1431,7 +1322,7 @@ 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++) { newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; @@ -1489,7 +1380,7 @@ 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}, @@ -1660,11 +1551,6 @@ el2.prev = el; el.next = el2; }, - removed = function (methodname) { - return function () { - throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object"); - }; - }, extractTransform = R._extractTransform = function (el, tstr) { if (tstr == null) { return el._.transform; @@ -1683,31 +1569,57 @@ 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; - t[0] = Str(t[0]).toLowerCase(); - if (t[0] == "t" && tlen == 3) { - m.translate(t[1], t[2]); - } else if (t[0] == "r") { + 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 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) { - m.rotate(t[1], t[2], t[3]); + 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 (t[0] == "s") { + } 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) { - m.scale(t[1], t[2], t[3], t[4]); + 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 (t[0] == "m" && tlen == 7) { + } else if (command == "m" && tlen == 7) { m.add(t[1], t[2], t[3], t[4], t[5], t[6]); } _.dirtyT = 1; @@ -1731,20 +1643,21 @@ } }, getEmpty = function (item) { - switch (item[0]) { - case "t": return ["t", 0, 0]; - case "m": return ["m", 1, 0, 0, 1, 0, 0]; + 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 ["r", 0, item[2], item[3]]; + return [l, 0, item[2], item[3]]; } else { - return ["r", 0]; + return [l, 0]; } case "s": if (item.length == 5) { - return ["s", 1, 1, item[3], item[4]]; + return [l, 1, 1, item[3], item[4]]; } else if (item.length == 3) { - return ["s", 1, 1]; + return [l, 1, 1]; } else { - return ["s", 1]; + return [l, 1]; } } }, @@ -1761,8 +1674,8 @@ tt1 = t1[i] || getEmpty(t2[i]); tt2 = t2[i] || getEmpty(tt1); if ((tt1[0] != tt2[0]) || - (tt1[0] == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || - (tt1[0] == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + (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; } @@ -1807,47 +1720,12 @@ height: h }; }; - /*\ - * Raphael.pathToRelative - [ method ] - ** - * Utility method - ** - * Converts path to relative form - > Parameters - - pathString (string|array) path string or array of segments - = (array) array of segments. - \*/ + R.pathToRelative = pathToRelative; R._engine = {}; - /*\ - * Raphael.path2curve - [ method ] - ** - * Utility method - ** - * Converts path to a new path where all segments are cubic bezier curves. - > Parameters - - pathString (string|array) path string or array of segments - = (array) array of segments. - \*/ + R.path2curve = path2curve; - /*\ - * Raphael.matrix - [ method ] - ** - * Utility method - ** - * Returns matrix based on given parameters. - > Parameters - - a (number) - - b (number) - - c (number) - - d (number) - - e (number) - - f (number) - = (object) @Matrix - \*/ + R.matrix = function (a, b, c, d, e, f) { return new Matrix(a, b, c, d, e, f); }; @@ -1869,6 +1747,7 @@ } } (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]], @@ -1895,33 +1774,42 @@ this.e = out[0][2]; this.f = out[1][2]; }; + 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); }; + matrixproto.clone = function () { return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); }; + matrixproto.translate = function (x, y) { this.add(1, 0, 0, 1, x, y); }; + matrixproto.scale = function (x, y, cx, cy) { y == null && (y = x); - this.add(1, 0, 0, 1, cx, cy); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); this.add(x, 0, 0, y, 0, 0); - this.add(1, 0, 0, 1, -cx, -cy); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); }; + 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); }; + matrixproto.x = function (x, y) { return x * this.a + y * this.c + this.e; }; + matrixproto.y = function (x, y) { return x * this.b + y * this.d + this.f; }; @@ -1949,6 +1837,7 @@ a[0] && (a[0] /= mag); a[1] && (a[1] /= mag); } + matrixproto.split = function () { var out = {}; // translation @@ -1984,10 +1873,16 @@ out.noRotation = !+out.shear.toFixed(9) && !out.rotate; return out; }; - matrixproto.toTransformString = function () { - var s = this.split(); + + matrixproto.toTransformString = function (shorter) { + var s = shorter || this[split](); if (s.isSimple) { - return "t" + [s.dx, s.dy] + "s" + [s.scalex, s.scaley, 0, 0] + "r" + [s.rotate, 0, 0]; + 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)]; } @@ -1998,14 +1893,7 @@ 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)) { - /*\ - * Paper.safari - [ method ] - ** - * There is an inconvenient rendering bug in Safari (WebKit): - * sometimes the rendering should be forced. - * This method should help with dealing with this bug. - \*/ + paperproto.safari = function () { var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"}); setTimeout(function () {rect.remove();}); @@ -2014,7 +1902,6 @@ paperproto.safari = fun; } - // Events var preventDefault = function () { this.returnValue = false; }, @@ -2129,21 +2016,40 @@ } drag = []; }, - /*\ - * Raphael.el - [ property (object) ] - ** - * You can add your own method to elements. This is usefull when you want to hack default functionality or - * want to wrap some common transformation or attributes in one method. In difference to canvas methods, - * you can redefine element method at any time. Expending element methods wouldn’t affect set. - > Usage - | Raphael.el.red = function () { - | this.attr({fill: "#f00"}); - | }; - | // then use it - | paper.circle(100, 100, 20).red(); - \*/ + elproto = R.el = {}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for (var i = events.length; i--;) { (function (eventName) { R[eventName] = elproto[eventName] = function (fn, scope) { @@ -2167,64 +2073,42 @@ })(events[i]); } - /*\ - * Element.hover - [ method ] - ** - * Adds event handlers for hover for the element. - > Parameters - - f_in (function) handler for hover in - - f_out (function) handler for hover out - - icontext (object) #optional context for hover in handler - - ocontext (object) #optional context for hover out handler - = (object) @Element - \*/ + + 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]); + } + return this; + } + 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); }; - /*\ - * Element.unhover - [ method ] - ** - * Removes event handlers for hover for the element. - > Parameters - - f_in (function) handler for hover in - - f_out (function) handler for hover out - = (object) @Element - \*/ + elproto.unhover = function (f_in, f_out) { return this.unmouseover(f_in).unmouseout(f_out); }; - /*\ - * Element.drag - [ method ] - ** - * Adds event handlers for drag of the element. - > Parameters - - onmove (function) handler for moving - - onstart (function) handler for drag start - - onend (function) handler for drag end - - mcontext (object) #optional context for moving handler - - scontext (object) #optional context for drag start handler - - econtext (object) #optional context for drag end handler - * Additionaly following `drag` events will be triggered: `drag.start.` on start, - * `drag.end.` on end and `drag.move.` on every move. When element will be dragged over another element - * `drag.over.` will be fired as well. - * - * Start event and start handler will be called in specified context or in context of the element with following parameters: - o x (number) x position of the mouse - o y (number) y position of the mouse - o event (object) DOM event object - * Move event and move handler will be called in specified context or in context of the element with following parameters: - o dx (number) shift by x from the start point - o dy (number) shift by y from the start point - o x (number) x position of the mouse - o y (number) y position of the mouse - o event (object) DOM event object - * End event and end handler will be called in specified context or in context of the element with following parameters: - o event (object) DOM event object - = (object) @Element - \*/ + var draggable = []; + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { function start(e) { (e.originalEvent || e).preventDefault(); @@ -2241,279 +2125,90 @@ 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; }; - /*\ - * Element.onDragOver - [ method ] - ** - * Shortcut for assigning event handler for `drag.over.` event, where id is id of the element (see @Element.id). - > Parameters - - f (function) handler for event - \*/ + elproto.onDragOver = function (f) { f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id); }; - /*\ - * Element.undrag - [ method ] - ** - * Removes all drag event handlers from given element. - \*/ + elproto.undrag = function () { - var i = drag.length; - while (i--) if (drag[i].el == this) { - R.unmousedown(drag[i].start); - drag.splice(i++, 1); + 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); } - !drag.length && R.unmousemove(dragMove).unmouseup(dragUp); - }; - /*\ - * Paper.circle - [ method ] - ** - * Draws a circle. - ** - > Parameters - ** - - x (number) x coordinate of the centre - - y (number) y coordinate of the centre - - r (number) radius - = (object) Raphaël element object with type “circle” - ** - > Usage - | var c = paper.circle(50, 50, 40); - \*/ + !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; }; - /*\ - * Paper.rect - [ method ] - * - * Draws a rectangle. - ** - > Parameters - ** - - x (number) x coordinate of the top left corner - - y (number) y coordinate of the top left corner - - width (number) width - - height (number) height - - r (number) #optional radius for rounded corners, default is 0 - = (object) Raphaël element object with type “rect” - ** - > Usage - | // regular rectangle - | var c = paper.rect(10, 10, 50, 50); - | // rectangle with rounded corners - | var c = paper.rect(40, 40, 50, 50, 10); - \*/ + 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; }; - /*\ - * Paper.ellipse - [ method ] - ** - * Draws an ellipse. - ** - > Parameters - ** - - x (number) x coordinate of the centre - - y (number) y coordinate of the centre - - rx (number) horizontal radius - - ry (number) vertical radius - = (object) Raphaël element object with type “ellipse” - ** - > Usage - | var c = paper.ellipse(50, 50, 40, 20); - \*/ + 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; }; - /*\ - * Paper.path - [ method ] - ** - * Creates a path element by given path data string. - ** - > Parameters - ** - - pathString (string) path data in SVG path string format. - = (object) Raphaël element object with type “path” - # Details of a path's data attribute's format are described in the SVG specification. - ** - > Usage - | var c = paper.path("M10 10L90 90"); - | // draw a diagonal line: - | // move to 10,10, line to 90,90 - \*/ + 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; }; - /*\ - * Paper.image - [ method ] - ** - * Embeds an image into the surface. - ** - > Parameters - ** - - src (string) URI of the source image - - x (number) x coordinate position - - y (number) y coordinate position - - width (number) width of the image - - height (number) height of the image - = (object) Raphaël element object with type “image” - ** - > Usage - | var c = paper.image("apple.png", 10, 10, 80, 80); - \*/ + 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; }; - /*\ - * Paper.text - [ method ] - ** - * Draws a text string. If you need line breaks, put “\n” in the string. - ** - > Parameters - ** - - x (number) x coordinate position - - y (number) y coordinate position - - text (string) The text string to draw - = (object) Raphaël element object with type “text” - ** - > Usage - | var t = paper.text(50, 50, "Raphaël\nkicks\nbutt!"); - \*/ + 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; }; - /*\ - * Paper.set - [ method ] - ** - * Creates array-like object to keep and operate several elements at once. - * Warning: it doesn’t create any elements for itself in the page, it just groups existing elements. - * Sets act as pseudo elements — all methods available to an element can be used on a set. - = (object) array-like object that represents set of elements - ** - > Usage - | var st = paper.set(); - | st.push( - | paper.circle(10, 10, 5), - | paper.circle(30, 10, 5) - | ); - | st.attr({fill: "red"}); // changes the fill of both circles - \*/ + 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; }; - /*\ - * Paper.setStart - [ method ] - ** - * Creates @Paper.set. All elements that will be created after calling this method and before calling - * @Paper.setFinish will be added to the set. - ** - > Usage - | paper.setStart(); - | paper.circle(10, 10, 5), - | paper.circle(30, 10, 5) - | var st = paper.setFinish(); - | st.attr({fill: "red"}); // changes the fill of both circles - \*/ + paperproto.setStart = function (set) { this.__set__ = set || this.set(); }; - /*\ - * Paper.setFinish - [ method ] - ** - * See @Paper.setStart. This method finishes catching and returns resulting set. - ** - = (object) set - \*/ + paperproto.setFinish = function (set) { var out = this.__set__; delete this.__set__; return out; }; - /*\ - * Paper.setSize - [ method ] - ** - * If you need to change dimensions of the canvas call this method - ** - > Parameters - ** - - width (number) new width of the canvas - - height (number) new height of the canvas - > Usage - | var st = paper.set(); - | st.push( - | paper.circle(10, 10, 5), - | paper.circle(30, 10, 5) - | ); - | st.attr({fill: "red"}); - \*/ - paperproto.setSize = R._engine.setSize; - /*\ - * Paper.setViewBox - [ method ] - ** - * Sets the view box of the paper. Practically it gives you ability to zoom and pan whole paper surface by - * specifying new boundaries. - ** - > Parameters - ** - x, y, w, h, fit - - x (number) new x position, default is `0` - - y (number) new y position, default is `0` - - w (number) new width of the canvas - - h (number) new height of the canvas - - fit (boolean) `true` if you want graphics to fit into new boundary box - \*/ - paperproto.setViewBox = R._engine.setViewBox; - /*\ - * Paper.top - [ property ] - ** - * Points to the topmost element on the paper - \*/ - /*\ - * Paper.bottom - [ property ] - ** - * Points to the bottom element on the paper - \*/ + + 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; - /*\ - * Paper.raphael - [ property ] - ** - * Points to the @Raphael object/function - \*/ + paperproto.raphael = R; var getOffset = function (elem) { var box = elem.getBoundingClientRect(), @@ -2528,20 +2223,7 @@ x: left }; }; - /*\ - * Paper.getElementByPoint - [ method ] - ** - * Returns you topmost element under given point. - ** - = (object) Raphaël element object - > Parameters - ** - - x (number) x coordinate from the top left corner of the window - - y (number) y coordinate from the top left corner of the window - > Usage - | paper.getElementByPoint(mouseX, mouseY).attr({stroke: "#f00"}); - \*/ + paperproto.getElementByPoint = function (x, y) { var paper = this, svg = paper.canvas, @@ -2567,17 +2249,7 @@ target = target && target.raphael ? paper.getById(target.raphaelid) : null; return target; }; - /*\ - * Paper.getById - [ method ] - ** - * Returns you element by its internal ID. - ** - > Parameters - ** - - id (number) id - = (object) Raphaël element object - \*/ + paperproto.getById = function (id) { var bot = this.bottom; while (bot) { @@ -2588,20 +2260,7 @@ } return null; }; - /*\ - * Paper.forEach - [ method ] - ** - * Executes given function for each element on the paper - * - * If callback function returns `false` it will stop loop running. - ** - > Parameters - ** - - callback (function) function to run - - thisArg (object) context object for the callback - = (object) Paper object - \*/ + paperproto.forEach = function (callback, thisArg) { var bot = this.bottom; while (bot) { @@ -2618,23 +2277,7 @@ function x_y_w_h() { return this.x + S + this.y + S + this.width + " \xd7 " + this.height; } - /*\ - * Element.getBBox - [ method ] - ** - * Return bounding box for a given element - ** - > Parameters - ** - - isWithoutTransform (boolean) flag, `true` if you want to have bounding box before transformations. Default is `false`. - = (object) Bounding box object: - o { - o x: (number) top left corner x - o y: (number) top left corner y - o width: (number) width - o height: (number) height - o } - \*/ + elproto.getBBox = function (isWithoutTransform) { if (this.removed) { return {}; @@ -2660,40 +2303,16 @@ } return _.bbox; }; - /*\ - * Element.clone - [ method ] - ** - = (object) clone of a given element - ** - \*/ + elproto.clone = function () { if (this.removed) { return null; } - return this.paper[this.type]().attr(this.attr()); - }; - /*\ - * Element.glow - [ method ] - ** - * Return set of elements that create glow-like effect around given element. See @Paper.set. - * - * Note: Glow is not connected to the element. If you change element attributes it won’t adjust itself. - ** - > Parameters - ** - - glow (object) #optional parameters object with all properties optional: - o { - o width (number) size of the glow, default is `10` - o fill (boolean) will it be filled, default is `false` - o opacity: opacity, default is `0.5` - o offsetx: horizontal offset, default is `0` - o offsety: vertical offset, default is `0` - o color: glow colour, default is `black` - o } - = (object) @Paper.set of elements that represents glow - \*/ + 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; @@ -2793,7 +2412,7 @@ sp += p.shift() + p; } subpaths.end = sp; - point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[1], p[2], p[3], p[4], p[5], p[6], 1); + 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; }; @@ -2801,66 +2420,19 @@ var getTotalLength = getLengthFactory(1), getPointAtLength = getLengthFactory(), getSubpathsAtLength = getLengthFactory(0, 1); - /*\ - * Raphael.getTotalLength - [ method ] - ** - * Returns length of the given path in pixels. - ** - > Parameters - ** - - path (string) SVG path string. - ** - = (number) length. - \*/ + R.getTotalLength = getTotalLength; - /*\ - * Raphael.getPointAtLength - [ method ] - ** - * Return coordinates of the point located at the given length on the given path. - ** - > Parameters - ** - - path (string) SVG path string - - length (number) - ** - = (object) representation of the point: - o { - o x: (number) x coordinate - o y: (number) y coordinate - o alpha: (number) angle of derivative - o } - \*/ + R.getPointAtLength = getPointAtLength; - /*\ - * Raphael.getSubpath - [ method ] - ** - * Return subpath of a given path from given length to given length. - ** - > Parameters - ** - - path (string) SVG path string - - from (number) position of the start of the segment - - to (number) position of the end of the segment - ** - = (string) pathstring for the segment - \*/ + R.getSubpath = function (path, from, to) { - if (abs(this.getTotalLength(path) - to) < 1e-6) { + 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; }; - /*\ - * Element.getTotalLength - [ method ] - ** - * Returns length of the path in pixels. Only works for element of “path” type. - = (number) length. - \*/ + elproto.getTotalLength = function () { if (this.type != "path") {return;} if (this.node.getTotalLength) { @@ -2868,61 +2440,17 @@ } return getTotalLength(this.attrs.path); }; - /*\ - * Element.getPointAtLength - [ method ] - ** - * Return coordinates of the point located at the given length on the given path. Only works for element of “path” type. - ** - > Parameters - ** - - length (number) - ** - = (object) representation of the point: - o { - o x: (number) x coordinate - o y: (number) y coordinate - o alpha: (number) angle of derivative - o } - \*/ + elproto.getPointAtLength = function (length) { if (this.type != "path") {return;} return getPointAtLength(this.attrs.path, length); }; - /*\ - * Element.getSubpath - [ method ] - ** - * Return subpath of a given element from given length to given length. Only works for element of “path” type. - ** - > Parameters - ** - - from (number) position of the start of the segment - - to (number) position of the end of the segment - ** - = (string) pathstring for the segment - \*/ + elproto.getSubpath = function (from, to) { if (this.type != "path") {return;} return R.getSubpath(this.attrs.path, from, to); }; - /*\ - * Raphael.easing_formulas - [ property ] - ** - * Object that contains easing formulas for animation. You could extend it with your own. By default it has following list of easing: - #
    - #
  • “linear”
  • - #
  • “<” or “easeIn” or “ease-in”
  • - #
  • “>” or “easeOut” or “ease-out”
  • - #
  • “<>” or “easeInOut” or “ease-in-out”
  • - #
  • “backIn” or “back-in”
  • - #
  • “backOut” or “back-out”
  • - #
  • “elastic”
  • - #
  • “bounce”
  • - #
- #

See also Easing demo.

- \*/ + var ef = R.easing_formulas = { linear: function (n) { return n; @@ -3013,7 +2541,9 @@ t = e.t, that = e.el, set = {}, - now; + now, + init = {}, + key; if (e.initstatus) { time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; e.status = e.initstatus; @@ -3077,7 +2607,7 @@ } break; default: - var from2 = [].concat(from[attr]); + var from2 = [][concat](from[attr]); now = []; i = that.paper.customAttributes[attr].length; while (i--) { @@ -3104,6 +2634,10 @@ 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) { @@ -3117,35 +2651,11 @@ upto255 = function (color) { return color > 255 ? 255 : color < 0 ? 0 : color; }; - /*\ - * Element.animateWith - [ method ] - ** - * Acts similar to @Element.animate, but ensure that given animation runs in sync with another given element. - ** - > Parameters - ** - - params (object) final attributes for the element, see also @Element.attr - - ms (number) number of milliseconds for animation to run - - easing (string) #optional easing type. Accept on of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` - - callback (function) #optional callback function. Will be called at the end of animation. - * or - - animation (object) animation object, see @Raphael.animation - ** - = (object) original element - \*/ - elproto.animateWith = function (element, params, ms, easing, callback) { - this.animate(params, ms, easing, callback); - var start, el; - for (var i = 0, ii = animationElements.length; i < ii; i++) { - el = animationElements[i]; - if (el.el.id == element.id) { - start = el.timestamp; - } else if (el.el.id == this.id) { - el.start = start; - } - } - return this.animate(params, ms, easing, callback); + + 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, @@ -3204,49 +2714,29 @@ return this; }; function Animation(anim, ms) { - var percents = []; - this.anim = anim; + var percents = [], + newAnim = {}; this.ms = ms; this.times = 1; - if (this.anim) { - for (var attr in this.anim) if (this.anim[has](attr)) { - percents.push(+attr); + 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.delay - [ method ] - ** - * Creates a copy of existing animation object with given delay. - ** - > Parameters - ** - - delay (number) number of ms to pass between animation start and actual animation - ** - = (object) new altered Animation object - \*/ + Animation.prototype.delay = function (delay) { var a = new Animation(this.anim, this.ms); a.times = this.times; a.del = +delay || 0; return a; }; - /*\ - * Animation.repeat - [ method ] - ** - * Creates a copy of existing animation object with given repetition. - ** - > Parameters - ** - - repeat (number) number iterations of animation. For infinite animation pass `Infinity` - ** - = (object) new altered Animation object - \*/ + Animation.prototype.repeat = function (times) { var a = new Animation(this.anim, this.ms); a.del = this.del; @@ -3299,7 +2789,7 @@ return; } if (!isInAnim) { - for (attr in params) if (params[has](attr)) { + 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]); @@ -3382,8 +2872,8 @@ } break; case "csv": - var values = Str(params[attr]).split(separator), - from2 = Str(from[attr]).split(separator); + var values = Str(params[attr])[split](separator), + from2 = Str(from[attr])[split](separator); if (attr == "clip-rect") { from[attr] = from2; diff[attr] = []; @@ -3395,8 +2885,8 @@ to[attr] = values; break; default: - values = [].concat(params[attr]); - from2 = [].concat(from[attr]); + values = [][concat](params[attr]); + from2 = [][concat](from[attr]); diff[attr] = []; i = element.paper.customAttributes[attr].length; while (i--) { @@ -3442,13 +2932,16 @@ totalOrigin: totalOrigin }; animationElements.push(e); - if (status && !isInAnim) { + 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; @@ -3456,23 +2949,11 @@ } eve("anim.start." + element.id, element, anim); } - /*\ - * Raphael.animation - [ method ] - ** - * Creates an animation object that can be passed to the @Element.animate or @Element.animateWith methods. - * See also @Animation.delay and @Animation.repeat methods. - ** - > Parameters - ** - - params (object) final attributes for the element, see also @Element.attr - - ms (number) number of milliseconds for animation to run - - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` - - callback (function) #optional callback function. Will be called at the end of animation. - ** - = (object) @Animation - \*/ + 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; @@ -3482,7 +2963,7 @@ var p = {}, json, attr; - for (attr in params) if (params[has](attr) && toFloat(attr) != attr) { + for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) { json = true; p[attr] = params[attr]; } @@ -3494,23 +2975,7 @@ return new Animation({100: p}, ms); } }; - /*\ - * Element.animate - [ method ] - ** - * Creates and starts animation for given element. - ** - > Parameters - ** - - params (object) final attributes for the element, see also @Element.attr - - ms (number) number of milliseconds for animation to run - - easing (string) #optional easing type. Accept one of @Raphael.easing_formulas or CSS format: `cubic‐bezier(XX, XX, XX, XX)` - - callback (function) #optional callback function. Will be called at the end of animation. - * or - - animation (object) animation object, see @Raphael.animation - ** - = (object) original element - \*/ + elproto.animate = function (params, ms, easing, callback) { var element = this; if (element.removed) { @@ -3521,49 +2986,14 @@ runAnimation(anim, element, anim.percents[0], null, element.attr()); return element; }; - /*\ - * Element.setTime - [ method ] - ** - * Sets the status of animation of the element in milliseconds. Similar to @Element.status method. - ** - > Parameters - ** - - anim (object) animation object - - value (number) number of milliseconds from the beginning of the animation - ** - = (object) original element if `value` is specified - * Note, that during animation following events are triggered: - * - * On each animation frame event `anim.frame.`, on start `anim.start.` and on end `anim.finish.`. - \*/ + elproto.setTime = function (anim, value) { if (anim && value != null) { this.status(anim, mmin(value, anim.ms) / anim.ms); } return this; }; - /*\ - * Element.status - [ method ] - ** - * Gets or sets the status of animation of the element. - ** - > Parameters - ** - - anim (object) #optional animation object - - value (number) #optional 0 – 1. If specified, method works like a setter and sets the status of a given animation to the value. This will cause animation to jump to the given position. - ** - = (number) status - * or - = (array) status if `anim` is not specified. Array of objects in format: - o { - o anim: (object) animation object - o status: (number) status - o } - * or - = (object) original element if `value` is specified - \*/ + elproto.status = function (anim, value) { var out = [], i = 0, @@ -3580,7 +3010,10 @@ if (anim) { return e.status; } - out.push({anim: e.anim, status: e.status}); + out.push({ + anim: e.anim, + status: e.status + }); } } if (anim) { @@ -3589,18 +3022,7 @@ return out; } }; - /*\ - * Element.pause - [ method ] - ** - * Stops animation of the element with ability to resume it later on. - ** - > Parameters - ** - - anim (object) #optional animation object - ** - = (object) original element - \*/ + 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) { @@ -3609,18 +3031,7 @@ } return this; }; - /*\ - * Element.resume - [ method ] - ** - * Resumes animation if it was paused with @Element.pause method. - ** - > Parameters - ** - - anim (object) #optional animation object - ** - = (object) original element - \*/ + 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]; @@ -3631,18 +3042,7 @@ } return this; }; - /*\ - * Element.stop - [ method ] - ** - * Stops animation of the element. - ** - > Parameters - ** - - anim (object) #optional animation object - ** - = (object) original element - \*/ + 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) { @@ -3670,13 +3070,7 @@ } }, setproto = Set.prototype; - /*\ - * Set.push - [ method ] - ** - * Adds each argument to the current set. - = (object) original element - \*/ + setproto.push = function () { var item, len; @@ -3690,34 +3084,15 @@ } return this; }; - /*\ - * Set.pop - [ method ] - ** - * Removes last element and returns it. - = (object) element - \*/ + setproto.pop = function () { this.length && delete this[this.length--]; return this.items.pop(); }; - /*\ - * Set.forEach - [ method ] - ** - * Executes given function for each element in the set. - * - * If function returns `false` it will stop loop running. - ** - > Parameters - ** - - callback (function) function to run - - thisArg (object) context object for the callback - = (object) Set object - \*/ + setproto.forEach = function (callback, thisArg) { for (var i = 0, ii = this.items.length; i < ii; i++) { - if (callback.call(thisArg, this.items[i]) === false) { + if (callback.call(thisArg, this.items[i], i) === false) { return this; } } @@ -3745,11 +3120,46 @@ } 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, @@ -3764,7 +3174,7 @@ !--len && callback.call(set); }); easing = R.is(easing, string) ? easing : collector; - var anim = params instanceof Animation ? params : R.animation(params, ms, 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); @@ -3810,6 +3220,7 @@ return "Rapha\xebl\u2018s set"; }; + R.registerFont = function (font) { if (!font.face) { return font; @@ -3849,6 +3260,7 @@ } return font; }; + paperproto.getFont = function (family, weight, style, stretch) { stretch = stretch || "normal"; style = style || "normal"; @@ -3877,31 +3289,52 @@ } 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), + 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), + 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, 0]]})); + curr && curr.d && out.push(this.path(curr.d).attr({ + fill: "#000", + stroke: "none", + transform: [["t", shift * scale, 0]] + })); } - out.scale(scale, scale, top, height).translate(x - top, y - height); + 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) { @@ -3909,24 +3342,36 @@ })); 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; }; - /*\ - * Raphael.st - [ property (object) ] - ** - * You can add your own method to elements. This is usefull when you want to hack default functionality or - * want to wrap some common transformation or attributes in one method. In difference to canvas methods, - * you can redefine element method at any time. Expending element methods wouldn’t affect set. - > Usage - | Raphael.el.red = function () { - | this.attr({fill: "#f00"}); - | }; - | // then use it - | paper.circle(100, 100, 20).red(); - \*/ + R.st = setproto; // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html (function (doc, loaded, f) { @@ -3944,283 +3389,15 @@ })(document, "DOMContentLoaded"); oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); - - /* - * Eve 0.2.3 - JavaScript Events Library - * - * Copyright (c) 2010 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) - * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. - */ - - var eve = R.eve = (function () { - var version = "0.2.3", - has = "hasOwnProperty", - separator = /[\.\/]/, - wildcard = "*", - fun = function () {}, - numsort = function (a, b) { - return a - b; - }, - current_event, - events = {n: {}}, - /*\ - * eve - [ method ] - ** - * Fires event with given `name`, given scope and other parameters. - ** - > Arguments - ** - - name (string) name of the event, dot (`.`) or slash (`/`) separated - - scope (object) context for the event handlers - - varargs (...) the rest of arguments will be sent to event handlers - ** - = (array) array of errors, if any. Each element of the array is in format: - o { - o error (string) error message - o func (function) handler that caused error - o } - \*/ - eve = function (name, scope) { - var e = events, - args = Array.prototype.slice.call(arguments, 2), - listeners = eve.listeners(name), - z = 0, - f = false, - l, - indexed = [], - queue = {}, - errors = []; - current_event = name; - 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]; - } - } - indexed.sort(numsort); - while (indexed[z] < 0) { - l = queue[indexed[z++]]; - if (l.apply(scope, args) === f) { - return f; - } - } - for (i = 0; i < ii; i++) { - l = listeners[i]; - if ("zIndex" in l) { - if (l.zIndex == indexed[z]) { - if (l.apply(scope, args) === f) { - return f; - } - do { - z++; - l = queue[indexed[z]]; - if (l) { - if (l.apply(scope, args) === f) { - return f; - } - } - } while (l) - } else { - queue[l.zIndex] = l; - } - } else { - if (l.apply(scope, args) === f) { - return f; - } - } - } - }; - /*\ - * eve.listeners - [ method ] - ** - * Internal method which gives you array of all event handlers that will be triggered by the given `name`. - ** - > Arguments - ** - - name (string) name of the event, dot (`.`) or slash (`/`) separated - ** - = (array) array of event handlers - \*/ - 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 - [ method ] - ** - * Binds given event handler with a given name. You can use wildcards “`*`” for the names: - | eve.on("*.under.*", f); - | eve("mouse.under.floor"); // triggers f - * Use @eve to trigger the listener. - ** - > Arguments - ** - - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards - - f (function) event handler function - ** - = (function) returned function accept one number parameter that represents z-index of the handler. It is optional feature and only used when you need to ensure that some subset of handlers will be invoked in a given order, despite of the order of assignment. - > Example: - | eve.on("mouse", eat)(2); - | eve.on("mouse", scream); - | eve.on("mouse", catch)(1); - * This will ensure that `catch` function will be called before `eat`. - * If you want to put you hadler before not indexed handlers specify negative value. - * Note: I assume most of the time you don’t need to worry about z-index, but it’s nice to have this feature “just in case”. - \*/ - 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.nt - [ method ] - ** - * Could be used inside event handler to figure out actual name of the event. - ** - > Arguments - ** - - subname (string) #optional subname of the event - ** - = (string) name of the event, if `subname` is not specified - * or - = (boolean) `true`, if current event’s name contains `subname` - \*/ - eve.nt = function (subname) { - if (subname) { - return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); - } - return current_event; - }; - /*\ - * eve.unbind - [ method ] - ** - * Removes given function from the list of event listeners assigned to given name. - ** - > Arguments - ** - - name (string) name of the event, dot (`.`) or slash (`/`) separated, with optional wildcards - - f (function) event handler function - \*/ - eve.unbind = function (name, f) { - var names = name.split(separator), - e, - key, - splice, - cur = [events]; - for (var i = 0, ii = names.length; i < ii; i++) { - for (var 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 (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { - e.f.splice(i, 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 (i = 0, ii = funcs.length; i < ii; i++) if (funcs[i] == f) { - funcs.splice(i, 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.version - [ property (string) ] - ** - * Current version of the library. - \*/ - eve.version = version; - eve.toString = function () { - return "You are running Eve " + version; - }; - return eve; - })(); - - // Eve finished eve.on("DOMload", function () { loaded = true; }); })(); + // ┌─────────────────────────────────────────────────────────────────────┐ \\ -// │ Raphaël 2 - JavaScript Vector Library │ \\ +// │ Raphaël - JavaScript Vector Library │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ // │ SVG Module │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ @@ -4236,9 +3413,11 @@ window.Raphael.svg && function (R) { math = Math, mmax = math.max, abs = math.abs, + pow = math.pow, separator = /[, ]+/, - E = ""; - // SVG + eve = R.eve, + E = "", + S = " "; var xlink = "http://www.w3.org/1999/xlink", markers = { block: "M5,0 0,2.5 5,5z", @@ -4269,16 +3448,6 @@ window.Raphael.svg && function (R) { } return el; }, - gradients = {}, - rgGrad = /^url\(#(.*)\)$/, - removeGradientFill = function (node, paper) { - var oid = node.getAttribute("fill"); - oid = oid && oid.match(rgGrad); - if (oid && !--gradients[oid[1]]) { - delete gradients[oid[1]]; - paper.defs.removeChild(g.doc.getElementById(oid[1])); - } - }, addGradientFill = function (element, gradient) { var type = "linear", id = element.id + gradient, @@ -4325,30 +3494,33 @@ window.Raphael.svg && function (R) { if (!dots) { return null; } - if (element.gradient) { + id = id.replace(/[\(\)\s,\xb0#]/g, "_"); + + if (element.gradient && id != element.gradient.id) { SVG.defs.removeChild(element.gradient); delete element.gradient; } - id = id.replace(/[\(\)\s,\xb0#]/g, "-"); - 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" - })); + 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, { @@ -4430,7 +3602,7 @@ window.Raphael.svg && function (R) { if (type != "none") { var pathId = "raphael-marker-" + type, markerId = "raphael-marker-" + se + type + w + h; - if (!g.doc.getElementById(pathId)) { + if (!R._g.doc.getElementById(pathId)) { p.defs.appendChild($($("path"), { "stroke-linecap": "round", d: markers[type], @@ -4440,7 +3612,7 @@ window.Raphael.svg && function (R) { } else { markerCounter[pathId]++; } - var marker = g.doc.getElementById(markerId), + var marker = R._g.doc.getElementById(markerId), use; if (!marker) { marker = $($("marker"), { @@ -4499,41 +3671,43 @@ window.Raphael.svg && function (R) { delete o._.arrows[se + "String"]; } for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { - var item = g.doc.getElementById(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 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, + var node = o.node, attrs = o.attrs, - 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 = [], - i = value.length; - while (i--) { - dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; - } - $(node, {"stroke-dasharray": dashes.join(",")}); - } - }; + vis = node.style.visibility; + node.style.visibility = "hidden"; for (var att in params) { if (params[has](att)) { if (!R._availableAttrs[has](att)) { @@ -4549,7 +3723,7 @@ window.Raphael.svg && function (R) { case "title": case "target": var pn = node.parentNode; - if (lowerCase.call(pn.tagName) != "a") { + if (pn.tagName.toLowerCase() != "a") { var hl = $("a"); pn.insertBefore(hl, node); hl.appendChild(node); @@ -4579,7 +3753,7 @@ window.Raphael.svg && function (R) { o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); var el = $("clipPath"), rc = $("rect"); - el.id = R._createUUID(); + el.id = R.createUUID(); $(rc, { x: rect[0], y: rect[1], @@ -4592,10 +3766,13 @@ window.Raphael.svg && function (R) { o.clip = rc; } if (!value) { - var clip = g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E)); - clip && clip.parentNode.removeChild(clip); - $(node, {"clip-path": E}); - delete o.clip; + 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": @@ -4674,7 +3851,7 @@ window.Raphael.svg && function (R) { } node.setAttribute(att, value); if (attrs["stroke-dasharray"]) { - addDashes(o, attrs["stroke-dasharray"]); + addDashes(o, attrs["stroke-dasharray"], params); } if (o._.arrows) { "startString" in o._.arrows && addArrow(o, o._.arrows.startString); @@ -4682,14 +3859,14 @@ window.Raphael.svg && function (R) { } break; case "stroke-dasharray": - addDashes(o, value); + 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.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); @@ -4722,7 +3899,7 @@ window.Raphael.svg && function (R) { $(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 = g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + 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)}); @@ -4752,7 +3929,7 @@ window.Raphael.svg && function (R) { // fall case "fill-opacity": if (attrs.gradient) { - gradient = g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + 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}); @@ -4773,6 +3950,7 @@ window.Raphael.svg && function (R) { } tuneText(o, params); + node.style.visibility = vis; }, leading = 1.2, tuneText = function (el, params) { @@ -4815,55 +3993,16 @@ window.Raphael.svg && function (R) { Element = function (node, svg) { var X = 0, Y = 0; - /*\ - * Element.node - [ property (object) ] - ** - * Gives you a reference to the DOM object, so you can assign event handlers or just mess around. - > Usage - | // draw a circle at coordinate 10,10 with radius of 10 - | var c = paper.circle(10, 10, 10); - | c.node.onclick = function () { - | c.attr("fill", "red"); - | }; - \*/ + this[0] = this.node = node; - /*\ - * Element.raphael - [ property (object) ] - ** - * Internal reference to @Raphael object. In case it is not available. - > Usage - | Raphael.el.red = function () { - | var hsb = this.paper.raphael.rgb2hsb(this.attr("fill")); - | hsb.h = 1; - | this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex}); - | } - \*/ + node.raphael = true; - /*\ - * Element.id - [ property (number) ] - ** - * Unique id of the element. Especially usesful when you want to listen to events of the element, - * because all events are fired in format `..`. Also useful for @Paper.getById method. - \*/ + this.id = R._oid++; node.raphaelid = this.id; this.matrix = R.matrix(); this.realPath = null; - /*\ - * Element.paper - [ property (object) ] - ** - * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions. - > Usage - | Raphael.el.cross = function () { - | this.attr({fill: "red"}); - | this.paper.path("M10,10L50,50M50,10L10,50") - | .attr({stroke: "red"}); - | } - \*/ + this.paper = svg; this.attrs = this.attrs || {}; this._ = { @@ -4876,21 +4015,11 @@ window.Raphael.svg && function (R) { dirty: 1 }; !svg.bottom && (svg.bottom = this); - /*\ - * Element.prev - [ property (object) ] - ** - * Reference to the previous element in the hierarchy. - \*/ + this.prev = svg.top; svg.top && (svg.top.next = this); svg.top = this; - /*\ - * Element.next - [ property (object) ] - ** - * Reference to the next element in the hierarchy. - \*/ + this.next = null; }, elproto = R.el; @@ -4903,22 +4032,14 @@ window.Raphael.svg && function (R) { SVG.canvas && SVG.canvas.appendChild(el); var p = new Element(el, SVG); p.type = "path"; - setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString}); + setFillAndStroke(p, { + fill: "none", + stroke: "#000", + path: pathString + }); return p; }; - /*\ - * Element.rotate - [ method ] - ** - * Adds rotation by given angle around given point to the list of - * transformations of the element. - > Parameters - - deg (number) angle in degrees - - cx (number) #optional x coordinate of the centre of rotation - - cy (number) #optional y coordinate of the centre of rotation - * If cx & cy aren’t specified centre of the shape is used as a point of rotation. - = (object) @Element - \*/ + elproto.rotate = function (deg, cx, cy) { if (this.removed) { return this; @@ -4938,20 +4059,7 @@ window.Raphael.svg && function (R) { this.transform(this._.transform.concat([["r", deg, cx, cy]])); return this; }; - /*\ - * Element.scale - [ method ] - ** - * Adds scale by given amount relative to given point to the list of - * transformations of the element. - > Parameters - - sx (number) horisontal scale amount - - sy (number) vertical scale amount - - cx (number) #optional x coordinate of the centre of scale - - cy (number) #optional y coordinate of the centre of scale - * If cx & cy aren’t specified centre of the shape is used instead. - = (object) @Element - \*/ + elproto.scale = function (sx, sy, cx, cy) { if (this.removed) { return this; @@ -4973,16 +4081,7 @@ window.Raphael.svg && function (R) { this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); return this; }; - /*\ - * Element.translate - [ method ] - ** - * Adds translation by given amount to the list of transformations of the element. - > Parameters - - dx (number) horisontal shift - - dy (number) vertical shift - = (object) @Element - \*/ + elproto.translate = function (dx, dy) { if (this.removed) { return this; @@ -4996,41 +4095,7 @@ window.Raphael.svg && function (R) { this.transform(this._.transform.concat([["t", dx, dy]])); return this; }; - /*\ - * Element.transform - [ method ] - ** - * Adds transformation to the element which is separate to other attributes, - * i.e. translation doesn’t change `x` or `y` of the rectange. The format - * of transformation string is similar to the path string syntax: - | "t100,100r30,100,100s2,2,100,100r45s1.5" - * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for - * scale and `m` is for matrix. - * - * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100; - * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin - * coordinates as optional parameters, the default is the centre point of the element. - * Matrix accepts six parameters. - > Usage - | var el = paper.rect(10, 20, 300, 200); - | // translate 100, 100, rotate 45°, translate -100, 0 - | el.transform("t100,100r45t-100,0"); - | // if you want you can append or prepend transformations - | el.transform("...t50,50"); - | el.transform("s2..."); - | // or even wrap - | el.transform("t50,50...t-50-50"); - | // to reset transformation call method with empty string - | el.transform(""); - | // to get current value call it without parameters - | console.log(el.transform()); - > Parameters - - tstr (string) #optional transformation string - * If tstr isn’t specified - = (string) current transformation string - * else - = (object) @Element - \*/ + elproto.transform = function (tstr) { var _ = this._; if (tstr == null) { @@ -5049,43 +4114,31 @@ window.Raphael.svg && function (R) { return this; }; - /*\ - * Element.hide - [ method ] - ** - * Makes element invisible. See @Element.show. - = (object) @Element - \*/ + elproto.hide = function () { !this.removed && this.paper.safari(this.node.style.display = "none"); return this; }; - /*\ - * Element.show - [ method ] - ** - * Makes element visible. See @Element.hide. - = (object) @Element - \*/ + elproto.show = function () { !this.removed && this.paper.safari(this.node.style.display = ""); return this; }; - /*\ - * Element.remove - [ method ] - ** - * Removes element form the paper. - \*/ + elproto.remove = function () { if (this.removed) { return; } + var paper = this.paper; + paper.__set__ && paper.__set__.exclude(this); eve.unbind("*.*." + this.id); - R._tear(this, this.paper); + if (this.gradient) { + paper.defs.removeChild(this.gradient); + } + R._tear(this, paper); this.node.parentNode.removeChild(this.node); for (var i in this) { - delete this[i]; + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } this.removed = true; }; @@ -5105,87 +4158,7 @@ window.Raphael.svg && function (R) { hide && this.hide(); return bbox; }; - /*\ - * Element.attr - [ method ] - ** - * Sets the attributes of the element. - > Parameters - - attrName (string) attribute’s name - - value (string) value - * or - - params (object) object of name/value pairs - * or - - attrName (string) attribute’s name - * or - - attrNames (array) in this case method returns array of current values for given attribute names - = (object) @Element if attrsName & value or params are passed in. - = (...) value of the attribute if only attrsName is passed in. - = (array) array of values of the attribute if attrsNames is passed in. - = (object) object of attributes if nothing is passed in. - > Possible parameters - #

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

- o arrow-end (string) arrowhead on the end of the path. The format for string is `[-[-]]`. Possible types: `classic`, `block`, `open`, `oval`, `diamond`, `none`, width: `wide`, `narrow`, `midium`, length: `long`, `short`, `midium`. - o clip-rect (string) comma or space separated values: x, y, width and height - o cursor (string) CSS type of the cursor - o cx (number) - o cy (number) - o fill (string) colour, gradient or image - o fill-opacity (number) - o font (string) - o font-family (string) - o font-size (number) font size in pixels - o font-weight (string) - o height (number) - o href (string) URL, if specified element behaves as hyperlink - o opacity (number) - o path (string) SVG path string format - o r (number) - o rx (number) - o ry (number) - o src (string) image URL, only works for @Element.image element - o stroke (string) stroke colour - o stroke-dasharray (string) [“”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”] - o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”] - o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”] - o stroke-miterlimit (number) - o stroke-opacity (number) - o stroke-width (number) stroke width in pixels, default is '1' - o target (string) used with href - o text (string) contents of the text element. Use `\n` for multiline text - o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`” - o title (string) will create tooltip with a given text - o transform (string) see @Element.transform - o width (number) - o x (number) - o y (number) - > Gradients - * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90° - * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black. - * - * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” – - * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point - * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses. - > Path String - #

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

- > Colour Parsing - #
    - #
  • Colour name (“red”, “green”, “cornflowerblue”, etc)
  • - #
  • #••• — shortened HTML colour: (“#000”, “#fc0”, etc)
  • - #
  • #•••••• — full length HTML colour: (“#000000”, “#bd2300”)
  • - #
  • rgb(•••, •••, •••) — red, green and blue channels’ values: (“rgb(200, 100, 0)”)
  • - #
  • rgb(•••%, •••%, •••%) — same as above, but in %: (“rgb(100%, 175%, 0%)”)
  • - #
  • rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“rgba(200, 100, 0, .5)”)
  • - #
  • rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“rgba(100%, 175%, 0%, 50%)”)
  • - #
  • hsb(•••, •••, •••) — hue, saturation and brightness values: (“hsb(0.5, 0.25, 1)”)
  • - #
  • hsb(•••%, •••%, •••%) — same as above, but in %
  • - #
  • hsba(•••, •••, •••, •••) — same as above, but with opacity
  • - #
  • hsl(•••, •••, •••) — almost the same as hsb, see Wikipedia page
  • - #
  • hsl(•••%, •••%, •••%) — same as above, but in %
  • - #
  • hsla(•••, •••, •••) — same as above, but with opacity
  • - #
  • Optionally for hsb and hsl you could specify hue as a degree: “hsl(240deg, 1, .5)” or, if you want to go fancy, “hsl(240°, 1, .5)”
  • - #
- \*/ + elproto.attr = function (name, value) { if (this.removed) { return this; @@ -5233,7 +4206,10 @@ window.Raphael.svg && function (R) { } else if (name != null && R.is(name, "object")) { params = name; } - for (var key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { + 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)) { @@ -5243,47 +4219,36 @@ window.Raphael.svg && function (R) { setFillAndStroke(this, params); return this; }; - /*\ - * Element.toFront - [ method ] - ** - * Moves the element so it is the closest to the viewer’s eyes, on top of other elements. - = (object) @Element - \*/ + elproto.toFront = function () { if (this.removed) { return this; } - this.node.parentNode.appendChild(this.node); + 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; }; - /*\ - * Element.toBack - [ method ] - ** - * Moves the element so it is the furthest from the viewer’s eyes, behind other elements. - = (object) @Element - \*/ + 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); - var svg = this.paper; + 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; }; - /*\ - * Element.insertAfter - [ method ] - ** - * Inserts current object after the given one. - = (object) @Element - \*/ + elproto.insertAfter = function (element) { if (this.removed) { return this; @@ -5297,13 +4262,7 @@ window.Raphael.svg && function (R) { R._insertafter(this, element, this.paper); return this; }; - /*\ - * Element.insertBefore - [ method ] - ** - * Inserts current object before the given one. - = (object) @Element - \*/ + elproto.insertBefore = function (element) { if (this.removed) { return this; @@ -5320,7 +4279,7 @@ window.Raphael.svg && function (R) { var fltr = $("filter"), blur = $("feGaussianBlur"); t.attrs.blur = size; - fltr.id = R._createUUID(); + fltr.id = R.createUUID(); $(blur, {stdDeviation: +size || 1.5}); fltr.appendChild(blur); t.paper.defs.appendChild(fltr); @@ -5477,20 +4436,11 @@ window.Raphael.svg && function (R) { this._viewBox = [x, y, w, h, !!fit]; return this; }; - /*\ - * Paper.renderfix - [ method ] - ** - * Fixes the issue of Firefox and IE9 regarding subpixel rendering. If paper is dependant - * on other elements after reflow it could shift half pixel which cause for lines to lost their crispness. - * This method fixes the issue. - ** - Special thanks to Mariusz Nowak (http://www.medikoo.com/) for this method. - \*/ + R.prototype.renderfix = function () { var cnvs = this.canvas, s = cnvs.style, - pos = cnvs.getScreenCTM(), + pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(), left = -pos.e % 1, top = -pos.f % 1; if (left || top) { @@ -5504,12 +4454,7 @@ window.Raphael.svg && function (R) { } } }; - /*\ - * Paper.clear - [ method ] - ** - * Clears the paper, i.e. removes all the elements. - \*/ + R.prototype.clear = function () { R.eve("clear", this); var c = this.canvas; @@ -5521,17 +4466,12 @@ window.Raphael.svg && function (R) { c.appendChild(this.desc); c.appendChild(this.defs = $("defs")); }; - /*\ - * Paper.remove - [ method ] - ** - * Removes the paper from the DOM. - \*/ + R.prototype.remove = function () { eve("remove", this); this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); for (var i in this) { - this[i] = removed(i); + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } }; var setproto = R.st; @@ -5548,7 +4488,7 @@ window.Raphael.svg && function (R) { }(window.Raphael); // ┌─────────────────────────────────────────────────────────────────────┐ \\ -// │ Raphaël 2 - JavaScript Vector Library │ \\ +// │ Raphaël - JavaScript Vector Library │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ // │ VML Module │ \\ // ├─────────────────────────────────────────────────────────────────────┤ \\ @@ -5556,6 +4496,8 @@ window.Raphael.svg && function (R) { // │ 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, @@ -5567,26 +4509,27 @@ window.Raphael.vml && function (R) { abs = math.abs, fillString = "fill", separator = /[, ]+/, + eve = R.eve, + ms = " progid:DXImageTransform.Microsoft", S = " ", - E = ""; - // VML - var map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, + 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}, + 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 = path2curve); + 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 = lowerCase.call(command) == "m", + isMove = command.toLowerCase() == "m", res = map[command]; args.replace(val, function (value) { if (isMove && vals.length == 2) { @@ -5664,7 +4607,7 @@ window.Raphael.vml && function (R) { R.toString = function () { return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; }; - addArrow = function (o, value, isEnd) { + var addArrow = function (o, value, isEnd) { var values = Str(value).toLowerCase().split("-"), se = isEnd ? "end" : "start", i = values.length, @@ -5691,7 +4634,7 @@ window.Raphael.vml && function (R) { 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 || {}; @@ -5716,15 +4659,20 @@ window.Raphael.vml && function (R) { params.target && (node.target = params.target); params.cursor && (s.cursor = params.cursor); "blur" in params && o.blur(params.blur); - "transform" in params && o.transform(params.transform); if (params.path && o.type == "path" || newpath) { - node.path = path2vml(a.path); + 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; + 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) { @@ -5732,9 +4680,8 @@ window.Raphael.vml && function (R) { if (rect.length == 4) { rect[2] = +rect[2] + (+rect[0]); rect[3] = +rect[3] + (+rect[1]); - var div = node.clipRect || g.doc.createElement("div"), - dstyle = div.style, - group = node.parentNode; + 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"; @@ -5742,13 +4689,13 @@ window.Raphael.vml && function (R) { dstyle.left = 0; dstyle.width = o.paper.width + "px"; dstyle.height = o.paper.height + "px"; - group.parentNode.insertBefore(div, group); - div.appendChild(group); + node.parentNode.insertBefore(div, node); + div.appendChild(node); node.clipRect = div; } } if (!params["clip-rect"]) { - node.clipRect && (node.clipRect.style.clip = E); + node.clipRect && (node.clipRect.style.clip = "auto"); } } if (o.textpath) { @@ -5875,13 +4822,13 @@ window.Raphael.vml && function (R) { 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(fontSize ? fontSize[0] : a["font-size"]); + 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.paper.canvas.style.display = "none"; res.X = a.x; res.Y = a.y + res.H / 2; @@ -5910,10 +4857,11 @@ window.Raphael.vml && function (R) { 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", @@ -5967,7 +4915,7 @@ window.Raphael.vml && function (R) { o.appendChild(fill); } return 1; - }; + }, Element = function (node, vml) { this[0] = this.node = node; node.raphael = true; @@ -6002,19 +4950,21 @@ window.Raphael.vml && function (R) { if (tstr == null) { return this._.transform; } - R._extractTransform(this, tstr); + 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(), - vbs = this.paper._viewBoxShift, skew = this.skew, o = this.node, split, - isGrad = Str(this.attrs.fill).indexOf("-") + 1; + isGrad = ~Str(this.attrs.fill).indexOf("-"), + isPatt = !Str(this.attrs.fill).indexOf("url("); matrix.translate(-.5, -.5); - if (vbs) { - matrix.scale(vbs.scale, vbs.scale, -1, -1); - matrix.translate(vbs.dx, vbs.dy); - } - if (isGrad || this.type == "image") { + if (isPatt || isGrad || this.type == "image") { skew.matrix = "1 0 0 1"; skew.offset = "0 0"; split = matrix.split(); @@ -6035,6 +4985,7 @@ window.Raphael.vml && function (R) { skew.matrix = Str(matrix); skew.offset = matrix.offset(); } + oldt && (this._.transform = oldt); return this; }; elproto.rotate = function (deg, cx, cy) { @@ -6114,27 +5065,24 @@ window.Raphael.vml && function (R) { if (this.removed) { return {}; } - if (this.type == "text") { - return { - x: this.X + (this.bbx || 0) - this.W / 2, - y: this.Y - this.H, - width: this.W, - height: this.H - }; - } else { - return pathDimensions(this.attrs.path); - } + return { + x: this.X + (this.bbx || 0) - this.W / 2, + y: this.Y - this.H, + width: this.W, + height: this.H + }; }; 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) { - delete this[i]; + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } this.removed = true; }; @@ -6183,11 +5131,11 @@ window.Raphael.vml && function (R) { } value == null && R.is(name, "object") && (params = name); for (var key in params) { - R.eve("attr." + key + "." + this.id, this, params[key]); + 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])); + 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]; @@ -6204,7 +5152,7 @@ window.Raphael.vml && function (R) { }; elproto.toFront = function () { !this.removed && this.node.parentNode.appendChild(this.node); - this.paper && this.paper.top != this && tofront(this, this.paper); + this.paper && this.paper.top != this && R._tofront(this, this.paper); return this; }; elproto.toBack = function () { @@ -6213,7 +5161,7 @@ window.Raphael.vml && function (R) { } if (this.node.parentNode.firstChild != this.node) { this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); - toback(this, this.paper); + R._toback(this, this.paper); } return this; }; @@ -6221,7 +5169,7 @@ window.Raphael.vml && function (R) { if (this.removed) { return this; } - if (element.constructor == Set) { + if (element.constructor == R.st.constructor) { element = element[element.length - 1]; } if (element.node.nextSibling) { @@ -6236,7 +5184,7 @@ window.Raphael.vml && function (R) { if (this.removed) { return this; } - if (element.constructor == Set) { + if (element.constructor == R.st.constructor) { element = element[0]; } element.node.parentNode.insertBefore(this.node, element.node); @@ -6355,11 +5303,16 @@ window.Raphael.vml && function (R) { path.textpathok = true; o.string = Str(text); o.on = true; - el.style.cssText = "position:absolute;left:0;top:0;width:1px;height:1px"; + 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: availableAttrs.font, text: text}; + attr = { + fill: "#000", + stroke: "none", + font: R._availableAttrs.font, + text: text + }; p.shape = el; p.path = path; p.textpath = o; @@ -6390,7 +5343,7 @@ window.Raphael.vml && function (R) { cs.height = height; cs.clip = "rect(0 " + width + " " + height + " 0)"; if (this._viewBox) { - setViewBox.apply(this, this._viewBox); + R._engine.setViewBox.apply(this, this._viewBox); } return this; }; @@ -6421,8 +5374,8 @@ window.Raphael.vml && function (R) { }); return this; }; - var createNode, - initWin = function (win) { + var createNode; + R._engine.initWin = function (win) { var doc = win.document; doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); try { @@ -6436,7 +5389,7 @@ window.Raphael.vml && function (R) { }; } }; - initWin(R._g.win); + R._engine.initWin(R._g.win); R._engine.create = function () { var con = R._getContainer.apply(0, arguments), container = con.container, @@ -6484,7 +5437,7 @@ window.Raphael.vml && function (R) { R.prototype.clear = function () { R.eve("clear", this); this.canvas.innerHTML = E; - this.span = g.doc.createElement("span"); + 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; @@ -6493,8 +5446,20 @@ window.Raphael.vml && function (R) { R.eve("remove", this); this.canvas.parentNode.removeChild(this.canvas); for (var i in this) { - this[i] = removed(i); + this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null; } return true; }; + + 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