X-Git-Url: http://git.roojs.org/?a=blobdiff_plain;f=raphael.core.js;h=8344f1476eaed14f4463f2ad77ac1275dd221d93;hb=9dbae9c67d7949b0689b67e2e1f28a11114b1ede;hp=cfa2a8afdce9b9ce32e0980a0159295474870785;hpb=e1fb048f1336c6cb34e2bf7cb274c1b0e1aeca72;p=raphael diff --git a/raphael.core.js b/raphael.core.js index cfa2a8a..8344f14 100644 --- a/raphael.core.js +++ b/raphael.core.js @@ -1,10 +1,11 @@ // ┌─────────────────────────────────────────────────────────────────────┐ \\ -// │ "Raphaël 2.0" - 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. │ \\ // └─────────────────────────────────────────────────────────────────────┘ \\ + (function () { /*\ * Raphael @@ -26,7 +27,7 @@ - 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, }) + - 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, }). See @Paper.add. - 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`. @@ -60,17 +61,7 @@ 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 +74,7 @@ } } } - R.version = "2.0.0"; + R.version = "2.0.1"; R.eve = eve; var loaded, separator = /[, ]+/, @@ -99,7 +90,41 @@ was: Object.prototype[has].call(g.win, "Raphael"), is: g.win.Raphael }, - Paper = function () {}, + Paper = function () { + /*\ + * Paper.ca + [ property (object) ] + ** + * Shortcut for @Paper.customAttributes + \*/ + /*\ + * 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 + ", 0.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: "0.5 .8 1"}); + | c.animate({hsb: [1, 0, 0.5]}, 1e3); + \*/ + this.ca = this.customAttributes = {}; + }, paperproto, appendChild = "appendChild", apply = "apply", @@ -109,7 +134,7 @@ S = " ", Str = String, split = "split", - events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel".split(S), + events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S), touchMap = { mousedown: "touchstart", mousemove: "touchmove", @@ -131,14 +156,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", @@ -158,6 +182,7 @@ gradient: 0, height: 0, href: "http://raphaeljs.com/", + "letter-spacing": 0, opacity: 1, path: "M0,0", r: 0, @@ -213,7 +238,7 @@ return a.key - b.key; }, sortByNumber = function (a, b) { - return a - b; + return toFloat(a) - toFloat(b); }, fun = function () {}, pipe = function (x) { @@ -256,11 +281,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]; @@ -281,7 +306,8 @@ ** * 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"); + R.type = (g.win.SVGAngle || + g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); if (R.type == "VML") { var d = g.doc.createElement("div"), b; @@ -313,9 +339,10 @@ ** * 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. + * you need to extend the `Raphael.fn` object. You should modify the `fn` object before a + * Raphaël instance is created, otherwise it will take no effect. Please note that the + * ability for namespaced plugins was removed in Raphael 2.0. It is up to the plugin to + * ensure any namespacing ensures proper context. > Usage | Raphael.fn.arrow = function (x1, y1, x2, y2, size) { | return this.path( ... ); @@ -333,33 +360,6 @@ | 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; /*\ @@ -381,7 +381,7 @@ 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; @@ -467,7 +467,13 @@ return value; }; - var createUUID = R._createUUID = (function (uuidRegEx, uuidReplacer) { + /*\ + * Raphael.createUUID + [ method ] + ** + * Returns RFC4122, version 4 ID + \*/ + var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { return function () { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); }; @@ -489,8 +495,8 @@ 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); } }; var toHex = function (color) { @@ -620,7 +626,7 @@ 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; @@ -803,7 +809,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; @@ -875,7 +881,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]); @@ -886,7 +892,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]); @@ -899,7 +905,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]); @@ -990,6 +996,32 @@ delete this.start; }; + // 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; + } /*\ * Raphael.parsePathString [ method ] @@ -1013,7 +1045,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); }); @@ -1022,7 +1054,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; @@ -1060,7 +1094,7 @@ c.replace(pathValues, function (a, b) { b && params.push(+b); }); - data.push([name][concat](params)); + data.push([b][concat](params)); }); } data.toString = R._path2string; @@ -1134,6 +1168,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}; @@ -1284,9 +1323,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]) { @@ -1305,17 +1344,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]) { @@ -1330,11 +1383,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; @@ -1436,7 +1489,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; @@ -1665,11 +1718,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; @@ -1688,31 +1736,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; @@ -1736,20 +1810,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]; } } }, @@ -1766,8 +1841,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; } @@ -2091,10 +2166,15 @@ * Return transform string that represents given matrix = (string) transform string \*/ - 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)]; } @@ -2566,6 +2646,7 @@ elproto.unhover = function (f_in, f_out) { return this.unmouseover(f_in).unmouseout(f_out); }; + var draggable = []; /*\ * Element.drag [ method ] @@ -2612,6 +2693,7 @@ 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; }; @@ -2621,7 +2703,7 @@ ** * 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 + - f (function) handler for event, first argument would be the element you are dragging over \*/ elproto.onDragOver = function (f) { f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id); @@ -2633,13 +2715,13 @@ * 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); + !draggable.length && R.unmousemove(dragMove).unmouseup(dragUp); }; /*\ * Paper.circle @@ -2715,13 +2797,26 @@ [ 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. - ** + - pathString (string) #optional path string in SVG format. + * Path string consists of one-letter commands, followed by comma seprarated arguments in numercal form. Example: + | "M10,20L30,40" + * Here we can see two commands: “M”, with arguments `(10, 20)` and “L” with arguments `(30, 40)`. Upper case letter mean command is absolute, lower case—relative. + * + #

