1define(["./raphael.core"], function(R) {
2    if (R && !R.svg) {
3        return;
4    }
5
6    var has = "hasOwnProperty",
7        Str = String,
8        toFloat = parseFloat,
9        toInt = parseInt,
10        math = Math,
11        mmax = math.max,
12        abs = math.abs,
13        pow = math.pow,
14        separator = /[, ]+/,
15        eve = R.eve,
16        E = "",
17        S = " ";
18    var xlink = "http://www.w3.org/1999/xlink",
19        markers = {
20            block: "M5,0 0,2.5 5,5z",
21            classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z",
22            diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z",
23            open: "M6,1 1,3.5 6,6",
24            oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z"
25        },
26        markerCounter = {};
27    R.toString = function () {
28        return  "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version;
29    };
30    var $ = function (el, attr) {
31        if (attr) {
32            if (typeof el == "string") {
33                el = $(el);
34            }
35            for (var key in attr) if (attr[has](key)) {
36                if (key.substring(0, 6) == "xlink:") {
37                    el.setAttributeNS(xlink, key.substring(6), Str(attr[key]));
38                } else {
39                    el.setAttribute(key, Str(attr[key]));
40                }
41            }
42        } else {
43            el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
44            el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)");
45        }
46        return el;
47    },
48    addGradientFill = function (element, gradient) {
49        var type = "linear",
50            id = element.id + gradient,
51            fx = .5, fy = .5,
52            o = element.node,
53            SVG = element.paper,
54            s = o.style,
55            el = R._g.doc.getElementById(id);
56        if (!el) {
57            gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) {
58                type = "radial";
59                if (_fx && _fy) {
60                    fx = toFloat(_fx);
61                    fy = toFloat(_fy);
62                    var dir = ((fy > .5) * 2 - 1);
63                    pow(fx - .5, 2) + pow(fy - .5, 2) > .25 &&
64                        (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) &&
65                        fy != .5 &&
66                        (fy = fy.toFixed(5) - 1e-5 * dir);
67                }
68                return E;
69            });
70            gradient = gradient.split(/\s*\-\s*/);
71            if (type == "linear") {
72                var angle = gradient.shift();
73                angle = -toFloat(angle);
74                if (isNaN(angle)) {
75                    return null;
76                }
77                var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))],
78                    max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1);
79                vector[2] *= max;
80                vector[3] *= max;
81                if (vector[2] < 0) {
82                    vector[0] = -vector[2];
83                    vector[2] = 0;
84                }
85                if (vector[3] < 0) {
86                    vector[1] = -vector[3];
87                    vector[3] = 0;
88                }
89            }
90            var dots = R._parseDots(gradient);
91            if (!dots) {
92                return null;
93            }
94            id = id.replace(/[\(\)\s,\xb0#]/g, "_");
95
96            if (element.gradient && id != element.gradient.id) {
97                SVG.defs.removeChild(element.gradient);
98                delete element.gradient;
99            }
100
101            if (!element.gradient) {
102                el = $(type + "Gradient", {id: id});
103                element.gradient = el;
104                $(el, type == "radial" ? {
105                    fx: fx,
106                    fy: fy
107                } : {
108                    x1: vector[0],
109                    y1: vector[1],
110                    x2: vector[2],
111                    y2: vector[3],
112                    gradientTransform: element.matrix.invert()
113                });
114                SVG.defs.appendChild(el);
115                for (var i = 0, ii = dots.length; i < ii; i++) {
116                    el.appendChild($("stop", {
117                        offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
118                        "stop-color": dots[i].color || "#fff",
119                        "stop-opacity": isFinite(dots[i].opacity) ? dots[i].opacity : 1
120                    }));
121                }
122            }
123        }
124        $(o, {
125            fill: fillurl(id),
126            opacity: 1,
127            "fill-opacity": 1
128        });
129        s.fill = E;
130        s.opacity = 1;
131        s.fillOpacity = 1;
132        return 1;
133    },
134    isIE9or10 = function () {
135      var mode = document.documentMode;
136      return mode && (mode === 9 || mode === 10);
137    },
138    fillurl = function (id) {
139      if (isIE9or10()) {
140          return "url('#" + id + "')";
141      }
142      var location = document.location;
143      var locationString = (
144          location.protocol + '//' +
145          location.host +
146          location.pathname +
147          location.search
148      );
149      return "url('" + locationString + "#" + id + "')";
150    },
151    updatePosition = function (o) {
152        var bbox = o.getBBox(1);
153        $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
154    },
155    addArrow = function (o, value, isEnd) {
156        if (o.type == "path") {
157            var values = Str(value).toLowerCase().split("-"),
158                p = o.paper,
159                se = isEnd ? "end" : "start",
160                node = o.node,
161                attrs = o.attrs,
162                stroke = attrs["stroke-width"],
163                i = values.length,
164                type = "classic",
165                from,
166                to,
167                dx,
168                refX,
169                attr,
170                w = 3,
171                h = 3,
172                t = 5;
173            while (i--) {
174                switch (values[i]) {
175                    case "block":
176                    case "classic":
177                    case "oval":
178                    case "diamond":
179                    case "open":
180                    case "none":
181                        type = values[i];
182                        break;
183                    case "wide": h = 5; break;
184                    case "narrow": h = 2; break;
185                    case "long": w = 5; break;
186                    case "short": w = 2; break;
187                }
188            }
189            if (type == "open") {
190                w += 2;
191                h += 2;
192                t += 2;
193                dx = 1;
194                refX = isEnd ? 4 : 1;
195                attr = {
196                    fill: "none",
197                    stroke: attrs.stroke
198                };
199            } else {
200                refX = dx = w / 2;
201                attr = {
202                    fill: attrs.stroke,
203                    stroke: "none"
204                };
205            }
206            if (o._.arrows) {
207                if (isEnd) {
208                    o._.arrows.endPath && markerCounter[o._.arrows.endPath]--;
209                    o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--;
210                } else {
211                    o._.arrows.startPath && markerCounter[o._.arrows.startPath]--;
212                    o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--;
213                }
214            } else {
215                o._.arrows = {};
216            }
217            if (type != "none") {
218                var pathId = "raphael-marker-" + type,
219                    markerId = "raphael-marker-" + se + type + w + h + "-obj" + o.id;
220                if (!R._g.doc.getElementById(pathId)) {
221                    p.defs.appendChild($($("path"), {
222                        "stroke-linecap": "round",
223                        d: markers[type],
224                        id: pathId
225                    }));
226                    markerCounter[pathId] = 1;
227                } else {
228                    markerCounter[pathId]++;
229                }
230                var marker = R._g.doc.getElementById(markerId),
231                    use;
232                if (!marker) {
233                    marker = $($("marker"), {
234                        id: markerId,
235                        markerHeight: h,
236                        markerWidth: w,
237                        orient: "auto",
238                        refX: refX,
239                        refY: h / 2
240                    });
241                    use = $($("use"), {
242                        "xlink:href": "#" + pathId,
243                        transform: (isEnd ? "rotate(180 " + w / 2 + " " + h / 2 + ") " : E) + "scale(" + w / t + "," + h / t + ")",
244                        "stroke-width": (1 / ((w / t + h / t) / 2)).toFixed(4)
245                    });
246                    marker.appendChild(use);
247                    p.defs.appendChild(marker);
248                    markerCounter[markerId] = 1;
249                } else {
250                    markerCounter[markerId]++;
251                    use = marker.getElementsByTagName("use")[0];
252                }
253                $(use, attr);
254                var delta = dx * (type != "diamond" && type != "oval");
255                if (isEnd) {
256                    from = o._.arrows.startdx * stroke || 0;
257                    to = R.getTotalLength(attrs.path) - delta * stroke;
258                } else {
259                    from = delta * stroke;
260                    to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
261                }
262                attr = {};
263                attr["marker-" + se] = "url(#" + markerId + ")";
264                if (to || from) {
265                    attr.d = R.getSubpath(attrs.path, from, to);
266                }
267                $(node, attr);
268                o._.arrows[se + "Path"] = pathId;
269                o._.arrows[se + "Marker"] = markerId;
270                o._.arrows[se + "dx"] = delta;
271                o._.arrows[se + "Type"] = type;
272                o._.arrows[se + "String"] = value;
273            } else {
274                if (isEnd) {
275                    from = o._.arrows.startdx * stroke || 0;
276                    to = R.getTotalLength(attrs.path) - from;
277                } else {
278                    from = 0;
279                    to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0);
280                }
281                o._.arrows[se + "Path"] && $(node, {d: R.getSubpath(attrs.path, from, to)});
282                delete o._.arrows[se + "Path"];
283                delete o._.arrows[se + "Marker"];
284                delete o._.arrows[se + "dx"];
285                delete o._.arrows[se + "Type"];
286                delete o._.arrows[se + "String"];
287            }
288            for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
289                var item = R._g.doc.getElementById(attr);
290                item && item.parentNode.removeChild(item);
291            }
292        }
293    },
294    dasharray = {
295        "-": [3, 1],
296        ".": [1, 1],
297        "-.": [3, 1, 1, 1],
298        "-..": [3, 1, 1, 1, 1, 1],
299        ". ": [1, 3],
300        "- ": [4, 3],
301        "--": [8, 3],
302        "- .": [4, 3, 1, 3],
303        "--.": [8, 3, 1, 3],
304        "--..": [8, 3, 1, 3, 1, 3]
305    },
306    addDashes = function (o, value, params) {
307        value = dasharray[Str(value).toLowerCase()];
308        if (value) {
309            var width = o.attrs["stroke-width"] || "1",
310                butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
311                dashes = [],
312                i = value.length;
313            while (i--) {
314                dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
315            }
316            $(o.node, {"stroke-dasharray": dashes.join(",")});
317        }
318        else {
319          $(o.node, {"stroke-dasharray": "none"});
320        }
321    },
322    setFillAndStroke = function (o, params) {
323        var node = o.node,
324            attrs = o.attrs,
325            vis = node.style.visibility;
326        node.style.visibility = "hidden";
327        for (var att in params) {
328            if (params[has](att)) {
329                if (!R._availableAttrs[has](att)) {
330                    continue;
331                }
332                var value = params[att];
333                attrs[att] = value;
334                switch (att) {
335                    case "blur":
336                        o.blur(value);
337                        break;
338                    case "title":
339                        var title = node.getElementsByTagName("title");
340
341                        // Use the existing <title>.
342                        if (title.length && (title = title[0])) {
343                          title.firstChild.nodeValue = value;
344                        } else {
345                          title = $("title");
346                          var val = R._g.doc.createTextNode(value);
347                          title.appendChild(val);
348                          node.appendChild(title);
349                        }
350                        break;
351                    case "href":
352                    case "target":
353                        var pn = node.parentNode;
354                        if (pn.tagName.toLowerCase() != "a") {
355                            var hl = $("a");
356                            pn.insertBefore(hl, node);
357                            hl.appendChild(node);
358                            pn = hl;
359                        }
360                        if (att == "target") {
361                            pn.setAttributeNS(xlink, "show", value == "blank" ? "new" : value);
362                        } else {
363                            pn.setAttributeNS(xlink, att, value);
364                        }
365                        break;
366                    case "cursor":
367                        node.style.cursor = value;
368                        break;
369                    case "transform":
370                        o.transform(value);
371                        break;
372                    case "arrow-start":
373                        addArrow(o, value);
374                        break;
375                    case "arrow-end":
376                        addArrow(o, value, 1);
377                        break;
378                    case "clip-rect":
379                        var rect = Str(value).split(separator);
380                        if (rect.length == 4) {
381                            o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
382                            var el = $("clipPath"),
383                                rc = $("rect");
384                            el.id = R.createUUID();
385                            $(rc, {
386                                x: rect[0],
387                                y: rect[1],
388                                width: rect[2],
389                                height: rect[3]
390                            });
391                            el.appendChild(rc);
392                            o.paper.defs.appendChild(el);
393                            $(node, {"clip-path": "url(#" + el.id + ")"});
394                            o.clip = rc;
395                        }
396                        if (!value) {
397                            var path = node.getAttribute("clip-path");
398                            if (path) {
399                                var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
400                                clip && clip.parentNode.removeChild(clip);
401                                $(node, {"clip-path": E});
402                                delete o.clip;
403                            }
404                        }
405                    break;
406                    case "path":
407                        if (o.type == "path") {
408                            $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"});
409                            o._.dirty = 1;
410                            if (o._.arrows) {
411                                "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
412                                "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
413                            }
414                        }
415                        break;
416                    case "width":
417                        node.setAttribute(att, value);
418                        o._.dirty = 1;
419                        if (attrs.fx) {
420                            att = "x";
421                            value = attrs.x;
422                        } else {
423                            break;
424                        }
425                    case "x":
426                        if (attrs.fx) {
427                            value = -attrs.x - (attrs.width || 0);
428                        }
429                    case "rx":
430                        if (att == "rx" && o.type == "rect") {
431                            break;
432                        }
433                    case "cx":
434                        node.setAttribute(att, value);
435                        o.pattern && updatePosition(o);
436                        o._.dirty = 1;
437                        break;
438                    case "height":
439                        node.setAttribute(att, value);
440                        o._.dirty = 1;
441                        if (attrs.fy) {
442                            att = "y";
443                            value = attrs.y;
444                        } else {
445                            break;
446                        }
447                    case "y":
448                        if (attrs.fy) {
449                            value = -attrs.y - (attrs.height || 0);
450                        }
451                    case "ry":
452                        if (att == "ry" && o.type == "rect") {
453                            break;
454                        }
455                    case "cy":
456                        node.setAttribute(att, value);
457                        o.pattern && updatePosition(o);
458                        o._.dirty = 1;
459                        break;
460                    case "r":
461                        if (o.type == "rect") {
462                            $(node, {rx: value, ry: value});
463                        } else {
464                            node.setAttribute(att, value);
465                        }
466                        o._.dirty = 1;
467                        break;
468                    case "src":
469                        if (o.type == "image") {
470                            node.setAttributeNS(xlink, "href", value);
471                        }
472                        break;
473                    case "stroke-width":
474                        if (o._.sx != 1 || o._.sy != 1) {
475                            value /= mmax(abs(o._.sx), abs(o._.sy)) || 1;
476                        }
477                        node.setAttribute(att, value);
478                        if (attrs["stroke-dasharray"]) {
479                            addDashes(o, attrs["stroke-dasharray"], params);
480                        }
481                        if (o._.arrows) {
482                            "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
483                            "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
484                        }
485                        break;
486                    case "stroke-dasharray":
487                        addDashes(o, value, params);
488                        break;
489                    case "fill":
490                        var isURL = Str(value).match(R._ISURL);
491                        if (isURL) {
492                            el = $("pattern");
493                            var ig = $("image");
494                            el.id = R.createUUID();
495                            $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
496                            $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
497                            el.appendChild(ig);
498
499                            (function (el) {
500                                R._preload(isURL[1], function () {
501                                    var w = this.offsetWidth,
502                                        h = this.offsetHeight;
503                                    $(el, {width: w, height: h});
504                                    $(ig, {width: w, height: h});
505                                });
506                            })(el);
507                            o.paper.defs.appendChild(el);
508                            $(node, {fill: "url(#" + el.id + ")"});
509                            o.pattern = el;
510                            o.pattern && updatePosition(o);
511                            break;
512                        }
513                        var clr = R.getRGB(value);
514                        if (!clr.error) {
515                            delete params.gradient;
516                            delete attrs.gradient;
517                            !R.is(attrs.opacity, "undefined") &&
518                                R.is(params.opacity, "undefined") &&
519                                $(node, {opacity: attrs.opacity});
520                            !R.is(attrs["fill-opacity"], "undefined") &&
521                                R.is(params["fill-opacity"], "undefined") &&
522                                $(node, {"fill-opacity": attrs["fill-opacity"]});
523                        } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
524                            if ("opacity" in attrs || "fill-opacity" in attrs) {
525                                var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
526                                if (gradient) {
527                                    var stops = gradient.getElementsByTagName("stop");
528                                    $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
529                                }
530                            }
531                            attrs.gradient = value;
532                            attrs.fill = "none";
533                            break;
534                        }
535                        clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
536                    case "stroke":
537                        clr = R.getRGB(value);
538                        node.setAttribute(att, clr.hex);
539                        att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity});
540                        if (att == "stroke" && o._.arrows) {
541                            "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
542                            "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1);
543                        }
544                        break;
545                    case "gradient":
546                        (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value);
547                        break;
548                    case "opacity":
549                        if (attrs.gradient && !attrs[has]("stroke-opacity")) {
550                            $(node, {"stroke-opacity": value > 1 ? value / 100 : value});
551                        }
552                        // fall
553                    case "fill-opacity":
554                        if (attrs.gradient) {
555                            gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
556                            if (gradient) {
557                                stops = gradient.getElementsByTagName("stop");
558                                $(stops[stops.length - 1], {"stop-opacity": value});
559                            }
560                            break;
561                        }
562                    default:
563                        att == "font-size" && (value = toInt(value, 10) + "px");
564                        var cssrule = att.replace(/(\-.)/g, function (w) {
565                            return w.substring(1).toUpperCase();
566                        });
567                        node.style[cssrule] = value;
568                        o._.dirty = 1;
569                        node.setAttribute(att, value);
570                        break;
571                }
572            }
573        }
574
575        tuneText(o, params);
576        node.style.visibility = vis;
577    },
578    leading = 1.2,
579    tuneText = function (el, params) {
580        if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
581            return;
582        }
583        var a = el.attrs,
584            node = el.node,
585            fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10;
586
587        if (params[has]("text")) {
588            a.text = params.text;
589            while (node.firstChild) {
590                node.removeChild(node.firstChild);
591            }
592            var texts = Str(params.text).split("\n"),
593                tspans = [],
594                tspan;
595            for (var i = 0, ii = texts.length; i < ii; i++) {
596                tspan = $("tspan");
597                i && $(tspan, {dy: fontSize * leading, x: a.x});
598                tspan.appendChild(R._g.doc.createTextNode(texts[i]));
599                node.appendChild(tspan);
600                tspans[i] = tspan;
601            }
602        } else {
603            tspans = node.getElementsByTagName("tspan");
604            for (i = 0, ii = tspans.length; i < ii; i++) if (i) {
605                $(tspans[i], {dy: fontSize * leading, x: a.x});
606            } else {
607                $(tspans[0], {dy: 0});
608            }
609        }
610        $(node, {x: a.x, y: a.y});
611        el._.dirty = 1;
612        var bb = el._getBBox(),
613            dif = a.y - (bb.y + bb.height / 2);
614        dif && R.is(dif, "finite") && $(tspans[0], {dy: dif});
615    },
616    getRealNode = function (node) {
617        if (node.parentNode && node.parentNode.tagName.toLowerCase() === "a") {
618            return node.parentNode;
619        } else {
620            return node;
621        }
622    },
623    Element = function (node, svg) {
624        var X = 0,
625            Y = 0;
626        /*\
627         * Element.node
628         [ property (object) ]
629         **
630         * Gives you a reference to the DOM object, so you can assign event handlers or just mess around.
631         **
632         * Note: Don’t mess with it.
633         > Usage
634         | // draw a circle at coordinate 10,10 with radius of 10
635         | var c = paper.circle(10, 10, 10);
636         | c.node.onclick = function () {
637         |     c.attr("fill", "red");
638         | };
639        \*/
640        this[0] = this.node = node;
641        /*\
642         * Element.raphael
643         [ property (object) ]
644         **
645         * Internal reference to @Raphael object. In case it is not available.
646         > Usage
647         | Raphael.el.red = function () {
648         |     var hsb = this.paper.raphael.rgb2hsb(this.attr("fill"));
649         |     hsb.h = 1;
650         |     this.attr({fill: this.paper.raphael.hsb2rgb(hsb).hex});
651         | }
652        \*/
653        node.raphael = true;
654        /*\
655         * Element.id
656         [ property (number) ]
657         **
658         * Unique id of the element. Especially useful when you want to listen to events of the element,
659         * because all events are fired in format `<module>.<action>.<id>`. Also useful for @Paper.getById method.
660        \*/
661        this.id = guid();
662        node.raphaelid = this.id;
663
664        /**
665        * Method that returns a 5 letter/digit id, enough for 36^5 = 60466176 elements
666        * @returns {string} id
667        */
668        function guid() {
669            return ("0000" + (Math.random()*Math.pow(36,5) << 0).toString(36)).slice(-5);
670        }
671
672        this.matrix = R.matrix();
673        this.realPath = null;
674        /*\
675         * Element.paper
676         [ property (object) ]
677         **
678         * Internal reference to “paper” where object drawn. Mainly for use in plugins and element extensions.
679         > Usage
680         | Raphael.el.cross = function () {
681         |     this.attr({fill: "red"});
682         |     this.paper.path("M10,10L50,50M50,10L10,50")
683         |         .attr({stroke: "red"});
684         | }
685        \*/
686        this.paper = svg;
687        this.attrs = this.attrs || {};
688        this._ = {
689            transform: [],
690            sx: 1,
691            sy: 1,
692            deg: 0,
693            dx: 0,
694            dy: 0,
695            dirty: 1
696        };
697        !svg.bottom && (svg.bottom = this);
698        /*\
699         * Element.prev
700         [ property (object) ]
701         **
702         * Reference to the previous element in the hierarchy.
703        \*/
704        this.prev = svg.top;
705        svg.top && (svg.top.next = this);
706        svg.top = this;
707        /*\
708         * Element.next
709         [ property (object) ]
710         **
711         * Reference to the next element in the hierarchy.
712        \*/
713        this.next = null;
714    },
715    elproto = R.el;
716
717    Element.prototype = elproto;
718    elproto.constructor = Element;
719
720    R._engine.path = function (pathString, SVG) {
721        var el = $("path");
722        SVG.canvas && SVG.canvas.appendChild(el);
723        var p = new Element(el, SVG);
724        p.type = "path";
725        setFillAndStroke(p, {
726            fill: "none",
727            stroke: "#000",
728            path: pathString
729        });
730        return p;
731    };
732    /*\
733     * Element.rotate
734     [ method ]
735     **
736     * Deprecated! Use @Element.transform instead.
737     * Adds rotation by given angle around given point to the list of
738     * transformations of the element.
739     > Parameters
740     - deg (number) angle in degrees
741     - cx (number) #optional x coordinate of the centre of rotation
742     - cy (number) #optional y coordinate of the centre of rotation
743     * If cx & cy aren’t specified centre of the shape is used as a point of rotation.
744     = (object) @Element
745    \*/
746    elproto.rotate = function (deg, cx, cy) {
747        if (this.removed) {
748            return this;
749        }
750        deg = Str(deg).split(separator);
751        if (deg.length - 1) {
752            cx = toFloat(deg[1]);
753            cy = toFloat(deg[2]);
754        }
755        deg = toFloat(deg[0]);
756        (cy == null) && (cx = cy);
757        if (cx == null || cy == null) {
758            var bbox = this.getBBox(1);
759            cx = bbox.x + bbox.width / 2;
760            cy = bbox.y + bbox.height / 2;
761        }
762        this.transform(this._.transform.concat([["r", deg, cx, cy]]));
763        return this;
764    };
765    /*\
766     * Element.scale
767     [ method ]
768     **
769     * Deprecated! Use @Element.transform instead.
770     * Adds scale by given amount relative to given point to the list of
771     * transformations of the element.
772     > Parameters
773     - sx (number) horisontal scale amount
774     - sy (number) vertical scale amount
775     - cx (number) #optional x coordinate of the centre of scale
776     - cy (number) #optional y coordinate of the centre of scale
777     * If cx & cy aren’t specified centre of the shape is used instead.
778     = (object) @Element
779    \*/
780    elproto.scale = function (sx, sy, cx, cy) {
781        if (this.removed) {
782            return this;
783        }
784        sx = Str(sx).split(separator);
785        if (sx.length - 1) {
786            sy = toFloat(sx[1]);
787            cx = toFloat(sx[2]);
788            cy = toFloat(sx[3]);
789        }
790        sx = toFloat(sx[0]);
791        (sy == null) && (sy = sx);
792        (cy == null) && (cx = cy);
793        if (cx == null || cy == null) {
794            var bbox = this.getBBox(1);
795        }
796        cx = cx == null ? bbox.x + bbox.width / 2 : cx;
797        cy = cy == null ? bbox.y + bbox.height / 2 : cy;
798        this.transform(this._.transform.concat([["s", sx, sy, cx, cy]]));
799        return this;
800    };
801    /*\
802     * Element.translate
803     [ method ]
804     **
805     * Deprecated! Use @Element.transform instead.
806     * Adds translation by given amount to the list of transformations of the element.
807     > Parameters
808     - dx (number) horisontal shift
809     - dy (number) vertical shift
810     = (object) @Element
811    \*/
812    elproto.translate = function (dx, dy) {
813        if (this.removed) {
814            return this;
815        }
816        dx = Str(dx).split(separator);
817        if (dx.length - 1) {
818            dy = toFloat(dx[1]);
819        }
820        dx = toFloat(dx[0]) || 0;
821        dy = +dy || 0;
822        this.transform(this._.transform.concat([["t", dx, dy]]));
823        return this;
824    };
825    /*\
826     * Element.transform
827     [ method ]
828     **
829     * Adds transformation to the element which is separate to other attributes,
830     * i.e. translation doesn’t change `x` or `y` of the rectange. The format
831     * of transformation string is similar to the path string syntax:
832     | "t100,100r30,100,100s2,2,100,100r45s1.5"
833     * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for
834     * scale and `m` is for matrix.
835     *
836     * There are also alternative “absolute” translation, rotation and scale: `T`, `R` and `S`. They will not take previous transformation into account. For example, `...T100,0` will always move element 100 px horisontally, while `...t100,0` could move it vertically if there is `r90` before. Just compare results of `r90t100,0` and `r90T100,0`.
837     *
838     * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100;
839     * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin
840     * coordinates as optional parameters, the default is the centre point of the element.
841     * Matrix accepts six parameters.
842     > Usage
843     | var el = paper.rect(10, 20, 300, 200);
844     | // translate 100, 100, rotate 45°, translate -100, 0
845     | el.transform("t100,100r45t-100,0");
846     | // if you want you can append or prepend transformations
847     | el.transform("...t50,50");
848     | el.transform("s2...");
849     | // or even wrap
850     | el.transform("t50,50...t-50-50");
851     | // to reset transformation call method with empty string
852     | el.transform("");
853     | // to get current value call it without parameters
854     | console.log(el.transform());
855     > Parameters
856     - tstr (string) #optional transformation string
857     * If tstr isn’t specified
858     = (string) current transformation string
859     * else
860     = (object) @Element
861    \*/
862    elproto.transform = function (tstr) {
863        var _ = this._;
864        if (tstr == null) {
865            return _.transform;
866        }
867        R._extractTransform(this, tstr);
868
869        this.clip && $(this.clip, {transform: this.matrix.invert()});
870        this.pattern && updatePosition(this);
871        this.node && $(this.node, {transform: this.matrix});
872
873        if (_.sx != 1 || _.sy != 1) {
874            var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1;
875            this.attr({"stroke-width": sw});
876        }
877
878        return this;
879    };
880    /*\
881     * Element.hide
882     [ method ]
883     **
884     * Makes element invisible. See @Element.show.
885     = (object) @Element
886    \*/
887    elproto.hide = function () {
888        if(!this.removed) this.node.style.display = "none";
889        return this;
890    };
891    /*\
892     * Element.show
893     [ method ]
894     **
895     * Makes element visible. See @Element.hide.
896     = (object) @Element
897    \*/
898    elproto.show = function () {
899        if(!this.removed) this.node.style.display = "";
900        return this;
901    };
902    /*\
903     * Element.remove
904     [ method ]
905     **
906     * Removes element from the paper.
907    \*/
908    elproto.remove = function () {
909        var node = getRealNode(this.node);
910        if (this.removed || !node.parentNode) {
911            return;
912        }
913        var paper = this.paper;
914        paper.__set__ && paper.__set__.exclude(this);
915        eve.unbind("raphael.*.*." + this.id);
916        if (this.gradient) {
917            paper.defs.removeChild(this.gradient);
918        }
919        R._tear(this, paper);
920
921        node.parentNode.removeChild(node);
922
923        // Remove custom data for element
924        this.removeData();
925
926        for (var i in this) {
927            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
928        }
929        this.removed = true;
930    };
931    elproto._getBBox = function () {
932        if (this.node.style.display == "none") {
933            this.show();
934            var hide = true;
935        }
936        var canvasHidden = false,
937            containerStyle;
938        if (this.paper.canvas.parentElement) {
939          containerStyle = this.paper.canvas.parentElement.style;
940        } //IE10+ can't find parentElement
941        else if (this.paper.canvas.parentNode) {
942          containerStyle = this.paper.canvas.parentNode.style;
943        }
944
945        if(containerStyle && containerStyle.display == "none") {
946          canvasHidden = true;
947          containerStyle.display = "";
948        }
949        var bbox = {};
950        try {
951            bbox = this.node.getBBox();
952        } catch(e) {
953            // Firefox 3.0.x, 25.0.1 (probably more versions affected) play badly here - possible fix
954            bbox = {
955                x: this.node.clientLeft,
956                y: this.node.clientTop,
957                width: this.node.clientWidth,
958                height: this.node.clientHeight
959            }
960        } finally {
961            bbox = bbox || {};
962            if(canvasHidden){
963              containerStyle.display = "none";
964            }
965        }
966        hide && this.hide();
967        return bbox;
968    };
969    /*\
970     * Element.attr
971     [ method ]
972     **
973     * Sets the attributes of the element.
974     > Parameters
975     - attrName (string) attribute’s name
976     - value (string) value
977     * or
978     - params (object) object of name/value pairs
979     * or
980     - attrName (string) attribute’s name
981     * or
982     - attrNames (array) in this case method returns array of current values for given attribute names
983     = (object) @Element if attrsName & value or params are passed in.
984     = (...) value of the attribute if only attrsName is passed in.
985     = (array) array of values of the attribute if attrsNames is passed in.
986     = (object) object of attributes if nothing is passed in.
987     > Possible parameters
988     # <p>Please refer to the <a href="http://www.w3.org/TR/SVG/" title="The W3C Recommendation for the SVG language describes these properties in detail.">SVG specification</a> for an explanation of these parameters.</p>
989     o arrow-end (string) arrowhead on the end of the path. The format for string is `<type>[-<width>[-<length>]]`. Possible types: `classic`, `block`, `open`, `oval`, `diamond`, `none`, width: `wide`, `narrow`, `medium`, length: `long`, `short`, `midium`.
990     o clip-rect (string) comma or space separated values: x, y, width and height
991     o cursor (string) CSS type of the cursor
992     o cx (number) the x-axis coordinate of the center of the circle, or ellipse
993     o cy (number) the y-axis coordinate of the center of the circle, or ellipse
994     o fill (string) colour, gradient or image
995     o fill-opacity (number)
996     o font (string)
997     o font-family (string)
998     o font-size (number) font size in pixels
999     o font-weight (string)
1000     o height (number)
1001     o href (string) URL, if specified element behaves as hyperlink
1002     o opacity (number)
1003     o path (string) SVG path string format
1004     o r (number) radius of the circle, ellipse or rounded corner on the rect
1005     o rx (number) horisontal radius of the ellipse
1006     o ry (number) vertical radius of the ellipse
1007     o src (string) image URL, only works for @Element.image element
1008     o stroke (string) stroke colour
1009     o stroke-dasharray (string) [“”, “none”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”]
1010     o stroke-linecap (string) [“`butt`”, “`square`”, “`round`”]
1011     o stroke-linejoin (string) [“`bevel`”, “`round`”, “`miter`”]
1012     o stroke-miterlimit (number)
1013     o stroke-opacity (number)
1014     o stroke-width (number) stroke width in pixels, default is '1'
1015     o target (string) used with href
1016     o text (string) contents of the text element. Use `\n` for multiline text
1017     o text-anchor (string) [“`start`”, “`middle`”, “`end`”], default is “`middle`”
1018     o title (string) will create tooltip with a given text
1019     o transform (string) see @Element.transform
1020     o width (number)
1021     o x (number)
1022     o y (number)
1023     > Gradients
1024     * Linear gradient format: “`‹angle›-‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`90-#fff-#000`” – 90°
1025     * gradient from white to black or “`0-#fff-#f00:20-#000`” – 0° gradient from white via red (at 20%) to black.
1026     *
1027     * radial gradient: “`r[(‹fx›, ‹fy›)]‹colour›[-‹colour›[:‹offset›]]*-‹colour›`”, example: “`r#fff-#000`” –
1028     * gradient from white to black or “`r(0.25, 0.75)#fff-#000`” – gradient from white to black with focus point
1029     * at 0.25, 0.75. Focus point coordinates are in 0..1 range. Radial gradients can only be applied to circles and ellipses.
1030     > Path String
1031     # <p>Please refer to <a href="http://www.w3.org/TR/SVG/paths.html#PathData" title="Details of a path’s data attribute’s format are described in the SVG specification.">SVG documentation regarding path string</a>. Raphaël fully supports it.</p>
1032     > Colour Parsing
1033     # <ul>
1034     #     <li>Colour name (“<code>red</code>”, “<code>green</code>”, “<code>cornflowerblue</code>”, etc)</li>
1035     #     <li>#••• — shortened HTML colour: (“<code>#000</code>”, “<code>#fc0</code>”, etc)</li>
1036     #     <li>#•••••• — full length HTML colour: (“<code>#000000</code>”, “<code>#bd2300</code>”)</li>
1037     #     <li>rgb(•••, •••, •••) — red, green and blue channels’ values: (“<code>rgb(200,&nbsp;100,&nbsp;0)</code>”)</li>
1038     #     <li>rgb(•••%, •••%, •••%) — same as above, but in %: (“<code>rgb(100%,&nbsp;175%,&nbsp;0%)</code>”)</li>
1039     #     <li>rgba(•••, •••, •••, •••) — red, green and blue channels’ values: (“<code>rgba(200,&nbsp;100,&nbsp;0, .5)</code>”)</li>
1040     #     <li>rgba(•••%, •••%, •••%, •••%) — same as above, but in %: (“<code>rgba(100%,&nbsp;175%,&nbsp;0%, 50%)</code>”)</li>
1041     #     <li>hsb(•••, •••, •••) — hue, saturation and brightness values: (“<code>hsb(0.5,&nbsp;0.25,&nbsp;1)</code>”)</li>
1042     #     <li>hsb(•••%, •••%, •••%) — same as above, but in %</li>
1043     #     <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li>
1044     #     <li>hsl(•••, •••, •••) — almost the same as hsb, see <a href="http://en.wikipedia.org/wiki/HSL_and_HSV" title="HSL and HSV - Wikipedia, the free encyclopedia">Wikipedia page</a></li>
1045     #     <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
1046     #     <li>hsla(•••, •••, •••, •••) — same as above, but with opacity</li>
1047     #     <li>Optionally for hsb and hsl you could specify hue as a degree: “<code>hsl(240deg,&nbsp;1,&nbsp;.5)</code>” or, if you want to go fancy, “<code>hsl(240°,&nbsp;1,&nbsp;.5)</code>”</li>
1048     # </ul>
1049    \*/
1050    elproto.attr = function (name, value) {
1051        if (this.removed) {
1052            return this;
1053        }
1054        if (name == null) {
1055            var res = {};
1056            for (var a in this.attrs) if (this.attrs[has](a)) {
1057                res[a] = this.attrs[a];
1058            }
1059            res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient;
1060            res.transform = this._.transform;
1061            return res;
1062        }
1063        if (value == null && R.is(name, "string")) {
1064            if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) {
1065                return this.attrs.gradient;
1066            }
1067            if (name == "transform") {
1068                return this._.transform;
1069            }
1070            var names = name.split(separator),
1071                out = {};
1072            for (var i = 0, ii = names.length; i < ii; i++) {
1073                name = names[i];
1074                if (name in this.attrs) {
1075                    out[name] = this.attrs[name];
1076                } else if (R.is(this.paper.customAttributes[name], "function")) {
1077                    out[name] = this.paper.customAttributes[name].def;
1078                } else {
1079                    out[name] = R._availableAttrs[name];
1080                }
1081            }
1082            return ii - 1 ? out : out[names[0]];
1083        }
1084        if (value == null && R.is(name, "array")) {
1085            out = {};
1086            for (i = 0, ii = name.length; i < ii; i++) {
1087                out[name[i]] = this.attr(name[i]);
1088            }
1089            return out;
1090        }
1091        if (value != null) {
1092            var params = {};
1093            params[name] = value;
1094        } else if (name != null && R.is(name, "object")) {
1095            params = name;
1096        }
1097        for (var key in params) {
1098            eve("raphael.attr." + key + "." + this.id, this, params[key]);
1099        }
1100        for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
1101            var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
1102            this.attrs[key] = params[key];
1103            for (var subkey in par) if (par[has](subkey)) {
1104                params[subkey] = par[subkey];
1105            }
1106        }
1107        setFillAndStroke(this, params);
1108        return this;
1109    };
1110    /*\
1111     * Element.toFront
1112     [ method ]
1113     **
1114     * Moves the element so it is the closest to the viewer’s eyes, on top of other elements.
1115     = (object) @Element
1116    \*/
1117    elproto.toFront = function () {
1118        if (this.removed) {
1119            return this;
1120        }
1121        var node = getRealNode(this.node);
1122        node.parentNode.appendChild(node);
1123        var svg = this.paper;
1124        svg.top != this && R._tofront(this, svg);
1125        return this;
1126    };
1127    /*\
1128     * Element.toBack
1129     [ method ]
1130     **
1131     * Moves the element so it is the furthest from the viewer’s eyes, behind other elements.
1132     = (object) @Element
1133    \*/
1134    elproto.toBack = function () {
1135        if (this.removed) {
1136            return this;
1137        }
1138        var node = getRealNode(this.node);
1139        var parentNode = node.parentNode;
1140        parentNode.insertBefore(node, parentNode.firstChild);
1141        R._toback(this, this.paper);
1142        var svg = this.paper;
1143        return this;
1144    };
1145    /*\
1146     * Element.insertAfter
1147     [ method ]
1148     **
1149     * Inserts current object after the given one.
1150     = (object) @Element
1151    \*/
1152    elproto.insertAfter = function (element) {
1153        if (this.removed || !element) {
1154            return this;
1155        }
1156
1157        var node = getRealNode(this.node);
1158        var afterNode = getRealNode(element.node || element[element.length - 1].node);
1159        if (afterNode.nextSibling) {
1160            afterNode.parentNode.insertBefore(node, afterNode.nextSibling);
1161        } else {
1162            afterNode.parentNode.appendChild(node);
1163        }
1164        R._insertafter(this, element, this.paper);
1165        return this;
1166    };
1167    /*\
1168     * Element.insertBefore
1169     [ method ]
1170     **
1171     * Inserts current object before the given one.
1172     = (object) @Element
1173    \*/
1174    elproto.insertBefore = function (element) {
1175        if (this.removed || !element) {
1176            return this;
1177        }
1178
1179        var node = getRealNode(this.node);
1180        var beforeNode = getRealNode(element.node || element[0].node);
1181        beforeNode.parentNode.insertBefore(node, beforeNode);
1182        R._insertbefore(this, element, this.paper);
1183        return this;
1184    };
1185    elproto.blur = function (size) {
1186        // Experimental. No Safari support. Use it on your own risk.
1187        var t = this;
1188        if (+size !== 0) {
1189            var fltr = $("filter"),
1190                blur = $("feGaussianBlur");
1191            t.attrs.blur = size;
1192            fltr.id = R.createUUID();
1193            $(blur, {stdDeviation: +size || 1.5});
1194            fltr.appendChild(blur);
1195            t.paper.defs.appendChild(fltr);
1196            t._blur = fltr;
1197            $(t.node, {filter: "url(#" + fltr.id + ")"});
1198        } else {
1199            if (t._blur) {
1200                t._blur.parentNode.removeChild(t._blur);
1201                delete t._blur;
1202                delete t.attrs.blur;
1203            }
1204            t.node.removeAttribute("filter");
1205        }
1206        return t;
1207    };
1208    R._engine.circle = function (svg, x, y, r) {
1209        var el = $("circle");
1210        svg.canvas && svg.canvas.appendChild(el);
1211        var res = new Element(el, svg);
1212        res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"};
1213        res.type = "circle";
1214        $(el, res.attrs);
1215        return res;
1216    };
1217    R._engine.rect = function (svg, x, y, w, h, r) {
1218        var el = $("rect");
1219        svg.canvas && svg.canvas.appendChild(el);
1220        var res = new Element(el, svg);
1221        res.attrs = {x: x, y: y, width: w, height: h, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"};
1222        res.type = "rect";
1223        $(el, res.attrs);
1224        return res;
1225    };
1226    R._engine.ellipse = function (svg, x, y, rx, ry) {
1227        var el = $("ellipse");
1228        svg.canvas && svg.canvas.appendChild(el);
1229        var res = new Element(el, svg);
1230        res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"};
1231        res.type = "ellipse";
1232        $(el, res.attrs);
1233        return res;
1234    };
1235    R._engine.image = function (svg, src, x, y, w, h) {
1236        var el = $("image");
1237        $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"});
1238        el.setAttributeNS(xlink, "href", src);
1239        svg.canvas && svg.canvas.appendChild(el);
1240        var res = new Element(el, svg);
1241        res.attrs = {x: x, y: y, width: w, height: h, src: src};
1242        res.type = "image";
1243        return res;
1244    };
1245    R._engine.text = function (svg, x, y, text) {
1246        var el = $("text");
1247        svg.canvas && svg.canvas.appendChild(el);
1248        var res = new Element(el, svg);
1249        res.attrs = {
1250            x: x,
1251            y: y,
1252            "text-anchor": "middle",
1253            text: text,
1254            "font-family": R._availableAttrs["font-family"],
1255            "font-size": R._availableAttrs["font-size"],
1256            stroke: "none",
1257            fill: "#000"
1258        };
1259        res.type = "text";
1260        setFillAndStroke(res, res.attrs);
1261        return res;
1262    };
1263    R._engine.setSize = function (width, height) {
1264        this.width = width || this.width;
1265        this.height = height || this.height;
1266        this.canvas.setAttribute("width", this.width);
1267        this.canvas.setAttribute("height", this.height);
1268        if (this._viewBox) {
1269            this.setViewBox.apply(this, this._viewBox);
1270        }
1271        return this;
1272    };
1273    R._engine.create = function () {
1274        var con = R._getContainer.apply(0, arguments),
1275            container = con && con.container;
1276        if (!container) {
1277            throw new Error("SVG container not found.");
1278        }
1279        var x = con.x,
1280            y = con.y,
1281            width = con.width,
1282            height = con.height,
1283            cnvs = $("svg"),
1284            css = "overflow:hidden;",
1285            isFloating;
1286        x = x || 0;
1287        y = y || 0;
1288        width = width || 512;
1289        height = height || 342;
1290        $(cnvs, {
1291            height: height,
1292            version: 1.1,
1293            width: width,
1294            xmlns: "http://www.w3.org/2000/svg",
1295            "xmlns:xlink": "http://www.w3.org/1999/xlink"
1296        });
1297        if (container == 1) {
1298            cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px";
1299            R._g.doc.body.appendChild(cnvs);
1300            isFloating = 1;
1301        } else {
1302            cnvs.style.cssText = css + "position:relative";
1303            if (container.firstChild) {
1304                container.insertBefore(cnvs, container.firstChild);
1305            } else {
1306                container.appendChild(cnvs);
1307            }
1308        }
1309        container = new R._Paper;
1310        container.width = width;
1311        container.height = height;
1312        container.canvas = cnvs;
1313        container.clear();
1314        container._left = container._top = 0;
1315        isFloating && (container.renderfix = function () {});
1316        container.renderfix();
1317        return container;
1318    };
1319    R._engine.setViewBox = function (x, y, w, h, fit) {
1320        eve("raphael.setViewBox", this, this._viewBox, [x, y, w, h, fit]);
1321        var paperSize = this.getSize(),
1322            size = mmax(w / paperSize.width, h / paperSize.height),
1323            top = this.top,
1324            aspectRatio = fit ? "xMidYMid meet" : "xMinYMin",
1325            vb,
1326            sw;
1327        if (x == null) {
1328            if (this._vbSize) {
1329                size = 1;
1330            }
1331            delete this._vbSize;
1332            vb = "0 0 " + this.width + S + this.height;
1333        } else {
1334            this._vbSize = size;
1335            vb = x + S + y + S + w + S + h;
1336        }
1337        $(this.canvas, {
1338            viewBox: vb,
1339            preserveAspectRatio: aspectRatio
1340        });
1341        while (size && top) {
1342            sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1;
1343            top.attr({"stroke-width": sw});
1344            top._.dirty = 1;
1345            top._.dirtyT = 1;
1346            top = top.prev;
1347        }
1348        this._viewBox = [x, y, w, h, !!fit];
1349        return this;
1350    };
1351    /*\
1352     * Paper.renderfix
1353     [ method ]
1354     **
1355     * Fixes the issue of Firefox and IE9 regarding subpixel rendering. If paper is dependent
1356     * on other elements after reflow it could shift half pixel which cause for lines to lost their crispness.
1357     * This method fixes the issue.
1358     **
1359       Special thanks to Mariusz Nowak (http://www.medikoo.com/) for this method.
1360    \*/
1361    R.prototype.renderfix = function () {
1362        var cnvs = this.canvas,
1363            s = cnvs.style,
1364            pos;
1365        try {
1366            pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix();
1367        } catch (e) {
1368            pos = cnvs.createSVGMatrix();
1369        }
1370        var left = -pos.e % 1,
1371            top = -pos.f % 1;
1372        if (left || top) {
1373            if (left) {
1374                this._left = (this._left + left) % 1;
1375                s.left = this._left + "px";
1376            }
1377            if (top) {
1378                this._top = (this._top + top) % 1;
1379                s.top = this._top + "px";
1380            }
1381        }
1382    };
1383    /*\
1384     * Paper.clear
1385     [ method ]
1386     **
1387     * Clears the paper, i.e. removes all the elements.
1388    \*/
1389    R.prototype.clear = function () {
1390        R.eve("raphael.clear", this);
1391        var c = this.canvas;
1392        while (c.firstChild) {
1393            c.removeChild(c.firstChild);
1394        }
1395        this.bottom = this.top = null;
1396        (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version));
1397        c.appendChild(this.desc);
1398        c.appendChild(this.defs = $("defs"));
1399    };
1400    /*\
1401     * Paper.remove
1402     [ method ]
1403     **
1404     * Removes the paper from the DOM.
1405    \*/
1406    R.prototype.remove = function () {
1407        eve("raphael.remove", this);
1408        this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
1409        for (var i in this) {
1410            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
1411        }
1412    };
1413    var setproto = R.st;
1414    for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) {
1415        setproto[method] = (function (methodname) {
1416            return function () {
1417                var arg = arguments;
1418                return this.forEach(function (el) {
1419                    el[methodname].apply(el, arg);
1420                });
1421            };
1422        })(method);
1423    }
1424});
1425