2 * Raphael 0.5.4b - JavaScript Vector Library
4 * Copyright (c) 2008 Dmitry Baranovskiy (raphaeljs.com)
5 * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
7 var Raphael = (function (type) {
9 return r._create.apply(r, arguments);
14 function Matrix(m11, m12, m21, m22, dx, dy) {
16 [m11 || 1, m12 || 0, 0],
17 [m21 || 0, m22 || 1, 0],
18 [dx || 0, dy || 0, 1],
22 C._getX = C._getY = C._getW = C._getH = function (x) { return x; };
25 Matrix.prototype.toString = function () {
26 return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.m[0][0] +
27 ", M12=" + this.m[1][0] + ", M21=" + this.m[0][1] + ", M22=" + this.m[1][1] +
28 ", Dx=" + this.m[2][0] + ", Dy=" + this.m[2][1] + ", sizingmethod='auto expand', filtertype='bilinear')";
30 var thePath = function (params, pathString, VML) {
31 var g = document.createElement("rvml:group"), gl = g.style;
32 gl.position = "absolute";
35 gl.width = VML.width + "px";
36 gl.height = VML.height + "px";
37 var el = document.createElement("rvml:shape"), ol = el.style;
38 ol.width = VML.width + "px";
39 ol.height = VML.height + "px";
41 if (params["class"]) {
42 el.className = params["class"];
44 el.coordsize = this.coordsize;
45 el.coordorigin = this.coordorigin;
47 VML.canvas.appendChild(g);
48 var p = new Element(el, g, VML);
49 setFillAndStroke(p, params);
50 if (params.gradient) {
51 addGrdientFill(p, params.gradient);
56 p.last = {x: 0, y: 0, bx: 0, by: 0, isAbsolute: true};
58 p.absolutely = function () {
59 this.isAbsolute = true;
62 p.relatively = function () {
63 this.isAbsolute = false;
66 p.redraw = function () {
68 var oldPath = this.path;
70 for (var i = 0, ii = oldPath.length; i < ii; i++) {
71 if (oldPath[i].type != "end") {
72 this[oldPath[i].type + "To"].apply(this, oldPath[i].arg);
78 p.moveTo = function (x, y) {
79 var d = this.isAbsolute?"m":"t";
80 var _getX = this.isAbsolute ? VML._getX : VML._getW;
81 var _getY = this.isAbsolute ? VML._getY : VML._getH;
82 d += Math.round(_getX(parseFloat(x, 10))) + " " + Math.round(_getY(parseFloat(y, 10)));
83 this[0].path = this.Path += d;
84 this.last.x = Math.round(_getX(parseFloat(x, 10)));
85 this.last.y = Math.round(_getY(parseFloat(y, 10)));
86 this.last.isAbsolute = this.isAbsolute;
87 this.path.push({type: "move", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
90 p.lineTo = function (x, y) {
91 var d = this.isAbsolute?"l":"r";
92 var _getX = this.isAbsolute ? VML._getX : VML._getW;
93 var _getY = this.isAbsolute ? VML._getY : VML._getH;
94 d += Math.round(_getX(parseFloat(x, 10))) + " " + Math.round(_getY(parseFloat(y, 10)));
95 this[0].path = this.Path += d;
96 this.last.x = Math.round(_getX(parseFloat(x, 10)));
97 this.last.y = Math.round(_getY(parseFloat(y, 10)));
98 this.last.isAbsolute = this.isAbsolute;
99 this.path.push({type: "line", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
102 p.cplineTo = function (x1, y1, w1) {
104 return this.lineTo(x1, y1);
107 p._getX = this.isAbsolute ? VML._getX : VML._getW;
108 p._getY = this.isAbsolute ? VML._getY : VML._getH;
109 var x = Math.round(p._getX(Math.round(parseFloat(x1, 10) * 100) / 100));
110 var y = Math.round(p._getY(Math.round(parseFloat(y1, 10) * 100) / 100));
111 var w = Math.round(VML._getW(Math.round(parseFloat(w1, 10) * 100) / 100));
112 var d = this.isAbsolute?"c":"v";
113 var attr = [this.last.x + w, this.last.y, x - w, y, x, y];
114 d += attr.join(" ") + " ";
115 this.last.x = attr[4];
116 this.last.y = attr[5];
117 this.last.bx = attr[2];
118 this.last.by = attr[3];
119 this[0].path = this.Path += d;
120 this.path.push({type: "cpline", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
124 p.curveTo = function () {
125 var d = this.isAbsolute?"c":"v";
126 var _getX = this.isAbsolute ? VML._getX : VML._getW;
127 var _getY = this.isAbsolute ? VML._getY : VML._getH;
128 if (arguments.length == 6) {
129 this.last.x = Math.round(_getX(parseFloat(arguments[4], 10)));
130 this.last.y = Math.round(_getY(parseFloat(arguments[5], 10)));
131 this.last.bx = Math.round(_getX(parseFloat(arguments[2], 10)));
132 this.last.by = Math.round(_getY(parseFloat(arguments[3], 10)));
133 d += Math.round(_getX(parseFloat(arguments[0], 10))) + " " + Math.round(_getY(parseFloat(arguments[1], 10))) + " " +
134 Math.round(_getX(parseFloat(arguments[2], 10))) + " " + Math.round(_getY(parseFloat(arguments[3], 10))) + " " +
135 Math.round(_getX(parseFloat(arguments[4], 10))) + " " + Math.round(_getY(parseFloat(arguments[5], 10))) + " ";
136 this.last.isAbsolute = this.isAbsolute;
138 this[0].path = this.Path += d;
139 this.path.push({type: "curve", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
142 p.addRoundedCorner = function (r, dir) {
143 var R = .5522 * r, rollback = this.isAbsolute, o = this;
146 rollback = function () {
150 rollback = function () {};
156 o.curveTo(-R, 0, -r, -(r - R), -r, -r);
159 o.curveTo(-R, 0, -r, r - R, -r, r);
166 o.curveTo(R, 0, r, -(r - R), r, -r);
169 o.curveTo(R, 0, r, r - R, r, r);
176 o.curveTo(0, -R, -(R - r), -r, r, -r);
179 o.curveTo(0, -R, R - r, -r, -r, -r);
186 o.curveTo(0, R, -(R - r), r, r, r);
189 o.curveTo(0, R, R - r, r, -r, r);
194 actions[dir.charAt(0)]()[dir.charAt(1)]();
198 p.andClose = function () {
199 this[0].path = (this.Path += "x e");
202 if (typeof pathString == "string") {
203 pathString = pathString.replace(/([mzlhvcsqta])/ig, ",$1,").replace(/([^,])\-/ig, "$1,-");
204 path = pathString.split(",");
205 var i = 1, ii = path.length;
209 p.absolutely().moveTo(path[++i], path[++i]);
212 p.relatively().moveTo(path[++i], path[++i]);
215 p.absolutely().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
218 p.relatively().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
221 p.absolutely().lineTo(path[++i], path[++i]);
224 p.relatively().lineTo(path[++i], path[++i]);
227 p.absolutely().lineTo(path[++i], 0);
230 p.relatively().lineTo(path[++i], 0);
233 p.absolutely().lineTo(0, path[++i]);
236 p.relatively().lineTo(0, path[++i]);
248 var setFillAndStroke = function (o, params) {
249 o[0].attrs = o[0].attrs || {};
250 for (var par in params) {
251 o[0].attrs[par] = params[par];
253 params["font-family"] && (o[0].style.fontFamily = params["font-family"]);
254 params["font-size"] && (o[0].style.fontSize = params["font-size"]);
255 params["font"] && (o[0].style.font = params["font"]);
256 params["font-weight"] && (o[0].style.fontWeight = params["font-weight"]);
257 if (typeof params.opacity != "undefined" || typeof params["stroke-width"] != "undefined" || typeof params.fill != "undefined" || typeof params.stroke != "undefined") {
259 var fill = (o.getElementsByTagName("fill") && o.getElementsByTagName("fill")[0]) || document.createElement("rvml:fill");
260 if ("fill-opacity" in params || "opacity" in params) {
261 fill.opacity = ((params["fill-opacity"] + 1 || 2) - 1) * ((params.opacity + 1 || 2) - 1);
263 params.fill && (fill.on = true);
264 if (fill.on && params.fill) {
265 fill.color = params.fill;
267 if (params.fill == "none") {
271 var stroke = (o.getElementsByTagName("stroke") && o.getElementsByTagName("stroke")[0]) || document.createElement("rvml:stroke");
272 if ((params.stroke && params.stroke != "none") || params["stroke-width"] || params["stroke-opacity"] || params["stroke-dasharray"]) {
275 if (params.stroke == "none" || typeof stroke.on == "undefined") {
279 if (stroke.on && params.stroke) {
280 stroke.color = params.stroke;
282 stroke.opacity = ((params["stroke-opacity"] + 1 || 2) - 1) * ((params.opacity + 1 || 2) - 1);
283 stroke.joinstyle = params["stroke-linejoin"] || "miter";
284 stroke.miterlimit = params["stroke-miterlimit"] || 8;
285 stroke.endcap = {butt: "flat", square: "square", round: "round"}[params["stroke-linecap"] || "miter"];
286 stroke.weight = (parseFloat(params["stroke-width"], 10) || 1) + "px";
287 if (params["stroke-dasharray"]) {
288 var dashes = params["stroke-dasharray"].replace(" ", ",").split(","),
290 str = parseFloat(stroke.weight, 10);
291 for (var i = 0, ii = dashes.length; i < ii; i++) {
292 var res = dashes[i] / str;
297 stroke.dashstyle = dashesn.join(" ");
299 o.appendChild(stroke);
302 var addGrdientFill = function (o, gradient) {
303 o[0].attrs = o[0].attrs || {};
304 o[0].attrs.gradient = gradient;
306 var fill = o.getElementsByTagName("fill");
310 fill = document.createElement("rvml:fill");
312 if (gradient.dots.length) {
314 fill.type = (gradient.type.toLowerCase() == "linear") ? "gradient" : "gradientradial";
315 if (typeof gradient.dots[0].color != "undefined") {
316 fill.color = gradient.dots[0].color || "#000";
318 if (typeof gradient.dots[0].opacity != "undefined") {
319 fill.opacity = gradient.dots[0].opacity;
321 if (typeof gradient.dots[gradient.dots.length - 1].opacity != "undefined") {
322 fill.opacity2 = gradient.dots[gradient.dots.length - 1].opacity;
324 if (typeof gradient.dots[gradient.dots.length - 1].color != "undefined") {
325 fill.color2 = gradient.dots[gradient.dots.length - 1].color || "#000";
328 for (var i = 1, ii = gradient.dots.length - 1; i < ii; i++) {
329 colors += gradient.dots[i].offset + " " + gradient.dots[i].color;
335 fill.colors = colors;
337 if (gradient.vector) {
338 var angle = Math.round(Math.atan((parseInt(gradient.vector[3], 10) - parseInt(gradient.vector[1], 10)) / (parseInt(gradient.vector[2], 10) - parseInt(gradient.vector[0], 10))) * 57.29) + 180;
339 fill.angle = angle + 90;
341 if (gradient.type.toLowerCase() == "radial") {
342 fill.focusposition = "0.5, 0.5";
343 fill.focussize = "0, 0";
344 fill.method = "none";
348 var Element = function (node, group, vml) {
356 arguments.callee.name = "Element";
359 this.setBox = function (params) {
360 var gs = this.Group.style,
362 for (var i in params) {
363 this[0].attrs[i] = params[i];
365 var attr = this[0].attrs, x, y, w, h;
368 x = attr.cx - attr.r;
369 y = attr.cy - attr.r;
373 x = attr.cx - attr.rx;
374 y = attr.cy - attr.ry;
386 this.textpath.v = ["m", Math.round(attr.x), ", ", Math.round(attr.y - 2), "l", Math.round(attr.x) + 1, ", ", Math.round(attr.y - 2)].join("");
392 var left = vml.width / 2 - w / 2,
393 top = vml.height / 2 - h / 2;
394 gs.position = "absolute";
395 gs.left = x - left + "px";
396 gs.top = y - top + "px";
401 gs.width = vml.width + "px";
402 gs.height = vml.height + "px";
403 os.position = "absolute";
405 os.left = left + "px";
407 os.height = h + "px";
409 this.hide = function () {
410 this.Group.style.display = "none";
413 this.show = function () {
414 this.Group.style.display = "block";
417 this.rotate = function (deg) {
419 this.Group.style.rotation = Rotation;
422 this.translate = function (x, y) {
425 this.Group.style.left = this.X + "px";
426 this.Group.style.top = this.Y + "px";
430 this.matrix = function (xx, xy, yx, yy, dx, dy) {
431 tMatrix = new Matrix(xx, xy, yx, yy, dx, dy);
432 this.Group.style.filter = tMatrix;
435 this.scale = function (x, y) {
437 if (x != 0 && !(x == 1 && y == 1)) {
438 var dirx = Math.round(x / Math.abs(x)),
439 diry = Math.round(y / Math.abs(y));
440 if (dirx != 1 || diry != 1) {
441 this[0].style.filter = new Matrix(dirx, 0, 0, diry, 0, 0);
443 var width = parseInt(this[0].style.width, 10) * x * dirx;
444 var height = parseInt(this[0].style.height, 10) * y * diry;
445 var left = parseInt(this[0].style.left, 10);
446 var top = parseInt(this[0].style.top, 10);
447 this[0].style.left = this.X = left + this.W / 2 - width / 2;
448 this[0].style.top = this.Y = top + this.H / 2 - height / 2;
449 this[0].style.width = this.W = width;
450 this[0].style.height = this.H = height;
454 this.getBBox = function () {
456 x: this.Group.offsetLeft,
457 y: this.Group.offsetTop,
458 width: this.Group.offsetWidth,
459 height: this.Group.offsetHeight
462 this.remove = function () {
463 this[0].parentNode.removeChild(this[0]);
464 this.Group.parentNode.removeChild(this.Group);
465 this.shape && this.shape.parentNode.removeChild(this.shape);
467 this.attr = function () {
468 if (arguments.length == 1 && typeof arguments[0] == "string") {
469 return this[0].attrs[arguments[0]];
471 if (this[0].attrs && arguments.length == 1 && arguments[0] instanceof Array) {
473 for (var i = 0, ii = arguments[0].length; i < ii; i++) {
474 values[arguments[0][i]] = this[0].attrs[arguments[0][i]];
478 if (this[0].tagName.toLowerCase() == "group") {
479 var children = this[0].childNodes;
480 this[0].attrs = this[0].attrs || {};
481 if (arguments.length == 2) {
482 this[0].attrs[arguments[0]] = arguments[1];
483 } else if (arguments.length = 1 || typeof arguments[0] == "object") {
484 for (var j in arguments[0]) {
485 this[0].attrs[j] = arguments[0][j];
488 for (var i = 0, ii = children.length; i < ii; i++) {
489 this.attr.apply(new item(children[i], this[0], vml), arguments);
493 if (arguments.length == 2) {
495 params[arguments[0]] = arguments[1];
497 if (arguments.length == 1 && typeof arguments[0] == "object") {
498 params = arguments[0];
501 setFillAndStroke(this, params);
503 if (params.gradient) {
504 addGrdientFill(this, params.gradient);
506 if (params.text && this.type == "text") {
507 this[0].string = params.text;
510 this[0].id = params.id;
516 this.toFront = function () {
517 this.Group.parentNode.appendChild(this.Group);
520 this.toBack = function () {
521 if (this.Group.parentNode.firstChild != this.Group) {
522 this.Group.parentNode.insertBefore(this.Group, this.Group.parentNode.firstChild);
527 var theCircle = function (vml, x, y, r) {
528 var g = document.createElement("rvml:group");
529 var o = document.createElement("rvml:oval");
531 vml.canvas.appendChild(g);
532 var res = new Element(o, g, vml);
533 setFillAndStroke(res, {stroke: "#000", fill: "none"});
534 res.setBox({x: x - r, y: y - r, w: r * 2, h: r * 2});
541 var theRect = function (vml, x, y, w, h, r) {
542 var g = document.createElement("rvml:group");
543 var o = document.createElement(r ? "rvml:roundrect" : "rvml:rect");
545 o.arcsize = r / (Math.min(w, h));
548 vml.canvas.appendChild(g);
549 var res = new Element(o, g, vml);
550 setFillAndStroke(res, {stroke: "#000"});
551 res.setBox({x: x, y: y, w: w, h: h});
560 var theEllipse = function (vml, x, y, rx, ry) {
561 var g = document.createElement("rvml:group");
562 var o = document.createElement("rvml:oval");
564 vml.canvas.appendChild(g);
565 var res = new Element(o, g, vml);
566 setFillAndStroke(res, {stroke: "#000"});
567 res.setBox({x: x - rx, y: y - ry, w: rx * 2, h: ry * 2});
572 res.type = "ellipse";
575 var theImage = function (vml, src, x, y, w, h) {
576 var g = document.createElement("rvml:group");
577 var o = document.createElement("rvml:image");
580 vml.canvas.appendChild(g);
581 var res = new Element(o, g, vml);
582 res.setBox({x: x, y: y, w: w, h: h});
590 var theText = function (vml, x, y, text) {
592 var g = document.createElement("rvml:group"), gs = g.style;
593 var el = document.createElement("rvml:shape"), ol = el.style;
594 var path = document.createElement("rvml:path"), ps = path.style;
595 path.v = ["m", Math.round(x), ", ", Math.round(y - 2), "l", Math.round(x) + 1, ", ", Math.round(y - 2)].join("");
596 path.textpathok = true;
597 ol.width = vml.width;
598 ol.height = vml.height;
599 gs.position = "absolute";
602 gs.width = vml.width;
603 gs.height = vml.height;
604 var o = document.createElement("rvml:textpath");
607 o.coordsize = vml.coordsize;
608 o.coordorigin = vml.coordorigin;
610 el.appendChild(path);
612 vml.canvas.appendChild(g);
613 var res = new Element(o, g, vml);
623 var theGroup = function (vml) {
624 var el = document.createElement("rvml:group"), els = el.style;
625 els.position = "absolute";
628 els.width = vml.width;
629 els.height = vml.height;
631 vml.canvas.appendChild(el);
633 var res = new Element(el, el, vml);
635 if (f.charAt(0) != "_" && typeof vml[f] == "function") {
636 res[f] = (function (f) {
638 var e = vml[f].apply(vml, arguments);
639 el.appendChild(e[0].parentNode);
648 r._create = function () {
649 // container, width, height
650 // x, y, width, height
651 if (typeof arguments[0] == "string") {
652 var container = document.getElementById(arguments[0]);
653 var width = arguments[1];
654 var height = arguments[2];
656 if (typeof arguments[0] == "object") {
657 var container = arguments[0];
658 var width = arguments[1];
659 var height = arguments[2];
661 if (typeof arguments[0] == "number") {
665 width = arguments[2],
666 height = arguments[3];
669 throw new Error("VML container not found.");
671 if (!document.namespaces["rvml"]) {
672 document.namespaces.add("rvml","urn:schemas-microsoft-com:vml");
673 document.createStyleSheet().addRule("rvml\\:*", "behavior:url(#default#VML)");
675 var c = document.createElement("div"),
676 r = C.canvas = document.createElement("rvml:group"),
677 cs = c.style, rs = r.style;
680 width = width || "320px";
681 height = height || "200px";
682 cs.clip = "rect(0 " + width + " " + height + " 0)";
683 cs.position = "absolute";
686 r.coordsize = (width == "100%" ? width : parseFloat(width)) + " " + (height == "100%" ? height : parseFloat(height));
687 r.coordorigin = "0 0";
689 var b = document.createElement("rvml:rect"), bs = b.style;
690 bs.left = bs.top = 0;
692 bs.height = rs.height;
693 b.filled = b.stroked = "f";
697 if (container == 1) {
698 document.body.appendChild(c);
699 cs.position = "absolute";
711 cs.width = container.style.width = width;
712 cs.height = container.style.height = height;
713 if (container.firstChild) {
714 container.insertBefore(c, container.firstChild);
716 container.appendChild(c);
719 for (var prop in C) {
720 container[prop] = C[prop];
722 container.clear = function () {
724 for (var i = 0, ii = r.childNodes.length; i < ii; i++) {
725 if (r.childNodes[i] != b) {
726 todel.push(r.childNodes[i]);
729 for (i = 0, ii = todel.length; i < ii; i++) {
730 r.removeChild(todel[i]);
737 Matrix.prototype.toString = function () {
738 return "matrix(" + this.m[0][0] +
739 ", " + this.m[1][0] + ", " + this.m[0][1] + ", " + this.m[1][1] +
740 ", " + this.m[2][0] + ", " + this.m[2][1] + ")";
742 var thePath = function (params, pathString, SVG) {
743 var el = document.createElementNS(SVG.svgns, "path");
744 el.setAttribute("fill", "none");
746 for (var attr in params) {
747 if (params.gradient) {
748 addGrdientFill(el, params.gradient, SVG);
750 el.setAttribute(attr, params[attr]);
755 SVG.canvas.appendChild(el);
757 var p = new Element(el, SVG);
758 for (var attr in params) {
759 p.attrs[attr] = params[attr];
763 p.last = {x: 0, y: 0, bx: 0, by: 0};
764 p.absolutely = function () {
765 this.isAbsolute = true;
768 p.relatively = function () {
769 this.isAbsolute = false;
772 p.redraw = function () {
773 this[0].setAttribute("d", "M0 0");
774 var oldPath = this.path;
776 for (var i = 0, ii = oldPath.length; i < ii; i++) {
777 if (oldPath[i].type != "end") {
778 this[oldPath[i].type + "To"].apply(this, oldPath[i].arg);
784 p.moveTo = function (x, y) {
785 var d = this.isAbsolute?"M":"m";
786 var _getX = this.isAbsolute ? SVG._getX : SVG._getW;
787 var _getY = this.isAbsolute ? SVG._getY : SVG._getH;
788 d += _getX(parseFloat(x, 10)) + " " + _getY(parseFloat(y, 10)) + " ";
789 var oldD = this[0].getAttribute("d") || "";
790 this[0].setAttribute("d", oldD + d);
791 this.last.x = SVG._getX(parseFloat(x, 10));
792 this.last.y = SVG._getY(parseFloat(y, 10));
793 this.path.push({type: "move", arg: arguments, pos: this.isAbsolute});
796 p.lineTo = function (x, y) {
797 var d = this.isAbsolute?"L":"l";
798 var _getX = this.isAbsolute ? SVG._getX : SVG._getW;
799 var _getY = this.isAbsolute ? SVG._getY : SVG._getH;
800 d += _getX(parseFloat(x, 10)) + " " + _getY(parseFloat(y, 10)) + " ";
801 var oldD = this[0].getAttribute("d") || "";
802 this[0].setAttribute("d", oldD + d);
803 this.last.x = SVG._getX(parseFloat(x, 10));
804 this.last.y = SVG._getY(parseFloat(y, 10));
805 this.path.push({type: "line", arg: arguments, pos: this.isAbsolute});
808 p.cplineTo = function (x1, y1, w1) {
810 return this.lineTo(x1, y1);
813 p._getX = this.isAbsolute ? SVG._getX : SVG._getW;
814 p._getY = this.isAbsolute ? SVG._getY : SVG._getH;
815 var x = p._getX(Math.round(parseFloat(x1, 10) * 100) / 100);
816 var y = p._getY(Math.round(parseFloat(y1, 10) * 100) / 100);
817 var w = SVG._getW(Math.round(parseFloat(w1, 10) * 100) / 100);
818 var d = this.isAbsolute?"C":"c";
819 var attr = [this.last.x + w, this.last.y, x - w, y, x, y];
820 for (var i = 0, ii = attr.length; i < ii; i++) {
823 this.last.x = attr[4];
824 this.last.y = attr[5];
825 this.last.bx = attr[2];
826 this.last.by = attr[3];
827 var oldD = this[0].getAttribute("d") || "";
828 this[0].setAttribute("d", oldD + d);
829 this.path.push({type: "cpline", arg: arguments, pos: this.isAbsolute});
833 p.curveTo = function () {
835 p._getX = this.isAbsolute ? SVG._getX : SVG._getW;
836 p._getY = this.isAbsolute ? SVG._getY : SVG._getH;
837 if (arguments.length == 6) {
838 var d = this.isAbsolute?"C":"c";
839 for (var i = 0, ii = arguments.length; i < ii; i++) {
840 d += p[(i % 2 == 0) ? "_getX" : "_getY"](Math.round(parseFloat(arguments[i], 10) * 100) / 100) + " ";
842 this.last.x = p._getX((parseFloat(arguments[4], 10) * 100) / 100);
843 this.last.y = p._getY((parseFloat(arguments[5], 10) * 100) / 100);
844 this.last.bx = p._getX((parseFloat(arguments[2], 10) * 100) / 100);
845 this.last.by = p._getY((parseFloat(arguments[3], 10) * 100) / 100);
847 if (arguments.length == 4) {
848 var d = this.isAbsolute?"S":"s";
849 for (var i = 0, ii = arguments.length; i < ii; i++) {
850 d += p[i % 2 == 0 ? "_getX" : "_getY"]((parseFloat(arguments[i], 10) * 100) / 100) + " ";
853 this.last.x = p._getX((parseFloat(arguments[2], 10) * 100) / 100);
854 this.last.y = p._getY((parseFloat(arguments[3], 10) * 100) / 100);
855 this.last.bx = p._getX((parseFloat(arguments[0], 10) * 100) / 100);
856 this.last.by = p._getY((parseFloat(arguments[1], 10) * 100) / 100);
858 var oldD = this[0].getAttribute("d") || "";
859 this[0].setAttribute("d", oldD + d);
860 this.path.push({type: "curve", arg: arguments, pos: this.isAbsolute});
863 p.addRoundedCorner = function (r, dir) {
864 var R = .5522 * r, rollback = this.isAbsolute, o = this;
867 rollback = function () {
871 rollback = function () {};
877 o.curveTo(-R, 0, -r, -(r - R), -r, -r);
880 o.curveTo(-R, 0, -r, r - R, -r, r);
887 o.curveTo(R, 0, r, -(r - R), r, -r);
890 o.curveTo(R, 0, r, r - R, r, r);
897 o.curveTo(0, -R, -(R - r), -r, r, -r);
900 o.curveTo(0, -R, R - r, -r, -r, -r);
907 o.curveTo(0, R, -(R - r), r, r, r);
910 o.curveTo(0, R, R - r, r, -r, r);
915 actions[dir[0]]()[dir[1]]();
919 p.andClose = function () {
920 var oldD = this[0].getAttribute("d") || "";
921 this[0].setAttribute("d", oldD + "Z ");
922 this.path.push({type: "end"});
925 if (typeof pathString == "string") {
926 pathString = pathString.replace(/([mzlhvcsqta])/ig, ",$1,").replace(/([^,])\-/ig, "$1,-");
927 path = pathString.split(",");
928 var i = 1, ii = path.length;
932 p.absolutely().moveTo(path[++i], path[++i]);
935 p.relatively().moveTo(path[++i], path[++i]);
938 p.absolutely().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
941 p.relatively().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
944 p.relatively().curveTo(path[++i], path[++i], path[++i], path[++i]);
947 p.absolutely().curveTo(path[++i], path[++i], path[++i], path[++i]);
950 p.absolutely().lineTo(path[++i], path[++i]);
953 p.relatively().lineTo(path[++i], path[++i]);
956 p.absolutely().lineTo(path[++i], 0);
959 p.relatively().lineTo(path[++i], 0);
962 p.absolutely().lineTo(0, path[++i]);
965 p.relatively().lineTo(0, path[++i]);
976 var addGrdientFill = function (o, gradient, SVG) {
977 var el = document.createElementNS(SVG.svgns, gradient.type + "Gradient");
978 el.id = "raphael-gradient-" + SVG.gradients++;
979 if (gradient.vector && gradient.vector.length) {
980 el.setAttribute("x1", gradient.vector[0]);
981 el.setAttribute("y1", gradient.vector[1]);
982 el.setAttribute("x2", gradient.vector[2]);
983 el.setAttribute("y2", gradient.vector[3]);
985 SVG.defs.appendChild(el);
986 for (var i = 0, ii = gradient.dots.length; i < ii; i++) {
987 var stop = document.createElementNS(SVG.svgns, "stop");
988 stop.setAttribute("offset", gradient.dots[i].offset ? gradient.dots[i].offset : (i == 0) ? "0%" : "100%");
989 stop.setAttribute("stop-color", gradient.dots[i].color || "#fff");
990 if (typeof gradient.dots[i].opacity != "undefined") {
991 stop.setAttribute("stop-opacity", gradient.dots[i].opacity);
993 el.appendChild(stop);
995 o.setAttribute("fill", "url(#" + el.id + ")");
997 var Element = function (node, svg) {
1000 Rotation = {deg: 0, x: 0, y: 0},
1004 this.attrs = this.attrs || {};
1005 this.transformations = [];
1006 this.hide = function () {
1007 this[0].style.display = "none";
1010 this.show = function () {
1011 this[0].style.display = "block";
1014 this.rotate = function (deg) {
1015 var bbox = this.getBBox();
1016 this.transformations.push("rotate(" + deg + " " + (bbox.x + bbox.width / 2) + " " + (bbox.y + bbox.height / 2) + ")");
1017 this[0].setAttribute("transform", this.transformations.join(" "));
1020 this.translate = function (x, y) {
1021 this.transformations.push("translate(" + x + "," + y + ")");
1022 this[0].setAttribute("transform", this.transformations.join(" "));
1025 this.scale = function (x, y) {
1027 if (x != 0 && !(x == 1 && y == 1)) {
1028 var bbox = this.getBBox(),
1029 dx = bbox.x * (1 - x) + (bbox.width / 2 - bbox.width * x / 2),
1030 dy = bbox.y * (1 - y) + (bbox.height / 2 - bbox.height * y / 2);
1031 this.transformations.push(new Matrix(x, 0, 0, y, dx, dy));
1032 this[0].setAttribute("transform", this.transformations.join(" "));
1036 this.matrix = function (xx, xy, yx, yy, dx, dy) {
1037 this.transformations.push(new Matrix(xx, xy, yx, yy, dx, dy));
1038 this[0].setAttribute("transform", this.transformations.join(" "));
1041 this.remove = function () {
1042 this[0].parentNode.removeChild(this[0]);
1044 this.getBBox = function () {
1045 return this[0].getBBox();
1047 this.attr = function () {
1048 if (arguments.length == 1 && typeof arguments[0] == "string") {
1049 return this[0].getAttribute(arguments[0]);
1051 if (arguments.length == 1 && arguments[0] instanceof Array) {
1053 for (var j in arguments[0]) {
1054 values[arguments[0][j]] = this.attrs[arguments[0][j]];
1058 if (arguments.length == 2) {
1059 var att = arguments[0],
1060 value = arguments[1];
1062 this.attrs[att] = value;
1067 this[0].setAttribute(att, svg._getX(value));
1072 this[0].setAttribute(att, svg._getY(value));
1075 this[0].setAttribute(att, svg._getW(value));
1078 this[0].setAttribute(att, svg._getH(value));
1081 addGrdientFill(this[0], params.gradient, svg);
1083 case "stroke-dasharray":
1084 this[0].setAttribute(att, value.replace(" ", ","));
1087 if (this.type == "text") {
1088 this[0].removeChild(this[0].firstChild);
1089 this[0].appendChild(document.createTextNode(value));
1093 var cssrule = att.replace(/(\-.)/g, function (w) {
1094 return w.substring(1).toUpperCase();
1096 this[0].style[cssrule] = value;
1097 // Need following line for Firefox
1098 this[0].setAttribute(att, value);
1100 } else if (arguments.length = 1 && typeof arguments[0] == "object") {
1101 var params = arguments[0];
1102 for (var attr in params) {
1103 this.attrs[attr] = params[attr];
1104 if (attr == "stroke-dasharray") {
1105 this[0].setAttribute(attr, params[attr].replace(" ", ","));
1106 } else if (attr == "text" && this.type == "text") {
1107 this[0].removeChild(this[0].firstChild);
1108 this[0].appendChild(document.createTextNode(params[attr]));
1110 var cssrule = attr.replace(/(\-.)/g, function (w) {
1111 return w.substring(1).toUpperCase();
1113 this[0].style[cssrule] = params[attr];
1114 // Need following line for Firefox
1115 this[0].setAttribute(attr, params[attr]);
1118 if (params.gradient) {
1119 this[0].attrs.gradient = params.gradient;
1120 addGrdientFill(this[0], params.gradient, svg);
1125 this.toFront = function () {
1126 this[0].parentNode.appendChild(this[0]);
1128 this.toBack = function () {
1129 if (this[0].parentNode.firstChild != this[0]) {
1130 this[0].parentNode.insertBefore(this[0], this[0].parentNode.firstChild);
1134 var theCircle = function (svg, x, y, r) {
1135 var el = document.createElementNS(svg.svgns, "circle");
1136 el.setAttribute("cx", svg._getX(x));
1137 el.setAttribute("cy", svg._getY(y));
1138 el.setAttribute("r", r);
1139 el.setAttribute("fill", "none");
1140 el.setAttribute("stroke", "#000");
1141 el.attrs = el.attrs || {};
1145 el.attrs.stroke = "#000";
1147 svg.canvas.appendChild(el);
1149 var res = new Element(el, svg);
1150 res.type = "circle";
1153 var theRect = function (svg, x, y, w, h, r) {
1154 var el = document.createElementNS(svg.svgns, "rect");
1155 el.setAttribute("x", svg._getX(x));
1156 el.setAttribute("y", svg._getY(y));
1157 el.setAttribute("width", svg._getW(w));
1158 el.setAttribute("height", svg._getH(h));
1159 el.attrs = el.attrs || {};
1163 el.attrs.height = h;
1165 el.setAttribute("rx", r);
1166 el.setAttribute("ry", r);
1167 el.attrs.rx = el.attrs.ry = r;
1169 el.setAttribute("fill", "none");
1170 el.setAttribute("stroke", "#000");
1171 el.attrs.stroke = "#000";
1173 svg.canvas.appendChild(el);
1175 var res = new Element(el, svg);
1179 var theEllipse = function (svg, x, y, rx, ry) {
1180 var el = document.createElementNS(svg.svgns, "ellipse");
1181 el.setAttribute("cx", svg._getX(x));
1182 el.setAttribute("cy", svg._getY(y));
1183 el.setAttribute("rx", svg._getW(rx));
1184 el.setAttribute("ry", svg._getH(ry));
1185 el.setAttribute("fill", "none");
1186 el.setAttribute("stroke", "#000");
1187 el.attrs = el.attrs || {};
1192 el.attrs.stroke = "#000";
1194 svg.canvas.appendChild(el);
1196 var res = new Element(el, svg);
1197 res.type = "ellipse";
1200 var theImage = function (svg, src, x, y, w, h) {
1201 var el = document.createElementNS(svg.svgns, "image");
1202 el.setAttribute("x", svg._getX(x));
1203 el.setAttribute("y", svg._getY(y));
1204 el.setAttribute("width", svg._getW(w));
1205 el.setAttribute("height", svg._getH(h));
1206 el.setAttributeNS(svg.xlink, "href", src);
1208 svg.canvas.appendChild(el);
1210 var res = new Element(el, svg);
1214 var theText = function (svg, x, y, text) {
1215 var el = document.createElementNS(svg.svgns, "text");
1216 el.setAttribute("x", x);
1217 el.setAttribute("y", y);
1218 el.setAttribute("text-anchor", "middle");
1219 el.setAttribute("fill", "#000");
1220 el.attrs = el.attrs || {};
1223 el.attrs.fill = "#000";
1225 el.appendChild(document.createTextNode(text));
1228 svg.canvas.appendChild(el);
1230 var res = new Element(el, svg);
1234 var theGroup = function (svg) {
1235 var el = document.createElementNS(svg.svgns, "g");
1237 svg.canvas.appendChild(el);
1239 var i = new Element(el, svg);
1240 for (var f in svg) {
1241 if (f[0] != "_" && typeof svg[f] == "function") {
1242 i[f] = (function (f) {
1243 return function () {
1244 var e = svg[f].apply(svg, arguments);
1245 el.appendChild(e[0]);
1254 r._create = function () {
1255 // container, width, height
1256 // x, y, width, height
1257 if (typeof arguments[0] == "string") {
1258 var container = document.getElementById(arguments[0]);
1259 var width = arguments[1];
1260 var height = arguments[2];
1262 if (typeof arguments[0] == "object") {
1263 var container = arguments[0];
1264 var width = arguments[1];
1265 var height = arguments[2];
1267 if (typeof arguments[0] == "number") {
1271 width = arguments[2],
1272 height = arguments[3];
1275 throw new Error("SVG container not found.");
1277 C.canvas = document.createElementNS(C.svgns, "svg");
1278 C.canvas.setAttribute("width", width || 320);
1279 C.width = width || 320;
1280 C.canvas.setAttribute("height", height || 200);
1281 C.height = height || 200;
1282 if (container == 1) {
1283 document.body.appendChild(C.canvas);
1284 C.canvas.style.position = "absolute";
1285 C.canvas.style.left = x + "px";
1286 C.canvas.style.top = y + "px";
1288 if (container.firstChild) {
1289 container.insertBefore(C.canvas, container.firstChild);
1291 container.appendChild(C.canvas);
1296 clear: function () {
1297 while (this.canvas.firstChild) {
1298 this.canvas.removeChild(this.canvas.firstChild);
1300 this.defs = document.createElementNS(C.svgns, "defs");
1302 this.canvas.appendChild(this.defs);
1305 for (var prop in C) {
1306 if (prop != "create") {
1307 container[prop] = C[prop];
1313 C.svgns = "http://www.w3.org/2000/svg";
1314 C.xlink = "http://www.w3.org/1999/xlink";
1316 if (type == "VML" || type == "SVG") {
1317 C.circle = function (x, y, r) {
1318 return theCircle(this, x, y, r);
1320 C.rect = function (x, y, w, h, r) {
1321 return theRect(this, x, y, w, h, r);
1323 C.ellipse = function (x, y, rx, ry) {
1324 return theEllipse(this, x, y, rx, ry);
1326 C.path = function (params, pathString) {
1327 return thePath(params, pathString, this);
1329 C.image = function (src, x, y, w, h) {
1330 return theImage(this, src, x, y, w, h);
1332 C.text = function (x, y, text) {
1333 return theText(this, x, y, text);
1335 C.group = function () {
1336 return theGroup(this);
1338 C.linerect = function (x, y, w, h, r) {
1339 if (r && parseInt(r, 10)) {
1340 return this.path({stroke: "#000"}).moveTo(x + r, y).lineTo(x + w - r, y).addRoundedCorner(r, "rd").lineTo(x + w, y + h - r).addRoundedCorner(r, "dl").lineTo(x + r, y + h).addRoundedCorner(r, "lu").lineTo(x, y + r).addRoundedCorner(r, "ur").andClose();
1342 return this.path({stroke: "#000"}).moveTo(x, y).lineTo(x + w, y).lineTo(x + w, y + h).lineTo(x, y + h).andClose();
1344 C.drawGrid = function (x, y, w, h, wv, hv, color) {
1345 color = color || "#000";
1346 var res = this.group();
1347 var params = {stroke: color, "stroke-width": "1px", "stroke-opacity": .3};
1348 res.rect(x, y, w, h).attr(params);
1349 for (var i = 1; i < hv; i++) {
1350 var p = res.path(params);
1351 p.moveTo(x, y + i * Math.round(h / hv)).lineTo(x + w, y + i * Math.round(h / hv));
1353 for (var i = 1; i < wv; i++) {
1354 res.path(params).moveTo(x + i * Math.round(w / wv), y).lineTo(x + i * Math.round(w / wv), y + h);
1358 C.setGrid = function (xmin, ymin, xmax, ymax, w, h) {
1359 var xc = (xmax - xmin) / w;
1360 var yc = (ymax - ymin) / h;
1361 this._getX = function (x) {
1362 return xmin + x * xc;
1364 this._getY = function (y) {
1365 return ymin + y * yc;
1367 this._getW = function (w) {
1370 this._getH = function (h) {
1374 C.clearGrid = function () {
1375 this._getX = this._getY = this._getW = this._getH = function (x) { return x; };
1377 C.safari = function () {
1378 if (r.type == "SVG") {
1379 var rect = C.rect(-C.width, -C.width, C.width * 3, C.height * 3).attr({stroke: "none"});
1380 setTimeout(function () {rect.remove();}, 0);
1386 return function () {};
1388 })((!(window.SVGPreserveAspectRatio && window.SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN == 2) && !(window.CanvasRenderingContext2D)) ? "VML" : "SVG");
1391 Raphael.type = (!(window.SVGPreserveAspectRatio && window.SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN == 2) && !(window.CanvasRenderingContext2D)) ? "VML" : "SVG";
1392 Raphael.vml = !(Raphael.svg = (Raphael.type == "SVG"));
1393 if (!(window.SVGPreserveAspectRatio && window.SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN == 2) && window.CanvasRenderingContext2D) {
1394 Raphael.type = "Canvas only";
1395 Raphael.vml = Raphael.svg = false;
1397 Raphael.toString = function () {
1398 return "You browser supports " + this.type;
1400 Raphael.hsb2rgb = function (hue, saturation, brightness) {
1401 if (typeof hue == "object" && "h" in hue && "s" in hue && "b" in hue) {
1409 if (brightness == 0.0) {
1410 return {r: 0, g: 0, b: 0};
1412 var i = Math.floor(hue * 6),
1414 p = brightness * (1 - saturation),
1415 q = brightness * (1 - (saturation * f)),
1416 t = brightness * (1 - (saturation * (1 - f)));
1418 function () {red = brightness; green = t; blue = p;},
1419 function () {red = q; green = brightness; blue = p;},
1420 function () {red = p; green = brightness; blue = t;},
1421 function () {red = p; green = q; blue = brightness;},
1422 function () {red = t; green = p; blue = brightness;},
1423 function () {red = brightness; green = p; blue = q;},
1424 function () {red = brightness; green = t; blue = p;},
1427 var rgb = {r: red, g: green, b: blue};
1428 var r = Math.round(rgb.r).toString(16);
1429 if (r.length == 1) {
1432 var g = Math.round(rgb.g).toString(16);
1433 if (g.length == 1) {
1436 var b = Math.round(rgb.b).toString(16);
1437 if (b.length == 1) {
1440 rgb.hex = "#" + r + g + b;
1443 Raphael.rgb2hsb = function (red, green, blue) {
1444 if (typeof red == "object" && "r" in red && "h" in red && "b" in red) {
1449 if (red.charAt(0) == "#") {
1450 if (red.length == 4) {
1451 blue = parseInt(red.substring(3), 16);
1452 green = parseInt(red.substring(2, 3), 16);
1453 red = parseInt(red.substring(1, 2), 16);
1455 blue = parseInt(red.substring(5), 16);
1456 green = parseInt(red.substring(3, 5), 16);
1457 red = parseInt(red.substring(1, 3), 16);
1460 var max = Math.max(red, green, blue),
1461 min = Math.min(red, green, blue),
1466 return {h: 0, s: 0, b: max};
1468 var delta = (max - min);
1469 saturation = delta / max;
1471 hue = (green - blue) / delta;
1472 } else if (green == max) {
1473 hue = 2 + ((blue - red) / delta);
1475 hue = 4 + ((red - green) / delta);
1485 return {h: hue, s: saturation, b: brightness};
1487 Raphael.getColor = function (value) {
1488 var start = arguments.callee.start = arguments.callee.start || {h: 0, s: 1, b: value || 200};
1489 var rgb = this.hsb2rgb(start.h, start.s, start.b);
1495 start = {h: 0, s: 1, b: start.b};
1500 Raphael.getColor.reset = function () {
1501 this.start = undefined;