Here is short list of commands available, for more details see SVG path string format.

+ # + # + # + # + # + # + # + # + # + # + # + #
CommandNameParameters
Mmoveto(x y)+
Zclosepath(none)
Llineto(x y)+
Hhorizontal linetox+
Vvertical linetoy+
Ccurveto(x1 y1 x2 y2 x y)+
Ssmooth curveto(x2 y2 x y)+
Qquadratic Bézier curveto(x1 y1 x y)+
Tsmooth quadratic Bézier curveto(x y)+
Aelliptical arc(rx ry x-axis-rotation large-arc-flag sweep-flag x y)+
RCatmull-Rom curveto*x1 y1 (x y)+
+ * * “Catmull-Rom curveto” is a not standard SVG command and added in 2.0 to make life easier. > Usage | var c = paper.path("M10 10L90 90"); | // draw a diagonal line: @@ -3045,7 +3140,9 @@ if (this.removed) { return null; } - return this.paper[this.type]().attr(this.attr()); + var out = this.paper[this.type]().attr(this.attr()); + this.__set__ && this.__set__.push(out); + return out; }; /*\ * Element.glow @@ -3167,7 +3264,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; }; @@ -3222,7 +3319,7 @@ = (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); @@ -3387,7 +3484,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; @@ -3451,7 +3550,7 @@ } break; default: - var from2 = [].concat(from[attr]); + var from2 = [][concat](from[attr]); now = []; i = that.paper.customAttributes[attr].length; while (i--) { @@ -3478,6 +3577,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) { @@ -3513,10 +3616,9 @@ = (object) original element \*/ elproto.animateWith = function (element, anim, params, ms, easing, callback) { - var a = params ? R.animation(params, ms, easing, callback) : anim; + var a = params ? R.animation(params, ms, easing, callback) : anim, status = element.status(anim); - this.animate(a); - return this.status(a, status * anim.ms / a.ms); + return this.animate(a).status(a, status * anim.ms / a.ms); }; function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { var cx = 3 * p1x, @@ -3575,16 +3677,18 @@ 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; } @@ -3599,6 +3703,9 @@ - delay (number) number of ms to pass between animation start and actual animation ** = (object) new altered Animation object + | var anim = Raphael.animation({cx: 10, cy: 20}, 2e3); + | circle1.animate(anim); // run the given animation immediately + | circle2.animate(anim.delay(500)); // run the given animation after 500 ms \*/ Animation.prototype.delay = function (delay) { var a = new Animation(this.anim, this.ms); @@ -3670,7 +3777,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]); @@ -3753,8 +3860,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] = []; @@ -3766,8 +3873,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--) { @@ -3859,7 +3966,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]; } @@ -4097,7 +4204,7 @@ \*/ 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; } } @@ -4187,13 +4294,8 @@ = (boolean) `true` if object was found & removed from the set \*/ setproto.exclude = function (el) { - for (var i = 0, ii = this.length, found; i < ii; i++) if (found || this[i] == el) { - this[i] = this[i + 1]; - found = 1; - } - if (found) { - this.length--; - delete this[i]; + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); return true; } }; @@ -4381,14 +4483,14 @@ 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++) { @@ -4406,6 +4508,48 @@ return out; }; + /*\ + * Paper.add + [ method ] + ** + * Imports elements in JSON array in format `{type: type, }` + ** + > Parameters + ** + - json (array) + = (object) resulting set of imported elements + > Usage + | paper.import([ + | { + | type: "circle", + | cx: 10, + | cy: 10, + | r: 5 + | }, + | { + | type: "rect", + | x: 10, + | y: 10, + | width: 10, + | height: 10, + | fill: "#fc0" + | } + | ]); + \*/ + 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; + }; + /*\ * Raphael.format [ method ] @@ -4423,7 +4567,7 @@ | width = 40, | height = 50; | // this will draw a rectangular shape equivalent to "M10,20h40v50h-40z" - | paper.path(Raphael.format("M{1},{2}h{3}v{4}h{5}z", x, y, width, height, -width)); + | paper.path(Raphael.format("M{0},{1}h{2}v{3}h{4}z", x, y, width, height, -width)); \*/ R.format = function (token, params) { var args = R.is(params, array) ? [0][concat](params) : arguments; @@ -4537,4 +4681,4 @@ eve.on("DOMload", function () { loaded = true; }); -})(); \ No newline at end of file +})();