Initial commit to GIT
[raphael] / raphael.js
1 function Raphael() {
2     return (function (r, args) {
3         r.version = "0.5.2";
4         var C = {};
5         function Matrix(m11, m12, m21, m22, dx, dy) {
6             this.m = [
7                 [m11 || 1, m12 || 0, 0],
8                 [m21 || 0, m22 || 1, 0],
9                 [dx || 0, dy || 0, 1],
10             ];
11         }
12
13         C._getX = C._getY = C._getW = C._getH = function (x) { return x; };
14
15         if (r.vml) {
16             Matrix.prototype.toString = function () {
17                 return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.m[0][0] +
18                     ", M12=" + this.m[1][0] + ", M21=" + this.m[0][1] + ", M22=" + this.m[1][1] +
19                     ", Dx=" + this.m[2][0] + ", Dy=" + this.m[2][1] + ", sizingmethod='auto expand', filtertype='bilinear')";
20             };
21             var thePath = function (params, pathString, VML) {
22                 var g = document.createElement("rvml:group"), gl = g.style;
23                 gl.position = "absolute";
24                 gl.left = 0;
25                 gl.top = 0;
26                 gl.width = VML.width + "px";
27                 gl.height = VML.height + "px";
28                 var el = document.createElement("rvml:shape"), ol = el.style;
29                 ol.width = VML.width + "px";
30                 ol.height = VML.height + "px";
31                 el.path = "";
32                 if (params["class"]) {
33                     el.className = params["class"];
34                 }
35                 el.coordsize = this.coordsize;
36                 el.coordorigin = this.coordorigin;
37                 g.appendChild(el);
38                 VML.canvas.appendChild(g);
39                 var p = new Element(el, g, VML);
40                 setFillAndStroke(p, params);
41                 if (params.gradient) {
42                     addGrdientFill(p, params.gradient);
43                 }
44                 p.isAbsolute = true;
45                 p.type = "path";
46                 p.path = [];
47                 p.last = {x: 0, y: 0, bx: 0, by: 0, isAbsolute: true};
48                 p.Path = "";
49                 p.absolutely = function () {
50                     this.isAbsolute = true;
51                     return this;
52                 };
53                 p.relatively = function () {
54                     this.isAbsolute = false;
55                     return this;
56                 };
57                 p.redraw = function () {
58                     this.Path = "";
59                     var oldPath = this.path;
60                     this.path = [];
61                     for (var i = 0, ii = oldPath.length; i < ii; i++) {
62                         if (oldPath[i].type != "end") {
63                             this[oldPath[i].type + "To"].apply(this, oldPath[i].arg);
64                         } else {
65                             this.andClose();
66                         }
67                     };
68                 };
69                 p.moveTo = function (x, y) {
70                     var d = this.isAbsolute?"m":"t";
71                     var _getX = this.isAbsolute ? VML._getX : VML._getW;
72                     var _getY = this.isAbsolute ? VML._getY : VML._getH;
73                     d += Math.round(_getX(parseFloat(x, 10))) + " " + Math.round(_getY(parseFloat(y, 10)));
74                     this[0].path = this.Path += d;
75                     this.last.x = Math.round(_getX(parseFloat(x, 10)));
76                     this.last.y = Math.round(_getY(parseFloat(y, 10)));
77                     this.last.isAbsolute = this.isAbsolute;
78                     this.path.push({type: "move", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
79                     return this;
80                 };
81                 p.lineTo = function (x, y) {
82                     var d = this.isAbsolute?"l":"r";
83                     var _getX = this.isAbsolute ? VML._getX : VML._getW;
84                     var _getY = this.isAbsolute ? VML._getY : VML._getH;
85                     d += Math.round(_getX(parseFloat(x, 10))) + " " + Math.round(_getY(parseFloat(y, 10)));
86                     this[0].path = this.Path += d;
87                     this.last.x = Math.round(_getX(parseFloat(x, 10)));
88                     this.last.y = Math.round(_getY(parseFloat(y, 10)));
89                     this.last.isAbsolute = this.isAbsolute;
90                     this.path.push({type: "line", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
91                     return this;
92                 };
93                 p.cplineTo = function (x1, y1, w1) {
94                     if (!w1) {
95                         return this.lineTo(x1, y1);
96                     } else {
97                         var p = {};
98                         p._getX = this.isAbsolute ? VML._getX : VML._getW;
99                         p._getY = this.isAbsolute ? VML._getY : VML._getH;
100                         var x = Math.round(p._getX(Math.round(parseFloat(x1, 10) * 100) / 100));
101                         var y = Math.round(p._getY(Math.round(parseFloat(y1, 10) * 100) / 100));
102                         var w = Math.round(VML._getW(Math.round(parseFloat(w1, 10) * 100) / 100));
103                         var d = this.isAbsolute?"c":"v";
104                         var attr = [this.last.x + w, this.last.y, x - w, y, x, y];
105                         d += attr.join(" ") + " ";
106                         this.last.x = attr[4];
107                         this.last.y = attr[5];
108                         this.last.bx = attr[2];
109                         this.last.by = attr[3];
110                         this[0].path = this.Path += d;
111                         this.path.push({type: "cpline", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
112                         return this;
113                     }
114                 };
115                 p.curveTo = function () {
116                     var d = this.isAbsolute?"c":"v";
117                     var _getX = this.isAbsolute ? VML._getX : VML._getW;
118                     var _getY = this.isAbsolute ? VML._getY : VML._getH;
119                     if (arguments.length == 6) {
120                         this.last.x = Math.round(_getX(parseFloat(arguments[4], 10)));
121                         this.last.y = Math.round(_getY(parseFloat(arguments[5], 10)));
122                         this.last.bx = Math.round(_getX(parseFloat(arguments[2], 10)));
123                         this.last.by = Math.round(_getY(parseFloat(arguments[3], 10)));
124                         d += Math.round(_getX(parseFloat(arguments[0], 10))) + " " + Math.round(_getY(parseFloat(arguments[1], 10))) + " " +
125                              Math.round(_getX(parseFloat(arguments[2], 10))) + " " + Math.round(_getY(parseFloat(arguments[3], 10))) + " " +
126                              Math.round(_getX(parseFloat(arguments[4], 10))) + " " + Math.round(_getY(parseFloat(arguments[5], 10))) + " ";
127                         this.last.isAbsolute = this.isAbsolute;
128                     }
129                     this[0].path = this.Path += d;
130                     this.path.push({type: "curve", arg: [].slice.call(arguments, 0), pos: this.isAbsolute});
131                     return this;
132                 };
133                 p.addRoundedCorner = function (r, dir) {
134                     var R = .5522 * r, rollback = this.isAbsolute, o = this;
135                     if (rollback) {
136                         this.relatively();
137                         rollback = function () {
138                             o.absolutely();
139                         };
140                     } else {
141                         rollback = function () {};
142                     }
143                     var actions = {
144                         l: function () {
145                             return {
146                                 u: function () {
147                                     o.curveTo(-R, 0, -r, -(r - R), -r, -r);
148                                 },
149                                 d: function () {
150                                     o.curveTo(-R, 0, -r, r - R, -r, r);
151                                 }
152                             };
153                         },
154                         r: function () {
155                             return {
156                                 u: function () {
157                                     o.curveTo(R, 0, r, -(r - R), r, -r);
158                                 },
159                                 d: function () {
160                                     o.curveTo(R, 0, r, r - R, r, r);
161                                 }
162                             };
163                         },
164                         u: function () {
165                             return {
166                                 r: function () {
167                                     o.curveTo(0, -R, -(R - r), -r, r, -r);
168                                 },
169                                 l: function () {
170                                     o.curveTo(0, -R, R - r, -r, -r, -r);
171                                 }
172                             };
173                         },
174                         d: function () {
175                             return {
176                                 r: function () {
177                                     o.curveTo(0, R, -(R - r), r, r, r);
178                                 },
179                                 l: function () {
180                                     o.curveTo(0, R, R - r, r, -r, r);
181                                 }
182                             };
183                         }
184                     };
185                     actions[dir.charAt(0)]()[dir.charAt(1)]();
186                     rollback();
187                     return o;
188                 };
189                 p.andClose = function () {
190                     this[0].path = (this.Path += "x e");
191                     return this;
192                 };
193                 if (typeof pathString == "string") {
194                     pathString = pathString.replace(/([mzlhvcsqta])/ig, ",$1,").replace(/([^,])\-/ig, "$1,-");
195                     path = pathString.split(",");
196                     var i = 1, ii = path.length;
197                     while (i < ii) {
198                         switch (path[i]) {
199                             case "M":
200                                 p.absolutely().moveTo(path[++i], path[++i]);
201                                 break;
202                             case "m":
203                                 p.relatively().moveTo(path[++i], path[++i]);
204                                 break;
205                             case "C":
206                                 p.absolutely().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
207                                 break;
208                             case "c":
209                                 p.relatively().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
210                                 break;
211                             case "L":
212                                 p.absolutely().lineTo(path[++i], path[++i]);
213                                 break;
214                             case "l":
215                                 p.relatively().lineTo(path[++i], path[++i]);
216                                 break;
217                             case "H":
218                                 p.absolutely().lineTo(path[++i], 0);
219                                 break;
220                             case "h":
221                                 p.relatively().lineTo(path[++i], 0);
222                                 break;
223                             case "V":
224                                 p.absolutely().lineTo(0, path[++i]);
225                                 break;
226                             case "v":
227                                 p.relatively().lineTo(0, path[++i]);
228                                 break;
229                             case "Z":
230                             case "z":
231                                 p.andClose();
232                                 break;
233                         }
234                         i++;
235                     }
236                 }
237                 return p;
238             };
239             var setFillAndStroke = function (o, params) {
240                 params["font-family"] && (o[0].style.fontFamily = params["font-family"]);
241                 params["font-size"] && (o[0].style.fontSize = params["font-size"]);
242                 params["font"] && (o[0].style.font = params["font"]);
243                 params["font-weight"] && (o[0].style.fontWeight = params["font-weight"]);
244                 if (typeof params.opacity != "undefined" || typeof params["stroke-width"] != "undefined" || typeof params.fill != "undefined" || typeof params.stroke != "undefined") {
245                     o = o.shape || o[0];
246                     var fill = (o.getElementsByTagName("fill") && o.getElementsByTagName("fill")[0]) || document.createElement("rvml:fill");
247                     if ("fill-opacity" in params || "opacity" in params) {
248                         fill.opacity = ((params["fill-opacity"] + 1 || 2) - 1) * ((params.opacity + 1 || 2) - 1);
249                     }
250                     params.fill && (fill.on = true);
251                     if (fill.on) {
252                         fill.color = params.fill;
253                     }
254                     o.appendChild(fill);
255                     var stroke = (o.getElementsByTagName("stroke") && o.getElementsByTagName("stroke")[0]) || document.createElement("rvml:stroke");
256                     stroke.on = !!(params.stroke || params["stroke-width"] || params["stroke-opacity"] || params["stroke-dasharray"]);
257                     if (stroke.on) {
258                         stroke.color = params.stroke;
259                     }
260                     stroke.opacity = ((params["stroke-opacity"] + 1 || 2) - 1) * ((params.opacity + 1 || 2) - 1);
261                     stroke.joinstyle = params["stroke-linejoin"] || "miter";
262                     stroke.miterlimit = params["stroke-miterlimit"] || 8;
263                     stroke.endcap = {butt: "flat", square: "square", round: "round"}[params["stroke-linecap"] || "miter"];
264                     stroke.weight = parseFloat(params["stroke-width"], 10) + "px" || "1px";
265                     if (params["stroke-dasharray"]) {
266                         var dashes = params["stroke-dasharray"].replace(" ", ",").split(","),
267                             dashesn = [],
268                             str = parseFloat(stroke.weight, 10);
269                         for (var i = 0, ii = dashes.length; i < ii; i++) {
270                             var res = dashes[i] / str;
271                             if (!isNaN(res)) {
272                                 dashesn.push(res);
273                             }
274                         };
275                         stroke.dashstyle = dashesn.join(" ");
276                     }
277                     o.appendChild(stroke);
278                 }
279             };
280             var addGrdientFill = function (o, gradient) {
281                 o = o.shape || o[0];
282                 var fill = o.getElementsByTagName("fill");
283                 if (fill.length) {
284                     fill = fill[0];
285                 } else {
286                     fill = document.createElement("rvml:fill");
287                 }
288                 if (gradient.dots.length) {
289                     fill.on = true;
290                     fill.type = (gradient.type.toLowerCase() == "linear") ? "gradient" : "gradientradial";
291                     if (typeof gradient.dots[0].color != "undefined") {
292                         fill.color = gradient.dots[0].color || "#000";
293                     }
294                     if (typeof gradient.dots[0].opacity != "undefined") {
295                         fill.opacity = gradient.dots[0].opacity;
296                     }
297                     if (typeof gradient.dots[gradient.dots.length - 1].opacity != "undefined") {
298                         fill.opacity2 = gradient.dots[gradient.dots.length - 1].opacity;
299                     }
300                     if (typeof gradient.dots[gradient.dots.length - 1].color != "undefined") {
301                         fill.color2 = gradient.dots[gradient.dots.length - 1].color || "#000";
302                     }
303                     var colors = "";
304                     for (var i = 1, ii = gradient.dots.length - 1; i < ii; i++) {
305                         colors += gradient.dots[i].offset + " " + gradient.dots[i].color;
306                         if (i != ii - 1) {
307                             colors += ",";
308                         }
309                     };
310                     if (colors) {
311                         fill.colors = colors;
312                     }
313                     if (gradient.vector) {
314                         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;
315                         fill.angle = angle + 90;
316                     }
317                     if (gradient.type.toLowerCase() == "radial") {
318                         fill.focusposition = "0.5, 0.5";
319                         fill.focussize = "0, 0";
320                         fill.method = "none";
321                     }
322                 }
323             };
324             var Element = function (node, group, vml) {
325                 var X = 0,
326                     Y = 0,
327                     Rotation = 0,
328                     RotX = 0,
329                     RotY = 0,
330                     Scale = 1;
331                 this[0] = node;
332                 arguments.callee.name = "Element";
333                 this.Group = group;
334                 this.rotate = function (deg, x, y) {
335                     Rotation += deg;
336                     var alpha = Rotation * Math.PI / 180,
337                         c = Math.cos(alpha),
338                         s = Math.sin(alpha);
339                     this.Group.style.left = 0;
340                     this.Group.style.top = 0;
341                     this.Group.style.rotation = 0;
342                     var cx = vml.width / 2,
343                         cy = vml.height / 2,
344                         bbox = this.getBBox(),
345                         dx = cx - (bbox.x + bbox.width / 2),
346                         dy = cy - (bbox.y + bbox.height / 2),
347                         phi = Math.atan(dy / dx),
348                         g = Math.sqrt(dx * dx + dy * dy);
349                         RotX = -Math.round(dx - g * Math.cos(alpha + phi));
350                         RotY = -Math.round(dy - g * Math.sin(alpha + phi));
351                     this.Group.style.left = X + RotX;
352                     this.Group.style.top = Y + RotY;
353                     this.Group.style.rotation = Rotation;
354                     return this;
355                 };
356                 this.translate = function (x, y) {
357                     X += x;
358                     Y += y;
359                     this.Group.style.left = X + RotX;
360                     this.Group.style.top = Y + RotY;
361                     return this;
362                 };
363                 this.matrix = function (xx, xy, yx, yy, dx, dy) {
364                     tMatrix = new Matrix(xx, xy, yx, yy, dx, dy);
365                     this[0].style.filter = tMatrix;
366                     return this;
367                 };
368                 this.scale = function (times) {
369                     Scale *= times;
370                     if (Scale != 1) {
371                         this[0].style.width = parseInt(this[0].style.width, 10) * Scale;
372                         this[0].style.height = parseInt(this[0].style.height, 10) * Scale;
373                     }
374                     return this;
375                 };
376                 this.getBBox = function () {
377                     return {
378                         x: this.Group.offsetLeft,
379                         y: this.Group.offsetTop,
380                         width: this.Group.offsetWidth,
381                         height: this.Group.offsetHeight
382                     };
383                 };
384                 this.remove = function () {
385                     this[0].parentNode.removeChild(this[0]);
386                     this.Group.parentNode.removeChild(this.Group);
387                     this.shape && this.shape.parentNode.removeChild(this.shape);
388                 };
389                 this.attr = function () {
390                     if (this[0].tagName.toLowerCase() == "group") {
391                         var children = this[0].childNodes;
392                         for (var i = 0, ii = children.length; i < ii; i++) {
393                             this.attr.apply(new item(children[i], this[0], vml), arguments);
394                         };
395                     } else {
396                         if (arguments.length == 2) {
397                             var att = arguments[0],
398                                 value = arguments[1];
399                             switch (att) {
400                                 case "r":
401                                     this[0].style.width = this[0].style.height = value * 2 + "px";
402                                     this[0].style.left = vml._getX(this.cx) - value + "px";
403                                     this[0].style.top = vml._getY(this.cy) - value + "px";
404                                     this.r = value;
405                                     break;
406                                 case "rx":
407                                     this[0].style.width = value * 2 + "px";
408                                     this[0].style.left = vml._getX(this.cx) - value + "px";
409                                     this.rx = value;
410                                     break;
411                                 case "ry":
412                                     this[0].style.height = value * 2 + "px";
413                                     this[0].style.top = vml._getY(this.cy) - value + "px";
414                                     this.ry = value;
415                                     break;
416                                 case "cx":
417                                     if (this.r || this.rx) {
418                                         this[0].style.left = vml._getX(value) - (this.r || vml._getW(this.rx)) + "px";
419                                         this.cx = value;
420                                     }
421                                     break;
422                                 case "x":
423                                     this[0].style.left = vml._getX(value) + "px";
424                                     break;
425                                 case "cy":
426                                     if (this.r || this.ry) {
427                                         this[0].style.top = vml._getY(value) - (this.r || vml._getH(this.ry)) + "px";
428                                         this.cy = value;
429                                     }
430                                     break;
431                                 case "y":
432                                     this[0].style.top = vml._getY(value) + "px";
433                                     break;
434                                 case "fill":
435                                 case "fill-opacity":
436                                 case "joinstyle":
437                                 case "opacity":
438                                 case "stroke":
439                                 case "stroke-dasharray":
440                                 case "stroke-opacity":
441                                 case "stroke-width":
442                                     var params = {};
443                                     params[att] = value;
444                                     setFillAndStroke(this, params);
445                                     break;
446                                 case "font":
447                                 case "font-family":
448                                 case "font-size":
449                                 case "font-weight":
450                                 case "height":
451                                 case "width":
452                                     this[0].style[att] = value;
453                                     break;
454                                 case "id":
455                                     this[0].id = value;
456                                     break;
457                                 case "gradient":
458                                     addGrdientFill(this, value);
459                             }
460                         }
461                         if (arguments.length == 1 && typeof arguments[0] == "object") {
462                             var params = arguments[0];
463                             setFillAndStroke(this, params);
464                             if (params.gradient) {
465                                 addGrdientFill(this, params.gradient);
466                             }
467                             if (params.id) {
468                                 this[0].id = params.id;
469                             }
470                         }
471                     }
472                     return this;
473                 };
474                 this.toFront = function () {
475                     this.Group.parentNode.appendChild(this.Group);
476                 };
477             };
478             var theCircle = function (vml, x, y, r) {
479                 var g = document.createElement("rvml:group"), gl = g.style;
480                 gl.position = "absolute";
481                 gl.left = 0;
482                 gl.top = 0;
483                 gl.width = vml.width;
484                 gl.height = vml.height;
485                 var o = document.createElement("rvml:oval"), ol = o.style;
486                 ol.width = ol.height = r * 2 + "px";
487                 ol.top = vml._getY(y) - r + "px";
488                 ol.left = vml._getX(x) - r + "px";
489                 g.appendChild(o);
490                 vml.canvas.appendChild(g);
491                 var res = new Element(o, g, vml);
492                 setFillAndStroke(res, {stroke: "#000"});
493                 res.cx = x;
494                 res.cy = y;
495                 res.r = r;
496                 res.type = "circle";
497                 return res;
498             };
499             var theRect = function (vml, x, y, w, h, r) {
500                 var g = document.createElement("rvml:group"), gl = g.style;
501                 gl.position = "absolute";
502                 gl.left = 0;
503                 gl.top = 0;
504                 gl.width = vml.width;
505                 gl.height = vml.height;
506                 var o = document.createElement(r ? "rvml:roundrect" : "rvml:rect"), ol = o.style;
507                 ol.height = vml._getH(h) + "px";
508                 ol.width = vml._getW(w) + "px";
509                 ol.top = vml._getY(y) + "px";
510                 ol.left = vml._getX(x) + "px";
511                 if (r) {
512                     o.arcsize = r / (Math.min(w, h));
513                 }
514                 g.appendChild(o);
515                 vml.canvas.appendChild(g);
516                 var res = new Element(o, g, vml);
517                 setFillAndStroke(res, {stroke: "#000"});
518                 res.cx = x;
519                 res.cy = y;
520                 res.r = r;
521                 res.type = "rect";
522                 return res;
523             };
524             var theEllipse = function (vml, x, y, rx, ry) {
525                 var g = document.createElement("rvml:group"), gl = g.style;
526                 gl.position = "absolute";
527                 gl.left = 0;
528                 gl.top = 0;
529                 gl.width = vml.width;
530                 gl.height = vml.height;
531                 var o = document.createElement("rvml:oval"), ol = o.style;
532                 ol.width = rx * 2 + "px";
533                 ol.height = ry * 2 + "px";
534                 ol.top = y - ry + "px";
535                 ol.left = x - rx + "px";
536                 g.appendChild(o);
537                 vml.canvas.appendChild(g);
538                 var res = new Element(o, g, vml);
539                 setFillAndStroke(res, {stroke: "#000"});
540                 res.cx = x;
541                 res.cy = y;
542                 res.rx = rx;
543                 res.ry = ry;
544                 res.type = "ellipse";
545                 return res;
546             };
547             var theImage = function (vml, src, x, y, w, h) {
548                 var g = document.createElement("rvml:group");
549                 g.style.position = "absolute";
550                 g.style.left = 0;
551                 g.style.top = 0;
552                 g.style.width = vml.width;
553                 g.style.height = vml.height;
554                 g.coordsize = vml.coordsize;
555                 g.coordorigin = vml.coordorigin;
556                 var o = document.createElement("rvml:image");
557                 o.src = src;
558                 o.style.position = "absolute";
559                 o.style.width = w + "px";
560                 o.style.height = h + "px";
561                 o.style.top = y + "px";
562                 o.style.left = x + "px";
563                 o.coordsize = vml.coordsize;
564                 o.coordorigin = vml.coordorigin;
565                 g.appendChild(o);
566                 vml.canvas.appendChild(g);
567                 var res = new Element(o, g, vml);
568                 res.type = "image";
569                 return res;
570             };
571             var theText = function (vml, x, y, text) {
572                 var g = document.createElement("rvml:group"), gs = g.style;
573                 var el = document.createElement("rvml:shape"), ol = el.style;
574                 var path = document.createElement("rvml:path"), ps = path.style;
575                 path.v = ["m", x, ", ", y, "l", x + 1, ", ", y].join("");
576                 path.textpathok = true;
577                 ps.position = "absolute";
578                 ps.top = 0;
579                 ps.left = 0;
580                 ol.width = vml.width + "px";
581                 ol.height = vml.height + "px";
582                 gs.position = "absolute";
583                 gs.left = 0;
584                 gs.top = 0;
585                 gs.width = vml.width;
586                 gs.height = vml.height;
587                 g.coordsize = vml.coordsize;
588                 g.coordorigin = vml.coordorigin;
589                 var o = document.createElement("rvml:textpath");
590                 o.string = text;
591                 o.on = true;
592                 o.coordsize = vml.coordsize;
593                 o.coordorigin = vml.coordorigin;
594                 el.appendChild(o);
595                 el.appendChild(path);
596                 g.appendChild(el);
597                 vml.canvas.appendChild(g);
598                 var res = new Element(o, g, vml);
599                 res.shape = el;
600                 res.type = "text";
601                 return res;
602             };
603             var theText2 = function (vml, x, y, text) {
604                 var g = document.createElement("rvml:group");
605                 g.style.position = "absolute";
606                 g.style.left = 0;
607                 g.style.top = 0;
608                 g.style.width = vml.width;
609                 g.style.height = vml.height;
610                 g.coordsize = vml.coordsize;
611                 g.coordorigin = vml.coordorigin;
612                 var o = document.createElement("rvml:textbox");
613                 o.style.position = "absolute";
614                 o.style.top = y  + "px";
615                 o.style.left = x + "px";
616                 o.innerHTML = "<div>" + text + "</div>";
617                 o.coordsize = vml.coordsize;
618                 o.coordorigin = vml.coordorigin;
619                 g.appendChild(o);
620                 vml.canvas.appendChild(g);
621                 var res = new Element(o, g, vml);
622                 res.type = "text";
623                 return res;
624             };
625             var theGroup = function (vml) {
626                 var el = document.createElement("rvml:group"), els = el.style;
627                 els.position = "absolute";
628                 els.left = 0;
629                 els.top = 0;
630                 els.width = vml.width;
631                 els.height = vml.height;
632                 if (vml.canvas) {
633                     vml.canvas.appendChild(el);
634                 }
635                 var res = new Element(el, el, vml);
636                 for (var f in vml) {
637                     if (f.charAt(0) != "_" && typeof vml[f] == "function") {
638                         res[f] = (function (f) {
639                             return function () {
640                                 var e = vml[f].apply(vml, arguments);
641                                 el.appendChild(e[0].parentNode);
642                                 return e;
643                             };
644                         })(f);
645                     }
646                 }
647                 res.type = "group";
648                 return res;
649             };
650             r._create = function () {
651                 // container, width, height
652                 // x, y, width, height
653                 if (typeof arguments[0] == "string") {
654                     var container = document.getElementById(arguments[0]);
655                     var width = arguments[1];
656                     var height = arguments[2];
657                 }
658                 if (typeof arguments[0] == "object") {
659                     var container = arguments[0];
660                     var width = arguments[1];
661                     var height = arguments[2];
662                 }
663                 if (typeof arguments[0] == "number") {
664                     var container = 1,
665                         x = arguments[0],
666                         y = arguments[1],
667                         width = arguments[2],
668                         height = arguments[3];
669                 }
670                 if (!container) {
671                     throw new Error("VML container not found.");
672                 }
673                 document.namespaces.add("rvml","urn:schemas-microsoft-com:vml");
674                 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;
678                 C.width = width;
679                 C.height = height;
680                 width = width || "320px";
681                 height = height || "200px";
682                 cs.clip = "rect(0 " + width + " " + height + " 0)";
683                 cs.position = "absolute";
684                 rs.width  = width;
685                 rs.height = height;
686                 r.coordsize = (width == "100%" ? width : parseFloat(width)) + " " + (height == "100%" ? height : parseFloat(height));
687                 r.coordorigin = "0 0";
688
689                 var b = document.createElement("rvml:rect"), bs = b.style;
690                 bs.left = bs.top = 0;
691                 bs.width  = rs.width;
692                 bs.height = rs.height;
693                 b.filled = b.stroked = "f";
694
695                 r.appendChild(b);
696                 c.appendChild(r);
697                 if (container == 1) {
698                     document.body.appendChild(c);
699                     cs.position = "absolute";
700                     cs.left = x + "px";
701                     cs.top = y + "px";
702                     cs.width = width;
703                     cs.height = height;
704                     container = {
705                         style: {
706                             width: width,
707                             height: height
708                         }
709                     };
710                 } else {
711                     cs.width = container.style.width = width;
712                     cs.height = container.style.height = height;
713                     if (container.firstChild) {
714                         container.insertBefore(c, container.firstChild);
715                     } else {
716                         container.appendChild(c);
717                     }
718                 }
719                 for (var prop in C) {
720                     container[prop] = C[prop];
721                 }
722                 container.clear = function () {
723                     var todel = [];
724                     for (var i = 0, ii = r.childNodes.length; i < ii; i++) {
725                         if (r.childNodes[i] != b) {
726                             todel.push(r.childNodes[i]);
727                         }
728                     }
729                     for (i = 0, ii = todel.length; i < ii; i++) {
730                         r.removeChild(todel[i]);
731                     }
732                 };
733                 return container;
734             };
735         }
736         if (r.svg) {
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] + ")";
741             };
742             var thePath = function (params, pathString, SVG) {
743                 var el = document.createElementNS(SVG.svgns, "path");
744                 el.setAttribute("fill", "none");
745                 if (params) {
746                     for (var attr in params) {
747                         if (params.gradient) {
748                             addGrdientFill(el, params.gradient, SVG);
749                         } else {
750                             el.setAttribute(attr, params[attr]);
751                         }
752                     }
753                 }
754                 if (SVG.canvas) {
755                     SVG.canvas.appendChild(el);
756                 }
757                 var p = new Element(el, SVG);
758                 p.isAbsolute = true;
759                 p.path = [];
760                 p.last = {x: 0, y: 0, bx: 0, by: 0};
761                 p.absolutely = function () {
762                     this.isAbsolute = true;
763                     return this;
764                 };
765                 p.relatively = function () {
766                     this.isAbsolute = false;
767                     return this;
768                 };
769                 p.redraw = function () {
770                     this[0].setAttribute("d", "M0 0");
771                     var oldPath = this.path;
772                     this.path = [];
773                     for (var i = 0, ii = oldPath.length; i < ii; i++) {
774                         if (oldPath[i].type != "end") {
775                             this[oldPath[i].type + "To"].apply(this, oldPath[i].arg);
776                         } else {
777                             this.andClose();
778                         }
779                     };
780                 };
781                 p.moveTo = function (x, y) {
782                     var d = this.isAbsolute?"M":"m";
783                     var _getX = this.isAbsolute ? SVG._getX : SVG._getW;
784                     var _getY = this.isAbsolute ? SVG._getY : SVG._getH;
785                     d += _getX(parseFloat(x, 10)) + " " + _getY(parseFloat(y, 10)) + " ";
786                     var oldD = this[0].getAttribute("d") || "";
787                     this[0].setAttribute("d", oldD + d);
788                     this.last.x = SVG._getX(parseFloat(x, 10));
789                     this.last.y = SVG._getY(parseFloat(y, 10));
790                     this.path.push({type: "move", arg: arguments, pos: this.isAbsolute});
791                     return this;
792                 };
793                 p.lineTo = function (x, y) {
794                     var d = this.isAbsolute?"L":"l";
795                     var _getX = this.isAbsolute ? SVG._getX : SVG._getW;
796                     var _getY = this.isAbsolute ? SVG._getY : SVG._getH;
797                     d += _getX(parseFloat(x, 10)) + " " + _getY(parseFloat(y, 10)) + " ";
798                     var oldD = this[0].getAttribute("d") || "";
799                     this[0].setAttribute("d", oldD + d);
800                     this.last.x = SVG._getX(parseFloat(x, 10));
801                     this.last.y = SVG._getY(parseFloat(y, 10));
802                     this.path.push({type: "line", arg: arguments, pos: this.isAbsolute});
803                     return this;
804                 };
805                 p.cplineTo = function (x1, y1, w1) {
806                     if (!w1) {
807                         return this.lineTo(x1, y1);
808                     } else {
809                         var p = {};
810                         p._getX = this.isAbsolute ? SVG._getX : SVG._getW;
811                         p._getY = this.isAbsolute ? SVG._getY : SVG._getH;
812                         var x = p._getX(Math.round(parseFloat(x1, 10) * 100) / 100);
813                         var y = p._getY(Math.round(parseFloat(y1, 10) * 100) / 100);
814                         var w = SVG._getW(Math.round(parseFloat(w1, 10) * 100) / 100);
815                         var d = this.isAbsolute?"C":"c";
816                         var attr = [this.last.x + w, this.last.y, x - w, y, x, y];
817                         for (var i = 0, ii = attr.length; i < ii; i++) {
818                             d += attr[i] + " ";
819                         }
820                         this.last.x = attr[4];
821                         this.last.y = attr[5];
822                         this.last.bx = attr[2];
823                         this.last.by = attr[3];
824                         var oldD = this[0].getAttribute("d") || "";
825                         this[0].setAttribute("d", oldD + d);
826                         this.path.push({type: "cpline", arg: arguments, pos: this.isAbsolute});
827                         return this;
828                     }
829                 };
830                 p.curveTo = function () {
831                     var p = {};
832                     p._getX = this.isAbsolute ? SVG._getX : SVG._getW;
833                     p._getY = this.isAbsolute ? SVG._getY : SVG._getH;
834                     if (arguments.length == 6) {
835                         var d = this.isAbsolute?"C":"c";
836                         for (var i = 0, ii = arguments.length; i < ii; i++) {
837                             d += p[(i % 2 == 0) ? "_getX" : "_getY"](Math.round(parseFloat(arguments[i], 10) * 100) / 100) + " ";
838                         }
839                         this.last.x = p._getX((parseFloat(arguments[4], 10) * 100) / 100);
840                         this.last.y = p._getY((parseFloat(arguments[5], 10) * 100) / 100);
841                         this.last.bx = p._getX((parseFloat(arguments[2], 10) * 100) / 100);
842                         this.last.by = p._getY((parseFloat(arguments[3], 10) * 100) / 100);
843                     } else {
844                         if (arguments.length == 4) {
845                             var d = this.isAbsolute?"S":"s";
846                             for (var i = 0, ii = arguments.length; i < ii; i++) {
847                                 d += p[i % 2 == 0 ? "_getX" : "_getY"]((parseFloat(arguments[i], 10) * 100) / 100) + " ";
848                             }
849                         }
850                         this.last.x = p._getX((parseFloat(arguments[2], 10) * 100) / 100);
851                         this.last.y = p._getY((parseFloat(arguments[3], 10) * 100) / 100);
852                         this.last.bx = p._getX((parseFloat(arguments[0], 10) * 100) / 100);
853                         this.last.by = p._getY((parseFloat(arguments[1], 10) * 100) / 100);
854                     }
855                     var oldD = this[0].getAttribute("d") || "";
856                     this[0].setAttribute("d", oldD + d);
857                     this.path.push({type: "curve", arg: arguments, pos: this.isAbsolute});
858                     return this;
859                 };
860                 p.addRoundedCorner = function (r, dir) {
861                     var R = .5522 * r, rollback = this.isAbsolute, o = this;
862                     if (rollback) {
863                         this.relatively();
864                         rollback = function () {
865                             o.absolutely();
866                         };
867                     } else {
868                         rollback = function () {};
869                     }
870                     var actions = {
871                         l: function () {
872                             return {
873                                 u: function () {
874                                     o.curveTo(-R, 0, -r, -(r - R), -r, -r);
875                                 },
876                                 d: function () {
877                                     o.curveTo(-R, 0, -r, r - R, -r, r);
878                                 }
879                             };
880                         },
881                         r: function () {
882                             return {
883                                 u: function () {
884                                     o.curveTo(R, 0, r, -(r - R), r, -r);
885                                 },
886                                 d: function () {
887                                     o.curveTo(R, 0, r, r - R, r, r);
888                                 }
889                             };
890                         },
891                         u: function () {
892                             return {
893                                 r: function () {
894                                     o.curveTo(0, -R, -(R - r), -r, r, -r);
895                                 },
896                                 l: function () {
897                                     o.curveTo(0, -R, R - r, -r, -r, -r);
898                                 }
899                             };
900                         },
901                         d: function () {
902                             return {
903                                 r: function () {
904                                     o.curveTo(0, R, -(R - r), r, r, r);
905                                 },
906                                 l: function () {
907                                     o.curveTo(0, R, R - r, r, -r, r);
908                                 }
909                             };
910                         }
911                     };
912                     actions[dir[0]]()[dir[1]]();
913                     rollback();
914                     return o;
915                 };
916                 p.andClose = function () {
917                     var oldD = this[0].getAttribute("d") || "";
918                     this[0].setAttribute("d", oldD + "Z ");
919                     this.path.push({type: "end"});
920                     return this;
921                 };
922                 if (typeof pathString == "string") {
923                     pathString = pathString.replace(/([mzlhvcsqta])/ig, ",$1,").replace(/([^,])\-/ig, "$1,-");
924                     path = pathString.split(",");
925                     console.log(params.fill);
926                     console.log(path);
927                     var i = 1, ii = path.length;
928                     while (i < ii) {
929                         switch (path[i]) {
930                             case "M":
931                                 p.absolutely().moveTo(path[++i], path[++i]);
932                                 break;
933                             case "m":
934                                 p.relatively().moveTo(path[++i], path[++i]);
935                                 break;
936                             case "C":
937                                 p.absolutely().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
938                                 break;
939                             case "c":
940                                 p.relatively().curveTo(path[++i], path[++i], path[++i], path[++i], path[++i], path[++i]);
941                                 break;
942                             case "s":
943                                 p.relatively().curveTo(path[++i], path[++i], path[++i], path[++i]);
944                                 break;
945                             case "S":
946                                 p.absolutely().curveTo(path[++i], path[++i], path[++i], path[++i]);
947                                 break;
948                             case "L":
949                                 p.absolutely().lineTo(path[++i], path[++i]);
950                                 break;
951                             case "l":
952                                 p.relatively().lineTo(path[++i], path[++i]);
953                                 break;
954                             case "H":
955                                 p.absolutely().lineTo(path[++i], 0);
956                                 break;
957                             case "h":
958                                 p.relatively().lineTo(path[++i], 0);
959                                 break;
960                             case "V":
961                                 p.absolutely().lineTo(0, path[++i]);
962                                 break;
963                             case "v":
964                                 p.relatively().lineTo(0, path[++i]);
965                                 break;
966                             case "z":
967                                 p.andClose();
968                                 break;
969                         }
970                         i++;
971                     }
972                 }
973                 return p;
974             };
975             var addGrdientFill = function (o, gradient, SVG) {
976                 var el = document.createElementNS(SVG.svgns, gradient.type + "Gradient");
977                 el.id = "raphael-gradient-" + SVG.gradients++;
978                 if (gradient.vector && gradient.vector.length) {
979                     el.setAttribute("x1", gradient.vector[0]);
980                     el.setAttribute("y1", gradient.vector[1]);
981                     el.setAttribute("x2", gradient.vector[2]);
982                     el.setAttribute("y2", gradient.vector[3]);
983                 }
984                 SVG.defs.appendChild(el);
985                 for (var i = 0, ii = gradient.dots.length; i < ii; i++) {
986                     var stop = document.createElementNS(SVG.svgns, "stop");
987                     stop.setAttribute("offset", gradient.dots[i].offset ? gradient.dots[i].offset : (i == 0) ? "0%" : "100%");
988                     stop.setAttribute("stop-color", gradient.dots[i].color || "#fff");
989                     if (typeof gradient.dots[i].opacity != "undefined") {
990                         stop.setAttribute("stop-opacity", gradient.dots[i].opacity);
991                     }
992                     el.appendChild(stop);
993                 };
994                 o.setAttribute("fill", "url(#" + el.id + ")");
995             };
996             var Element = function (node, svg) {
997                 var X = 0,
998                     Y = 0,
999                     Rotation = {deg: 0, x: 0, y: 0},
1000                     Scale = 1,
1001                     tMatrix = null;
1002                 this[0] = node;
1003                 this.rotate = function (deg) {
1004                     var tr =    ((X || Y) ? "translate(" + X + "," + Y + ")" : "") +
1005                                 ((Scale - 1) ? " scale(" + Scale + ")" : "") +
1006                                 (tMatrix ? " " + tMatrix : "");
1007                     var bbox = this.getBBox();
1008                     Rotation.x = (bbox.x + bbox.width / 2);
1009                     Rotation.y = (bbox.y + bbox.height / 2);
1010                     Rotation.deg += deg;
1011                     this[0].setAttribute("transform", tr + " rotate(" + Rotation.deg + " " + Rotation.x + " " + Rotation.y + ")");
1012                     return this;
1013                 };
1014                 this.translate = function (x, y) {
1015                     X += x;
1016                     Y += y;
1017                     var tr =    ((Scale - 1) ? " scale(" + Scale + ")" : "") +
1018                                 (tMatrix ? " " + tMatrix : "") +
1019                                 (Rotation.deg ? " rotate(" + Rotation.deg + " " + (X + Rotation.x) + " " + (Y + Rotation.y) + ")" : "");
1020                     this[0].setAttribute("transform", tr + " translate(" + X + "," + Y + ")");
1021                     Rotation.x += X;
1022                     Rotation.y += Y;
1023                     return this;
1024                 };
1025                 this.scale = function (times) {
1026                     var tr =    ((X || Y) ? "translate(" + X + "," + Y + ")" : "") +
1027                                 (tMatrix ? " " + tMatrix : "");
1028                     Scale *= times;
1029                     this[0].setAttribute("transform", tr + " scale(" + Scale + ")");
1030                     Rotation.x = (this.getBBox().x + this.getBBox().width / 2);
1031                     Rotation.y = (this.getBBox().y + this.getBBox().height / 2);
1032                     var tr =    ((X || Y) ? "translate(" + X + "," + Y + ")" : "") + " scale(" + Scale + ")" +
1033                                 (tMatrix ? " " + tMatrix : "") +
1034                                 (Rotation.deg ? " rotate(" + Rotation.deg + " " + Rotation.x + " " + Rotation.y + ")" : "");
1035                     return this;
1036                 };
1037                 this.matrix = function (xx, xy, yx, yy, dx, dy) {
1038                     var tr =    ((X || Y) ? "translate(" + X + "," + Y + ")" : "") +
1039                                 ((Scale - 1) ? " scale(" + Scale + ")" : "") +
1040                                 (Rotation.deg ? " rotate(" + Rotation.deg + " " + Rotation.x + " " + Rotation.y + ")" : "");
1041                     tMatrix = new Matrix(xx, xy, yx, yy, dx, dy);
1042                     this[0].setAttribute("transform", tr + " " + tMatrix);
1043                     return this;
1044                 };
1045                 this.remove = function () {
1046                     this[0].parentNode.removeChild(this[0]);
1047                 };
1048                 this.getBBox = function () {
1049                     return this[0].getBBox();
1050                 };
1051                 this.attr = function () {
1052                     if (arguments.length == 2) {
1053                         var att = arguments[0],
1054                             value = arguments[1];
1055                         this[att] = value;
1056                         switch (att) {
1057                             case "rx":
1058                             case "cx":
1059                             case "x":
1060                                 this[0].setAttribute(att, svg._getX(value));
1061                                 break;
1062                             case "ry":
1063                             case "cy":
1064                             case "y":
1065                                 this[0].setAttribute(att, svg._getY(value));
1066                                 break;
1067                             case "width":
1068                             case "rx":
1069                                 this[0].setAttribute(att, svg._getW(value));
1070                                 break;
1071                             case "height":
1072                             case "ry":
1073                                 this[0].setAttribute(att, svg._getH(value));
1074                                 break;
1075                             case "gradient":
1076                                 addGrdientFill(this[0], params.gradient, svg);
1077                                 break;
1078                             case "stroke-dasharray":
1079                                 this[0].setAttribute(att, value.replace(" ", ","));
1080                                 break;
1081                             default :
1082                                 var cssrule = att.replace(/(\-.)/g, function (w) {
1083                                     return w.substring(1).toUpperCase();
1084                                 });
1085                                 this[0].style[cssrule] = value;
1086                                 // Need following line for Firefox
1087                                 this[0].setAttribute(att, value);
1088                         }
1089                     } else if (arguments.length = 1 && typeof arguments[0] == "object") {
1090                         var params = arguments[0];
1091                         if (params) {
1092                             for (var attr in params) {
1093                                 if (attr == "stroke-dasharray") {
1094                                     this[0].setAttribute(attr, params[attr].replace(" ", ","));
1095                                 } else {
1096                                     var cssrule = attr.replace(/(\-.)/g, function (w) {
1097                                         return w.substring(1).toUpperCase();
1098                                     });
1099                                     this[0].style[cssrule] = params[attr];
1100                                     // Need following line for Firefox
1101                                     this[0].setAttribute(attr, params[attr]);
1102                                 }
1103                             }
1104                         }
1105                         if (params.gradient) {
1106                             addGrdientFill(this[0], params.gradient, svg);
1107                         }
1108                     }
1109                     return this;
1110                 };
1111                 this.toFront = function () {
1112                     this[0].parentNode.appendChild(this[0]);
1113                 };
1114             };
1115             var theCircle = function (svg, x, y, r) {
1116                 var el = document.createElementNS(svg.svgns, "circle");
1117                 el.setAttribute("cx", svg._getX(x));
1118                 el.setAttribute("cy", svg._getY(y));
1119                 el.setAttribute("r", r);
1120                 el.setAttribute("fill", "none");
1121                 el.setAttribute("stroke", "#000");
1122                 if (svg.canvas) {
1123                     svg.canvas.appendChild(el);
1124                 }
1125                 var res = new Element(el, svg);
1126                 res.type = "circle";
1127                 return res;
1128             };
1129             var theRect = function (svg, x, y, w, h, r) {
1130                 var el = document.createElementNS(svg.svgns, "rect");
1131                 el.setAttribute("x", svg._getX(x));
1132                 el.setAttribute("y", svg._getY(y));
1133                 el.setAttribute("width", svg._getW(w));
1134                 el.setAttribute("height", svg._getH(h));
1135                 if (r) {
1136                     el.setAttribute("rx", r);
1137                     el.setAttribute("ry", r);
1138                 }
1139                 el.setAttribute("fill", "none");
1140                 el.setAttribute("stroke", "#000");
1141                 if (svg.canvas) {
1142                     svg.canvas.appendChild(el);
1143                 }
1144                 var res = new Element(el, svg);
1145                 res.type = "rect";
1146                 return res;
1147             };
1148             var theEllipse = function (svg, x, y, rx, ry) {
1149                 var el = document.createElementNS(svg.svgns, "ellipse");
1150                 el.setAttribute("cx", svg._getX(x));
1151                 el.setAttribute("cy", svg._getY(y));
1152                 el.setAttribute("rx", svg._getW(rx));
1153                 el.setAttribute("ry", svg._getH(ry));
1154                 el.setAttribute("fill", "none");
1155                 el.setAttribute("stroke", "#000");
1156                 if (svg.canvas) {
1157                     svg.canvas.appendChild(el);
1158                 }
1159                 var res = new Element(el, svg);
1160                 res.type = "ellipse";
1161                 return res;
1162             };
1163             var theImage = function (svg, src, x, y, w, h) {
1164                 var el = document.createElementNS(svg.svgns, "image");
1165                 el.setAttribute("x", svg._getX(x));
1166                 el.setAttribute("y", svg._getY(y));
1167                 el.setAttribute("width", svg._getW(w));
1168                 el.setAttribute("height", svg._getH(h));
1169                 el.setAttributeNS(svg.xlink, "href", src);
1170                 if (svg.canvas) {
1171                     svg.canvas.appendChild(el);
1172                 }
1173                 var res = new Element(el, svg);
1174                 res.type = "image";
1175                 return res;
1176             };
1177             var theText = function (svg, x, y, text) {
1178                 var el = document.createElementNS(svg.svgns, "text");
1179                 el.setAttribute("x", x);
1180                 el.setAttribute("y", y);
1181                 el.setAttribute("text-anchor", "middle");
1182                 el.appendChild(document.createTextNode(text));
1183                 if (svg.canvas) {
1184                     svg.canvas.appendChild(el);
1185                 }
1186                 var res = new Element(el, svg);
1187                 res.type = "text";
1188                 return res;
1189             };
1190             var theGroup = function (svg) {
1191                 var el = document.createElementNS(svg.svgns, "g");
1192                 if (svg.canvas) {
1193                     svg.canvas.appendChild(el);
1194                 }
1195                 var i = new Element(el, svg);
1196                 for (var f in svg) {
1197                     if (f[0] != "_" && typeof svg[f] == "function") {
1198                         i[f] = (function (f) {
1199                             return function () {
1200                                 var e = svg[f].apply(svg, arguments);
1201                                 el.appendChild(e[0]);
1202                                 return e;
1203                             };
1204                         })(f);
1205                     }
1206                 }
1207                 i.type = "group";
1208                 return i;
1209             };
1210             r._create = function () {
1211                 // container, width, height
1212                 // x, y, width, height
1213                 if (typeof arguments[0] == "string") {
1214                     var container = document.getElementById(arguments[0]);
1215                     var width = arguments[1];
1216                     var height = arguments[2];
1217                 }
1218                 if (typeof arguments[0] == "object") {
1219                     var container = arguments[0];
1220                     var width = arguments[1];
1221                     var height = arguments[2];
1222                 }
1223                 if (typeof arguments[0] == "number") {
1224                     var container = 1,
1225                         x = arguments[0],
1226                         y = arguments[1],
1227                         width = arguments[2],
1228                         height = arguments[3];
1229                 }
1230                 if (!container) {
1231                     throw new Error("SVG container not found.");
1232                 }
1233                 C.canvas = document.createElementNS(C.svgns, "svg");
1234                 C.canvas.setAttribute("width", width || 320);
1235                 C.width = width || 320;
1236                 C.canvas.setAttribute("height", height || 200);
1237                 C.height = height || 200;
1238                 if (container == 1) {
1239                     document.body.appendChild(C.canvas);
1240                     C.canvas.style.position = "absolute";
1241                     C.canvas.style.left = x + "px";
1242                     C.canvas.style.top = y + "px";
1243                 } else {
1244                     if (container.firstChild) {
1245                         container.insertBefore(C.canvas, container.firstChild);
1246                     } else {
1247                         container.appendChild(C.canvas);
1248                     }
1249                 }
1250                 container = {
1251                     canvas: C.canvas,
1252                     clear: function () {
1253                         while (this.canvas.firstChild) {
1254                             this.canvas.removeChild(this.canvas.firstChild);
1255                         }
1256                         this.defs = document.createElementNS(C.svgns, "defs");
1257                         this.gradients = 0;
1258                         this.canvas.appendChild(this.defs);
1259                     }
1260                 };
1261                 for (var prop in C) {
1262                     if (prop != "create") {
1263                         container[prop] = C[prop];
1264                     }
1265                 }
1266                 container.clear();
1267                 return container;
1268             };
1269             C.svgns = "http://www.w3.org/2000/svg";
1270             C.xlink = "http://www.w3.org/1999/xlink";
1271         }
1272         if (r.vml || r.svg) {
1273             C.circle = function (x, y, r) {
1274                 return theCircle(this, x, y, r);
1275             };
1276             C.rect = function (x, y, w, h, r) {
1277                 return theRect(this, x, y, w, h, r);
1278             };
1279             C.ellipse = function (x, y, rx, ry) {
1280                 return theEllipse(this, x, y, rx, ry);
1281             };
1282             C.path = function (params, pathString) {
1283                 return thePath(params, pathString, this);
1284             };
1285             C.image = function (src, x, y, w, h) {
1286                 return theImage(this, src, x, y, w, h);
1287             };
1288             C.text = function (x, y, text) {
1289                 return theText(this, x, y, text);
1290             };
1291             C.group = function () {
1292                 return theGroup(this);
1293             };
1294             C.linerect = function (x, y, w, h, r) {
1295                 if (r && parseInt(r, 10)) {
1296                     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();
1297                 }
1298                 return this.path({stroke: "#000"}).moveTo(x, y).lineTo(x + w, y).lineTo(x + w, y + h).lineTo(x, y + h).andClose();
1299             };
1300             C.drawGrid = function (x, y, w, h, wv, hv, color) {
1301                 color = color || "#000";
1302                 var res = this.group();
1303                 var params = {stroke: color, "stroke-width": "1px", "stroke-opacity": .3};
1304                 res.rect(x, y, w, h).attr(params);
1305                 for (var i = 1; i < hv; i++) {
1306                     var p = res.path(params);
1307                     p.moveTo(x, y + i * Math.round(h / hv)).lineTo(x + w, y + i * Math.round(h / hv));
1308                 }
1309                 for (var i = 1; i < wv; i++) {
1310                     res.path(params).moveTo(x + i * Math.round(w / wv), y).lineTo(x + i * Math.round(w / wv), y + h);
1311                 }
1312                 return res;
1313             };
1314             C.setGrid = function (xmin, ymin, xmax, ymax, w, h) {
1315                 var xc = (xmax - xmin) / w;
1316                 var yc = (ymax - ymin) / h;
1317                 this._getX = function (x) {
1318                     return xmin + x * xc;
1319                 };
1320                 this._getY = function (y) {
1321                     return ymin + y * yc;
1322                 };
1323                 this._getW = function (w) {
1324                     return w * xc;
1325                 };
1326                 this._getH = function (h) {
1327                     return h * yc;
1328                 };
1329             };
1330             C.clearGrid = function () {
1331                 this._getX = this._getY = this._getW = this._getH = function (x) { return x; };
1332             };
1333             C.safari = function () {
1334                 if (this.type == "SVG") {
1335                     var rect = C.rect(0, 0, C.width, C.height).attr("stroke-width", 0);
1336                     setTimeout(function () {rect.remove();}, 0);
1337                 }
1338             };
1339             Raphael = function () {
1340                 return r._create.apply(r, arguments);
1341             };
1342             return r._create.apply(r, args);
1343         } else {
1344             return null;
1345         }
1346     })(arguments.callee, arguments);
1347 }
1348
1349
1350 Raphael.type = (!(window.SVGPreserveAspectRatio && window.SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN == 2) && !(window.CanvasRenderingContext2D)) ? "VML" : "SVG";
1351 Raphael.vml = !(Raphael.svg = (Raphael.type == "SVG"));
1352 if (!(window.SVGPreserveAspectRatio && window.SVGPreserveAspectRatio.SVG_PRESERVEASPECTRATIO_XMINYMIN == 2) && window.CanvasRenderingContext2D) {
1353     Raphael.type = "Canvas only";
1354     Raphael.vml = Raphael.svg = false;
1355 }
1356 Raphael.toString = function () {
1357     return "You browser supports " + this.type;
1358 };