annotate js-lib/raphael.js @ 94:0f19af92260e laserkard

saving progress.
author Robert McIntyre <rlm@mit.edu>
date Mon, 26 Jul 2010 20:33:17 -0400
parents e0dadfad3dc4
children
rev   line source
rlm@83 1 /*!
rlm@83 2 * Raphael 1.4.7 - JavaScript Vector Library
rlm@83 3 *
rlm@83 4 * Copyright (c) 2010 Dmitry Baranovskiy (http://raphaeljs.com)
rlm@83 5 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
rlm@83 6 */
rlm@83 7
rlm@83 8 Raphael = (function () {
rlm@83 9 function R() {
rlm@83 10 if (R.is(arguments[0], array)) {
rlm@83 11 var a = arguments[0],
rlm@83 12 cnv = create[apply](R, a.splice(0, 3 + R.is(a[0], nu))),
rlm@83 13 res = cnv.set();
rlm@83 14 for (var i = 0, ii = a[length]; i < ii; i++) {
rlm@83 15 var j = a[i] || {};
rlm@83 16 elements.test(j.type) && res[push](cnv[j.type]().attr(j));
rlm@83 17 }
rlm@83 18 return res;
rlm@83 19 }
rlm@83 20 return create[apply](R, arguments);
rlm@83 21 }
rlm@83 22 R.version = "1.4.7";
rlm@83 23 var separator = /[, ]+/,
rlm@83 24 elements = /^(circle|rect|path|ellipse|text|image)$/,
rlm@83 25 proto = "prototype",
rlm@83 26 has = "hasOwnProperty",
rlm@83 27 doc = document,
rlm@83 28 win = window,
rlm@83 29 oldRaphael = {
rlm@83 30 was: Object[proto][has].call(win, "Raphael"),
rlm@83 31 is: win.Raphael
rlm@83 32 },
rlm@83 33 Paper = function () {},
rlm@83 34 appendChild = "appendChild",
rlm@83 35 apply = "apply",
rlm@83 36 concat = "concat",
rlm@83 37 supportsTouch = "createTouch" in doc,
rlm@83 38 E = "",
rlm@83 39 S = " ",
rlm@83 40 Str = String,
rlm@83 41 split = "split",
rlm@83 42 events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend orientationchange touchcancel gesturestart gesturechange gestureend"[split](S),
rlm@83 43 touchMap = {
rlm@83 44 mousedown: "touchstart",
rlm@83 45 mousemove: "touchmove",
rlm@83 46 mouseup: "touchend"
rlm@83 47 },
rlm@83 48 join = "join",
rlm@83 49 length = "length",
rlm@83 50 lowerCase = String[proto].toLowerCase,
rlm@83 51 math = Math,
rlm@83 52 mmax = math.max,
rlm@83 53 mmin = math.min,
rlm@83 54 nu = "number",
rlm@83 55 string = "string",
rlm@83 56 array = "array",
rlm@83 57 toString = "toString",
rlm@83 58 fillString = "fill",
rlm@83 59 objectToString = Object[proto][toString],
rlm@83 60 paper = {},
rlm@83 61 pow = math.pow,
rlm@83 62 push = "push",
rlm@83 63 rg = /^(?=[\da-f]$)/,
rlm@83 64 ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i,
rlm@83 65 colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+\s*,\s*[\d\.]+\s*,\s*[\d\.]+(?:\s*,\s*[\d\.]+)?)\s*\)|rgba?\(\s*([\d\.]+%\s*,\s*[\d\.]+%\s*,\s*[\d\.]+%(?:\s*,\s*[\d\.]+%)?)\s*\)|hsb\(\s*([\d\.]+(?:deg|\xb0)?\s*,\s*[\d\.]+\s*,\s*[\d\.]+)\s*\)|hsb\(\s*([\d\.]+(?:deg|\xb0|%)\s*,\s*[\d\.]+%\s*,\s*[\d\.]+%)\s*\)|hsl\(\s*([\d\.]+(?:deg|\xb0)?\s*,\s*[\d\.]+\s*,\s*[\d\.]+)\s*\)|hsl\(\s*([\d\.]+(?:deg|\xb0|%)\s*,\s*[\d\.]+%\s*,\s*[\d\.]+%)\s*\))\s*$/i,
rlm@83 66 round = math.round,
rlm@83 67 setAttribute = "setAttribute",
rlm@83 68 toFloat = parseFloat,
rlm@83 69 toInt = parseInt,
rlm@83 70 ms = " progid:DXImageTransform.Microsoft",
rlm@83 71 upperCase = String[proto].toUpperCase,
rlm@83 72 availableAttrs = {blur: 0, "clip-rect": "0 0 1e9 1e9", cursor: "default", cx: 0, cy: 0, fill: "#fff", "fill-opacity": 1, font: '10px "Arial"', "font-family": '"Arial"', "font-size": "10", "font-style": "normal", "font-weight": 400, gradient: 0, height: 0, href: "http://raphaeljs.com/", opacity: 1, path: "M0,0", r: 0, rotation: 0, rx: 0, ry: 0, scale: "1 1", src: "", stroke: "#000", "stroke-dasharray": "", "stroke-linecap": "butt", "stroke-linejoin": "butt", "stroke-miterlimit": 0, "stroke-opacity": 1, "stroke-width": 1, target: "_blank", "text-anchor": "middle", title: "Raphael", translation: "0 0", width: 0, x: 0, y: 0},
rlm@83 73 availableAnimAttrs = {along: "along", blur: nu, "clip-rect": "csv", cx: nu, cy: nu, fill: "colour", "fill-opacity": nu, "font-size": nu, height: nu, opacity: nu, path: "path", r: nu, rotation: "csv", rx: nu, ry: nu, scale: "csv", stroke: "colour", "stroke-opacity": nu, "stroke-width": nu, translation: "csv", width: nu, x: nu, y: nu},
rlm@83 74 rp = "replace";
rlm@83 75 R.type = (win.SVGAngle || doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML");
rlm@83 76 if (R.type == "VML") {
rlm@83 77 var d = doc.createElement("div"),
rlm@83 78 b;
rlm@83 79 d.innerHTML = '<v:shape adj="1"/>';
rlm@83 80 b = d.firstChild;
rlm@83 81 b.style.behavior = "url(#default#VML)";
rlm@83 82 if (!(b && typeof b.adj == "object")) {
rlm@83 83 return R.type = null;
rlm@83 84 }
rlm@83 85 d = null;
rlm@83 86 }
rlm@83 87 R.svg = !(R.vml = R.type == "VML");
rlm@83 88 Paper[proto] = R[proto];
rlm@83 89 R._id = 0;
rlm@83 90 R._oid = 0;
rlm@83 91 R.fn = {};
rlm@83 92 R.is = function (o, type) {
rlm@83 93 type = lowerCase.call(type);
rlm@83 94 return (type == "object" && o === Object(o)) ||
rlm@83 95 (type == "undefined" && typeof o == type) ||
rlm@83 96 (type == "null" && o == null) ||
rlm@83 97 (type == "array" && Array.isArray && Array.isArray(o)) ||
rlm@83 98 lowerCase.call(objectToString.call(o).slice(8, -1)) == type;
rlm@83 99 };
rlm@83 100
rlm@83 101 R.setWindow = function (newwin) {
rlm@83 102 win = newwin;
rlm@83 103 doc = win.document;
rlm@83 104 };
rlm@83 105 // colour utilities
rlm@83 106 var toHex = function (color) {
rlm@83 107 if (R.vml) {
rlm@83 108 // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/
rlm@83 109 var trim = /^\s+|\s+$/g;
rlm@83 110 toHex = cacher(function (color) {
rlm@83 111 var bod;
rlm@83 112 color = Str(color)[rp](trim, E);
rlm@83 113 try {
rlm@83 114 var docum = new win.ActiveXObject("htmlfile");
rlm@83 115 docum.write("<body>");
rlm@83 116 docum.close();
rlm@83 117 bod = docum.body;
rlm@83 118 } catch(e) {
rlm@83 119 bod = win.createPopup().document.body;
rlm@83 120 }
rlm@83 121 var range = bod.createTextRange();
rlm@83 122 try {
rlm@83 123 bod.style.color = color;
rlm@83 124 var value = range.queryCommandValue("ForeColor");
rlm@83 125 value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16);
rlm@83 126 return "#" + ("000000" + value[toString](16)).slice(-6);
rlm@83 127 } catch(e) {
rlm@83 128 return "none";
rlm@83 129 }
rlm@83 130 });
rlm@83 131 } else {
rlm@83 132 var i = doc.createElement("i");
rlm@83 133 i.title = "Rapha\xebl Colour Picker";
rlm@83 134 i.style.display = "none";
rlm@83 135 doc.body[appendChild](i);
rlm@83 136 toHex = cacher(function (color) {
rlm@83 137 i.style.color = color;
rlm@83 138 return doc.defaultView.getComputedStyle(i, E).getPropertyValue("color");
rlm@83 139 });
rlm@83 140 }
rlm@83 141 return toHex(color);
rlm@83 142 },
rlm@83 143 hsbtoString = function () {
rlm@83 144 return "hsb(" + [this.h, this.s, this.b] + ")";
rlm@83 145 },
rlm@83 146 hsltoString = function () {
rlm@83 147 return "hsl(" + [this.h, this.s, this.l] + ")";
rlm@83 148 },
rlm@83 149 rgbtoString = function () {
rlm@83 150 return this.hex;
rlm@83 151 };
rlm@83 152 R.hsb2rgb = function (h, s, b) {
rlm@83 153 if (R.is(h, "object") && "h" in h && "s" in h && "b" in h) {
rlm@83 154 b = h.b;
rlm@83 155 s = h.s;
rlm@83 156 h = h.h;
rlm@83 157 }
rlm@83 158 return R.hsl2rgb(h, s, b / 2);
rlm@83 159 };
rlm@83 160 R.hsl2rgb = function (h, s, l) {
rlm@83 161 if (R.is(h, "object") && "h" in h && "s" in h && "l" in h) {
rlm@83 162 l = h.l;
rlm@83 163 s = h.s;
rlm@83 164 h = h.h;
rlm@83 165 }
rlm@83 166 if (h > 1 || s > 1 || l > 1) {
rlm@83 167 h /= 255;
rlm@83 168 s /= 255;
rlm@83 169 l /= 255;
rlm@83 170 }
rlm@83 171 var rgb = {},
rlm@83 172 channels = ["r", "g", "b"],
rlm@83 173 t2, t1, t3, r, g, b;
rlm@83 174 if (!s) {
rlm@83 175 rgb = {
rlm@83 176 r: l,
rlm@83 177 g: l,
rlm@83 178 b: l
rlm@83 179 };
rlm@83 180 } else {
rlm@83 181 if (l < .5) {
rlm@83 182 t2 = l * (1 + s);
rlm@83 183 } else {
rlm@83 184 t2 = l + s - l * s;
rlm@83 185 }
rlm@83 186 t1 = 2 * l - t2;
rlm@83 187 for (var i = 0, ii = channels.length; i < ii; i++) {
rlm@83 188 t3 = h + 1 / 3 * -(i - 1);
rlm@83 189 t3 < 0 && t3++;
rlm@83 190 t3 > 1 && t3--;
rlm@83 191 if (t3 * 6 < 1) {
rlm@83 192 rgb[channels[i]] = t1 + (t2 - t1) * 6 * t3;
rlm@83 193 } else if (t3 * 2 < 1) {
rlm@83 194 rgb[channels[i]] = t2;
rlm@83 195 } else if (t3 * 3 < 2) {
rlm@83 196 rgb[channels[i]] = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
rlm@83 197 } else {
rlm@83 198 rgb[channels[i]] = t1;
rlm@83 199 }
rlm@83 200 }
rlm@83 201 }
rlm@83 202 rgb.r *= 255;
rlm@83 203 rgb.g *= 255;
rlm@83 204 rgb.b *= 255;
rlm@83 205 r = (~~rgb.r)[toString](16);
rlm@83 206 g = (~~rgb.g)[toString](16);
rlm@83 207 b = (~~rgb.b)[toString](16);
rlm@83 208 r = r[rp](rg, "0");
rlm@83 209 g = g[rp](rg, "0");
rlm@83 210 b = b[rp](rg, "0");
rlm@83 211 rgb.hex = "#" + r + g + b;
rlm@83 212 rgb.toString = rgbtoString;
rlm@83 213 return rgb;
rlm@83 214 };
rlm@83 215 R.rgb2hsb = function (red, green, blue) {
rlm@83 216 if (green == null && R.is(red, "object") && "r" in red && "g" in red && "b" in red) {
rlm@83 217 blue = red.b;
rlm@83 218 green = red.g;
rlm@83 219 red = red.r;
rlm@83 220 }
rlm@83 221 if (green == null && R.is(red, string)) {
rlm@83 222 var clr = R.getRGB(red);
rlm@83 223 red = clr.r;
rlm@83 224 green = clr.g;
rlm@83 225 blue = clr.b;
rlm@83 226 }
rlm@83 227 if (red > 1 || green > 1 || blue > 1) {
rlm@83 228 red /= 255;
rlm@83 229 green /= 255;
rlm@83 230 blue /= 255;
rlm@83 231 }
rlm@83 232 var max = mmax(red, green, blue),
rlm@83 233 min = mmin(red, green, blue),
rlm@83 234 hue,
rlm@83 235 saturation,
rlm@83 236 brightness = max;
rlm@83 237 if (min == max) {
rlm@83 238 return {h: 0, s: 0, b: max, toString: hsbtoString};
rlm@83 239 } else {
rlm@83 240 var delta = (max - min);
rlm@83 241 saturation = delta / max;
rlm@83 242 if (red == max) {
rlm@83 243 hue = (green - blue) / delta;
rlm@83 244 } else if (green == max) {
rlm@83 245 hue = 2 + ((blue - red) / delta);
rlm@83 246 } else {
rlm@83 247 hue = 4 + ((red - green) / delta);
rlm@83 248 }
rlm@83 249 hue /= 6;
rlm@83 250 hue < 0 && hue++;
rlm@83 251 hue > 1 && hue--;
rlm@83 252 }
rlm@83 253 return {h: hue, s: saturation, b: brightness, toString: hsbtoString};
rlm@83 254 };
rlm@83 255 R.rgb2hsl = function (red, green, blue) {
rlm@83 256 if (green == null && R.is(red, "object") && "r" in red && "g" in red && "b" in red) {
rlm@83 257 blue = red.b;
rlm@83 258 green = red.g;
rlm@83 259 red = red.r;
rlm@83 260 }
rlm@83 261 if (green == null && R.is(red, string)) {
rlm@83 262 var clr = R.getRGB(red);
rlm@83 263 red = clr.r;
rlm@83 264 green = clr.g;
rlm@83 265 blue = clr.b;
rlm@83 266 }
rlm@83 267 if (red > 1 || green > 1 || blue > 1) {
rlm@83 268 red /= 255;
rlm@83 269 green /= 255;
rlm@83 270 blue /= 255;
rlm@83 271 }
rlm@83 272 var max = mmax(red, green, blue),
rlm@83 273 min = mmin(red, green, blue),
rlm@83 274 h,
rlm@83 275 s,
rlm@83 276 l = (max + min) / 2,
rlm@83 277 hsl;
rlm@83 278 if (min == max) {
rlm@83 279 hsl = {h: 0, s: 0, l: l};
rlm@83 280 } else {
rlm@83 281 var delta = max - min;
rlm@83 282 s = l < .5 ? delta / (max + min) : delta / (2 - max - min);
rlm@83 283 if (red == max) {
rlm@83 284 h = (green - blue) / delta;
rlm@83 285 } else if (green == max) {
rlm@83 286 h = 2 + (blue - red) / delta;
rlm@83 287 } else {
rlm@83 288 h = 4 + (red - green) / delta;
rlm@83 289 }
rlm@83 290 h /= 6;
rlm@83 291 h < 0 && h++;
rlm@83 292 h > 1 && h--;
rlm@83 293 hsl = {h: h, s: s, l: l};
rlm@83 294 }
rlm@83 295 hsl.toString = hsltoString;
rlm@83 296 return hsl;
rlm@83 297 };
rlm@83 298 var p2s = /,?([achlmqrstvxz]),?/gi,
rlm@83 299 commaSpaces = /\s*,\s*/,
rlm@83 300 hsrg = {hs: 1, rg: 1};
rlm@83 301 R._path2string = function () {
rlm@83 302 return this.join(",")[rp](p2s, "$1");
rlm@83 303 };
rlm@83 304 function cacher(f, scope, postprocessor) {
rlm@83 305 function newf() {
rlm@83 306 var arg = Array[proto].slice.call(arguments, 0),
rlm@83 307 args = arg[join]("\u25ba"),
rlm@83 308 cache = newf.cache = newf.cache || {},
rlm@83 309 count = newf.count = newf.count || [];
rlm@83 310 if (cache[has](args)) {
rlm@83 311 return postprocessor ? postprocessor(cache[args]) : cache[args];
rlm@83 312 }
rlm@83 313 count[length] >= 1e3 && delete cache[count.shift()];
rlm@83 314 count[push](args);
rlm@83 315 cache[args] = f[apply](scope, arg);
rlm@83 316 return postprocessor ? postprocessor(cache[args]) : cache[args];
rlm@83 317 }
rlm@83 318 return newf;
rlm@83 319 }
rlm@83 320
rlm@83 321 R.getRGB = cacher(function (colour) {
rlm@83 322 if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) {
rlm@83 323 return {r: -1, g: -1, b: -1, hex: "none", error: 1};
rlm@83 324 }
rlm@83 325 if (colour == "none") {
rlm@83 326 return {r: -1, g: -1, b: -1, hex: "none"};
rlm@83 327 }
rlm@83 328 !(hsrg[has](colour.substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour));
rlm@83 329 var res,
rlm@83 330 red,
rlm@83 331 green,
rlm@83 332 blue,
rlm@83 333 opacity,
rlm@83 334 t,
rlm@83 335 rgb = colour.match(colourRegExp);
rlm@83 336 if (rgb) {
rlm@83 337 if (rgb[2]) {
rlm@83 338 blue = toInt(rgb[2].substring(5), 16);
rlm@83 339 green = toInt(rgb[2].substring(3, 5), 16);
rlm@83 340 red = toInt(rgb[2].substring(1, 3), 16);
rlm@83 341 }
rlm@83 342 if (rgb[3]) {
rlm@83 343 blue = toInt((t = rgb[3].charAt(3)) + t, 16);
rlm@83 344 green = toInt((t = rgb[3].charAt(2)) + t, 16);
rlm@83 345 red = toInt((t = rgb[3].charAt(1)) + t, 16);
rlm@83 346 }
rlm@83 347 if (rgb[4]) {
rlm@83 348 rgb = rgb[4][split](commaSpaces);
rlm@83 349 red = toFloat(rgb[0]);
rlm@83 350 green = toFloat(rgb[1]);
rlm@83 351 blue = toFloat(rgb[2]);
rlm@83 352 opacity = toFloat(rgb[3]);
rlm@83 353 }
rlm@83 354 if (rgb[5]) {
rlm@83 355 rgb = rgb[5][split](commaSpaces);
rlm@83 356 red = toFloat(rgb[0]) * 2.55;
rlm@83 357 green = toFloat(rgb[1]) * 2.55;
rlm@83 358 blue = toFloat(rgb[2]) * 2.55;
rlm@83 359 opacity = toFloat(rgb[3]);
rlm@83 360 }
rlm@83 361 if (rgb[6]) {
rlm@83 362 rgb = rgb[6][split](commaSpaces);
rlm@83 363 red = toFloat(rgb[0]);
rlm@83 364 green = toFloat(rgb[1]);
rlm@83 365 blue = toFloat(rgb[2]);
rlm@83 366 (rgb[0].slice(-3) == "deg" || rgb[0].slice(-1) == "\xb0") && (red /= 360);
rlm@83 367 return R.hsb2rgb(red, green, blue);
rlm@83 368 }
rlm@83 369 if (rgb[7]) {
rlm@83 370 rgb = rgb[7][split](commaSpaces);
rlm@83 371 red = toFloat(rgb[0]) * 2.55;
rlm@83 372 green = toFloat(rgb[1]) * 2.55;
rlm@83 373 blue = toFloat(rgb[2]) * 2.55;
rlm@83 374 (rgb[0].slice(-3) == "deg" || rgb[0].slice(-1) == "\xb0") && (red /= 360 * 2.55);
rlm@83 375 return R.hsb2rgb(red, green, blue);
rlm@83 376 }
rlm@83 377 if (rgb[8]) {
rlm@83 378 rgb = rgb[8][split](commaSpaces);
rlm@83 379 red = toFloat(rgb[0]);
rlm@83 380 green = toFloat(rgb[1]);
rlm@83 381 blue = toFloat(rgb[2]);
rlm@83 382 (rgb[0].slice(-3) == "deg" || rgb[0].slice(-1) == "\xb0") && (red /= 360);
rlm@83 383 return R.hsl2rgb(red, green, blue);
rlm@83 384 }
rlm@83 385 if (rgb[9]) {
rlm@83 386 rgb = rgb[9][split](commaSpaces);
rlm@83 387 red = toFloat(rgb[0]) * 2.55;
rlm@83 388 green = toFloat(rgb[1]) * 2.55;
rlm@83 389 blue = toFloat(rgb[2]) * 2.55;
rlm@83 390 (rgb[0].slice(-3) == "deg" || rgb[0].slice(-1) == "\xb0") && (red /= 360 * 2.55);
rlm@83 391 return R.hsl2rgb(red, green, blue);
rlm@83 392 }
rlm@83 393 rgb = {r: red, g: green, b: blue};
rlm@83 394 var r = (~~red)[toString](16),
rlm@83 395 g = (~~green)[toString](16),
rlm@83 396 b = (~~blue)[toString](16);
rlm@83 397 r = r[rp](rg, "0");
rlm@83 398 g = g[rp](rg, "0");
rlm@83 399 b = b[rp](rg, "0");
rlm@83 400 rgb.hex = "#" + r + g + b;
rlm@83 401 isFinite(toFloat(opacity)) && (rgb.o = opacity);
rlm@83 402 return rgb;
rlm@83 403 }
rlm@83 404 return {r: -1, g: -1, b: -1, hex: "none", error: 1};
rlm@83 405 }, R);
rlm@83 406 R.getColor = function (value) {
rlm@83 407 var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75},
rlm@83 408 rgb = this.hsb2rgb(start.h, start.s, start.b);
rlm@83 409 start.h += .075;
rlm@83 410 if (start.h > 1) {
rlm@83 411 start.h = 0;
rlm@83 412 start.s -= .2;
rlm@83 413 start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b});
rlm@83 414 }
rlm@83 415 return rgb.hex;
rlm@83 416 };
rlm@83 417 R.getColor.reset = function () {
rlm@83 418 delete this.start;
rlm@83 419 };
rlm@83 420 // path utilities
rlm@83 421 var pathCommand = /([achlmqstvz])[\s,]*((-?\d*\.?\d*(?:e[-+]?\d+)?\s*,?\s*)+)/ig,
rlm@83 422 pathValues = /(-?\d*\.?\d*(?:e[-+]?\d+)?)\s*,?\s*/ig;
rlm@83 423 R.parsePathString = cacher(function (pathString) {
rlm@83 424 if (!pathString) {
rlm@83 425 return null;
rlm@83 426 }
rlm@83 427 var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, q: 4, s: 4, t: 2, v: 1, z: 0},
rlm@83 428 data = [];
rlm@83 429 if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption
rlm@83 430 data = pathClone(pathString);
rlm@83 431 }
rlm@83 432 if (!data[length]) {
rlm@83 433 Str(pathString)[rp](pathCommand, function (a, b, c) {
rlm@83 434 var params = [],
rlm@83 435 name = lowerCase.call(b);
rlm@83 436 c[rp](pathValues, function (a, b) {
rlm@83 437 b && params[push](+b);
rlm@83 438 });
rlm@83 439 if (name == "m" && params[length] > 2) {
rlm@83 440 data[push]([b][concat](params.splice(0, 2)));
rlm@83 441 name = "l";
rlm@83 442 b = b == "m" ? "l" : "L";
rlm@83 443 }
rlm@83 444 while (params[length] >= paramCounts[name]) {
rlm@83 445 data[push]([b][concat](params.splice(0, paramCounts[name])));
rlm@83 446 if (!paramCounts[name]) {
rlm@83 447 break;
rlm@83 448 }
rlm@83 449 }
rlm@83 450 });
rlm@83 451 }
rlm@83 452 data[toString] = R._path2string;
rlm@83 453 return data;
rlm@83 454 });
rlm@83 455 R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
rlm@83 456 var t1 = 1 - t,
rlm@83 457 x = pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
rlm@83 458 y = pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y,
rlm@83 459 mx = p1x + 2 * t * (c1x - p1x) + t * t * (c2x - 2 * c1x + p1x),
rlm@83 460 my = p1y + 2 * t * (c1y - p1y) + t * t * (c2y - 2 * c1y + p1y),
rlm@83 461 nx = c1x + 2 * t * (c2x - c1x) + t * t * (p2x - 2 * c2x + c1x),
rlm@83 462 ny = c1y + 2 * t * (c2y - c1y) + t * t * (p2y - 2 * c2y + c1y),
rlm@83 463 ax = (1 - t) * p1x + t * c1x,
rlm@83 464 ay = (1 - t) * p1y + t * c1y,
rlm@83 465 cx = (1 - t) * c2x + t * p2x,
rlm@83 466 cy = (1 - t) * c2y + t * p2y,
rlm@83 467 alpha = (90 - math.atan((mx - nx) / (my - ny)) * 180 / math.PI);
rlm@83 468 (mx > nx || my < ny) && (alpha += 180);
rlm@83 469 return {x: x, y: y, m: {x: mx, y: my}, n: {x: nx, y: ny}, start: {x: ax, y: ay}, end: {x: cx, y: cy}, alpha: alpha};
rlm@83 470 };
rlm@83 471 var pathDimensions = cacher(function (path) {
rlm@83 472 if (!path) {
rlm@83 473 return {x: 0, y: 0, width: 0, height: 0};
rlm@83 474 }
rlm@83 475 path = path2curve(path);
rlm@83 476 var x = 0,
rlm@83 477 y = 0,
rlm@83 478 X = [],
rlm@83 479 Y = [],
rlm@83 480 p;
rlm@83 481 for (var i = 0, ii = path[length]; i < ii; i++) {
rlm@83 482 p = path[i];
rlm@83 483 if (p[0] == "M") {
rlm@83 484 x = p[1];
rlm@83 485 y = p[2];
rlm@83 486 X[push](x);
rlm@83 487 Y[push](y);
rlm@83 488 } else {
rlm@83 489 var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
rlm@83 490 X = X[concat](dim.min.x, dim.max.x);
rlm@83 491 Y = Y[concat](dim.min.y, dim.max.y);
rlm@83 492 x = p[5];
rlm@83 493 y = p[6];
rlm@83 494 }
rlm@83 495 }
rlm@83 496 var xmin = mmin[apply](0, X),
rlm@83 497 ymin = mmin[apply](0, Y);
rlm@83 498 return {
rlm@83 499 x: xmin,
rlm@83 500 y: ymin,
rlm@83 501 width: mmax[apply](0, X) - xmin,
rlm@83 502 height: mmax[apply](0, Y) - ymin
rlm@83 503 };
rlm@83 504 }),
rlm@83 505 pathClone = function (pathArray) {
rlm@83 506 var res = [];
rlm@83 507 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
rlm@83 508 pathArray = R.parsePathString(pathArray);
rlm@83 509 }
rlm@83 510 for (var i = 0, ii = pathArray[length]; i < ii; i++) {
rlm@83 511 res[i] = [];
rlm@83 512 for (var j = 0, jj = pathArray[i][length]; j < jj; j++) {
rlm@83 513 res[i][j] = pathArray[i][j];
rlm@83 514 }
rlm@83 515 }
rlm@83 516 res[toString] = R._path2string;
rlm@83 517 return res;
rlm@83 518 },
rlm@83 519 pathToRelative = cacher(function (pathArray) {
rlm@83 520 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
rlm@83 521 pathArray = R.parsePathString(pathArray);
rlm@83 522 }
rlm@83 523 var res = [],
rlm@83 524 x = 0,
rlm@83 525 y = 0,
rlm@83 526 mx = 0,
rlm@83 527 my = 0,
rlm@83 528 start = 0;
rlm@83 529 if (pathArray[0][0] == "M") {
rlm@83 530 x = pathArray[0][1];
rlm@83 531 y = pathArray[0][2];
rlm@83 532 mx = x;
rlm@83 533 my = y;
rlm@83 534 start++;
rlm@83 535 res[push](["M", x, y]);
rlm@83 536 }
rlm@83 537 for (var i = start, ii = pathArray[length]; i < ii; i++) {
rlm@83 538 var r = res[i] = [],
rlm@83 539 pa = pathArray[i];
rlm@83 540 if (pa[0] != lowerCase.call(pa[0])) {
rlm@83 541 r[0] = lowerCase.call(pa[0]);
rlm@83 542 switch (r[0]) {
rlm@83 543 case "a":
rlm@83 544 r[1] = pa[1];
rlm@83 545 r[2] = pa[2];
rlm@83 546 r[3] = pa[3];
rlm@83 547 r[4] = pa[4];
rlm@83 548 r[5] = pa[5];
rlm@83 549 r[6] = +(pa[6] - x).toFixed(3);
rlm@83 550 r[7] = +(pa[7] - y).toFixed(3);
rlm@83 551 break;
rlm@83 552 case "v":
rlm@83 553 r[1] = +(pa[1] - y).toFixed(3);
rlm@83 554 break;
rlm@83 555 case "m":
rlm@83 556 mx = pa[1];
rlm@83 557 my = pa[2];
rlm@83 558 default:
rlm@83 559 for (var j = 1, jj = pa[length]; j < jj; j++) {
rlm@83 560 r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3);
rlm@83 561 }
rlm@83 562 }
rlm@83 563 } else {
rlm@83 564 r = res[i] = [];
rlm@83 565 if (pa[0] == "m") {
rlm@83 566 mx = pa[1] + x;
rlm@83 567 my = pa[2] + y;
rlm@83 568 }
rlm@83 569 for (var k = 0, kk = pa[length]; k < kk; k++) {
rlm@83 570 res[i][k] = pa[k];
rlm@83 571 }
rlm@83 572 }
rlm@83 573 var len = res[i][length];
rlm@83 574 switch (res[i][0]) {
rlm@83 575 case "z":
rlm@83 576 x = mx;
rlm@83 577 y = my;
rlm@83 578 break;
rlm@83 579 case "h":
rlm@83 580 x += +res[i][len - 1];
rlm@83 581 break;
rlm@83 582 case "v":
rlm@83 583 y += +res[i][len - 1];
rlm@83 584 break;
rlm@83 585 default:
rlm@83 586 x += +res[i][len - 2];
rlm@83 587 y += +res[i][len - 1];
rlm@83 588 }
rlm@83 589 }
rlm@83 590 res[toString] = R._path2string;
rlm@83 591 return res;
rlm@83 592 }, 0, pathClone),
rlm@83 593 pathToAbsolute = cacher(function (pathArray) {
rlm@83 594 if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption
rlm@83 595 pathArray = R.parsePathString(pathArray);
rlm@83 596 }
rlm@83 597 var res = [],
rlm@83 598 x = 0,
rlm@83 599 y = 0,
rlm@83 600 mx = 0,
rlm@83 601 my = 0,
rlm@83 602 start = 0;
rlm@83 603 if (pathArray[0][0] == "M") {
rlm@83 604 x = +pathArray[0][1];
rlm@83 605 y = +pathArray[0][2];
rlm@83 606 mx = x;
rlm@83 607 my = y;
rlm@83 608 start++;
rlm@83 609 res[0] = ["M", x, y];
rlm@83 610 }
rlm@83 611 for (var i = start, ii = pathArray[length]; i < ii; i++) {
rlm@83 612 var r = res[i] = [],
rlm@83 613 pa = pathArray[i];
rlm@83 614 if (pa[0] != upperCase.call(pa[0])) {
rlm@83 615 r[0] = upperCase.call(pa[0]);
rlm@83 616 switch (r[0]) {
rlm@83 617 case "A":
rlm@83 618 r[1] = pa[1];
rlm@83 619 r[2] = pa[2];
rlm@83 620 r[3] = pa[3];
rlm@83 621 r[4] = pa[4];
rlm@83 622 r[5] = pa[5];
rlm@83 623 r[6] = +(pa[6] + x);
rlm@83 624 r[7] = +(pa[7] + y);
rlm@83 625 break;
rlm@83 626 case "V":
rlm@83 627 r[1] = +pa[1] + y;
rlm@83 628 break;
rlm@83 629 case "H":
rlm@83 630 r[1] = +pa[1] + x;
rlm@83 631 break;
rlm@83 632 case "M":
rlm@83 633 mx = +pa[1] + x;
rlm@83 634 my = +pa[2] + y;
rlm@83 635 default:
rlm@83 636 for (var j = 1, jj = pa[length]; j < jj; j++) {
rlm@83 637 r[j] = +pa[j] + ((j % 2) ? x : y);
rlm@83 638 }
rlm@83 639 }
rlm@83 640 } else {
rlm@83 641 for (var k = 0, kk = pa[length]; k < kk; k++) {
rlm@83 642 res[i][k] = pa[k];
rlm@83 643 }
rlm@83 644 }
rlm@83 645 switch (r[0]) {
rlm@83 646 case "Z":
rlm@83 647 x = mx;
rlm@83 648 y = my;
rlm@83 649 break;
rlm@83 650 case "H":
rlm@83 651 x = r[1];
rlm@83 652 break;
rlm@83 653 case "V":
rlm@83 654 y = r[1];
rlm@83 655 break;
rlm@83 656 case "M":
rlm@83 657 mx = res[i][res[i][length] - 2];
rlm@83 658 my = res[i][res[i][length] - 1];
rlm@83 659 default:
rlm@83 660 x = res[i][res[i][length] - 2];
rlm@83 661 y = res[i][res[i][length] - 1];
rlm@83 662 }
rlm@83 663 }
rlm@83 664 res[toString] = R._path2string;
rlm@83 665 return res;
rlm@83 666 }, null, pathClone),
rlm@83 667 l2c = function (x1, y1, x2, y2) {
rlm@83 668 return [x1, y1, x2, y2, x2, y2];
rlm@83 669 },
rlm@83 670 q2c = function (x1, y1, ax, ay, x2, y2) {
rlm@83 671 var _13 = 1 / 3,
rlm@83 672 _23 = 2 / 3;
rlm@83 673 return [
rlm@83 674 _13 * x1 + _23 * ax,
rlm@83 675 _13 * y1 + _23 * ay,
rlm@83 676 _13 * x2 + _23 * ax,
rlm@83 677 _13 * y2 + _23 * ay,
rlm@83 678 x2,
rlm@83 679 y2
rlm@83 680 ];
rlm@83 681 },
rlm@83 682 a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) {
rlm@83 683 // for more information of where this math came from visit:
rlm@83 684 // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
rlm@83 685 var PI = math.PI,
rlm@83 686 _120 = PI * 120 / 180,
rlm@83 687 rad = PI / 180 * (+angle || 0),
rlm@83 688 res = [],
rlm@83 689 xy,
rlm@83 690 rotate = cacher(function (x, y, rad) {
rlm@83 691 var X = x * math.cos(rad) - y * math.sin(rad),
rlm@83 692 Y = x * math.sin(rad) + y * math.cos(rad);
rlm@83 693 return {x: X, y: Y};
rlm@83 694 });
rlm@83 695 if (!recursive) {
rlm@83 696 xy = rotate(x1, y1, -rad);
rlm@83 697 x1 = xy.x;
rlm@83 698 y1 = xy.y;
rlm@83 699 xy = rotate(x2, y2, -rad);
rlm@83 700 x2 = xy.x;
rlm@83 701 y2 = xy.y;
rlm@83 702 var cos = math.cos(PI / 180 * angle),
rlm@83 703 sin = math.sin(PI / 180 * angle),
rlm@83 704 x = (x1 - x2) / 2,
rlm@83 705 y = (y1 - y2) / 2;
rlm@83 706 var h = (x * x) / (rx * rx) + (y * y) / (ry * ry);
rlm@83 707 if (h > 1) {
rlm@83 708 h = math.sqrt(h);
rlm@83 709 rx = h * rx;
rlm@83 710 ry = h * ry;
rlm@83 711 }
rlm@83 712 var rx2 = rx * rx,
rlm@83 713 ry2 = ry * ry,
rlm@83 714 k = (large_arc_flag == sweep_flag ? -1 : 1) *
rlm@83 715 math.sqrt(math.abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))),
rlm@83 716 cx = k * rx * y / ry + (x1 + x2) / 2,
rlm@83 717 cy = k * -ry * x / rx + (y1 + y2) / 2,
rlm@83 718 f1 = math.asin(((y1 - cy) / ry).toFixed(7)),
rlm@83 719 f2 = math.asin(((y2 - cy) / ry).toFixed(7));
rlm@83 720
rlm@83 721 f1 = x1 < cx ? PI - f1 : f1;
rlm@83 722 f2 = x2 < cx ? PI - f2 : f2;
rlm@83 723 f1 < 0 && (f1 = PI * 2 + f1);
rlm@83 724 f2 < 0 && (f2 = PI * 2 + f2);
rlm@83 725 if (sweep_flag && f1 > f2) {
rlm@83 726 f1 = f1 - PI * 2;
rlm@83 727 }
rlm@83 728 if (!sweep_flag && f2 > f1) {
rlm@83 729 f2 = f2 - PI * 2;
rlm@83 730 }
rlm@83 731 } else {
rlm@83 732 f1 = recursive[0];
rlm@83 733 f2 = recursive[1];
rlm@83 734 cx = recursive[2];
rlm@83 735 cy = recursive[3];
rlm@83 736 }
rlm@83 737 var df = f2 - f1;
rlm@83 738 if (math.abs(df) > _120) {
rlm@83 739 var f2old = f2,
rlm@83 740 x2old = x2,
rlm@83 741 y2old = y2;
rlm@83 742 f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1);
rlm@83 743 x2 = cx + rx * math.cos(f2);
rlm@83 744 y2 = cy + ry * math.sin(f2);
rlm@83 745 res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]);
rlm@83 746 }
rlm@83 747 df = f2 - f1;
rlm@83 748 var c1 = math.cos(f1),
rlm@83 749 s1 = math.sin(f1),
rlm@83 750 c2 = math.cos(f2),
rlm@83 751 s2 = math.sin(f2),
rlm@83 752 t = math.tan(df / 4),
rlm@83 753 hx = 4 / 3 * rx * t,
rlm@83 754 hy = 4 / 3 * ry * t,
rlm@83 755 m1 = [x1, y1],
rlm@83 756 m2 = [x1 + hx * s1, y1 - hy * c1],
rlm@83 757 m3 = [x2 + hx * s2, y2 - hy * c2],
rlm@83 758 m4 = [x2, y2];
rlm@83 759 m2[0] = 2 * m1[0] - m2[0];
rlm@83 760 m2[1] = 2 * m1[1] - m2[1];
rlm@83 761 if (recursive) {
rlm@83 762 return [m2, m3, m4][concat](res);
rlm@83 763 } else {
rlm@83 764 res = [m2, m3, m4][concat](res)[join]()[split](",");
rlm@83 765 var newres = [];
rlm@83 766 for (var i = 0, ii = res[length]; i < ii; i++) {
rlm@83 767 newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x;
rlm@83 768 }
rlm@83 769 return newres;
rlm@83 770 }
rlm@83 771 },
rlm@83 772 findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) {
rlm@83 773 var t1 = 1 - t;
rlm@83 774 return {
rlm@83 775 x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x,
rlm@83 776 y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y
rlm@83 777 };
rlm@83 778 },
rlm@83 779 curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
rlm@83 780 var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x),
rlm@83 781 b = 2 * (c1x - p1x) - 2 * (c2x - c1x),
rlm@83 782 c = p1x - c1x,
rlm@83 783 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a,
rlm@83 784 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a,
rlm@83 785 y = [p1y, p2y],
rlm@83 786 x = [p1x, p2x],
rlm@83 787 dot;
rlm@83 788 math.abs(t1) > 1e12 && (t1 = .5);
rlm@83 789 math.abs(t2) > 1e12 && (t2 = .5);
rlm@83 790 if (t1 > 0 && t1 < 1) {
rlm@83 791 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
rlm@83 792 x[push](dot.x);
rlm@83 793 y[push](dot.y);
rlm@83 794 }
rlm@83 795 if (t2 > 0 && t2 < 1) {
rlm@83 796 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
rlm@83 797 x[push](dot.x);
rlm@83 798 y[push](dot.y);
rlm@83 799 }
rlm@83 800 a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y);
rlm@83 801 b = 2 * (c1y - p1y) - 2 * (c2y - c1y);
rlm@83 802 c = p1y - c1y;
rlm@83 803 t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a;
rlm@83 804 t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a;
rlm@83 805 math.abs(t1) > 1e12 && (t1 = .5);
rlm@83 806 math.abs(t2) > 1e12 && (t2 = .5);
rlm@83 807 if (t1 > 0 && t1 < 1) {
rlm@83 808 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1);
rlm@83 809 x[push](dot.x);
rlm@83 810 y[push](dot.y);
rlm@83 811 }
rlm@83 812 if (t2 > 0 && t2 < 1) {
rlm@83 813 dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2);
rlm@83 814 x[push](dot.x);
rlm@83 815 y[push](dot.y);
rlm@83 816 }
rlm@83 817 return {
rlm@83 818 min: {x: mmin[apply](0, x), y: mmin[apply](0, y)},
rlm@83 819 max: {x: mmax[apply](0, x), y: mmax[apply](0, y)}
rlm@83 820 };
rlm@83 821 }),
rlm@83 822 path2curve = cacher(function (path, path2) {
rlm@83 823 var p = pathToAbsolute(path),
rlm@83 824 p2 = path2 && pathToAbsolute(path2),
rlm@83 825 attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
rlm@83 826 attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null},
rlm@83 827 processPath = function (path, d) {
rlm@83 828 var nx, ny;
rlm@83 829 if (!path) {
rlm@83 830 return ["C", d.x, d.y, d.x, d.y, d.x, d.y];
rlm@83 831 }
rlm@83 832 !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null);
rlm@83 833 switch (path[0]) {
rlm@83 834 case "M":
rlm@83 835 d.X = path[1];
rlm@83 836 d.Y = path[2];
rlm@83 837 break;
rlm@83 838 case "A":
rlm@83 839 path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1))));
rlm@83 840 break;
rlm@83 841 case "S":
rlm@83 842 nx = d.x + (d.x - (d.bx || d.x));
rlm@83 843 ny = d.y + (d.y - (d.by || d.y));
rlm@83 844 path = ["C", nx, ny][concat](path.slice(1));
rlm@83 845 break;
rlm@83 846 case "T":
rlm@83 847 d.qx = d.x + (d.x - (d.qx || d.x));
rlm@83 848 d.qy = d.y + (d.y - (d.qy || d.y));
rlm@83 849 path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2]));
rlm@83 850 break;
rlm@83 851 case "Q":
rlm@83 852 d.qx = path[1];
rlm@83 853 d.qy = path[2];
rlm@83 854 path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4]));
rlm@83 855 break;
rlm@83 856 case "L":
rlm@83 857 path = ["C"][concat](l2c(d.x, d.y, path[1], path[2]));
rlm@83 858 break;
rlm@83 859 case "H":
rlm@83 860 path = ["C"][concat](l2c(d.x, d.y, path[1], d.y));
rlm@83 861 break;
rlm@83 862 case "V":
rlm@83 863 path = ["C"][concat](l2c(d.x, d.y, d.x, path[1]));
rlm@83 864 break;
rlm@83 865 case "Z":
rlm@83 866 path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y));
rlm@83 867 break;
rlm@83 868 }
rlm@83 869 return path;
rlm@83 870 },
rlm@83 871 fixArc = function (pp, i) {
rlm@83 872 if (pp[i][length] > 7) {
rlm@83 873 pp[i].shift();
rlm@83 874 var pi = pp[i];
rlm@83 875 while (pi[length]) {
rlm@83 876 pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6)));
rlm@83 877 }
rlm@83 878 pp.splice(i, 1);
rlm@83 879 ii = mmax(p[length], p2 && p2[length] || 0);
rlm@83 880 }
rlm@83 881 },
rlm@83 882 fixM = function (path1, path2, a1, a2, i) {
rlm@83 883 if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") {
rlm@83 884 path2.splice(i, 0, ["M", a2.x, a2.y]);
rlm@83 885 a1.bx = 0;
rlm@83 886 a1.by = 0;
rlm@83 887 a1.x = path1[i][1];
rlm@83 888 a1.y = path1[i][2];
rlm@83 889 ii = mmax(p[length], p2 && p2[length] || 0);
rlm@83 890 }
rlm@83 891 };
rlm@83 892 for (var i = 0, ii = mmax(p[length], p2 && p2[length] || 0); i < ii; i++) {
rlm@83 893 p[i] = processPath(p[i], attrs);
rlm@83 894 fixArc(p, i);
rlm@83 895 p2 && (p2[i] = processPath(p2[i], attrs2));
rlm@83 896 p2 && fixArc(p2, i);
rlm@83 897 fixM(p, p2, attrs, attrs2, i);
rlm@83 898 fixM(p2, p, attrs2, attrs, i);
rlm@83 899 var seg = p[i],
rlm@83 900 seg2 = p2 && p2[i],
rlm@83 901 seglen = seg[length],
rlm@83 902 seg2len = p2 && seg2[length];
rlm@83 903 attrs.x = seg[seglen - 2];
rlm@83 904 attrs.y = seg[seglen - 1];
rlm@83 905 attrs.bx = toFloat(seg[seglen - 4]) || attrs.x;
rlm@83 906 attrs.by = toFloat(seg[seglen - 3]) || attrs.y;
rlm@83 907 attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x);
rlm@83 908 attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y);
rlm@83 909 attrs2.x = p2 && seg2[seg2len - 2];
rlm@83 910 attrs2.y = p2 && seg2[seg2len - 1];
rlm@83 911 }
rlm@83 912 return p2 ? [p, p2] : p;
rlm@83 913 }, null, pathClone),
rlm@83 914 parseDots = cacher(function (gradient) {
rlm@83 915 var dots = [];
rlm@83 916 for (var i = 0, ii = gradient[length]; i < ii; i++) {
rlm@83 917 var dot = {},
rlm@83 918 par = gradient[i].match(/^([^:]*):?([\d\.]*)/);
rlm@83 919 dot.color = R.getRGB(par[1]);
rlm@83 920 if (dot.color.error) {
rlm@83 921 return null;
rlm@83 922 }
rlm@83 923 dot.color = dot.color.hex;
rlm@83 924 par[2] && (dot.offset = par[2] + "%");
rlm@83 925 dots[push](dot);
rlm@83 926 }
rlm@83 927 for (i = 1, ii = dots[length] - 1; i < ii; i++) {
rlm@83 928 if (!dots[i].offset) {
rlm@83 929 var start = toFloat(dots[i - 1].offset || 0),
rlm@83 930 end = 0;
rlm@83 931 for (var j = i + 1; j < ii; j++) {
rlm@83 932 if (dots[j].offset) {
rlm@83 933 end = dots[j].offset;
rlm@83 934 break;
rlm@83 935 }
rlm@83 936 }
rlm@83 937 if (!end) {
rlm@83 938 end = 100;
rlm@83 939 j = ii;
rlm@83 940 }
rlm@83 941 end = toFloat(end);
rlm@83 942 var d = (end - start) / (j - i + 1);
rlm@83 943 for (; i < j; i++) {
rlm@83 944 start += d;
rlm@83 945 dots[i].offset = start + "%";
rlm@83 946 }
rlm@83 947 }
rlm@83 948 }
rlm@83 949 return dots;
rlm@83 950 }),
rlm@83 951 getContainer = function (x, y, w, h) {
rlm@83 952 var container;
rlm@83 953 if (R.is(x, string) || R.is(x, "object")) {
rlm@83 954 container = R.is(x, string) ? doc.getElementById(x) : x;
rlm@83 955 if (container.tagName) {
rlm@83 956 if (y == null) {
rlm@83 957 return {
rlm@83 958 container: container,
rlm@83 959 width: container.style.pixelWidth || container.offsetWidth,
rlm@83 960 height: container.style.pixelHeight || container.offsetHeight
rlm@83 961 };
rlm@83 962 } else {
rlm@83 963 return {container: container, width: y, height: w};
rlm@83 964 }
rlm@83 965 }
rlm@83 966 } else {
rlm@83 967 return {container: 1, x: x, y: y, width: w, height: h};
rlm@83 968 }
rlm@83 969 },
rlm@83 970 plugins = function (con, add) {
rlm@83 971 var that = this;
rlm@83 972 for (var prop in add) {
rlm@83 973 if (add[has](prop) && !(prop in con)) {
rlm@83 974 switch (typeof add[prop]) {
rlm@83 975 case "function":
rlm@83 976 (function (f) {
rlm@83 977 con[prop] = con === that ? f : function () { return f[apply](that, arguments); };
rlm@83 978 })(add[prop]);
rlm@83 979 break;
rlm@83 980 case "object":
rlm@83 981 con[prop] = con[prop] || {};
rlm@83 982 plugins.call(this, con[prop], add[prop]);
rlm@83 983 break;
rlm@83 984 default:
rlm@83 985 con[prop] = add[prop];
rlm@83 986 break;
rlm@83 987 }
rlm@83 988 }
rlm@83 989 }
rlm@83 990 },
rlm@83 991 tear = function (el, paper) {
rlm@83 992 el == paper.top && (paper.top = el.prev);
rlm@83 993 el == paper.bottom && (paper.bottom = el.next);
rlm@83 994 el.next && (el.next.prev = el.prev);
rlm@83 995 el.prev && (el.prev.next = el.next);
rlm@83 996 },
rlm@83 997 tofront = function (el, paper) {
rlm@83 998 if (paper.top === el) {
rlm@83 999 return;
rlm@83 1000 }
rlm@83 1001 tear(el, paper);
rlm@83 1002 el.next = null;
rlm@83 1003 el.prev = paper.top;
rlm@83 1004 paper.top.next = el;
rlm@83 1005 paper.top = el;
rlm@83 1006 },
rlm@83 1007 toback = function (el, paper) {
rlm@83 1008 if (paper.bottom === el) {
rlm@83 1009 return;
rlm@83 1010 }
rlm@83 1011 tear(el, paper);
rlm@83 1012 el.next = paper.bottom;
rlm@83 1013 el.prev = null;
rlm@83 1014 paper.bottom.prev = el;
rlm@83 1015 paper.bottom = el;
rlm@83 1016 },
rlm@83 1017 insertafter = function (el, el2, paper) {
rlm@83 1018 tear(el, paper);
rlm@83 1019 el2 == paper.top && (paper.top = el);
rlm@83 1020 el2.next && (el2.next.prev = el);
rlm@83 1021 el.next = el2.next;
rlm@83 1022 el.prev = el2;
rlm@83 1023 el2.next = el;
rlm@83 1024 },
rlm@83 1025 insertbefore = function (el, el2, paper) {
rlm@83 1026 tear(el, paper);
rlm@83 1027 el2 == paper.bottom && (paper.bottom = el);
rlm@83 1028 el2.prev && (el2.prev.next = el);
rlm@83 1029 el.prev = el2.prev;
rlm@83 1030 el2.prev = el;
rlm@83 1031 el.next = el2;
rlm@83 1032 },
rlm@83 1033 removed = function (methodname) {
rlm@83 1034 return function () {
rlm@83 1035 throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object");
rlm@83 1036 };
rlm@83 1037 },
rlm@83 1038 radial_gradient = /^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/;
rlm@83 1039 R.pathToRelative = pathToRelative;
rlm@83 1040 // SVG
rlm@83 1041 if (R.svg) {
rlm@83 1042 Paper[proto].svgns = "http://www.w3.org/2000/svg";
rlm@83 1043 Paper[proto].xlink = "http://www.w3.org/1999/xlink";
rlm@83 1044 round = function (num) {
rlm@83 1045 return +num + (~~num === num) * .5;
rlm@83 1046 };
rlm@83 1047 var $ = function (el, attr) {
rlm@83 1048 if (attr) {
rlm@83 1049 for (var key in attr) {
rlm@83 1050 if (attr[has](key)) {
rlm@83 1051 el[setAttribute](key, Str(attr[key]));
rlm@83 1052 }
rlm@83 1053 }
rlm@83 1054 } else {
rlm@83 1055 el = doc.createElementNS(Paper[proto].svgns, el);
rlm@83 1056 el.style.webkitTapHighlightColor = "rgba(0,0,0,0)";
rlm@83 1057 return el;
rlm@83 1058 }
rlm@83 1059 };
rlm@83 1060 R[toString] = function () {
rlm@83 1061 return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
rlm@83 1062 };
rlm@83 1063 var thePath = function (pathString, SVG) {
rlm@83 1064 var el = $("path");
rlm@83 1065 SVG.canvas && SVG.canvas[appendChild](el);
rlm@83 1066 var p = new Element(el, SVG);
rlm@83 1067 p.type = "path";
rlm@83 1068 setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString});
rlm@83 1069 return p;
rlm@83 1070 };
rlm@83 1071 var addGradientFill = function (o, gradient, SVG) {
rlm@83 1072 var type = "linear",
rlm@83 1073 fx = .5, fy = .5,
rlm@83 1074 s = o.style;
rlm@83 1075 gradient = Str(gradient)[rp](radial_gradient, function (all, _fx, _fy) {
rlm@83 1076 type = "radial";
rlm@83 1077 if (_fx && _fy) {
rlm@83 1078 fx = toFloat(_fx);
rlm@83 1079 fy = toFloat(_fy);
rlm@83 1080 var dir = ((fy > .5) * 2 - 1);
rlm@83 1081 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
rlm@83 1082 (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
rlm@83 1083 fy != .5 &&
rlm@83 1084 (fy = fy.toFixed(5) - 1e-5 * dir);
rlm@83 1085 }
rlm@83 1086 return E;
rlm@83 1087 });
rlm@83 1088 gradient = gradient[split](/\s*\-\s*/);
rlm@83 1089 if (type == "linear") {
rlm@83 1090 var angle = gradient.shift();
rlm@83 1091 angle = -toFloat(angle);
rlm@83 1092 if (isNaN(angle)) {
rlm@83 1093 return null;
rlm@83 1094 }
rlm@83 1095 var vector = [0, 0, math.cos(angle * math.PI / 180), math.sin(angle * math.PI / 180)],
rlm@83 1096 max = 1 / (mmax(math.abs(vector[2]), math.abs(vector[3])) || 1);
rlm@83 1097 vector[2] *= max;
rlm@83 1098 vector[3] *= max;
rlm@83 1099 if (vector[2] < 0) {
rlm@83 1100 vector[0] = -vector[2];
rlm@83 1101 vector[2] = 0;
rlm@83 1102 }
rlm@83 1103 if (vector[3] < 0) {
rlm@83 1104 vector[1] = -vector[3];
rlm@83 1105 vector[3] = 0;
rlm@83 1106 }
rlm@83 1107 }
rlm@83 1108 var dots = parseDots(gradient);
rlm@83 1109 if (!dots) {
rlm@83 1110 return null;
rlm@83 1111 }
rlm@83 1112 var id = o.getAttribute(fillString);
rlm@83 1113 id = id.match(/^url\(#(.*)\)$/);
rlm@83 1114 id && SVG.defs.removeChild(doc.getElementById(id[1]));
rlm@83 1115
rlm@83 1116 var el = $(type + "Gradient");
rlm@83 1117 el.id = "r" + (R._id++)[toString](36);
rlm@83 1118 $(el, type == "radial" ? {fx: fx, fy: fy} : {x1: vector[0], y1: vector[1], x2: vector[2], y2: vector[3]});
rlm@83 1119 SVG.defs[appendChild](el);
rlm@83 1120 for (var i = 0, ii = dots[length]; i < ii; i++) {
rlm@83 1121 var stop = $("stop");
rlm@83 1122 $(stop, {
rlm@83 1123 offset: dots[i].offset ? dots[i].offset : !i ? "0%" : "100%",
rlm@83 1124 "stop-color": dots[i].color || "#fff"
rlm@83 1125 });
rlm@83 1126 el[appendChild](stop);
rlm@83 1127 }
rlm@83 1128 $(o, {
rlm@83 1129 fill: "url(#" + el.id + ")",
rlm@83 1130 opacity: 1,
rlm@83 1131 "fill-opacity": 1
rlm@83 1132 });
rlm@83 1133 s.fill = E;
rlm@83 1134 s.opacity = 1;
rlm@83 1135 s.fillOpacity = 1;
rlm@83 1136 return 1;
rlm@83 1137 };
rlm@83 1138 var updatePosition = function (o) {
rlm@83 1139 var bbox = o.getBBox();
rlm@83 1140 $(o.pattern, {patternTransform: R.format("translate({0},{1})", bbox.x, bbox.y)});
rlm@83 1141 };
rlm@83 1142 var setFillAndStroke = function (o, params) {
rlm@83 1143 var dasharray = {
rlm@83 1144 "": [0],
rlm@83 1145 "none": [0],
rlm@83 1146 "-": [3, 1],
rlm@83 1147 ".": [1, 1],
rlm@83 1148 "-.": [3, 1, 1, 1],
rlm@83 1149 "-..": [3, 1, 1, 1, 1, 1],
rlm@83 1150 ". ": [1, 3],
rlm@83 1151 "- ": [4, 3],
rlm@83 1152 "--": [8, 3],
rlm@83 1153 "- .": [4, 3, 1, 3],
rlm@83 1154 "--.": [8, 3, 1, 3],
rlm@83 1155 "--..": [8, 3, 1, 3, 1, 3]
rlm@83 1156 },
rlm@83 1157 node = o.node,
rlm@83 1158 attrs = o.attrs,
rlm@83 1159 rot = o.rotate(),
rlm@83 1160 addDashes = function (o, value) {
rlm@83 1161 value = dasharray[lowerCase.call(value)];
rlm@83 1162 if (value) {
rlm@83 1163 var width = o.attrs["stroke-width"] || "1",
rlm@83 1164 butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
rlm@83 1165 dashes = [];
rlm@83 1166 var i = value[length];
rlm@83 1167 while (i--) {
rlm@83 1168 dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
rlm@83 1169 }
rlm@83 1170 $(node, {"stroke-dasharray": dashes[join](",")});
rlm@83 1171 }
rlm@83 1172 };
rlm@83 1173 params[has]("rotation") && (rot = params.rotation);
rlm@83 1174 var rotxy = Str(rot)[split](separator);
rlm@83 1175 if (!(rotxy.length - 1)) {
rlm@83 1176 rotxy = null;
rlm@83 1177 } else {
rlm@83 1178 rotxy[1] = +rotxy[1];
rlm@83 1179 rotxy[2] = +rotxy[2];
rlm@83 1180 }
rlm@83 1181 toFloat(rot) && o.rotate(0, true);
rlm@83 1182 for (var att in params) {
rlm@83 1183 if (params[has](att)) {
rlm@83 1184 if (!availableAttrs[has](att)) {
rlm@83 1185 continue;
rlm@83 1186 }
rlm@83 1187 var value = params[att];
rlm@83 1188 attrs[att] = value;
rlm@83 1189 switch (att) {
rlm@83 1190 case "blur":
rlm@83 1191 o.blur(value);
rlm@83 1192 break;
rlm@83 1193 case "rotation":
rlm@83 1194 o.rotate(value, true);
rlm@83 1195 break;
rlm@83 1196 case "href":
rlm@83 1197 case "title":
rlm@83 1198 case "target":
rlm@83 1199 var pn = node.parentNode;
rlm@83 1200 if (lowerCase.call(pn.tagName) != "a") {
rlm@83 1201 var hl = $("a");
rlm@83 1202 pn.insertBefore(hl, node);
rlm@83 1203 hl[appendChild](node);
rlm@83 1204 pn = hl;
rlm@83 1205 }
rlm@83 1206 pn.setAttributeNS(o.paper.xlink, att, value);
rlm@83 1207 break;
rlm@83 1208 case "cursor":
rlm@83 1209 node.style.cursor = value;
rlm@83 1210 break;
rlm@83 1211 case "clip-rect":
rlm@83 1212 var rect = Str(value)[split](separator);
rlm@83 1213 if (rect[length] == 4) {
rlm@83 1214 o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
rlm@83 1215 var el = $("clipPath"),
rlm@83 1216 rc = $("rect");
rlm@83 1217 el.id = "r" + (R._id++)[toString](36);
rlm@83 1218 $(rc, {
rlm@83 1219 x: rect[0],
rlm@83 1220 y: rect[1],
rlm@83 1221 width: rect[2],
rlm@83 1222 height: rect[3]
rlm@83 1223 });
rlm@83 1224 el[appendChild](rc);
rlm@83 1225 o.paper.defs[appendChild](el);
rlm@83 1226 $(node, {"clip-path": "url(#" + el.id + ")"});
rlm@83 1227 o.clip = rc;
rlm@83 1228 }
rlm@83 1229 if (!value) {
rlm@83 1230 var clip = doc.getElementById(node.getAttribute("clip-path")[rp](/(^url\(#|\)$)/g, E));
rlm@83 1231 clip && clip.parentNode.removeChild(clip);
rlm@83 1232 $(node, {"clip-path": E});
rlm@83 1233 delete o.clip;
rlm@83 1234 }
rlm@83 1235 break;
rlm@83 1236 case "path":
rlm@83 1237 if (o.type == "path") {
rlm@83 1238 $(node, {d: value ? attrs.path = pathToAbsolute(value) : "M0,0"});
rlm@83 1239 }
rlm@83 1240 break;
rlm@83 1241 case "width":
rlm@83 1242 node[setAttribute](att, value);
rlm@83 1243 if (attrs.fx) {
rlm@83 1244 att = "x";
rlm@83 1245 value = attrs.x;
rlm@83 1246 } else {
rlm@83 1247 break;
rlm@83 1248 }
rlm@83 1249 case "x":
rlm@83 1250 if (attrs.fx) {
rlm@83 1251 value = -attrs.x - (attrs.width || 0);
rlm@83 1252 }
rlm@83 1253 case "rx":
rlm@83 1254 if (att == "rx" && o.type == "rect") {
rlm@83 1255 break;
rlm@83 1256 }
rlm@83 1257 case "cx":
rlm@83 1258 rotxy && (att == "x" || att == "cx") && (rotxy[1] += value - attrs[att]);
rlm@83 1259 node[setAttribute](att, value);
rlm@83 1260 o.pattern && updatePosition(o);
rlm@83 1261 break;
rlm@83 1262 case "height":
rlm@83 1263 node[setAttribute](att, value);
rlm@83 1264 if (attrs.fy) {
rlm@83 1265 att = "y";
rlm@83 1266 value = attrs.y;
rlm@83 1267 } else {
rlm@83 1268 break;
rlm@83 1269 }
rlm@83 1270 case "y":
rlm@83 1271 if (attrs.fy) {
rlm@83 1272 value = -attrs.y - (attrs.height || 0);
rlm@83 1273 }
rlm@83 1274 case "ry":
rlm@83 1275 if (att == "ry" && o.type == "rect") {
rlm@83 1276 break;
rlm@83 1277 }
rlm@83 1278 case "cy":
rlm@83 1279 rotxy && (att == "y" || att == "cy") && (rotxy[2] += value - attrs[att]);
rlm@83 1280 node[setAttribute](att, value);
rlm@83 1281 o.pattern && updatePosition(o);
rlm@83 1282 break;
rlm@83 1283 case "r":
rlm@83 1284 if (o.type == "rect") {
rlm@83 1285 $(node, {rx: value, ry: value});
rlm@83 1286 } else {
rlm@83 1287 node[setAttribute](att, value);
rlm@83 1288 }
rlm@83 1289 break;
rlm@83 1290 case "src":
rlm@83 1291 if (o.type == "image") {
rlm@83 1292 node.setAttributeNS(o.paper.xlink, "href", value);
rlm@83 1293 }
rlm@83 1294 break;
rlm@83 1295 case "stroke-width":
rlm@83 1296 node.style.strokeWidth = value;
rlm@83 1297 // Need following line for Firefox
rlm@83 1298 node[setAttribute](att, value);
rlm@83 1299 if (attrs["stroke-dasharray"]) {
rlm@83 1300 addDashes(o, attrs["stroke-dasharray"]);
rlm@83 1301 }
rlm@83 1302 break;
rlm@83 1303 case "stroke-dasharray":
rlm@83 1304 addDashes(o, value);
rlm@83 1305 break;
rlm@83 1306 case "translation":
rlm@83 1307 var xy = Str(value)[split](separator);
rlm@83 1308 xy[0] = +xy[0] || 0;
rlm@83 1309 xy[1] = +xy[1] || 0;
rlm@83 1310 if (rotxy) {
rlm@83 1311 rotxy[1] += xy[0];
rlm@83 1312 rotxy[2] += xy[1];
rlm@83 1313 }
rlm@83 1314 translate.call(o, xy[0], xy[1]);
rlm@83 1315 break;
rlm@83 1316 case "scale":
rlm@83 1317 xy = Str(value)[split](separator);
rlm@83 1318 o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, isNaN(toFloat(xy[2])) ? null : +xy[2], isNaN(toFloat(xy[3])) ? null : +xy[3]);
rlm@83 1319 break;
rlm@83 1320 case fillString:
rlm@83 1321 var isURL = Str(value).match(ISURL);
rlm@83 1322 if (isURL) {
rlm@83 1323 el = $("pattern");
rlm@83 1324 var ig = $("image");
rlm@83 1325 el.id = "r" + (R._id++)[toString](36);
rlm@83 1326 $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
rlm@83 1327 $(ig, {x: 0, y: 0});
rlm@83 1328 ig.setAttributeNS(o.paper.xlink, "href", isURL[1]);
rlm@83 1329 el[appendChild](ig);
rlm@83 1330
rlm@83 1331 var img = doc.createElement("img");
rlm@83 1332 img.style.cssText = "position:absolute;left:-9999em;top-9999em";
rlm@83 1333 img.onload = function () {
rlm@83 1334 $(el, {width: this.offsetWidth, height: this.offsetHeight});
rlm@83 1335 $(ig, {width: this.offsetWidth, height: this.offsetHeight});
rlm@83 1336 doc.body.removeChild(this);
rlm@83 1337 o.paper.safari();
rlm@83 1338 };
rlm@83 1339 doc.body[appendChild](img);
rlm@83 1340 img.src = isURL[1];
rlm@83 1341 o.paper.defs[appendChild](el);
rlm@83 1342 node.style.fill = "url(#" + el.id + ")";
rlm@83 1343 $(node, {fill: "url(#" + el.id + ")"});
rlm@83 1344 o.pattern = el;
rlm@83 1345 o.pattern && updatePosition(o);
rlm@83 1346 break;
rlm@83 1347 }
rlm@83 1348 var clr = R.getRGB(value);
rlm@83 1349 if (!clr.error) {
rlm@83 1350 delete params.gradient;
rlm@83 1351 delete attrs.gradient;
rlm@83 1352 !R.is(attrs.opacity, "undefined") &&
rlm@83 1353 R.is(params.opacity, "undefined") &&
rlm@83 1354 $(node, {opacity: attrs.opacity});
rlm@83 1355 !R.is(attrs["fill-opacity"], "undefined") &&
rlm@83 1356 R.is(params["fill-opacity"], "undefined") &&
rlm@83 1357 $(node, {"fill-opacity": attrs["fill-opacity"]});
rlm@83 1358 } else if ((({circle: 1, ellipse: 1})[has](o.type) || Str(value).charAt() != "r") && addGradientFill(node, value, o.paper)) {
rlm@83 1359 attrs.gradient = value;
rlm@83 1360 attrs.fill = "none";
rlm@83 1361 break;
rlm@83 1362 }
rlm@83 1363 clr[has]("o") && $(node, {"fill-opacity": clr.o > 1 ? clr.o / 100 : clr.o});
rlm@83 1364 case "stroke":
rlm@83 1365 clr = R.getRGB(value);
rlm@83 1366 node[setAttribute](att, clr.hex);
rlm@83 1367 att == "stroke" && clr[has]("o") && $(node, {"stroke-opacity": clr.o > 1 ? clr.o / 100 : clr.o});
rlm@83 1368 break;
rlm@83 1369 case "gradient":
rlm@83 1370 (({circle: 1, ellipse: 1})[has](o.type) || Str(value).charAt() != "r") && addGradientFill(node, value, o.paper);
rlm@83 1371 break;
rlm@83 1372 case "opacity":
rlm@83 1373 case "fill-opacity":
rlm@83 1374 if (attrs.gradient) {
rlm@83 1375 var gradient = doc.getElementById(node.getAttribute(fillString)[rp](/^url\(#|\)$/g, E));
rlm@83 1376 if (gradient) {
rlm@83 1377 var stops = gradient.getElementsByTagName("stop");
rlm@83 1378 stops[stops[length] - 1][setAttribute]("stop-opacity", value);
rlm@83 1379 }
rlm@83 1380 break;
rlm@83 1381 }
rlm@83 1382 default:
rlm@83 1383 att == "font-size" && (value = toInt(value, 10) + "px");
rlm@83 1384 var cssrule = att[rp](/(\-.)/g, function (w) {
rlm@83 1385 return upperCase.call(w.substring(1));
rlm@83 1386 });
rlm@83 1387 node.style[cssrule] = value;
rlm@83 1388 // Need following line for Firefox
rlm@83 1389 node[setAttribute](att, value);
rlm@83 1390 break;
rlm@83 1391 }
rlm@83 1392 }
rlm@83 1393 }
rlm@83 1394
rlm@83 1395 tuneText(o, params);
rlm@83 1396 if (rotxy) {
rlm@83 1397 o.rotate(rotxy.join(S));
rlm@83 1398 } else {
rlm@83 1399 toFloat(rot) && o.rotate(rot, true);
rlm@83 1400 }
rlm@83 1401 };
rlm@83 1402 var leading = 1.2,
rlm@83 1403 tuneText = function (el, params) {
rlm@83 1404 if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
rlm@83 1405 return;
rlm@83 1406 }
rlm@83 1407 var a = el.attrs,
rlm@83 1408 node = el.node,
rlm@83 1409 fontSize = node.firstChild ? toInt(doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
rlm@83 1410
rlm@83 1411 if (params[has]("text")) {
rlm@83 1412 a.text = params.text;
rlm@83 1413 while (node.firstChild) {
rlm@83 1414 node.removeChild(node.firstChild);
rlm@83 1415 }
rlm@83 1416 var texts = Str(params.text)[split]("\n");
rlm@83 1417 for (var i = 0, ii = texts[length]; i < ii; i++) if (texts[i]) {
rlm@83 1418 var tspan = $("tspan");
rlm@83 1419 i && $(tspan, {dy: fontSize * leading, x: a.x});
rlm@83 1420 tspan[appendChild](doc.createTextNode(texts[i]));
rlm@83 1421 node[appendChild](tspan);
rlm@83 1422 }
rlm@83 1423 } else {
rlm@83 1424 texts = node.getElementsByTagName("tspan");
rlm@83 1425 for (i = 0, ii = texts[length]; i < ii; i++) {
rlm@83 1426 i && $(texts[i], {dy: fontSize * leading, x: a.x});
rlm@83 1427 }
rlm@83 1428 }
rlm@83 1429 $(node, {y: a.y});
rlm@83 1430 var bb = el.getBBox(),
rlm@83 1431 dif = a.y - (bb.y + bb.height / 2);
rlm@83 1432 dif && isFinite(dif) && $(node, {y: a.y + dif});
rlm@83 1433 },
rlm@83 1434 Element = function (node, svg) {
rlm@83 1435 var X = 0,
rlm@83 1436 Y = 0;
rlm@83 1437 this[0] = node;
rlm@83 1438 this.id = R._oid++;
rlm@83 1439 this.node = node;
rlm@83 1440 node.raphael = this;
rlm@83 1441 this.paper = svg;
rlm@83 1442 this.attrs = this.attrs || {};
rlm@83 1443 this.transformations = []; // rotate, translate, scale
rlm@83 1444 this._ = {
rlm@83 1445 tx: 0,
rlm@83 1446 ty: 0,
rlm@83 1447 rt: {deg: 0, cx: 0, cy: 0},
rlm@83 1448 sx: 1,
rlm@83 1449 sy: 1
rlm@83 1450 };
rlm@83 1451 !svg.bottom && (svg.bottom = this);
rlm@83 1452 this.prev = svg.top;
rlm@83 1453 svg.top && (svg.top.next = this);
rlm@83 1454 svg.top = this;
rlm@83 1455 this.next = null;
rlm@83 1456 };
rlm@83 1457 Element[proto].rotate = function (deg, cx, cy) {
rlm@83 1458 if (this.removed) {
rlm@83 1459 return this;
rlm@83 1460 }
rlm@83 1461 if (deg == null) {
rlm@83 1462 if (this._.rt.cx) {
rlm@83 1463 return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S);
rlm@83 1464 }
rlm@83 1465 return this._.rt.deg;
rlm@83 1466 }
rlm@83 1467 var bbox = this.getBBox();
rlm@83 1468 deg = Str(deg)[split](separator);
rlm@83 1469 if (deg[length] - 1) {
rlm@83 1470 cx = toFloat(deg[1]);
rlm@83 1471 cy = toFloat(deg[2]);
rlm@83 1472 }
rlm@83 1473 deg = toFloat(deg[0]);
rlm@83 1474 if (cx != null) {
rlm@83 1475 this._.rt.deg = deg;
rlm@83 1476 } else {
rlm@83 1477 this._.rt.deg += deg;
rlm@83 1478 }
rlm@83 1479 (cy == null) && (cx = null);
rlm@83 1480 this._.rt.cx = cx;
rlm@83 1481 this._.rt.cy = cy;
rlm@83 1482 cx = cx == null ? bbox.x + bbox.width / 2 : cx;
rlm@83 1483 cy = cy == null ? bbox.y + bbox.height / 2 : cy;
rlm@83 1484 if (this._.rt.deg) {
rlm@83 1485 this.transformations[0] = R.format("rotate({0} {1} {2})", this._.rt.deg, cx, cy);
rlm@83 1486 this.clip && $(this.clip, {transform: R.format("rotate({0} {1} {2})", -this._.rt.deg, cx, cy)});
rlm@83 1487 } else {
rlm@83 1488 this.transformations[0] = E;
rlm@83 1489 this.clip && $(this.clip, {transform: E});
rlm@83 1490 }
rlm@83 1491 $(this.node, {transform: this.transformations[join](S)});
rlm@83 1492 return this;
rlm@83 1493 };
rlm@83 1494 Element[proto].hide = function () {
rlm@83 1495 !this.removed && (this.node.style.display = "none");
rlm@83 1496 return this;
rlm@83 1497 };
rlm@83 1498 Element[proto].show = function () {
rlm@83 1499 !this.removed && (this.node.style.display = "");
rlm@83 1500 return this;
rlm@83 1501 };
rlm@83 1502 Element[proto].remove = function () {
rlm@83 1503 if (this.removed) {
rlm@83 1504 return;
rlm@83 1505 }
rlm@83 1506 tear(this, this.paper);
rlm@83 1507 this.node.parentNode.removeChild(this.node);
rlm@83 1508 for (var i in this) {
rlm@83 1509 delete this[i];
rlm@83 1510 }
rlm@83 1511 this.removed = true;
rlm@83 1512 };
rlm@83 1513 Element[proto].getBBox = function () {
rlm@83 1514 if (this.removed) {
rlm@83 1515 return this;
rlm@83 1516 }
rlm@83 1517 if (this.type == "path") {
rlm@83 1518 return pathDimensions(this.attrs.path);
rlm@83 1519 }
rlm@83 1520 if (this.node.style.display == "none") {
rlm@83 1521 this.show();
rlm@83 1522 var hide = true;
rlm@83 1523 }
rlm@83 1524 var bbox = {};
rlm@83 1525 try {
rlm@83 1526 bbox = this.node.getBBox();
rlm@83 1527 } catch(e) {
rlm@83 1528 // Firefox 3.0.x plays badly here
rlm@83 1529 } finally {
rlm@83 1530 bbox = bbox || {};
rlm@83 1531 }
rlm@83 1532 if (this.type == "text") {
rlm@83 1533 bbox = {x: bbox.x, y: Infinity, width: 0, height: 0};
rlm@83 1534 for (var i = 0, ii = this.node.getNumberOfChars(); i < ii; i++) {
rlm@83 1535 var bb = this.node.getExtentOfChar(i);
rlm@83 1536 (bb.y < bbox.y) && (bbox.y = bb.y);
rlm@83 1537 (bb.y + bb.height - bbox.y > bbox.height) && (bbox.height = bb.y + bb.height - bbox.y);
rlm@83 1538 (bb.x + bb.width - bbox.x > bbox.width) && (bbox.width = bb.x + bb.width - bbox.x);
rlm@83 1539 }
rlm@83 1540 }
rlm@83 1541 hide && this.hide();
rlm@83 1542 return bbox;
rlm@83 1543 };
rlm@83 1544 Element[proto].attr = function (name, value) {
rlm@83 1545 if (this.removed) {
rlm@83 1546 return this;
rlm@83 1547 }
rlm@83 1548 if (name == null) {
rlm@83 1549 var res = {};
rlm@83 1550 for (var i in this.attrs) if (this.attrs[has](i)) {
rlm@83 1551 res[i] = this.attrs[i];
rlm@83 1552 }
rlm@83 1553 this._.rt.deg && (res.rotation = this.rotate());
rlm@83 1554 (this._.sx != 1 || this._.sy != 1) && (res.scale = this.scale());
rlm@83 1555 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
rlm@83 1556 return res;
rlm@83 1557 }
rlm@83 1558 if (value == null && R.is(name, string)) {
rlm@83 1559 if (name == "translation") {
rlm@83 1560 return translate.call(this);
rlm@83 1561 }
rlm@83 1562 if (name == "rotation") {
rlm@83 1563 return this.rotate();
rlm@83 1564 }
rlm@83 1565 if (name == "scale") {
rlm@83 1566 return this.scale();
rlm@83 1567 }
rlm@83 1568 if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
rlm@83 1569 return this.attrs.gradient;
rlm@83 1570 }
rlm@83 1571 return this.attrs[name];
rlm@83 1572 }
rlm@83 1573 if (value == null && R.is(name, array)) {
rlm@83 1574 var values = {};
rlm@83 1575 for (var j = 0, jj = name.length; j < jj; j++) {
rlm@83 1576 values[name[j]] = this.attr(name[j]);
rlm@83 1577 }
rlm@83 1578 return values;
rlm@83 1579 }
rlm@83 1580 if (value != null) {
rlm@83 1581 var params = {};
rlm@83 1582 params[name] = value;
rlm@83 1583 setFillAndStroke(this, params);
rlm@83 1584 } else if (name != null && R.is(name, "object")) {
rlm@83 1585 setFillAndStroke(this, name);
rlm@83 1586 }
rlm@83 1587 return this;
rlm@83 1588 };
rlm@83 1589 Element[proto].toFront = function () {
rlm@83 1590 if (this.removed) {
rlm@83 1591 return this;
rlm@83 1592 }
rlm@83 1593 this.node.parentNode[appendChild](this.node);
rlm@83 1594 var svg = this.paper;
rlm@83 1595 svg.top != this && tofront(this, svg);
rlm@83 1596 return this;
rlm@83 1597 };
rlm@83 1598 Element[proto].toBack = function () {
rlm@83 1599 if (this.removed) {
rlm@83 1600 return this;
rlm@83 1601 }
rlm@83 1602 if (this.node.parentNode.firstChild != this.node) {
rlm@83 1603 this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
rlm@83 1604 toback(this, this.paper);
rlm@83 1605 var svg = this.paper;
rlm@83 1606 }
rlm@83 1607 return this;
rlm@83 1608 };
rlm@83 1609 Element[proto].insertAfter = function (element) {
rlm@83 1610 if (this.removed) {
rlm@83 1611 return this;
rlm@83 1612 }
rlm@83 1613 var node = element.node || element[element.length].node;
rlm@83 1614 if (node.nextSibling) {
rlm@83 1615 node.parentNode.insertBefore(this.node, node.nextSibling);
rlm@83 1616 } else {
rlm@83 1617 node.parentNode[appendChild](this.node);
rlm@83 1618 }
rlm@83 1619 insertafter(this, element, this.paper);
rlm@83 1620 return this;
rlm@83 1621 };
rlm@83 1622 Element[proto].insertBefore = function (element) {
rlm@83 1623 if (this.removed) {
rlm@83 1624 return this;
rlm@83 1625 }
rlm@83 1626 var node = element.node || element[0].node;
rlm@83 1627 node.parentNode.insertBefore(this.node, node);
rlm@83 1628 insertbefore(this, element, this.paper);
rlm@83 1629 return this;
rlm@83 1630 };
rlm@83 1631 Element[proto].blur = function (size) {
rlm@83 1632 // Experimental. No Safari support. Use it on your own risk.
rlm@83 1633 var t = this;
rlm@83 1634 if (+size !== 0) {
rlm@83 1635 var fltr = $("filter"),
rlm@83 1636 blur = $("feGaussianBlur");
rlm@83 1637 t.attrs.blur = size;
rlm@83 1638 fltr.id = "r" + (R._id++)[toString](36);
rlm@83 1639 $(blur, {stdDeviation: +size || 1.5});
rlm@83 1640 fltr.appendChild(blur);
rlm@83 1641 t.paper.defs.appendChild(fltr);
rlm@83 1642 t._blur = fltr;
rlm@83 1643 $(t.node, {filter: "url(#" + fltr.id + ")"});
rlm@83 1644 } else {
rlm@83 1645 if (t._blur) {
rlm@83 1646 t._blur.parentNode.removeChild(t._blur);
rlm@83 1647 delete t._blur;
rlm@83 1648 delete t.attrs.blur;
rlm@83 1649 }
rlm@83 1650 t.node.removeAttribute("filter");
rlm@83 1651 }
rlm@83 1652 };
rlm@83 1653 var theCircle = function (svg, x, y, r) {
rlm@83 1654 var el = $("circle");
rlm@83 1655 svg.canvas && svg.canvas[appendChild](el);
rlm@83 1656 var res = new Element(el, svg);
rlm@83 1657 res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
rlm@83 1658 res.type = "circle";
rlm@83 1659 $(el, res.attrs);
rlm@83 1660 return res;
rlm@83 1661 };
rlm@83 1662 var theRect = function (svg, x, y, w, h, r) {
rlm@83 1663 var el = $("rect");
rlm@83 1664 svg.canvas && svg.canvas[appendChild](el);
rlm@83 1665 var res = new Element(el, svg);
rlm@83 1666 res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
rlm@83 1667 res.type = "rect";
rlm@83 1668 $(el, res.attrs);
rlm@83 1669 return res;
rlm@83 1670 };
rlm@83 1671 var theEllipse = function (svg, x, y, rx, ry) {
rlm@83 1672 var el = $("ellipse");
rlm@83 1673 svg.canvas && svg.canvas[appendChild](el);
rlm@83 1674 var res = new Element(el, svg);
rlm@83 1675 res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
rlm@83 1676 res.type = "ellipse";
rlm@83 1677 $(el, res.attrs);
rlm@83 1678 return res;
rlm@83 1679 };
rlm@83 1680 var theImage = function (svg, src, x, y, w, h) {
rlm@83 1681 var el = $("image");
rlm@83 1682 $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
rlm@83 1683 el.setAttributeNS(svg.xlink, "href", src);
rlm@83 1684 svg.canvas && svg.canvas[appendChild](el);
rlm@83 1685 var res = new Element(el, svg);
rlm@83 1686 res.attrs = {x: x, y: y, width: w, height: h, src: src};
rlm@83 1687 res.type = "image";
rlm@83 1688 return res;
rlm@83 1689 };
rlm@83 1690 var theText = function (svg, x, y, text) {
rlm@83 1691 var el = $("text");
rlm@83 1692 $(el, {x: x, y: y, "text-anchor": "middle"});
rlm@83 1693 svg.canvas && svg.canvas[appendChild](el);
rlm@83 1694 var res = new Element(el, svg);
rlm@83 1695 res.attrs = {x: x, y: y, "text-anchor": "middle", text: text, font: availableAttrs.font, stroke: "none", fill: "#000"};
rlm@83 1696 res.type = "text";
rlm@83 1697 setFillAndStroke(res, res.attrs);
rlm@83 1698 return res;
rlm@83 1699 };
rlm@83 1700 var setSize = function (width, height) {
rlm@83 1701 this.width = width || this.width;
rlm@83 1702 this.height = height || this.height;
rlm@83 1703 this.canvas[setAttribute]("width", this.width);
rlm@83 1704 this.canvas[setAttribute]("height", this.height);
rlm@83 1705 return this;
rlm@83 1706 };
rlm@83 1707 var create = function () {
rlm@83 1708 var con = getContainer[apply](0, arguments),
rlm@83 1709 container = con && con.container,
rlm@83 1710 x = con.x,
rlm@83 1711 y = con.y,
rlm@83 1712 width = con.width,
rlm@83 1713 height = con.height;
rlm@83 1714 if (!container) {
rlm@83 1715 throw new Error("SVG container not found.");
rlm@83 1716 }
rlm@83 1717 var cnvs = $("svg");
rlm@83 1718 x = x || 0;
rlm@83 1719 y = y || 0;
rlm@83 1720 width = width || 512;
rlm@83 1721 height = height || 342;
rlm@83 1722 $(cnvs, {
rlm@83 1723 xmlns: "http://www.w3.org/2000/svg",
rlm@83 1724 version: 1.1,
rlm@83 1725 width: width,
rlm@83 1726 height: height
rlm@83 1727 });
rlm@83 1728 if (container == 1) {
rlm@83 1729 cnvs.style.cssText = "position:absolute;left:" + x + "px;top:" + y + "px";
rlm@83 1730 doc.body[appendChild](cnvs);
rlm@83 1731 } else {
rlm@83 1732 if (container.firstChild) {
rlm@83 1733 container.insertBefore(cnvs, container.firstChild);
rlm@83 1734 } else {
rlm@83 1735 container[appendChild](cnvs);
rlm@83 1736 }
rlm@83 1737 }
rlm@83 1738 container = new Paper;
rlm@83 1739 container.width = width;
rlm@83 1740 container.height = height;
rlm@83 1741 container.canvas = cnvs;
rlm@83 1742 plugins.call(container, container, R.fn);
rlm@83 1743 container.clear();
rlm@83 1744 return container;
rlm@83 1745 };
rlm@83 1746 Paper[proto].clear = function () {
rlm@83 1747 var c = this.canvas;
rlm@83 1748 while (c.firstChild) {
rlm@83 1749 c.removeChild(c.firstChild);
rlm@83 1750 }
rlm@83 1751 this.bottom = this.top = null;
rlm@83 1752 (this.desc = $("desc"))[appendChild](doc.createTextNode("Created with Rapha\xebl"));
rlm@83 1753 c[appendChild](this.desc);
rlm@83 1754 c[appendChild](this.defs = $("defs"));
rlm@83 1755 };
rlm@83 1756 Paper[proto].remove = function () {
rlm@83 1757 this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
rlm@83 1758 for (var i in this) {
rlm@83 1759 this[i] = removed(i);
rlm@83 1760 }
rlm@83 1761 };
rlm@83 1762 }
rlm@83 1763
rlm@83 1764 // VML
rlm@83 1765 if (R.vml) {
rlm@83 1766 var map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"},
rlm@83 1767 bites = /([clmz]),?([^clmz]*)/gi,
rlm@83 1768 val = /-?[^,\s-]+/g,
rlm@83 1769 coordsize = 1e3 + S + 1e3,
rlm@83 1770 zoom = 10,
rlm@83 1771 pathlike = {path: 1, rect: 1},
rlm@83 1772 path2vml = function (path) {
rlm@83 1773 var total = /[ahqstv]/ig,
rlm@83 1774 command = pathToAbsolute;
rlm@83 1775 Str(path).match(total) && (command = path2curve);
rlm@83 1776 total = /[clmz]/g;
rlm@83 1777 if (command == pathToAbsolute && !Str(path).match(total)) {
rlm@83 1778 var res = Str(path)[rp](bites, function (all, command, args) {
rlm@83 1779 var vals = [],
rlm@83 1780 isMove = lowerCase.call(command) == "m",
rlm@83 1781 res = map[command];
rlm@83 1782 args[rp](val, function (value) {
rlm@83 1783 if (isMove && vals[length] == 2) {
rlm@83 1784 res += vals + map[command == "m" ? "l" : "L"];
rlm@83 1785 vals = [];
rlm@83 1786 }
rlm@83 1787 vals[push](round(value * zoom));
rlm@83 1788 });
rlm@83 1789 return res + vals;
rlm@83 1790 });
rlm@83 1791 return res;
rlm@83 1792 }
rlm@83 1793 var pa = command(path), p, r;
rlm@83 1794 res = [];
rlm@83 1795 for (var i = 0, ii = pa[length]; i < ii; i++) {
rlm@83 1796 p = pa[i];
rlm@83 1797 r = lowerCase.call(pa[i][0]);
rlm@83 1798 r == "z" && (r = "x");
rlm@83 1799 for (var j = 1, jj = p[length]; j < jj; j++) {
rlm@83 1800 r += round(p[j] * zoom) + (j != jj - 1 ? "," : E);
rlm@83 1801 }
rlm@83 1802 res[push](r);
rlm@83 1803 }
rlm@83 1804 return res[join](S);
rlm@83 1805 };
rlm@83 1806
rlm@83 1807 R[toString] = function () {
rlm@83 1808 return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version;
rlm@83 1809 };
rlm@83 1810 thePath = function (pathString, vml) {
rlm@83 1811 var g = createNode("group");
rlm@83 1812 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px";
rlm@83 1813 g.coordsize = vml.coordsize;
rlm@83 1814 g.coordorigin = vml.coordorigin;
rlm@83 1815 var el = createNode("shape"), ol = el.style;
rlm@83 1816 ol.width = vml.width + "px";
rlm@83 1817 ol.height = vml.height + "px";
rlm@83 1818 el.coordsize = coordsize;
rlm@83 1819 el.coordorigin = vml.coordorigin;
rlm@83 1820 g[appendChild](el);
rlm@83 1821 var p = new Element(el, g, vml),
rlm@83 1822 attr = {fill: "none", stroke: "#000"};
rlm@83 1823 pathString && (attr.path = pathString);
rlm@83 1824 p.isAbsolute = true;
rlm@83 1825 p.type = "path";
rlm@83 1826 p.path = [];
rlm@83 1827 p.Path = E;
rlm@83 1828 setFillAndStroke(p, attr);
rlm@83 1829 vml.canvas[appendChild](g);
rlm@83 1830 return p;
rlm@83 1831 };
rlm@83 1832 setFillAndStroke = function (o, params) {
rlm@83 1833 o.attrs = o.attrs || {};
rlm@83 1834 var node = o.node,
rlm@83 1835 a = o.attrs,
rlm@83 1836 s = node.style,
rlm@83 1837 xy,
rlm@83 1838 newpath = (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.r != a.r) && o.type == "rect",
rlm@83 1839 res = o;
rlm@83 1840
rlm@83 1841 for (var par in params) if (params[has](par)) {
rlm@83 1842 a[par] = params[par];
rlm@83 1843 }
rlm@83 1844 if (newpath) {
rlm@83 1845 a.path = rectPath(a.x, a.y, a.width, a.height, a.r);
rlm@83 1846 o.X = a.x;
rlm@83 1847 o.Y = a.y;
rlm@83 1848 o.W = a.width;
rlm@83 1849 o.H = a.height;
rlm@83 1850 }
rlm@83 1851 params.href && (node.href = params.href);
rlm@83 1852 params.title && (node.title = params.title);
rlm@83 1853 params.target && (node.target = params.target);
rlm@83 1854 params.cursor && (s.cursor = params.cursor);
rlm@83 1855 "blur" in params && o.blur(params.blur);
rlm@83 1856 if (params.path && o.type == "path" || newpath) {
rlm@83 1857 node.path = path2vml(a.path);
rlm@83 1858 }
rlm@83 1859 if (params.rotation != null) {
rlm@83 1860 o.rotate(params.rotation, true);
rlm@83 1861 }
rlm@83 1862 if (params.translation) {
rlm@83 1863 xy = Str(params.translation)[split](separator);
rlm@83 1864 translate.call(o, xy[0], xy[1]);
rlm@83 1865 if (o._.rt.cx != null) {
rlm@83 1866 o._.rt.cx +=+ xy[0];
rlm@83 1867 o._.rt.cy +=+ xy[1];
rlm@83 1868 o.setBox(o.attrs, xy[0], xy[1]);
rlm@83 1869 }
rlm@83 1870 }
rlm@83 1871 if (params.scale) {
rlm@83 1872 xy = Str(params.scale)[split](separator);
rlm@83 1873 o.scale(+xy[0] || 1, +xy[1] || +xy[0] || 1, +xy[2] || null, +xy[3] || null);
rlm@83 1874 }
rlm@83 1875 if ("clip-rect" in params) {
rlm@83 1876 var rect = Str(params["clip-rect"])[split](separator);
rlm@83 1877 if (rect[length] == 4) {
rlm@83 1878 rect[2] = +rect[2] + (+rect[0]);
rlm@83 1879 rect[3] = +rect[3] + (+rect[1]);
rlm@83 1880 var div = node.clipRect || doc.createElement("div"),
rlm@83 1881 dstyle = div.style,
rlm@83 1882 group = node.parentNode;
rlm@83 1883 dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect);
rlm@83 1884 if (!node.clipRect) {
rlm@83 1885 dstyle.position = "absolute";
rlm@83 1886 dstyle.top = 0;
rlm@83 1887 dstyle.left = 0;
rlm@83 1888 dstyle.width = o.paper.width + "px";
rlm@83 1889 dstyle.height = o.paper.height + "px";
rlm@83 1890 group.parentNode.insertBefore(div, group);
rlm@83 1891 div[appendChild](group);
rlm@83 1892 node.clipRect = div;
rlm@83 1893 }
rlm@83 1894 }
rlm@83 1895 if (!params["clip-rect"]) {
rlm@83 1896 node.clipRect && (node.clipRect.style.clip = E);
rlm@83 1897 }
rlm@83 1898 }
rlm@83 1899 if (o.type == "image" && params.src) {
rlm@83 1900 node.src = params.src;
rlm@83 1901 }
rlm@83 1902 if (o.type == "image" && params.opacity) {
rlm@83 1903 node.filterOpacity = ms + ".Alpha(opacity=" + (params.opacity * 100) + ")";
rlm@83 1904 s.filter = (node.filterMatrix || E) + (node.filterOpacity || E);
rlm@83 1905 }
rlm@83 1906 params.font && (s.font = params.font);
rlm@83 1907 params["font-family"] && (s.fontFamily = '"' + params["font-family"][split](",")[0][rp](/^['"]+|['"]+$/g, E) + '"');
rlm@83 1908 params["font-size"] && (s.fontSize = params["font-size"]);
rlm@83 1909 params["font-weight"] && (s.fontWeight = params["font-weight"]);
rlm@83 1910 params["font-style"] && (s.fontStyle = params["font-style"]);
rlm@83 1911 if (params.opacity != null ||
rlm@83 1912 params["stroke-width"] != null ||
rlm@83 1913 params.fill != null ||
rlm@83 1914 params.stroke != null ||
rlm@83 1915 params["stroke-width"] != null ||
rlm@83 1916 params["stroke-opacity"] != null ||
rlm@83 1917 params["fill-opacity"] != null ||
rlm@83 1918 params["stroke-dasharray"] != null ||
rlm@83 1919 params["stroke-miterlimit"] != null ||
rlm@83 1920 params["stroke-linejoin"] != null ||
rlm@83 1921 params["stroke-linecap"] != null) {
rlm@83 1922 node = o.shape || node;
rlm@83 1923 var fill = (node.getElementsByTagName(fillString) && node.getElementsByTagName(fillString)[0]),
rlm@83 1924 newfill = false;
rlm@83 1925 !fill && (newfill = fill = createNode(fillString));
rlm@83 1926 if ("fill-opacity" in params || "opacity" in params) {
rlm@83 1927 var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1);
rlm@83 1928 opacity < 0 && (opacity = 0);
rlm@83 1929 opacity > 1 && (opacity = 1);
rlm@83 1930 fill.opacity = opacity;
rlm@83 1931 }
rlm@83 1932 params.fill && (fill.on = true);
rlm@83 1933 if (fill.on == null || params.fill == "none") {
rlm@83 1934 fill.on = false;
rlm@83 1935 }
rlm@83 1936 if (fill.on && params.fill) {
rlm@83 1937 var isURL = params.fill.match(ISURL);
rlm@83 1938 if (isURL) {
rlm@83 1939 fill.src = isURL[1];
rlm@83 1940 fill.type = "tile";
rlm@83 1941 } else {
rlm@83 1942 fill.color = R.getRGB(params.fill).hex;
rlm@83 1943 fill.src = E;
rlm@83 1944 fill.type = "solid";
rlm@83 1945 if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill)) {
rlm@83 1946 a.fill = "none";
rlm@83 1947 a.gradient = params.fill;
rlm@83 1948 }
rlm@83 1949 }
rlm@83 1950 }
rlm@83 1951 newfill && node[appendChild](fill);
rlm@83 1952 var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]),
rlm@83 1953 newstroke = false;
rlm@83 1954 !stroke && (newstroke = stroke = createNode("stroke"));
rlm@83 1955 if ((params.stroke && params.stroke != "none") ||
rlm@83 1956 params["stroke-width"] ||
rlm@83 1957 params["stroke-opacity"] != null ||
rlm@83 1958 params["stroke-dasharray"] ||
rlm@83 1959 params["stroke-miterlimit"] ||
rlm@83 1960 params["stroke-linejoin"] ||
rlm@83 1961 params["stroke-linecap"]) {
rlm@83 1962 stroke.on = true;
rlm@83 1963 }
rlm@83 1964 (params.stroke == "none" || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false);
rlm@83 1965 var strokeColor = R.getRGB(params.stroke);
rlm@83 1966 stroke.on && params.stroke && (stroke.color = strokeColor.hex);
rlm@83 1967 opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1);
rlm@83 1968 var width = (toFloat(params["stroke-width"]) || 1) * .75;
rlm@83 1969 opacity < 0 && (opacity = 0);
rlm@83 1970 opacity > 1 && (opacity = 1);
rlm@83 1971 params["stroke-width"] == null && (width = a["stroke-width"]);
rlm@83 1972 params["stroke-width"] && (stroke.weight = width);
rlm@83 1973 width && width < 1 && (opacity *= width) && (stroke.weight = 1);
rlm@83 1974 stroke.opacity = opacity;
rlm@83 1975
rlm@83 1976 params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter");
rlm@83 1977 stroke.miterlimit = params["stroke-miterlimit"] || 8;
rlm@83 1978 params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round");
rlm@83 1979 if (params["stroke-dasharray"]) {
rlm@83 1980 var dasharray = {
rlm@83 1981 "-": "shortdash",
rlm@83 1982 ".": "shortdot",
rlm@83 1983 "-.": "shortdashdot",
rlm@83 1984 "-..": "shortdashdotdot",
rlm@83 1985 ". ": "dot",
rlm@83 1986 "- ": "dash",
rlm@83 1987 "--": "longdash",
rlm@83 1988 "- .": "dashdot",
rlm@83 1989 "--.": "longdashdot",
rlm@83 1990 "--..": "longdashdotdot"
rlm@83 1991 };
rlm@83 1992 stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E;
rlm@83 1993 }
rlm@83 1994 newstroke && node[appendChild](stroke);
rlm@83 1995 }
rlm@83 1996 if (res.type == "text") {
rlm@83 1997 s = res.paper.span.style;
rlm@83 1998 a.font && (s.font = a.font);
rlm@83 1999 a["font-family"] && (s.fontFamily = a["font-family"]);
rlm@83 2000 a["font-size"] && (s.fontSize = a["font-size"]);
rlm@83 2001 a["font-weight"] && (s.fontWeight = a["font-weight"]);
rlm@83 2002 a["font-style"] && (s.fontStyle = a["font-style"]);
rlm@83 2003 res.node.string && (res.paper.span.innerHTML = Str(res.node.string)[rp](/</g, "&#60;")[rp](/&/g, "&#38;")[rp](/\n/g, "<br>"));
rlm@83 2004 res.W = a.w = res.paper.span.offsetWidth;
rlm@83 2005 res.H = a.h = res.paper.span.offsetHeight;
rlm@83 2006 res.X = a.x;
rlm@83 2007 res.Y = a.y + round(res.H / 2);
rlm@83 2008
rlm@83 2009 // text-anchor emulationm
rlm@83 2010 switch (a["text-anchor"]) {
rlm@83 2011 case "start":
rlm@83 2012 res.node.style["v-text-align"] = "left";
rlm@83 2013 res.bbx = round(res.W / 2);
rlm@83 2014 break;
rlm@83 2015 case "end":
rlm@83 2016 res.node.style["v-text-align"] = "right";
rlm@83 2017 res.bbx = -round(res.W / 2);
rlm@83 2018 break;
rlm@83 2019 default:
rlm@83 2020 res.node.style["v-text-align"] = "center";
rlm@83 2021 break;
rlm@83 2022 }
rlm@83 2023 }
rlm@83 2024 };
rlm@83 2025 addGradientFill = function (o, gradient) {
rlm@83 2026 o.attrs = o.attrs || {};
rlm@83 2027 var attrs = o.attrs,
rlm@83 2028 fill,
rlm@83 2029 type = "linear",
rlm@83 2030 fxfy = ".5 .5";
rlm@83 2031 o.attrs.gradient = gradient;
rlm@83 2032 gradient = Str(gradient)[rp](radial_gradient, function (all, fx, fy) {
rlm@83 2033 type = "radial";
rlm@83 2034 if (fx && fy) {
rlm@83 2035 fx = toFloat(fx);
rlm@83 2036 fy = toFloat(fy);
rlm@83 2037 pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5);
rlm@83 2038 fxfy = fx + S + fy;
rlm@83 2039 }
rlm@83 2040 return E;
rlm@83 2041 });
rlm@83 2042 gradient = gradient[split](/\s*\-\s*/);
rlm@83 2043 if (type == "linear") {
rlm@83 2044 var angle = gradient.shift();
rlm@83 2045 angle = -toFloat(angle);
rlm@83 2046 if (isNaN(angle)) {
rlm@83 2047 return null;
rlm@83 2048 }
rlm@83 2049 }
rlm@83 2050 var dots = parseDots(gradient);
rlm@83 2051 if (!dots) {
rlm@83 2052 return null;
rlm@83 2053 }
rlm@83 2054 o = o.shape || o.node;
rlm@83 2055 fill = o.getElementsByTagName(fillString)[0] || createNode(fillString);
rlm@83 2056 !fill.parentNode && o.appendChild(fill);
rlm@83 2057 if (dots[length]) {
rlm@83 2058 fill.on = true;
rlm@83 2059 fill.method = "none";
rlm@83 2060 fill.color = dots[0].color;
rlm@83 2061 fill.color2 = dots[dots[length] - 1].color;
rlm@83 2062 var clrs = [];
rlm@83 2063 for (var i = 0, ii = dots[length]; i < ii; i++) {
rlm@83 2064 dots[i].offset && clrs[push](dots[i].offset + S + dots[i].color);
rlm@83 2065 }
rlm@83 2066 fill.colors && (fill.colors.value = clrs[length] ? clrs[join]() : "0% " + fill.color);
rlm@83 2067 if (type == "radial") {
rlm@83 2068 fill.type = "gradientradial";
rlm@83 2069 fill.focus = "100%";
rlm@83 2070 fill.focussize = fxfy;
rlm@83 2071 fill.focusposition = fxfy;
rlm@83 2072 } else {
rlm@83 2073 fill.type = "gradient";
rlm@83 2074 fill.angle = (270 - angle) % 360;
rlm@83 2075 }
rlm@83 2076 }
rlm@83 2077 return 1;
rlm@83 2078 };
rlm@83 2079 Element = function (node, group, vml) {
rlm@83 2080 var Rotation = 0,
rlm@83 2081 RotX = 0,
rlm@83 2082 RotY = 0,
rlm@83 2083 Scale = 1;
rlm@83 2084 this[0] = node;
rlm@83 2085 this.id = R._oid++;
rlm@83 2086 this.node = node;
rlm@83 2087 node.raphael = this;
rlm@83 2088 this.X = 0;
rlm@83 2089 this.Y = 0;
rlm@83 2090 this.attrs = {};
rlm@83 2091 this.Group = group;
rlm@83 2092 this.paper = vml;
rlm@83 2093 this._ = {
rlm@83 2094 tx: 0,
rlm@83 2095 ty: 0,
rlm@83 2096 rt: {deg:0},
rlm@83 2097 sx: 1,
rlm@83 2098 sy: 1
rlm@83 2099 };
rlm@83 2100 !vml.bottom && (vml.bottom = this);
rlm@83 2101 this.prev = vml.top;
rlm@83 2102 vml.top && (vml.top.next = this);
rlm@83 2103 vml.top = this;
rlm@83 2104 this.next = null;
rlm@83 2105 };
rlm@83 2106 Element[proto].rotate = function (deg, cx, cy) {
rlm@83 2107 if (this.removed) {
rlm@83 2108 return this;
rlm@83 2109 }
rlm@83 2110 if (deg == null) {
rlm@83 2111 if (this._.rt.cx) {
rlm@83 2112 return [this._.rt.deg, this._.rt.cx, this._.rt.cy][join](S);
rlm@83 2113 }
rlm@83 2114 return this._.rt.deg;
rlm@83 2115 }
rlm@83 2116 deg = Str(deg)[split](separator);
rlm@83 2117 if (deg[length] - 1) {
rlm@83 2118 cx = toFloat(deg[1]);
rlm@83 2119 cy = toFloat(deg[2]);
rlm@83 2120 }
rlm@83 2121 deg = toFloat(deg[0]);
rlm@83 2122 if (cx != null) {
rlm@83 2123 this._.rt.deg = deg;
rlm@83 2124 } else {
rlm@83 2125 this._.rt.deg += deg;
rlm@83 2126 }
rlm@83 2127 cy == null && (cx = null);
rlm@83 2128 this._.rt.cx = cx;
rlm@83 2129 this._.rt.cy = cy;
rlm@83 2130 this.setBox(this.attrs, cx, cy);
rlm@83 2131 this.Group.style.rotation = this._.rt.deg;
rlm@83 2132 // gradient fix for rotation. TODO
rlm@83 2133 // var fill = (this.shape || this.node).getElementsByTagName(fillString);
rlm@83 2134 // fill = fill[0] || {};
rlm@83 2135 // var b = ((360 - this._.rt.deg) - 270) % 360;
rlm@83 2136 // !R.is(fill.angle, "undefined") && (fill.angle = b);
rlm@83 2137 return this;
rlm@83 2138 };
rlm@83 2139 Element[proto].setBox = function (params, cx, cy) {
rlm@83 2140 if (this.removed) {
rlm@83 2141 return this;
rlm@83 2142 }
rlm@83 2143 var gs = this.Group.style,
rlm@83 2144 os = (this.shape && this.shape.style) || this.node.style;
rlm@83 2145 params = params || {};
rlm@83 2146 for (var i in params) if (params[has](i)) {
rlm@83 2147 this.attrs[i] = params[i];
rlm@83 2148 }
rlm@83 2149 cx = cx || this._.rt.cx;
rlm@83 2150 cy = cy || this._.rt.cy;
rlm@83 2151 var attr = this.attrs,
rlm@83 2152 x,
rlm@83 2153 y,
rlm@83 2154 w,
rlm@83 2155 h;
rlm@83 2156 switch (this.type) {
rlm@83 2157 case "circle":
rlm@83 2158 x = attr.cx - attr.r;
rlm@83 2159 y = attr.cy - attr.r;
rlm@83 2160 w = h = attr.r * 2;
rlm@83 2161 break;
rlm@83 2162 case "ellipse":
rlm@83 2163 x = attr.cx - attr.rx;
rlm@83 2164 y = attr.cy - attr.ry;
rlm@83 2165 w = attr.rx * 2;
rlm@83 2166 h = attr.ry * 2;
rlm@83 2167 break;
rlm@83 2168 case "image":
rlm@83 2169 x = +attr.x;
rlm@83 2170 y = +attr.y;
rlm@83 2171 w = attr.width || 0;
rlm@83 2172 h = attr.height || 0;
rlm@83 2173 break;
rlm@83 2174 case "text":
rlm@83 2175 this.textpath.v = ["m", round(attr.x), ", ", round(attr.y - 2), "l", round(attr.x) + 1, ", ", round(attr.y - 2)][join](E);
rlm@83 2176 x = attr.x - round(this.W / 2);
rlm@83 2177 y = attr.y - this.H / 2;
rlm@83 2178 w = this.W;
rlm@83 2179 h = this.H;
rlm@83 2180 break;
rlm@83 2181 case "rect":
rlm@83 2182 case "path":
rlm@83 2183 if (!this.attrs.path) {
rlm@83 2184 x = 0;
rlm@83 2185 y = 0;
rlm@83 2186 w = this.paper.width;
rlm@83 2187 h = this.paper.height;
rlm@83 2188 } else {
rlm@83 2189 var dim = pathDimensions(this.attrs.path);
rlm@83 2190 x = dim.x;
rlm@83 2191 y = dim.y;
rlm@83 2192 w = dim.width;
rlm@83 2193 h = dim.height;
rlm@83 2194 }
rlm@83 2195 break;
rlm@83 2196 default:
rlm@83 2197 x = 0;
rlm@83 2198 y = 0;
rlm@83 2199 w = this.paper.width;
rlm@83 2200 h = this.paper.height;
rlm@83 2201 break;
rlm@83 2202 }
rlm@83 2203 cx = (cx == null) ? x + w / 2 : cx;
rlm@83 2204 cy = (cy == null) ? y + h / 2 : cy;
rlm@83 2205 var left = cx - this.paper.width / 2,
rlm@83 2206 top = cy - this.paper.height / 2, t;
rlm@83 2207 gs.left != (t = left + "px") && (gs.left = t);
rlm@83 2208 gs.top != (t = top + "px") && (gs.top = t);
rlm@83 2209 this.X = pathlike[has](this.type) ? -left : x;
rlm@83 2210 this.Y = pathlike[has](this.type) ? -top : y;
rlm@83 2211 this.W = w;
rlm@83 2212 this.H = h;
rlm@83 2213 if (pathlike[has](this.type)) {
rlm@83 2214 os.left != (t = -left * zoom + "px") && (os.left = t);
rlm@83 2215 os.top != (t = -top * zoom + "px") && (os.top = t);
rlm@83 2216 } else if (this.type == "text") {
rlm@83 2217 os.left != (t = -left + "px") && (os.left = t);
rlm@83 2218 os.top != (t = -top + "px") && (os.top = t);
rlm@83 2219 } else {
rlm@83 2220 gs.width != (t = this.paper.width + "px") && (gs.width = t);
rlm@83 2221 gs.height != (t = this.paper.height + "px") && (gs.height = t);
rlm@83 2222 os.left != (t = x - left + "px") && (os.left = t);
rlm@83 2223 os.top != (t = y - top + "px") && (os.top = t);
rlm@83 2224 os.width != (t = w + "px") && (os.width = t);
rlm@83 2225 os.height != (t = h + "px") && (os.height = t);
rlm@83 2226 }
rlm@83 2227 };
rlm@83 2228 Element[proto].hide = function () {
rlm@83 2229 !this.removed && (this.Group.style.display = "none");
rlm@83 2230 return this;
rlm@83 2231 };
rlm@83 2232 Element[proto].show = function () {
rlm@83 2233 !this.removed && (this.Group.style.display = "block");
rlm@83 2234 return this;
rlm@83 2235 };
rlm@83 2236 Element[proto].getBBox = function () {
rlm@83 2237 if (this.removed) {
rlm@83 2238 return this;
rlm@83 2239 }
rlm@83 2240 if (pathlike[has](this.type)) {
rlm@83 2241 return pathDimensions(this.attrs.path);
rlm@83 2242 }
rlm@83 2243 return {
rlm@83 2244 x: this.X + (this.bbx || 0),
rlm@83 2245 y: this.Y,
rlm@83 2246 width: this.W,
rlm@83 2247 height: this.H
rlm@83 2248 };
rlm@83 2249 };
rlm@83 2250 Element[proto].remove = function () {
rlm@83 2251 if (this.removed) {
rlm@83 2252 return;
rlm@83 2253 }
rlm@83 2254 tear(this, this.paper);
rlm@83 2255 this.node.parentNode.removeChild(this.node);
rlm@83 2256 this.Group.parentNode.removeChild(this.Group);
rlm@83 2257 this.shape && this.shape.parentNode.removeChild(this.shape);
rlm@83 2258 for (var i in this) {
rlm@83 2259 delete this[i];
rlm@83 2260 }
rlm@83 2261 this.removed = true;
rlm@83 2262 };
rlm@83 2263 Element[proto].attr = function (name, value) {
rlm@83 2264 if (this.removed) {
rlm@83 2265 return this;
rlm@83 2266 }
rlm@83 2267 if (name == null) {
rlm@83 2268 var res = {};
rlm@83 2269 for (var i in this.attrs) if (this.attrs[has](i)) {
rlm@83 2270 res[i] = this.attrs[i];
rlm@83 2271 }
rlm@83 2272 this._.rt.deg && (res.rotation = this.rotate());
rlm@83 2273 (this._.sx != 1 || this._.sy != 1) && (res.scale = this.scale());
rlm@83 2274 res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
rlm@83 2275 return res;
rlm@83 2276 }
rlm@83 2277 if (value == null && R.is(name, string)) {
rlm@83 2278 if (name == "translation") {
rlm@83 2279 return translate.call(this);
rlm@83 2280 }
rlm@83 2281 if (name == "rotation") {
rlm@83 2282 return this.rotate();
rlm@83 2283 }
rlm@83 2284 if (name == "scale") {
rlm@83 2285 return this.scale();
rlm@83 2286 }
rlm@83 2287 if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) {
rlm@83 2288 return this.attrs.gradient;
rlm@83 2289 }
rlm@83 2290 return this.attrs[name];
rlm@83 2291 }
rlm@83 2292 if (this.attrs && value == null && R.is(name, array)) {
rlm@83 2293 var ii, values = {};
rlm@83 2294 for (i = 0, ii = name[length]; i < ii; i++) {
rlm@83 2295 values[name[i]] = this.attr(name[i]);
rlm@83 2296 }
rlm@83 2297 return values;
rlm@83 2298 }
rlm@83 2299 var params;
rlm@83 2300 if (value != null) {
rlm@83 2301 params = {};
rlm@83 2302 params[name] = value;
rlm@83 2303 }
rlm@83 2304 value == null && R.is(name, "object") && (params = name);
rlm@83 2305 if (params) {
rlm@83 2306 if (params.text && this.type == "text") {
rlm@83 2307 this.node.string = params.text;
rlm@83 2308 }
rlm@83 2309 setFillAndStroke(this, params);
rlm@83 2310 if (params.gradient && (({circle: 1, ellipse: 1})[has](this.type) || Str(params.gradient).charAt() != "r")) {
rlm@83 2311 addGradientFill(this, params.gradient);
rlm@83 2312 }
rlm@83 2313 (!pathlike[has](this.type) || this._.rt.deg) && this.setBox(this.attrs);
rlm@83 2314 }
rlm@83 2315 return this;
rlm@83 2316 };
rlm@83 2317 Element[proto].toFront = function () {
rlm@83 2318 !this.removed && this.Group.parentNode[appendChild](this.Group);
rlm@83 2319 this.paper.top != this && tofront(this, this.paper);
rlm@83 2320 return this;
rlm@83 2321 };
rlm@83 2322 Element[proto].toBack = function () {
rlm@83 2323 if (this.removed) {
rlm@83 2324 return this;
rlm@83 2325 }
rlm@83 2326 if (this.Group.parentNode.firstChild != this.Group) {
rlm@83 2327 this.Group.parentNode.insertBefore(this.Group, this.Group.parentNode.firstChild);
rlm@83 2328 toback(this, this.paper);
rlm@83 2329 }
rlm@83 2330 return this;
rlm@83 2331 };
rlm@83 2332 Element[proto].insertAfter = function (element) {
rlm@83 2333 if (this.removed) {
rlm@83 2334 return this;
rlm@83 2335 }
rlm@83 2336 if (element.constructor == Set) {
rlm@83 2337 element = element[element.length];
rlm@83 2338 }
rlm@83 2339 if (element.Group.nextSibling) {
rlm@83 2340 element.Group.parentNode.insertBefore(this.Group, element.Group.nextSibling);
rlm@83 2341 } else {
rlm@83 2342 element.Group.parentNode[appendChild](this.Group);
rlm@83 2343 }
rlm@83 2344 insertafter(this, element, this.paper);
rlm@83 2345 return this;
rlm@83 2346 };
rlm@83 2347 Element[proto].insertBefore = function (element) {
rlm@83 2348 if (this.removed) {
rlm@83 2349 return this;
rlm@83 2350 }
rlm@83 2351 if (element.constructor == Set) {
rlm@83 2352 element = element[0];
rlm@83 2353 }
rlm@83 2354 element.Group.parentNode.insertBefore(this.Group, element.Group);
rlm@83 2355 insertbefore(this, element, this.paper);
rlm@83 2356 return this;
rlm@83 2357 };
rlm@83 2358 var blurregexp = / progid:\S+Blur\([^\)]+\)/g;
rlm@83 2359 Element[proto].blur = function (size) {
rlm@83 2360 var s = this.node.runtimeStyle,
rlm@83 2361 f = s.filter;
rlm@83 2362 f = f.replace(blurregexp, E);
rlm@83 2363 if (+size !== 0) {
rlm@83 2364 this.attrs.blur = size;
rlm@83 2365 s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")";
rlm@83 2366 s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5));
rlm@83 2367 } else {
rlm@83 2368 s.filter = f;
rlm@83 2369 s.margin = 0;
rlm@83 2370 delete this.attrs.blur;
rlm@83 2371 }
rlm@83 2372 };
rlm@83 2373
rlm@83 2374 theCircle = function (vml, x, y, r) {
rlm@83 2375 var g = createNode("group"),
rlm@83 2376 o = createNode("oval"),
rlm@83 2377 ol = o.style;
rlm@83 2378 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px";
rlm@83 2379 g.coordsize = coordsize;
rlm@83 2380 g.coordorigin = vml.coordorigin;
rlm@83 2381 g[appendChild](o);
rlm@83 2382 var res = new Element(o, g, vml);
rlm@83 2383 res.type = "circle";
rlm@83 2384 setFillAndStroke(res, {stroke: "#000", fill: "none"});
rlm@83 2385 res.attrs.cx = x;
rlm@83 2386 res.attrs.cy = y;
rlm@83 2387 res.attrs.r = r;
rlm@83 2388 res.setBox({x: x - r, y: y - r, width: r * 2, height: r * 2});
rlm@83 2389 vml.canvas[appendChild](g);
rlm@83 2390 return res;
rlm@83 2391 };
rlm@83 2392 function rectPath(x, y, w, h, r) {
rlm@83 2393 if (r) {
rlm@83 2394 return R.format("M{0},{1}l{2},0a{3},{3},0,0,1,{3},{3}l0,{5}a{3},{3},0,0,1,{4},{3}l{6},0a{3},{3},0,0,1,{4},{4}l0,{7}a{3},{3},0,0,1,{3},{4}z", x + r, y, w - r * 2, r, -r, h - r * 2, r * 2 - w, r * 2 - h);
rlm@83 2395 } else {
rlm@83 2396 return R.format("M{0},{1}l{2},0,0,{3},{4},0z", x, y, w, h, -w);
rlm@83 2397 }
rlm@83 2398 }
rlm@83 2399 theRect = function (vml, x, y, w, h, r) {
rlm@83 2400 var path = rectPath(x, y, w, h, r),
rlm@83 2401 res = vml.path(path),
rlm@83 2402 a = res.attrs;
rlm@83 2403 res.X = a.x = x;
rlm@83 2404 res.Y = a.y = y;
rlm@83 2405 res.W = a.width = w;
rlm@83 2406 res.H = a.height = h;
rlm@83 2407 a.r = r;
rlm@83 2408 a.path = path;
rlm@83 2409 res.type = "rect";
rlm@83 2410 return res;
rlm@83 2411 };
rlm@83 2412 theEllipse = function (vml, x, y, rx, ry) {
rlm@83 2413 var g = createNode("group"),
rlm@83 2414 o = createNode("oval"),
rlm@83 2415 ol = o.style;
rlm@83 2416 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px";
rlm@83 2417 g.coordsize = coordsize;
rlm@83 2418 g.coordorigin = vml.coordorigin;
rlm@83 2419 g[appendChild](o);
rlm@83 2420 var res = new Element(o, g, vml);
rlm@83 2421 res.type = "ellipse";
rlm@83 2422 setFillAndStroke(res, {stroke: "#000"});
rlm@83 2423 res.attrs.cx = x;
rlm@83 2424 res.attrs.cy = y;
rlm@83 2425 res.attrs.rx = rx;
rlm@83 2426 res.attrs.ry = ry;
rlm@83 2427 res.setBox({x: x - rx, y: y - ry, width: rx * 2, height: ry * 2});
rlm@83 2428 vml.canvas[appendChild](g);
rlm@83 2429 return res;
rlm@83 2430 };
rlm@83 2431 theImage = function (vml, src, x, y, w, h) {
rlm@83 2432 var g = createNode("group"),
rlm@83 2433 o = createNode("image"),
rlm@83 2434 ol = o.style;
rlm@83 2435 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px";
rlm@83 2436 g.coordsize = coordsize;
rlm@83 2437 g.coordorigin = vml.coordorigin;
rlm@83 2438 o.src = src;
rlm@83 2439 g[appendChild](o);
rlm@83 2440 var res = new Element(o, g, vml);
rlm@83 2441 res.type = "image";
rlm@83 2442 res.attrs.src = src;
rlm@83 2443 res.attrs.x = x;
rlm@83 2444 res.attrs.y = y;
rlm@83 2445 res.attrs.w = w;
rlm@83 2446 res.attrs.h = h;
rlm@83 2447 res.setBox({x: x, y: y, width: w, height: h});
rlm@83 2448 vml.canvas[appendChild](g);
rlm@83 2449 return res;
rlm@83 2450 };
rlm@83 2451 theText = function (vml, x, y, text) {
rlm@83 2452 var g = createNode("group"),
rlm@83 2453 el = createNode("shape"),
rlm@83 2454 ol = el.style,
rlm@83 2455 path = createNode("path"),
rlm@83 2456 ps = path.style,
rlm@83 2457 o = createNode("textpath");
rlm@83 2458 g.style.cssText = "position:absolute;left:0;top:0;width:" + vml.width + "px;height:" + vml.height + "px";
rlm@83 2459 g.coordsize = coordsize;
rlm@83 2460 g.coordorigin = vml.coordorigin;
rlm@83 2461 path.v = R.format("m{0},{1}l{2},{1}", round(x * 10), round(y * 10), round(x * 10) + 1);
rlm@83 2462 path.textpathok = true;
rlm@83 2463 ol.width = vml.width;
rlm@83 2464 ol.height = vml.height;
rlm@83 2465 o.string = Str(text);
rlm@83 2466 o.on = true;
rlm@83 2467 el[appendChild](o);
rlm@83 2468 el[appendChild](path);
rlm@83 2469 g[appendChild](el);
rlm@83 2470 var res = new Element(o, g, vml);
rlm@83 2471 res.shape = el;
rlm@83 2472 res.textpath = path;
rlm@83 2473 res.type = "text";
rlm@83 2474 res.attrs.text = text;
rlm@83 2475 res.attrs.x = x;
rlm@83 2476 res.attrs.y = y;
rlm@83 2477 res.attrs.w = 1;
rlm@83 2478 res.attrs.h = 1;
rlm@83 2479 setFillAndStroke(res, {font: availableAttrs.font, stroke: "none", fill: "#000"});
rlm@83 2480 res.setBox();
rlm@83 2481 vml.canvas[appendChild](g);
rlm@83 2482 return res;
rlm@83 2483 };
rlm@83 2484 setSize = function (width, height) {
rlm@83 2485 var cs = this.canvas.style;
rlm@83 2486 width == +width && (width += "px");
rlm@83 2487 height == +height && (height += "px");
rlm@83 2488 cs.width = width;
rlm@83 2489 cs.height = height;
rlm@83 2490 cs.clip = "rect(0 " + width + " " + height + " 0)";
rlm@83 2491 return this;
rlm@83 2492 };
rlm@83 2493 var createNode;
rlm@83 2494 doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)");
rlm@83 2495 try {
rlm@83 2496 !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml");
rlm@83 2497 createNode = function (tagName) {
rlm@83 2498 return doc.createElement('<rvml:' + tagName + ' class="rvml">');
rlm@83 2499 };
rlm@83 2500 } catch (e) {
rlm@83 2501 createNode = function (tagName) {
rlm@83 2502 return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">');
rlm@83 2503 };
rlm@83 2504 }
rlm@83 2505 create = function () {
rlm@83 2506 var con = getContainer[apply](0, arguments),
rlm@83 2507 container = con.container,
rlm@83 2508 height = con.height,
rlm@83 2509 s,
rlm@83 2510 width = con.width,
rlm@83 2511 x = con.x,
rlm@83 2512 y = con.y;
rlm@83 2513 if (!container) {
rlm@83 2514 throw new Error("VML container not found.");
rlm@83 2515 }
rlm@83 2516 var res = new Paper,
rlm@83 2517 c = res.canvas = doc.createElement("div"),
rlm@83 2518 cs = c.style;
rlm@83 2519 x = x || 0;
rlm@83 2520 y = y || 0;
rlm@83 2521 width = width || 512;
rlm@83 2522 height = height || 342;
rlm@83 2523 width == +width && (width += "px");
rlm@83 2524 height == +height && (height += "px");
rlm@83 2525 res.width = 1e3;
rlm@83 2526 res.height = 1e3;
rlm@83 2527 res.coordsize = zoom * 1e3 + S + zoom * 1e3;
rlm@83 2528 res.coordorigin = "0 0";
rlm@83 2529 res.span = doc.createElement("span");
rlm@83 2530 res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
rlm@83 2531 c[appendChild](res.span);
rlm@83 2532 cs.cssText = R.format("width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height);
rlm@83 2533 if (container == 1) {
rlm@83 2534 doc.body[appendChild](c);
rlm@83 2535 cs.left = x + "px";
rlm@83 2536 cs.top = y + "px";
rlm@83 2537 cs.position = "absolute";
rlm@83 2538 } else {
rlm@83 2539 if (container.firstChild) {
rlm@83 2540 container.insertBefore(c, container.firstChild);
rlm@83 2541 } else {
rlm@83 2542 container[appendChild](c);
rlm@83 2543 }
rlm@83 2544 }
rlm@83 2545 plugins.call(res, res, R.fn);
rlm@83 2546 return res;
rlm@83 2547 };
rlm@83 2548 Paper[proto].clear = function () {
rlm@83 2549 this.canvas.innerHTML = E;
rlm@83 2550 this.span = doc.createElement("span");
rlm@83 2551 this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;";
rlm@83 2552 this.canvas[appendChild](this.span);
rlm@83 2553 this.bottom = this.top = null;
rlm@83 2554 };
rlm@83 2555 Paper[proto].remove = function () {
rlm@83 2556 this.canvas.parentNode.removeChild(this.canvas);
rlm@83 2557 for (var i in this) {
rlm@83 2558 this[i] = removed(i);
rlm@83 2559 }
rlm@83 2560 return true;
rlm@83 2561 };
rlm@83 2562 }
rlm@83 2563
rlm@83 2564 // rest
rlm@83 2565 // WebKit rendering bug workaround method
rlm@83 2566 if ((navigator.vendor == "Apple Computer, Inc.") && (navigator.userAgent.match(/Version\/(.*?)\s/)[1] < 4 || win.navigator.platform.slice(0, 2) == "iP")) {
rlm@83 2567 Paper[proto].safari = function () {
rlm@83 2568 var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"});
rlm@83 2569 win.setTimeout(function () {rect.remove();});
rlm@83 2570 };
rlm@83 2571 } else {
rlm@83 2572 Paper[proto].safari = function () {};
rlm@83 2573 }
rlm@83 2574
rlm@83 2575 // Events
rlm@83 2576 var preventDefault = function () {
rlm@83 2577 this.returnValue = false;
rlm@83 2578 },
rlm@83 2579 preventTouch = function () {
rlm@83 2580 return this.originalEvent.preventDefault();
rlm@83 2581 },
rlm@83 2582 stopPropagation = function () {
rlm@83 2583 this.cancelBubble = true;
rlm@83 2584 },
rlm@83 2585 stopTouch = function () {
rlm@83 2586 return this.originalEvent.stopPropagation();
rlm@83 2587 },
rlm@83 2588 addEvent = (function () {
rlm@83 2589 if (doc.addEventListener) {
rlm@83 2590 return function (obj, type, fn, element) {
rlm@83 2591 var realName = supportsTouch && touchMap[type] ? touchMap[type] : type;
rlm@83 2592 var f = function (e) {
rlm@83 2593 if (supportsTouch && touchMap[has](type)) {
rlm@83 2594 for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) {
rlm@83 2595 if (e.targetTouches[i].target == obj) {
rlm@83 2596 var olde = e;
rlm@83 2597 e = e.targetTouches[i];
rlm@83 2598 e.originalEvent = olde;
rlm@83 2599 e.preventDefault = preventTouch;
rlm@83 2600 e.stopPropagation = stopTouch;
rlm@83 2601 break;
rlm@83 2602 }
rlm@83 2603 }
rlm@83 2604 }
rlm@83 2605 return fn.call(element, e);
rlm@83 2606 };
rlm@83 2607 obj.addEventListener(realName, f, false);
rlm@83 2608 return function () {
rlm@83 2609 obj.removeEventListener(realName, f, false);
rlm@83 2610 return true;
rlm@83 2611 };
rlm@83 2612 };
rlm@83 2613 } else if (doc.attachEvent) {
rlm@83 2614 return function (obj, type, fn, element) {
rlm@83 2615 var f = function (e) {
rlm@83 2616 e = e || win.event;
rlm@83 2617 e.preventDefault = e.preventDefault || preventDefault;
rlm@83 2618 e.stopPropagation = e.stopPropagation || stopPropagation;
rlm@83 2619 return fn.call(element, e);
rlm@83 2620 };
rlm@83 2621 obj.attachEvent("on" + type, f);
rlm@83 2622 var detacher = function () {
rlm@83 2623 obj.detachEvent("on" + type, f);
rlm@83 2624 return true;
rlm@83 2625 };
rlm@83 2626 return detacher;
rlm@83 2627 };
rlm@83 2628 }
rlm@83 2629 })(),
rlm@83 2630 drag = [],
rlm@83 2631 dragMove = function (e) {
rlm@83 2632 var x = e.clientX,
rlm@83 2633 y = e.clientY,
rlm@83 2634 dragi,
rlm@83 2635 j = drag.length;
rlm@83 2636 while (j--) {
rlm@83 2637 dragi = drag[j];
rlm@83 2638 if (supportsTouch) {
rlm@83 2639 var i = e.touches.length,
rlm@83 2640 touch;
rlm@83 2641 while (i--) {
rlm@83 2642 touch = e.touches[i];
rlm@83 2643 if (touch.identifier == dragi.el._drag.id) {
rlm@83 2644 x = touch.clientX;
rlm@83 2645 y = touch.clientY;
rlm@83 2646 (e.originalEvent ? e.originalEvent : e).preventDefault();
rlm@83 2647 break;
rlm@83 2648 }
rlm@83 2649 }
rlm@83 2650 } else {
rlm@83 2651 e.preventDefault();
rlm@83 2652 }
rlm@83 2653 dragi.move && dragi.move.call(dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y);
rlm@83 2654 }
rlm@83 2655 },
rlm@83 2656 dragUp = function () {
rlm@83 2657 R.unmousemove(dragMove).unmouseup(dragUp);
rlm@83 2658 var i = drag.length,
rlm@83 2659 dragi;
rlm@83 2660 while (i--) {
rlm@83 2661 dragi = drag[i];
rlm@83 2662 dragi.el._drag = {};
rlm@83 2663 dragi.end && dragi.end.call(dragi.el);
rlm@83 2664 }
rlm@83 2665 drag = [];
rlm@83 2666 };
rlm@83 2667 for (var i = events[length]; i--;) {
rlm@83 2668 (function (eventName) {
rlm@83 2669 R[eventName] = Element[proto][eventName] = function (fn) {
rlm@83 2670 if (R.is(fn, "function")) {
rlm@83 2671 this.events = this.events || [];
rlm@83 2672 this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || doc, eventName, fn, this)});
rlm@83 2673 }
rlm@83 2674 return this;
rlm@83 2675 };
rlm@83 2676 R["un" + eventName] = Element[proto]["un" + eventName] = function (fn) {
rlm@83 2677 var events = this.events,
rlm@83 2678 l = events[length];
rlm@83 2679 while (l--) if (events[l].name == eventName && events[l].f == fn) {
rlm@83 2680 events[l].unbind();
rlm@83 2681 events.splice(l, 1);
rlm@83 2682 !events.length && delete this.events;
rlm@83 2683 return this;
rlm@83 2684 }
rlm@83 2685 return this;
rlm@83 2686 };
rlm@83 2687 })(events[i]);
rlm@83 2688 }
rlm@83 2689 Element[proto].hover = function (f_in, f_out) {
rlm@83 2690 return this.mouseover(f_in).mouseout(f_out);
rlm@83 2691 };
rlm@83 2692 Element[proto].unhover = function (f_in, f_out) {
rlm@83 2693 return this.unmouseover(f_in).unmouseout(f_out);
rlm@83 2694 };
rlm@83 2695 Element[proto].drag = function (onmove, onstart, onend) {
rlm@83 2696 this._drag = {};
rlm@83 2697 this.mousedown(function (e) {
rlm@83 2698 (e.originalEvent || e).preventDefault();
rlm@83 2699 this._drag.x = e.clientX;
rlm@83 2700 this._drag.y = e.clientY;
rlm@83 2701 this._drag.id = e.identifier;
rlm@83 2702 onstart && onstart.call(this, e.clientX, e.clientY);
rlm@83 2703 !drag.length && R.mousemove(dragMove).mouseup(dragUp);
rlm@83 2704 drag.push({el: this, move: onmove, end: onend});
rlm@83 2705 });
rlm@83 2706 return this;
rlm@83 2707 };
rlm@83 2708 Element[proto].undrag = function (onmove, onstart, onend) {
rlm@83 2709 var i = drag.length;
rlm@83 2710 while (i--) {
rlm@83 2711 drag[i].el == this && (drag[i].move == onmove && drag[i].end == onend) && drag.splice(i, 1);
rlm@83 2712 !drag.length && R.unmousemove(dragMove).unmouseup(dragUp);
rlm@83 2713 }
rlm@83 2714 };
rlm@83 2715 Paper[proto].circle = function (x, y, r) {
rlm@83 2716 return theCircle(this, x || 0, y || 0, r || 0);
rlm@83 2717 };
rlm@83 2718 Paper[proto].rect = function (x, y, w, h, r) {
rlm@83 2719 return theRect(this, x || 0, y || 0, w || 0, h || 0, r || 0);
rlm@83 2720 };
rlm@83 2721 Paper[proto].ellipse = function (x, y, rx, ry) {
rlm@83 2722 return theEllipse(this, x || 0, y || 0, rx || 0, ry || 0);
rlm@83 2723 };
rlm@83 2724 Paper[proto].path = function (pathString) {
rlm@83 2725 pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E);
rlm@83 2726 return thePath(R.format[apply](R, arguments), this);
rlm@83 2727 };
rlm@83 2728 Paper[proto].image = function (src, x, y, w, h) {
rlm@83 2729 return theImage(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0);
rlm@83 2730 };
rlm@83 2731 Paper[proto].text = function (x, y, text) {
rlm@83 2732 return theText(this, x || 0, y || 0, text || E);
rlm@83 2733 };
rlm@83 2734 Paper[proto].set = function (itemsArray) {
rlm@83 2735 arguments[length] > 1 && (itemsArray = Array[proto].splice.call(arguments, 0, arguments[length]));
rlm@83 2736 return new Set(itemsArray);
rlm@83 2737 };
rlm@83 2738 Paper[proto].setSize = setSize;
rlm@83 2739 Paper[proto].top = Paper[proto].bottom = null;
rlm@83 2740 Paper[proto].raphael = R;
rlm@83 2741 function x_y() {
rlm@83 2742 return this.x + S + this.y;
rlm@83 2743 }
rlm@83 2744 Element[proto].resetScale = function () {
rlm@83 2745 if (this.removed) {
rlm@83 2746 return this;
rlm@83 2747 }
rlm@83 2748 this._.sx = 1;
rlm@83 2749 this._.sy = 1;
rlm@83 2750 this.attrs.scale = "1 1";
rlm@83 2751 };
rlm@83 2752 Element[proto].scale = function (x, y, cx, cy) {
rlm@83 2753 if (this.removed) {
rlm@83 2754 return this;
rlm@83 2755 }
rlm@83 2756 if (x == null && y == null) {
rlm@83 2757 return {
rlm@83 2758 x: this._.sx,
rlm@83 2759 y: this._.sy,
rlm@83 2760 toString: x_y
rlm@83 2761 };
rlm@83 2762 }
rlm@83 2763 y = y || x;
rlm@83 2764 !+y && (y = x);
rlm@83 2765 var dx,
rlm@83 2766 dy,
rlm@83 2767 dcx,
rlm@83 2768 dcy,
rlm@83 2769 a = this.attrs;
rlm@83 2770 if (x != 0) {
rlm@83 2771 var bb = this.getBBox(),
rlm@83 2772 rcx = bb.x + bb.width / 2,
rlm@83 2773 rcy = bb.y + bb.height / 2,
rlm@83 2774 kx = x / this._.sx,
rlm@83 2775 ky = y / this._.sy;
rlm@83 2776 cx = (+cx || cx == 0) ? cx : rcx;
rlm@83 2777 cy = (+cy || cy == 0) ? cy : rcy;
rlm@83 2778 var dirx = ~~(x / math.abs(x)),
rlm@83 2779 diry = ~~(y / math.abs(y)),
rlm@83 2780 s = this.node.style,
rlm@83 2781 ncx = cx + (rcx - cx) * kx,
rlm@83 2782 ncy = cy + (rcy - cy) * ky;
rlm@83 2783 switch (this.type) {
rlm@83 2784 case "rect":
rlm@83 2785 case "image":
rlm@83 2786 var neww = a.width * dirx * kx,
rlm@83 2787 newh = a.height * diry * ky;
rlm@83 2788 this.attr({
rlm@83 2789 height: newh,
rlm@83 2790 r: a.r * mmin(dirx * kx, diry * ky),
rlm@83 2791 width: neww,
rlm@83 2792 x: ncx - neww / 2,
rlm@83 2793 y: ncy - newh / 2
rlm@83 2794 });
rlm@83 2795 break;
rlm@83 2796 case "circle":
rlm@83 2797 case "ellipse":
rlm@83 2798 this.attr({
rlm@83 2799 rx: a.rx * dirx * kx,
rlm@83 2800 ry: a.ry * diry * ky,
rlm@83 2801 r: a.r * mmin(dirx * kx, diry * ky),
rlm@83 2802 cx: ncx,
rlm@83 2803 cy: ncy
rlm@83 2804 });
rlm@83 2805 break;
rlm@83 2806 case "text":
rlm@83 2807 this.attr({
rlm@83 2808 x: ncx,
rlm@83 2809 y: ncy
rlm@83 2810 });
rlm@83 2811 break;
rlm@83 2812 case "path":
rlm@83 2813 var path = pathToRelative(a.path),
rlm@83 2814 skip = true;
rlm@83 2815 for (var i = 0, ii = path[length]; i < ii; i++) {
rlm@83 2816 var p = path[i],
rlm@83 2817 P0 = upperCase.call(p[0]);
rlm@83 2818 if (P0 == "M" && skip) {
rlm@83 2819 continue;
rlm@83 2820 } else {
rlm@83 2821 skip = false;
rlm@83 2822 }
rlm@83 2823 if (P0 == "A") {
rlm@83 2824 p[path[i][length] - 2] *= kx;
rlm@83 2825 p[path[i][length] - 1] *= ky;
rlm@83 2826 p[1] *= dirx * kx;
rlm@83 2827 p[2] *= diry * ky;
rlm@83 2828 p[5] = +!(dirx + diry ? !+p[5] : +p[5]);
rlm@83 2829 } else if (P0 == "H") {
rlm@83 2830 for (var j = 1, jj = p[length]; j < jj; j++) {
rlm@83 2831 p[j] *= kx;
rlm@83 2832 }
rlm@83 2833 } else if (P0 == "V") {
rlm@83 2834 for (j = 1, jj = p[length]; j < jj; j++) {
rlm@83 2835 p[j] *= ky;
rlm@83 2836 }
rlm@83 2837 } else {
rlm@83 2838 for (j = 1, jj = p[length]; j < jj; j++) {
rlm@83 2839 p[j] *= (j % 2) ? kx : ky;
rlm@83 2840 }
rlm@83 2841 }
rlm@83 2842 }
rlm@83 2843 var dim2 = pathDimensions(path);
rlm@83 2844 dx = ncx - dim2.x - dim2.width / 2;
rlm@83 2845 dy = ncy - dim2.y - dim2.height / 2;
rlm@83 2846 path[0][1] += dx;
rlm@83 2847 path[0][2] += dy;
rlm@83 2848 this.attr({path: path});
rlm@83 2849 break;
rlm@83 2850 }
rlm@83 2851 if (this.type in {text: 1, image:1} && (dirx != 1 || diry != 1)) {
rlm@83 2852 if (this.transformations) {
rlm@83 2853 this.transformations[2] = "scale("[concat](dirx, ",", diry, ")");
rlm@83 2854 this.node[setAttribute]("transform", this.transformations[join](S));
rlm@83 2855 dx = (dirx == -1) ? -a.x - (neww || 0) : a.x;
rlm@83 2856 dy = (diry == -1) ? -a.y - (newh || 0) : a.y;
rlm@83 2857 this.attr({x: dx, y: dy});
rlm@83 2858 a.fx = dirx - 1;
rlm@83 2859 a.fy = diry - 1;
rlm@83 2860 } else {
rlm@83 2861 this.node.filterMatrix = ms + ".Matrix(M11="[concat](dirx,
rlm@83 2862 ", M12=0, M21=0, M22=", diry,
rlm@83 2863 ", Dx=0, Dy=0, sizingmethod='auto expand', filtertype='bilinear')");
rlm@83 2864 s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E);
rlm@83 2865 }
rlm@83 2866 } else {
rlm@83 2867 if (this.transformations) {
rlm@83 2868 this.transformations[2] = E;
rlm@83 2869 this.node[setAttribute]("transform", this.transformations[join](S));
rlm@83 2870 a.fx = 0;
rlm@83 2871 a.fy = 0;
rlm@83 2872 } else {
rlm@83 2873 this.node.filterMatrix = E;
rlm@83 2874 s.filter = (this.node.filterMatrix || E) + (this.node.filterOpacity || E);
rlm@83 2875 }
rlm@83 2876 }
rlm@83 2877 a.scale = [x, y, cx, cy][join](S);
rlm@83 2878 this._.sx = x;
rlm@83 2879 this._.sy = y;
rlm@83 2880 }
rlm@83 2881 return this;
rlm@83 2882 };
rlm@83 2883 Element[proto].clone = function () {
rlm@83 2884 if (this.removed) {
rlm@83 2885 return null;
rlm@83 2886 }
rlm@83 2887 var attr = this.attr();
rlm@83 2888 delete attr.scale;
rlm@83 2889 delete attr.translation;
rlm@83 2890 return this.paper[this.type]().attr(attr);
rlm@83 2891 };
rlm@83 2892 var getPointAtSegmentLength = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) {
rlm@83 2893 var len = 0,
rlm@83 2894 old;
rlm@83 2895 for (var i = 0; i < 1.01; i+=.01) {
rlm@83 2896 var dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i);
rlm@83 2897 i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5));
rlm@83 2898 if (len >= length) {
rlm@83 2899 return dot;
rlm@83 2900 }
rlm@83 2901 old = dot;
rlm@83 2902 }
rlm@83 2903 }),
rlm@83 2904 getLengthFactory = function (istotal, subpath) {
rlm@83 2905 return function (path, length, onlystart) {
rlm@83 2906 path = path2curve(path);
rlm@83 2907 var x, y, p, l, sp = "", subpaths = {}, point,
rlm@83 2908 len = 0;
rlm@83 2909 for (var i = 0, ii = path.length; i < ii; i++) {
rlm@83 2910 p = path[i];
rlm@83 2911 if (p[0] == "M") {
rlm@83 2912 x = +p[1];
rlm@83 2913 y = +p[2];
rlm@83 2914 } else {
rlm@83 2915 l = segmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]);
rlm@83 2916 if (len + l > length) {
rlm@83 2917 if (subpath && !subpaths.start) {
rlm@83 2918 point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
rlm@83 2919 sp += ["C", point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y];
rlm@83 2920 if (onlystart) {return sp;}
rlm@83 2921 subpaths.start = sp;
rlm@83 2922 sp = ["M", point.x, point.y + "C", point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]][join]();
rlm@83 2923 len += l;
rlm@83 2924 x = +p[5];
rlm@83 2925 y = +p[6];
rlm@83 2926 continue;
rlm@83 2927 }
rlm@83 2928 if (!istotal && !subpath) {
rlm@83 2929 point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len);
rlm@83 2930 return {x: point.x, y: point.y, alpha: point.alpha};
rlm@83 2931 }
rlm@83 2932 }
rlm@83 2933 len += l;
rlm@83 2934 x = +p[5];
rlm@83 2935 y = +p[6];
rlm@83 2936 }
rlm@83 2937 sp += p;
rlm@83 2938 }
rlm@83 2939 subpaths.end = sp;
rlm@83 2940 point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[1], p[2], p[3], p[4], p[5], p[6], 1);
rlm@83 2941 point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha});
rlm@83 2942 return point;
rlm@83 2943 };
rlm@83 2944 },
rlm@83 2945 segmentLength = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) {
rlm@83 2946 var old = {x: 0, y: 0},
rlm@83 2947 len = 0;
rlm@83 2948 for (var i = 0; i < 1.01; i+=.01) {
rlm@83 2949 var dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i);
rlm@83 2950 i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5));
rlm@83 2951 old = dot;
rlm@83 2952 }
rlm@83 2953 return len;
rlm@83 2954 });
rlm@83 2955 var getTotalLength = getLengthFactory(1),
rlm@83 2956 getPointAtLength = getLengthFactory(),
rlm@83 2957 getSubpathsAtLength = getLengthFactory(0, 1);
rlm@83 2958 Element[proto].getTotalLength = function () {
rlm@83 2959 if (this.type != "path") {return;}
rlm@83 2960 if (this.node.getTotalLength) {
rlm@83 2961 return this.node.getTotalLength();
rlm@83 2962 }
rlm@83 2963 return getTotalLength(this.attrs.path);
rlm@83 2964 };
rlm@83 2965 Element[proto].getPointAtLength = function (length) {
rlm@83 2966 if (this.type != "path") {return;}
rlm@83 2967 if (this.node.getPointAtLength) {
rlm@83 2968 return this.node.getPointAtLength(length);
rlm@83 2969 }
rlm@83 2970 return getPointAtLength(this.attrs.path, length);
rlm@83 2971 };
rlm@83 2972 Element[proto].getSubpath = function (from, to) {
rlm@83 2973 if (this.type != "path") {return;}
rlm@83 2974 if (math.abs(this.getTotalLength() - to) < 1e-6) {
rlm@83 2975 return getSubpathsAtLength(this.attrs.path, from).end;
rlm@83 2976 }
rlm@83 2977 var a = getSubpathsAtLength(this.attrs.path, to, 1);
rlm@83 2978 return from ? getSubpathsAtLength(a, from).end : a;
rlm@83 2979 };
rlm@83 2980
rlm@83 2981 // animation easing formulas
rlm@83 2982 R.easing_formulas = {
rlm@83 2983 linear: function (n) {
rlm@83 2984 return n;
rlm@83 2985 },
rlm@83 2986 "<": function (n) {
rlm@83 2987 return pow(n, 3);
rlm@83 2988 },
rlm@83 2989 ">": function (n) {
rlm@83 2990 return pow(n - 1, 3) + 1;
rlm@83 2991 },
rlm@83 2992 "<>": function (n) {
rlm@83 2993 n = n * 2;
rlm@83 2994 if (n < 1) {
rlm@83 2995 return pow(n, 3) / 2;
rlm@83 2996 }
rlm@83 2997 n -= 2;
rlm@83 2998 return (pow(n, 3) + 2) / 2;
rlm@83 2999 },
rlm@83 3000 backIn: function (n) {
rlm@83 3001 var s = 1.70158;
rlm@83 3002 return n * n * ((s + 1) * n - s);
rlm@83 3003 },
rlm@83 3004 backOut: function (n) {
rlm@83 3005 n = n - 1;
rlm@83 3006 var s = 1.70158;
rlm@83 3007 return n * n * ((s + 1) * n + s) + 1;
rlm@83 3008 },
rlm@83 3009 elastic: function (n) {
rlm@83 3010 if (n == 0 || n == 1) {
rlm@83 3011 return n;
rlm@83 3012 }
rlm@83 3013 var p = .3,
rlm@83 3014 s = p / 4;
rlm@83 3015 return pow(2, -10 * n) * math.sin((n - s) * (2 * math.PI) / p) + 1;
rlm@83 3016 },
rlm@83 3017 bounce: function (n) {
rlm@83 3018 var s = 7.5625,
rlm@83 3019 p = 2.75,
rlm@83 3020 l;
rlm@83 3021 if (n < (1 / p)) {
rlm@83 3022 l = s * n * n;
rlm@83 3023 } else {
rlm@83 3024 if (n < (2 / p)) {
rlm@83 3025 n -= (1.5 / p);
rlm@83 3026 l = s * n * n + .75;
rlm@83 3027 } else {
rlm@83 3028 if (n < (2.5 / p)) {
rlm@83 3029 n -= (2.25 / p);
rlm@83 3030 l = s * n * n + .9375;
rlm@83 3031 } else {
rlm@83 3032 n -= (2.625 / p);
rlm@83 3033 l = s * n * n + .984375;
rlm@83 3034 }
rlm@83 3035 }
rlm@83 3036 }
rlm@83 3037 return l;
rlm@83 3038 }
rlm@83 3039 };
rlm@83 3040
rlm@83 3041 var animationElements = {length : 0},
rlm@83 3042 animation = function () {
rlm@83 3043 var Now = +new Date;
rlm@83 3044 for (var l in animationElements) if (l != "length" && animationElements[has](l)) {
rlm@83 3045 var e = animationElements[l];
rlm@83 3046 if (e.stop || e.el.removed) {
rlm@83 3047 delete animationElements[l];
rlm@83 3048 animationElements[length]--;
rlm@83 3049 continue;
rlm@83 3050 }
rlm@83 3051 var time = Now - e.start,
rlm@83 3052 ms = e.ms,
rlm@83 3053 easing = e.easing,
rlm@83 3054 from = e.from,
rlm@83 3055 diff = e.diff,
rlm@83 3056 to = e.to,
rlm@83 3057 t = e.t,
rlm@83 3058 prev = e.prev || 0,
rlm@83 3059 that = e.el,
rlm@83 3060 callback = e.callback,
rlm@83 3061 set = {},
rlm@83 3062 now;
rlm@83 3063 if (time < ms) {
rlm@83 3064 var pos = R.easing_formulas[easing] ? R.easing_formulas[easing](time / ms) : time / ms;
rlm@83 3065 for (var attr in from) if (from[has](attr)) {
rlm@83 3066 switch (availableAnimAttrs[attr]) {
rlm@83 3067 case "along":
rlm@83 3068 now = pos * ms * diff[attr];
rlm@83 3069 to.back && (now = to.len - now);
rlm@83 3070 var point = getPointAtLength(to[attr], now);
rlm@83 3071 that.translate(diff.sx - diff.x || 0, diff.sy - diff.y || 0);
rlm@83 3072 diff.x = point.x;
rlm@83 3073 diff.y = point.y;
rlm@83 3074 that.translate(point.x - diff.sx, point.y - diff.sy);
rlm@83 3075 to.rot && that.rotate(diff.r + point.alpha, point.x, point.y);
rlm@83 3076 break;
rlm@83 3077 case nu:
rlm@83 3078 now = +from[attr] + pos * ms * diff[attr];
rlm@83 3079 break;
rlm@83 3080 case "colour":
rlm@83 3081 now = "rgb(" + [
rlm@83 3082 upto255(round(from[attr].r + pos * ms * diff[attr].r)),
rlm@83 3083 upto255(round(from[attr].g + pos * ms * diff[attr].g)),
rlm@83 3084 upto255(round(from[attr].b + pos * ms * diff[attr].b))
rlm@83 3085 ][join](",") + ")";
rlm@83 3086 break;
rlm@83 3087 case "path":
rlm@83 3088 now = [];
rlm@83 3089 for (var i = 0, ii = from[attr][length]; i < ii; i++) {
rlm@83 3090 now[i] = [from[attr][i][0]];
rlm@83 3091 for (var j = 1, jj = from[attr][i][length]; j < jj; j++) {
rlm@83 3092 now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j];
rlm@83 3093 }
rlm@83 3094 now[i] = now[i][join](S);
rlm@83 3095 }
rlm@83 3096 now = now[join](S);
rlm@83 3097 break;
rlm@83 3098 case "csv":
rlm@83 3099 switch (attr) {
rlm@83 3100 case "translation":
rlm@83 3101 var x = diff[attr][0] * (time - prev),
rlm@83 3102 y = diff[attr][1] * (time - prev);
rlm@83 3103 t.x += x;
rlm@83 3104 t.y += y;
rlm@83 3105 now = x + S + y;
rlm@83 3106 break;
rlm@83 3107 case "rotation":
rlm@83 3108 now = +from[attr][0] + pos * ms * diff[attr][0];
rlm@83 3109 from[attr][1] && (now += "," + from[attr][1] + "," + from[attr][2]);
rlm@83 3110 break;
rlm@83 3111 case "scale":
rlm@83 3112 now = [+from[attr][0] + pos * ms * diff[attr][0], +from[attr][1] + pos * ms * diff[attr][1], (2 in to[attr] ? to[attr][2] : E), (3 in to[attr] ? to[attr][3] : E)][join](S);
rlm@83 3113 break;
rlm@83 3114 case "clip-rect":
rlm@83 3115 now = [];
rlm@83 3116 i = 4;
rlm@83 3117 while (i--) {
rlm@83 3118 now[i] = +from[attr][i] + pos * ms * diff[attr][i];
rlm@83 3119 }
rlm@83 3120 break;
rlm@83 3121 }
rlm@83 3122 break;
rlm@83 3123 }
rlm@83 3124 set[attr] = now;
rlm@83 3125 }
rlm@83 3126 that.attr(set);
rlm@83 3127 that._run && that._run.call(that);
rlm@83 3128 } else {
rlm@83 3129 if (to.along) {
rlm@83 3130 point = getPointAtLength(to.along, to.len * !to.back);
rlm@83 3131 that.translate(diff.sx - (diff.x || 0) + point.x - diff.sx, diff.sy - (diff.y || 0) + point.y - diff.sy);
rlm@83 3132 to.rot && that.rotate(diff.r + point.alpha, point.x, point.y);
rlm@83 3133 }
rlm@83 3134 (t.x || t.y) && that.translate(-t.x, -t.y);
rlm@83 3135 to.scale && (to.scale += E);
rlm@83 3136 that.attr(to);
rlm@83 3137 delete animationElements[l];
rlm@83 3138 animationElements[length]--;
rlm@83 3139 that.in_animation = null;
rlm@83 3140 R.is(callback, "function") && callback.call(that);
rlm@83 3141 }
rlm@83 3142 e.prev = time;
rlm@83 3143 }
rlm@83 3144 R.svg && that && that.paper && that.paper.safari();
rlm@83 3145 animationElements[length] && win.setTimeout(animation);
rlm@83 3146 },
rlm@83 3147 upto255 = function (color) {
rlm@83 3148 return mmax(mmin(color, 255), 0);
rlm@83 3149 },
rlm@83 3150 translate = function (x, y) {
rlm@83 3151 if (x == null) {
rlm@83 3152 return {x: this._.tx, y: this._.ty, toString: x_y};
rlm@83 3153 }
rlm@83 3154 this._.tx += +x;
rlm@83 3155 this._.ty += +y;
rlm@83 3156 switch (this.type) {
rlm@83 3157 case "circle":
rlm@83 3158 case "ellipse":
rlm@83 3159 this.attr({cx: +x + this.attrs.cx, cy: +y + this.attrs.cy});
rlm@83 3160 break;
rlm@83 3161 case "rect":
rlm@83 3162 case "image":
rlm@83 3163 case "text":
rlm@83 3164 this.attr({x: +x + this.attrs.x, y: +y + this.attrs.y});
rlm@83 3165 break;
rlm@83 3166 case "path":
rlm@83 3167 var path = pathToRelative(this.attrs.path);
rlm@83 3168 path[0][1] += +x;
rlm@83 3169 path[0][2] += +y;
rlm@83 3170 this.attr({path: path});
rlm@83 3171 break;
rlm@83 3172 }
rlm@83 3173 return this;
rlm@83 3174 };
rlm@83 3175 Element[proto].animateWith = function (element, params, ms, easing, callback) {
rlm@83 3176 animationElements[element.id] && (params.start = animationElements[element.id].start);
rlm@83 3177 return this.animate(params, ms, easing, callback);
rlm@83 3178 };
rlm@83 3179 Element[proto].animateAlong = along();
rlm@83 3180 Element[proto].animateAlongBack = along(1);
rlm@83 3181 function along(isBack) {
rlm@83 3182 return function (path, ms, rotate, callback) {
rlm@83 3183 var params = {back: isBack};
rlm@83 3184 R.is(rotate, "function") ? (callback = rotate) : (params.rot = rotate);
rlm@83 3185 path && path.constructor == Element && (path = path.attrs.path);
rlm@83 3186 path && (params.along = path);
rlm@83 3187 return this.animate(params, ms, callback);
rlm@83 3188 };
rlm@83 3189 }
rlm@83 3190 Element[proto].onAnimation = function (f) {
rlm@83 3191 this._run = f || 0;
rlm@83 3192 return this;
rlm@83 3193 };
rlm@83 3194 Element[proto].animate = function (params, ms, easing, callback) {
rlm@83 3195 if (R.is(easing, "function") || !easing) {
rlm@83 3196 callback = easing || null;
rlm@83 3197 }
rlm@83 3198 var from = {},
rlm@83 3199 to = {},
rlm@83 3200 diff = {};
rlm@83 3201 for (var attr in params) if (params[has](attr)) {
rlm@83 3202 if (availableAnimAttrs[has](attr)) {
rlm@83 3203 from[attr] = this.attr(attr);
rlm@83 3204 (from[attr] == null) && (from[attr] = availableAttrs[attr]);
rlm@83 3205 to[attr] = params[attr];
rlm@83 3206 switch (availableAnimAttrs[attr]) {
rlm@83 3207 case "along":
rlm@83 3208 var len = getTotalLength(params[attr]);
rlm@83 3209 var point = getPointAtLength(params[attr], len * !!params.back);
rlm@83 3210 var bb = this.getBBox();
rlm@83 3211 diff[attr] = len / ms;
rlm@83 3212 diff.tx = bb.x;
rlm@83 3213 diff.ty = bb.y;
rlm@83 3214 diff.sx = point.x;
rlm@83 3215 diff.sy = point.y;
rlm@83 3216 to.rot = params.rot;
rlm@83 3217 to.back = params.back;
rlm@83 3218 to.len = len;
rlm@83 3219 params.rot && (diff.r = toFloat(this.rotate()) || 0);
rlm@83 3220 break;
rlm@83 3221 case nu:
rlm@83 3222 diff[attr] = (to[attr] - from[attr]) / ms;
rlm@83 3223 break;
rlm@83 3224 case "colour":
rlm@83 3225 from[attr] = R.getRGB(from[attr]);
rlm@83 3226 var toColour = R.getRGB(to[attr]);
rlm@83 3227 diff[attr] = {
rlm@83 3228 r: (toColour.r - from[attr].r) / ms,
rlm@83 3229 g: (toColour.g - from[attr].g) / ms,
rlm@83 3230 b: (toColour.b - from[attr].b) / ms
rlm@83 3231 };
rlm@83 3232 break;
rlm@83 3233 case "path":
rlm@83 3234 var pathes = path2curve(from[attr], to[attr]);
rlm@83 3235 from[attr] = pathes[0];
rlm@83 3236 var toPath = pathes[1];
rlm@83 3237 diff[attr] = [];
rlm@83 3238 for (var i = 0, ii = from[attr][length]; i < ii; i++) {
rlm@83 3239 diff[attr][i] = [0];
rlm@83 3240 for (var j = 1, jj = from[attr][i][length]; j < jj; j++) {
rlm@83 3241 diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms;
rlm@83 3242 }
rlm@83 3243 }
rlm@83 3244 break;
rlm@83 3245 case "csv":
rlm@83 3246 var values = Str(params[attr])[split](separator),
rlm@83 3247 from2 = Str(from[attr])[split](separator);
rlm@83 3248 switch (attr) {
rlm@83 3249 case "translation":
rlm@83 3250 from[attr] = [0, 0];
rlm@83 3251 diff[attr] = [values[0] / ms, values[1] / ms];
rlm@83 3252 break;
rlm@83 3253 case "rotation":
rlm@83 3254 from[attr] = (from2[1] == values[1] && from2[2] == values[2]) ? from2 : [0, values[1], values[2]];
rlm@83 3255 diff[attr] = [(values[0] - from[attr][0]) / ms, 0, 0];
rlm@83 3256 break;
rlm@83 3257 case "scale":
rlm@83 3258 params[attr] = values;
rlm@83 3259 from[attr] = Str(from[attr])[split](separator);
rlm@83 3260 diff[attr] = [(values[0] - from[attr][0]) / ms, (values[1] - from[attr][1]) / ms, 0, 0];
rlm@83 3261 break;
rlm@83 3262 case "clip-rect":
rlm@83 3263 from[attr] = Str(from[attr])[split](separator);
rlm@83 3264 diff[attr] = [];
rlm@83 3265 i = 4;
rlm@83 3266 while (i--) {
rlm@83 3267 diff[attr][i] = (values[i] - from[attr][i]) / ms;
rlm@83 3268 }
rlm@83 3269 break;
rlm@83 3270 }
rlm@83 3271 to[attr] = values;
rlm@83 3272 }
rlm@83 3273 }
rlm@83 3274 }
rlm@83 3275 this.stop();
rlm@83 3276 this.in_animation = 1;
rlm@83 3277 animationElements[this.id] = {
rlm@83 3278 start: params.start || +new Date,
rlm@83 3279 ms: ms,
rlm@83 3280 easing: easing,
rlm@83 3281 from: from,
rlm@83 3282 diff: diff,
rlm@83 3283 to: to,
rlm@83 3284 el: this,
rlm@83 3285 callback: callback,
rlm@83 3286 t: {x: 0, y: 0}
rlm@83 3287 };
rlm@83 3288 ++animationElements[length] == 1 && animation();
rlm@83 3289 return this;
rlm@83 3290 };
rlm@83 3291 Element[proto].stop = function () {
rlm@83 3292 animationElements[this.id] && animationElements[length]--;
rlm@83 3293 delete animationElements[this.id];
rlm@83 3294 return this;
rlm@83 3295 };
rlm@83 3296 Element[proto].translate = function (x, y) {
rlm@83 3297 return this.attr({translation: x + " " + y});
rlm@83 3298 };
rlm@83 3299 Element[proto][toString] = function () {
rlm@83 3300 return "Rapha\xebl\u2019s object";
rlm@83 3301 };
rlm@83 3302 R.ae = animationElements;
rlm@83 3303
rlm@83 3304 // Set
rlm@83 3305 var Set = function (items) {
rlm@83 3306 this.items = [];
rlm@83 3307 this[length] = 0;
rlm@83 3308 this.type = "set";
rlm@83 3309 if (items) {
rlm@83 3310 for (var i = 0, ii = items[length]; i < ii; i++) {
rlm@83 3311 if (items[i] && (items[i].constructor == Element || items[i].constructor == Set)) {
rlm@83 3312 this[this.items[length]] = this.items[this.items[length]] = items[i];
rlm@83 3313 this[length]++;
rlm@83 3314 }
rlm@83 3315 }
rlm@83 3316 }
rlm@83 3317 };
rlm@83 3318 Set[proto][push] = function () {
rlm@83 3319 var item,
rlm@83 3320 len;
rlm@83 3321 for (var i = 0, ii = arguments[length]; i < ii; i++) {
rlm@83 3322 item = arguments[i];
rlm@83 3323 if (item && (item.constructor == Element || item.constructor == Set)) {
rlm@83 3324 len = this.items[length];
rlm@83 3325 this[len] = this.items[len] = item;
rlm@83 3326 this[length]++;
rlm@83 3327 }
rlm@83 3328 }
rlm@83 3329 return this;
rlm@83 3330 };
rlm@83 3331 Set[proto].pop = function () {
rlm@83 3332 delete this[this[length]--];
rlm@83 3333 return this.items.pop();
rlm@83 3334 };
rlm@83 3335 for (var method in Element[proto]) if (Element[proto][has](method)) {
rlm@83 3336 Set[proto][method] = (function (methodname) {
rlm@83 3337 return function () {
rlm@83 3338 for (var i = 0, ii = this.items[length]; i < ii; i++) {
rlm@83 3339 this.items[i][methodname][apply](this.items[i], arguments);
rlm@83 3340 }
rlm@83 3341 return this;
rlm@83 3342 };
rlm@83 3343 })(method);
rlm@83 3344 }
rlm@83 3345 Set[proto].attr = function (name, value) {
rlm@83 3346 if (name && R.is(name, array) && R.is(name[0], "object")) {
rlm@83 3347 for (var j = 0, jj = name[length]; j < jj; j++) {
rlm@83 3348 this.items[j].attr(name[j]);
rlm@83 3349 }
rlm@83 3350 } else {
rlm@83 3351 for (var i = 0, ii = this.items[length]; i < ii; i++) {
rlm@83 3352 this.items[i].attr(name, value);
rlm@83 3353 }
rlm@83 3354 }
rlm@83 3355 return this;
rlm@83 3356 };
rlm@83 3357 Set[proto].animate = function (params, ms, easing, callback) {
rlm@83 3358 (R.is(easing, "function") || !easing) && (callback = easing || null);
rlm@83 3359 var len = this.items[length],
rlm@83 3360 i = len,
rlm@83 3361 item,
rlm@83 3362 set = this,
rlm@83 3363 collector;
rlm@83 3364 callback && (collector = function () {
rlm@83 3365 !--len && callback.call(set);
rlm@83 3366 });
rlm@83 3367 easing = R.is(easing, string) ? easing : collector;
rlm@83 3368 item = this.items[--i].animate(params, ms, easing, collector);
rlm@83 3369 while (i--) {
rlm@83 3370 this.items[i].animateWith(item, params, ms, easing, collector);
rlm@83 3371 }
rlm@83 3372 return this;
rlm@83 3373 };
rlm@83 3374 Set[proto].insertAfter = function (el) {
rlm@83 3375 var i = this.items[length];
rlm@83 3376 while (i--) {
rlm@83 3377 this.items[i].insertAfter(el);
rlm@83 3378 }
rlm@83 3379 return this;
rlm@83 3380 };
rlm@83 3381 Set[proto].getBBox = function () {
rlm@83 3382 var x = [],
rlm@83 3383 y = [],
rlm@83 3384 w = [],
rlm@83 3385 h = [];
rlm@83 3386 for (var i = this.items[length]; i--;) {
rlm@83 3387 var box = this.items[i].getBBox();
rlm@83 3388 x[push](box.x);
rlm@83 3389 y[push](box.y);
rlm@83 3390 w[push](box.x + box.width);
rlm@83 3391 h[push](box.y + box.height);
rlm@83 3392 }
rlm@83 3393 x = mmin[apply](0, x);
rlm@83 3394 y = mmin[apply](0, y);
rlm@83 3395 return {
rlm@83 3396 x: x,
rlm@83 3397 y: y,
rlm@83 3398 width: mmax[apply](0, w) - x,
rlm@83 3399 height: mmax[apply](0, h) - y
rlm@83 3400 };
rlm@83 3401 };
rlm@83 3402 Set[proto].clone = function (s) {
rlm@83 3403 s = new Set;
rlm@83 3404 for (var i = 0, ii = this.items[length]; i < ii; i++) {
rlm@83 3405 s[push](this.items[i].clone());
rlm@83 3406 }
rlm@83 3407 return s;
rlm@83 3408 };
rlm@83 3409
rlm@83 3410 R.registerFont = function (font) {
rlm@83 3411 if (!font.face) {
rlm@83 3412 return font;
rlm@83 3413 }
rlm@83 3414 this.fonts = this.fonts || {};
rlm@83 3415 var fontcopy = {
rlm@83 3416 w: font.w,
rlm@83 3417 face: {},
rlm@83 3418 glyphs: {}
rlm@83 3419 },
rlm@83 3420 family = font.face["font-family"];
rlm@83 3421 for (var prop in font.face) if (font.face[has](prop)) {
rlm@83 3422 fontcopy.face[prop] = font.face[prop];
rlm@83 3423 }
rlm@83 3424 if (this.fonts[family]) {
rlm@83 3425 this.fonts[family][push](fontcopy);
rlm@83 3426 } else {
rlm@83 3427 this.fonts[family] = [fontcopy];
rlm@83 3428 }
rlm@83 3429 if (!font.svg) {
rlm@83 3430 fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10);
rlm@83 3431 for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) {
rlm@83 3432 var path = font.glyphs[glyph];
rlm@83 3433 fontcopy.glyphs[glyph] = {
rlm@83 3434 w: path.w,
rlm@83 3435 k: {},
rlm@83 3436 d: path.d && "M" + path.d[rp](/[mlcxtrv]/g, function (command) {
rlm@83 3437 return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M";
rlm@83 3438 }) + "z"
rlm@83 3439 };
rlm@83 3440 if (path.k) {
rlm@83 3441 for (var k in path.k) if (path[has](k)) {
rlm@83 3442 fontcopy.glyphs[glyph].k[k] = path.k[k];
rlm@83 3443 }
rlm@83 3444 }
rlm@83 3445 }
rlm@83 3446 }
rlm@83 3447 return font;
rlm@83 3448 };
rlm@83 3449 Paper[proto].getFont = function (family, weight, style, stretch) {
rlm@83 3450 stretch = stretch || "normal";
rlm@83 3451 style = style || "normal";
rlm@83 3452 weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400;
rlm@83 3453 if (!R.fonts) {
rlm@83 3454 return;
rlm@83 3455 }
rlm@83 3456 var font = R.fonts[family];
rlm@83 3457 if (!font) {
rlm@83 3458 var name = new RegExp("(^|\\s)" + family[rp](/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i");
rlm@83 3459 for (var fontName in R.fonts) if (R.fonts[has](fontName)) {
rlm@83 3460 if (name.test(fontName)) {
rlm@83 3461 font = R.fonts[fontName];
rlm@83 3462 break;
rlm@83 3463 }
rlm@83 3464 }
rlm@83 3465 }
rlm@83 3466 var thefont;
rlm@83 3467 if (font) {
rlm@83 3468 for (var i = 0, ii = font[length]; i < ii; i++) {
rlm@83 3469 thefont = font[i];
rlm@83 3470 if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) {
rlm@83 3471 break;
rlm@83 3472 }
rlm@83 3473 }
rlm@83 3474 }
rlm@83 3475 return thefont;
rlm@83 3476 };
rlm@83 3477 Paper[proto].print = function (x, y, string, font, size, origin) {
rlm@83 3478 origin = origin || "middle"; // baseline|middle
rlm@83 3479 var out = this.set(),
rlm@83 3480 letters = Str(string)[split](E),
rlm@83 3481 shift = 0,
rlm@83 3482 path = E,
rlm@83 3483 scale;
rlm@83 3484 R.is(font, string) && (font = this.getFont(font));
rlm@83 3485 if (font) {
rlm@83 3486 scale = (size || 16) / font.face["units-per-em"];
rlm@83 3487 var bb = font.face.bbox.split(separator),
rlm@83 3488 top = +bb[0],
rlm@83 3489 height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2);
rlm@83 3490 for (var i = 0, ii = letters[length]; i < ii; i++) {
rlm@83 3491 var prev = i && font.glyphs[letters[i - 1]] || {},
rlm@83 3492 curr = font.glyphs[letters[i]];
rlm@83 3493 shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) : 0;
rlm@83 3494 curr && curr.d && out[push](this.path(curr.d).attr({fill: "#000", stroke: "none", translation: [shift, 0]}));
rlm@83 3495 }
rlm@83 3496 out.scale(scale, scale, top, height).translate(x - top, y - height);
rlm@83 3497 }
rlm@83 3498 return out;
rlm@83 3499 };
rlm@83 3500
rlm@83 3501 var formatrg = /\{(\d+)\}/g;
rlm@83 3502 R.format = function (token, params) {
rlm@83 3503 var args = R.is(params, array) ? [0][concat](params) : arguments;
rlm@83 3504 token && R.is(token, string) && args[length] - 1 && (token = token[rp](formatrg, function (str, i) {
rlm@83 3505 return args[++i] == null ? E : args[i];
rlm@83 3506 }));
rlm@83 3507 return token || E;
rlm@83 3508 };
rlm@83 3509 R.ninja = function () {
rlm@83 3510 oldRaphael.was ? (Raphael = oldRaphael.is) : delete Raphael;
rlm@83 3511 return R;
rlm@83 3512 };
rlm@83 3513 R.el = Element[proto];
rlm@83 3514 return R;
rlm@83 3515 })();