Fix #5648 - New design for post release report
[raphael] / raphael.svg.js
index 61cc78b..76aac75 100644 (file)
@@ -1,5 +1,5 @@
 // ┌─────────────────────────────────────────────────────────────────────┐ \\
-// │ Raphaël 2 - JavaScript Vector Library                               │ \\
+// │ Raphaël - JavaScript Vector Library                                 │ \\
 // ├─────────────────────────────────────────────────────────────────────┤ \\
 // │ SVG Module                                                          │ \\
 // ├─────────────────────────────────────────────────────────────────────┤ \\
@@ -15,9 +15,11 @@ window.Raphael.svg && function (R) {
         math = Math,
         mmax = math.max,
         abs = math.abs,
+        pow = math.pow,
         separator = /[, ]+/,
-        E = "";
-    // SVG
+        eve = R.eve,
+        E = "",
+        S = " ";
     var xlink = "http://www.w3.org/1999/xlink",
         markers = {
             block: "M5,0 0,2.5 5,5z",
@@ -48,16 +50,6 @@ window.Raphael.svg && function (R) {
         }
         return el;
     },
-    gradients = {},
-    rgGrad = /^url\(#(.*)\)$/,
-    removeGradientFill = function (node, paper) {
-        var oid = node.getAttribute("fill");
-        oid = oid && oid.match(rgGrad);
-        if (oid && !--gradients[oid[1]]) {
-            delete gradients[oid[1]];
-            paper.defs.removeChild(g.doc.getElementById(oid[1]));
-        }
-    },
     addGradientFill = function (element, gradient) {
         var type = "linear",
             id = element.id + gradient,
@@ -104,30 +96,33 @@ window.Raphael.svg && function (R) {
             if (!dots) {
                 return null;
             }
-            if (element.gradient) {
+            id = id.replace(/[\(\)\s,\xb0#]/g, "_");
+            
+            if (element.gradient && id != element.gradient.id) {
                 SVG.defs.removeChild(element.gradient);
                 delete element.gradient;
             }
 
-            id = id.replace(/[\(\)\s,\xb0#]/g, "-");
-            el = $(type + "Gradient", {id: id});
-            element.gradient = el;
-            $(el, type == "radial" ? {
-                fx: fx,
-                fy: fy
-            } : {
-                x1: vector[0],
-                y1: vector[1],
-                x2: vector[2],
-                y2: vector[3],
-                gradientTransform: element.matrix.invert()
-            });
-            SVG.defs.appendChild(el);
-            for (var i = 0, ii = dots.length; i < ii; i++) {
-                el.appendChild($("stop", {
-                    offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
-                    "stop-color": dots[i].color || "#fff"
-                }));
+            if (!element.gradient) {
+                el = $(type + "Gradient", {id: id});
+                element.gradient = el;
+                $(el, type == "radial" ? {
+                    fx: fx,
+                    fy: fy
+                } : {
+                    x1: vector[0],
+                    y1: vector[1],
+                    x2: vector[2],
+                    y2: vector[3],
+                    gradientTransform: element.matrix.invert()
+                });
+                SVG.defs.appendChild(el);
+                for (var i = 0, ii = dots.length; i < ii; i++) {
+                    el.appendChild($("stop", {
+                        offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%",
+                        "stop-color": dots[i].color || "#fff"
+                    }));
+                }
             }
         }
         $(o, {
@@ -209,7 +204,7 @@ window.Raphael.svg && function (R) {
             if (type != "none") {
                 var pathId = "raphael-marker-" + type,
                     markerId = "raphael-marker-" + se + type + w + h;
-                if (!g.doc.getElementById(pathId)) {
+                if (!R._g.doc.getElementById(pathId)) {
                     p.defs.appendChild($($("path"), {
                         "stroke-linecap": "round",
                         d: markers[type],
@@ -219,7 +214,7 @@ window.Raphael.svg && function (R) {
                 } else {
                     markerCounter[pathId]++;
                 }
-                var marker = g.doc.getElementById(markerId),
+                var marker = R._g.doc.getElementById(markerId),
                     use;
                 if (!marker) {
                     marker = $($("marker"), {
@@ -278,41 +273,43 @@ window.Raphael.svg && function (R) {
                 delete o._.arrows[se + "String"];
             }
             for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) {
-                var item = g.doc.getElementById(attr);
+                var item = R._g.doc.getElementById(attr);
                 item && item.parentNode.removeChild(item);
             }
         }
     },
+    dasharray = {
+        "": [0],
+        "none": [0],
+        "-": [3, 1],
+        ".": [1, 1],
+        "-.": [3, 1, 1, 1],
+        "-..": [3, 1, 1, 1, 1, 1],
+        ". ": [1, 3],
+        "- ": [4, 3],
+        "--": [8, 3],
+        "- .": [4, 3, 1, 3],
+        "--.": [8, 3, 1, 3],
+        "--..": [8, 3, 1, 3, 1, 3]
+    },
+    addDashes = function (o, value, params) {
+        value = dasharray[Str(value).toLowerCase()];
+        if (value) {
+            var width = o.attrs["stroke-width"] || "1",
+                butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
+                dashes = [],
+                i = value.length;
+            while (i--) {
+                dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
+            }
+            $(o.node, {"stroke-dasharray": dashes.join(",")});
+        }
+    },
     setFillAndStroke = function (o, params) {
-        var dasharray = {
-                "": [0],
-                "none": [0],
-                "-": [3, 1],
-                ".": [1, 1],
-                "-.": [3, 1, 1, 1],
-                "-..": [3, 1, 1, 1, 1, 1],
-                ". ": [1, 3],
-                "- ": [4, 3],
-                "--": [8, 3],
-                "- .": [4, 3, 1, 3],
-                "--.": [8, 3, 1, 3],
-                "--..": [8, 3, 1, 3, 1, 3]
-            },
-            node = o.node,
+        var node = o.node,
             attrs = o.attrs,
-            addDashes = function (o, value) {
-                value = dasharray[lowerCase.call(value)];
-                if (value) {
-                    var width = o.attrs["stroke-width"] || "1",
-                        butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0,
-                        dashes = [],
-                        i = value.length;
-                    while (i--) {
-                        dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt;
-                    }
-                    $(node, {"stroke-dasharray": dashes.join(",")});
-                }
-            };
+            vis = node.style.visibility;
+        node.style.visibility = "hidden";
         for (var att in params) {
             if (params[has](att)) {
                 if (!R._availableAttrs[has](att)) {
@@ -328,7 +325,7 @@ window.Raphael.svg && function (R) {
                     case "title":
                     case "target":
                         var pn = node.parentNode;
-                        if (lowerCase.call(pn.tagName) != "a") {
+                        if (pn.tagName.toLowerCase() != "a") {
                             var hl = $("a");
                             pn.insertBefore(hl, node);
                             hl.appendChild(node);
@@ -358,7 +355,7 @@ window.Raphael.svg && function (R) {
                             o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode);
                             var el = $("clipPath"),
                                 rc = $("rect");
-                            el.id = R._createUUID();
+                            el.id = R.createUUID();
                             $(rc, {
                                 x: rect[0],
                                 y: rect[1],
@@ -371,10 +368,13 @@ window.Raphael.svg && function (R) {
                             o.clip = rc;
                         }
                         if (!value) {
-                            var clip = g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E));
-                            clip && clip.parentNode.removeChild(clip);
-                            $(node, {"clip-path": E});
-                            delete o.clip;
+                            var path = node.getAttribute("clip-path");
+                            if (path) {
+                                var clip = R._g.doc.getElementById(path.replace(/(^url\(#|\)$)/g, E));
+                                clip && clip.parentNode.removeChild(clip);
+                                $(node, {"clip-path": E});
+                                delete o.clip;
+                            }
                         }
                     break;
                     case "path":
@@ -453,7 +453,7 @@ window.Raphael.svg && function (R) {
                         }
                         node.setAttribute(att, value);
                         if (attrs["stroke-dasharray"]) {
-                            addDashes(o, attrs["stroke-dasharray"]);
+                            addDashes(o, attrs["stroke-dasharray"], params);
                         }
                         if (o._.arrows) {
                             "startString" in o._.arrows && addArrow(o, o._.arrows.startString);
@@ -461,14 +461,14 @@ window.Raphael.svg && function (R) {
                         }
                         break;
                     case "stroke-dasharray":
-                        addDashes(o, value);
+                        addDashes(o, value, params);
                         break;
                     case "fill":
                         var isURL = Str(value).match(R._ISURL);
                         if (isURL) {
                             el = $("pattern");
                             var ig = $("image");
-                            el.id = R._createUUID();
+                            el.id = R.createUUID();
                             $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1});
                             $(ig, {x: 0, y: 0, "xlink:href": isURL[1]});
                             el.appendChild(ig);
@@ -501,7 +501,7 @@ window.Raphael.svg && function (R) {
                                 $(node, {"fill-opacity": attrs["fill-opacity"]});
                         } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) {
                             if ("opacity" in attrs || "fill-opacity" in attrs) {
-                                var gradient = g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+                                var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
                                 if (gradient) {
                                     var stops = gradient.getElementsByTagName("stop");
                                     $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)});
@@ -531,7 +531,7 @@ window.Raphael.svg && function (R) {
                         // fall
                     case "fill-opacity":
                         if (attrs.gradient) {
-                            gradient = g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
+                            gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E));
                             if (gradient) {
                                 stops = gradient.getElementsByTagName("stop");
                                 $(stops[stops.length - 1], {"stop-opacity": value});
@@ -552,6 +552,7 @@ window.Raphael.svg && function (R) {
         }
 
         tuneText(o, params);
+        node.style.visibility = vis;
     },
     leading = 1.2,
     tuneText = function (el, params) {
@@ -599,6 +600,8 @@ window.Raphael.svg && function (R) {
          [ property (object) ]
          **
          * Gives you a reference to the DOM object, so you can assign event handlers or just mess around.
+         **
+         * Note: Don’t mess with it.
          > Usage
          | // draw a circle at coordinate 10,10 with radius of 10
          | var c = paper.circle(10, 10, 10);
@@ -682,7 +685,11 @@ window.Raphael.svg && function (R) {
         SVG.canvas && SVG.canvas.appendChild(el);
         var p = new Element(el, SVG);
         p.type = "path";
-        setFillAndStroke(p, {fill: "none", stroke: "#000", path: pathString});
+        setFillAndStroke(p, {
+            fill: "none",
+            stroke: "#000",
+            path: pathString
+        });
         return p;
     };
     /*\
@@ -786,6 +793,8 @@ window.Raphael.svg && function (R) {
      * Each letter is a command. There are four commands: `t` is for translate, `r` is for rotate, `s` is for
      * scale and `m` is for matrix.
      *
+     * 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`.
+     *
      * So, the example line above could be read like “translate by 100, 100; rotate 30° around 100, 100; scale twice around 100, 100;
      * rotate 45° around centre; scale 1.5 times relative to centre”. As you can see rotate and scale commands have origin
      * coordinates as optional parameters, the default is the centre point of the element.
@@ -860,11 +869,16 @@ window.Raphael.svg && function (R) {
         if (this.removed) {
             return;
         }
+        var paper = this.paper;
+        paper.__set__ && paper.__set__.exclude(this);
         eve.unbind("*.*." + this.id);
-        R._tear(this, this.paper);
+        if (this.gradient) {
+            paper.defs.removeChild(this.gradient);
+        }
+        R._tear(this, paper);
         this.node.parentNode.removeChild(this.node);
         for (var i in this) {
-            delete this[i];
+            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
         }
         this.removed = true;
     };
@@ -907,8 +921,8 @@ window.Raphael.svg && function (R) {
      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`, `midium`, length: `long`, `short`, `midium`.
      o clip-rect (string) comma or space separated values: x, y, width and height
      o cursor (string) CSS type of the cursor
-     o cx (number)
-     o cy (number)
+     o cx (number) the x-axis coordinate of the center of the circle, or ellipse
+     o cy (number) the y-axis coordinate of the center of the circle, or ellipse
      o fill (string) colour, gradient or image
      o fill-opacity (number)
      o font (string)
@@ -919,9 +933,9 @@ window.Raphael.svg && function (R) {
      o href (string) URL, if specified element behaves as hyperlink
      o opacity (number)
      o path (string) SVG path string format
-     o r (number)
-     o rx (number)
-     o ry (number)
+     o r (number) radius of the circle, ellipse or rounded corner on the rect
+     o rx (number) horisontal radius of the ellipse
+     o ry (number) vertical radius of the ellipse
      o src (string) image URL, only works for @Element.image element
      o stroke (string) stroke colour
      o stroke-dasharray (string) [“”, “`-`”, “`.`”, “`-.`”, “`-..`”, “`. `”, “`- `”, “`--`”, “`- .`”, “`--.`”, “`--..`”]
@@ -961,7 +975,7 @@ window.Raphael.svg && function (R) {
      #     <li>hsba(•••, •••, •••, •••) — same as above, but with opacity</li>
      #     <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>
      #     <li>hsl(•••%, •••%, •••%) — same as above, but in %</li>
-     #     <li>hsla(•••, •••, •••) — same as above, but with opacity</li>
+     #     <li>hsla(•••, •••, •••, •••) — same as above, but with opacity</li>
      #     <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>
      # </ul>
     \*/
@@ -1012,7 +1026,10 @@ window.Raphael.svg && function (R) {
         } else if (name != null && R.is(name, "object")) {
             params = name;
         }
-        for (var key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
+        for (var key in params) {
+            eve("attr." + key + "." + this.id, this, params[key]);
+        }
+        for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) {
             var par = this.paper.customAttributes[key].apply(this, [].concat(params[key]));
             this.attrs[key] = params[key];
             for (var subkey in par) if (par[has](subkey)) {
@@ -1033,7 +1050,11 @@ window.Raphael.svg && function (R) {
         if (this.removed) {
             return this;
         }
-        this.node.parentNode.appendChild(this.node);
+        if (this.node.parentNode.tagName.toLowerCase() == "a") {
+            this.node.parentNode.parentNode.appendChild(this.node.parentNode);
+        } else {
+            this.node.parentNode.appendChild(this.node);
+        }
         var svg = this.paper;
         svg.top != this && R._tofront(this, svg);
         return this;
@@ -1049,11 +1070,14 @@ window.Raphael.svg && function (R) {
         if (this.removed) {
             return this;
         }
-        if (this.node.parentNode.firstChild != this.node) {
-            this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild);
-            R._toback(this, this.paper);
-            var svg = this.paper;
+        var parent = this.node.parentNode;
+        if (parent.tagName.toLowerCase() == "a") {
+            parent.parentNode.insertBefore(this.node.parentNode, this.node.parentNode.parentNode.firstChild); 
+        } else if (parent.firstChild != this.node) {
+            parent.insertBefore(this.node, this.node.parentNode.firstChild);
         }
+        R._toback(this, this.paper);
+        var svg = this.paper;
         return this;
     };
     /*\
@@ -1099,7 +1123,7 @@ window.Raphael.svg && function (R) {
             var fltr = $("filter"),
                 blur = $("feGaussianBlur");
             t.attrs.blur = size;
-            fltr.id = R._createUUID();
+            fltr.id = R.createUUID();
             $(blur, {stdDeviation: +size || 1.5});
             fltr.appendChild(blur);
             t.paper.defs.appendChild(fltr);
@@ -1269,7 +1293,7 @@ window.Raphael.svg && function (R) {
     R.prototype.renderfix = function () {
         var cnvs = this.canvas,
             s = cnvs.style,
-            pos = cnvs.getScreenCTM(),
+            pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(),
             left = -pos.e % 1,
             top = -pos.f % 1;
         if (left || top) {
@@ -1310,7 +1334,7 @@ window.Raphael.svg && function (R) {
         eve("remove", this);
         this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas);
         for (var i in this) {
-            this[i] = removed(i);
+            this[i] = typeof this[i] == "function" ? R._removedFactory(i) : null;
         }
     };
     var setproto = R.st;