Fix #5648 - New design for post release report
authorEdward <edward@roojs.com>
Fri, 18 Jan 2019 07:12:17 +0000 (15:12 +0800)
committerEdward <edward@roojs.com>
Fri, 18 Jan 2019 07:12:17 +0000 (15:12 +0800)
g.bar.0.51.js
g.bar.overlay.js [new file with mode: 0644]
g.bar.split.js [new file with mode: 0644]
g.pie.circular.js [new file with mode: 0644]
g.pie.sector.js [new file with mode: 0644]
seed/setFillAndStroke.js
seed/toSVG.js

index 796ef66..726c8a1 100644 (file)
@@ -227,7 +227,6 @@ if (typeof(Raphael) == 'undefined') {
         }
         opts.axis = opts.axis || "";
         
-        
         var allx = Array.prototype.concat.apply([], opts.xvalues),
             ally = Array.prototype.concat.apply([], opts.yvalues),
             
diff --git a/g.bar.overlay.js b/g.bar.overlay.js
new file mode 100644 (file)
index 0000000..fae7ede
--- /dev/null
@@ -0,0 +1,241 @@
+/*!
+ * g.Raphael 0.51 - Charting library, based on Raphaël
+ *
+ * Copyright (c) 2009-2012 Dmitry Baranovskiy (http://g.raphaeljs.com)
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
+ */
+
+if (typeof(Raphael) == 'undefined') {
+    // support for seed/simple browser usage
+    importz = imports['seed/importz.js'].importz;
+
+    Raphael = importz('Raphael');
+    Roo = importz('Roo');
+}
+
+(function () {
+    
+    function clearAr(ar) {
+        var ret = new Array();
+        //Roo.log(JSON.stringify(ar));
+        for (var i = 0; i < ar.length; i++) {
+            //print(typeof(ar[i]));
+            if (Raphael.is(ar[i], "object")) {
+                ret.push(clearAr(ar[i]));
+                continue;
+            }
+            ret.push(parseInt(ar[i]));
+        }
+        return ret;
+    }
+
+/*\
+ * Paper.vbarchart
+ [ method ]
+ **
+ * Creates a vertical bar chart
+ **
+ > Parameters
+ **
+ - x (number) x coordinate of the chart
+ - y (number) y coordinate of the chart
+ - width (number) width of the chart (respected by all elements in the set)
+ - height (number) height of the chart (respected by all elements in the set)
+ - values (array) values
+ - opts (object) options for the chart
+ o {
+ o type (string) type of endings of the bar. Default: 'square'. Other options are: 'round', 'sharp', 'soft'.
+ o gutter (number)(string) default '20%' (WHAT DOES IT DO?)
+ o vgutter (number)
+ o colors (array) colors be used repeatedly to plot the bars. If multicolumn bar is used each sequence of bars with use a different color.
+ o stacked (boolean) whether or not to tread values as in a stacked bar chart
+ o to
+ o stretch (boolean)
+ o }
+ **
+ = (object) path element of the popup
+ > Usage
+ | r.vbarchart(0, 0, 620, 260, [[76, 70], [67, 71]], {})
+ \*/
+
+    function MVBarchart(paper, x, y, width, height, values, opts) {
+        opts = opts || {};
+        values = clearAr(values);
+       
+        var chartinst = this,
+            chart = paper.set(),
+            bars = paper.set(),
+            covers = paper.set(),
+            barsteps = opts.barsteps || 20,
+            colors = opts.colors || chartinst.colors,
+            max = 3000;
+        
+        opts.axis = opts.axis || "";
+        opts.baroffset = opts.baroffset || 50;
+        opts.asixxheight = opts.asixxheight || 100;
+        opts.asixywidth = opts.asixywidth || 100;
+        opts.axisxlabels = opts.axisxlabels || [];
+        
+        // background
+        paper.rect(0, 0, width, height).attr({ stroke: "none", fill: (opts.background || "#F0F4F7") });
+//        background.toBack();
+        
+        // bar border
+        var barwidth = Math.floor((width - x - opts.asixywidth - opts.baroffset) / barsteps);
+        var barheight = height - y - opts.asixxheight || 100;
+        var path = ["M", x + 1, y, "l", 0, barheight]
+        
+        for (var i = 0; i < barsteps; i++) {
+            path = path.concat(["M", x + (i * barwidth), y + 1, "l", barwidth, 0, "l", 0, barheight]);
+        }
+        
+        paper.path(path).attr({ stroke: "#fff", "stroke-width": 2 });
+        
+        //bars
+        var unit = barheight / max;
+        var indicator = [];
+        values.forEach((value,i) => {
+            if (!Raphael.is(values[0], "array")) {
+                value = [value];
+            }
+    
+            value.forEach((v,k) => {
+                paper.rect(x + 1 + (k * barwidth) , y + (max - v) * unit, barwidth - 2, v * unit).attr({ stroke: "none", fill: colors[i%colors.length] });
+                paper.rect(x + 1 + (k * barwidth) + barwidth / 4 , y + (max - v) * unit - 42, barwidth / 2, 30, 5).attr({ stroke: "none", fill: "#0C014D" });
+                indicator = indicator.concat(["M", x + 1 + (k * barwidth) + barwidth / 4 + 10, y + (max - v) * unit - 12, "l", 5, 10, "l", 5, -10]);
+                paper.text(x + 1 + (k * barwidth) + barwidth / 2, y + (max - v)  * unit - 28, Roo.util.Format.number(v, 0)).attr({ 
+                    "font-size": "16",
+                    "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                    "font-weight": "bold",
+                    fill : "#fff"
+                });
+            });
+            
+        });
+        
+        paper.path(indicator).attr({ stroke: "none", fill: "#0C014D" });
+        
+        var ax = (opts.axis + "").split(/[,\s]+/),
+            axis = paper.set();
+        
+        // right axis
+        +ax[1] && axis.push(
+            chartinst.rightAxis(
+                x + width - opts.asixywidth ,
+                y + height - opts.asixxheight,
+                height - y - opts.asixxheight,
+                max,
+                opts.axisystep || 10,
+                opts.asixywidth,
+                paper
+            )
+        );
+        
+        // bottom axis
+        +ax[2] && axis.push(
+            chartinst.bottomAxis(
+                x ,
+                height - opts.asixxheight,
+                width,
+                opts.axisxlabels.length,
+                opts.axisxlabels,
+                barwidth,
+                opts.asixxheight,
+                paper
+            )
+        );
+        
+        chart.push(bars, covers);
+        chart.bars = bars;
+        chart.covers = covers;
+        return chart;
+    };
+    
+    //inheritance
+    var F = function() {};
+    F.prototype = Raphael.g;
+    MVBarchart.prototype = new F; //prototype reused by hbarchart
+    
+    Raphael.fn.mbarchart = function(x, y, width, height, values, opts) {
+        return new MVBarchart(this, x, y, width, height, values, opts);
+    };
+    
+    MVBarchart.prototype.rightAxis = function (x, y, length, max, steps, ewidth, paper)
+    {
+//        Roo.log('Right Axis');
+//        Roo.log([x, y, length, max, steps, ewidth]);
+        
+        var path = [],
+            color = "#bababa",
+            text = paper.set(),
+            d = Math.ceil(max / steps);
+        
+        var label = 0,
+            dx = length / steps;
+        
+        var Y = y;
+        
+        for(var i = 0; i <= steps; i++) {
+            
+            if(i != 0) {
+                paper.text(x + (ewidth / 2), Y + 15, label).attr({ 
+                    "font-size": "20",
+                    "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                    "font-weight": "bold",
+                    "text-anchor": "end",
+                    fill : color
+                });
+                path = path.concat(["M", x, Y, "l", (ewidth / 2), 0]);
+                
+            }
+            
+            label += d;
+            Y -= dx;
+        }
+        
+        var res = paper.path(path).attr({ stroke: color, "stroke-width": 2 });
+
+        res.text = text;
+        res.all = paper.set([res, text]);
+        res.remove = function () {
+            this.text.remove();
+            this.constructor.prototype.remove.call(this);
+        };
+
+        return res;
+    }
+    
+    MVBarchart.prototype.bottomAxis = function (x, y, length, steps, labels, barwidth, eheight, paper)
+    {
+//        Roo.log('Bottom Axis');
+//        Roo.log([x, y, length, steps, labels, barwidth]);
+        
+        var path = ["M", x, y, "l", length, 0],
+            color = "#bababa",
+            text = paper.set(),
+            offset = Math.round(barwidth / 2);
+    
+        labels.forEach((v,k) => {
+            paper.text(x + (k * barwidth) + offset, y + (eheight / 2), v).attr({ 
+                "font-size": "20",
+                "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                "font-weight": "bold",
+                fill : color
+            });
+        });
+        
+        var res = paper.path(path).attr({ stroke: color, "stroke-width": 2 });
+
+        res.text = text;
+        res.all = paper.set([res, text]);
+        res.remove = function () {
+            this.text.remove();
+            this.constructor.prototype.remove.call(this);
+        };
+
+        return res;
+    }
+    
+})();
\ No newline at end of file
diff --git a/g.bar.split.js b/g.bar.split.js
new file mode 100644 (file)
index 0000000..7c2c56e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * g.Raphael 0.5 - Charting library, based on Raphaël
+ *
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
+ */
+Raphael = typeof(Raphael) != 'undefined' ? Raphael :  (imports ? imports.seed.Raphael.Raphael : {});
+Roo = typeof(Roo) != 'undefined' ? Roo:  (imports ? imports.seed.Roo.Roo: {});
+//chartinst = typeof(chartinst) != 'undefined' ? chartinst:  (imports ? imports.chartinst.chartinst : {});
+
+
+(function () {
+
+    /**
+     * @param {Raphael} paper to draw on
+     * @param {int} cx - centre X
+     * @param {int} cy - centre Y
+     * @param {int} r - radius
+     * @param {Array} values
+     * @param {Object} opts options
+     *   cut : after this meany items - do not show a pie element?
+     *   
+     *   
+     * 
+     */
+
+    function Barsplitchart(paper, width, height, values, opts) {
+        
+        opts = opts || {};
+
+        var chartinst = this,
+            chart = paper.set();
+    
+        opts.top = opts.top || 50;
+        opts.bottom = opts.bottom || 50;
+        opts.left = opts.left || 20;
+        opts.right = opts.right || 20;
+        opts.barwidth = opts.barwidth || 100;
+        
+        paper.rect(0, 0, width, height).attr({ stroke: "none", fill: (opts.background || "#F0F4F7") });
+        
+        var cw = width - opts.left - opts.right,
+            ch = height - opts.top - opts.bottom;
+        
+        paper.rect(opts.left, opts.top, opts.barwidth, ch).attr({ stroke: "#CCCCCC", "stroke-dasharray": "--" });
+        paper.rect(opts.left + cw / 2, opts.top, opts.barwidth, ch).attr({ stroke: "#CCCCCC", "stroke-dasharray": "--" });
+        
+        values.forEach((v,k) => {
+            v = Math.min(100, v);
+            var bh = v * ch / 100,
+                bx = (k == 0) ? opts.left : opts.left + cw / 2,
+                by = opts.top + ch - bh;
+            
+            paper.rect(bx, by, opts.barwidth, bh).attr({ stroke: "none", fill: "#0A2BC4" });
+            
+            paper.rect(bx + opts.barwidth / 4 , by - 42, opts.barwidth / 2, 30, 5).attr({ stroke: "none", fill: "#0C014D" });
+            paper.path(["M", bx + opts.barwidth / 4 + 10, by - 12, "l", 5, 10, "l", 5, -10]).attr({ stroke: "none", fill: "#0C014D" });
+            paper.text(bx + opts.barwidth / 4 + 25, by - 28, Roo.util.Format.number(v, 0) + '%').attr({ 
+                "font-size": "16",
+                "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                "font-weight": "bold",
+                fill : "#fff"
+            });
+            
+            paper.text(bx + opts.barwidth + 25, opts.top + 50, opts.legend[k]).attr({ 
+                "font-size": "22",
+                "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                "font-weight": "bold",
+                "text-anchor": "start",
+                fill : "#0C024B"
+            });
+        });
+        
+        return chart;
+    };
+    
+    //inheritance
+    var F = function() {};
+    F.prototype = Raphael.g;
+    Barsplitchart.prototype = new F;
+    
+    //public
+    Raphael.fn.barsplitchart = function(width, height, values, opts) {
+        return new Barsplitchart(this, width, height, values, opts);
+    }
+    
+})();
diff --git a/g.pie.circular.js b/g.pie.circular.js
new file mode 100644 (file)
index 0000000..f90083c
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * g.Raphael 0.5 - Charting library, based on Raphaël
+ *
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
+ */
+Raphael = typeof(Raphael) != 'undefined' ? Raphael :  (imports ? imports.seed.Raphael.Raphael : {});
+Roo = typeof(Roo) != 'undefined' ? Roo:  (imports ? imports.seed.Roo.Roo: {});
+//chartinst = typeof(chartinst) != 'undefined' ? chartinst:  (imports ? imports.chartinst.chartinst : {});
+
+
+(function () {
+
+    /**
+     * @param {Raphael} paper to draw on
+     * @param {int} cx - centre X
+     * @param {int} cy - centre Y
+     * @param {int} r - radius
+     * @param {Array} values
+     * @param {Object} opts options
+     *   cut : after this meany items - do not show a pie element?
+     *   
+     *   
+     * 
+     */
+
+    function Piecircularchart(paper, width, height, cx, cy, r, values, opts) {
+        
+        opts = opts || {};
+
+        var chartinst = this,
+            chart = paper.set(),
+            len = values.length;
+        
+        opts.linewidth = opts.linewidth || 200;
+        
+        paper.rect(0, 0, width, height).attr({ stroke: "none", fill: (opts.background || "#F0F4F7") });
+        
+        for (var i = 0; i < len; i++) {
+            values[i] = {
+                value: values[i],
+                origin: i,
+                valueOf: function () { return this.value; }
+            };
+        }
+        
+        values.sort(function (a, b) {
+            return b.value - a.value;
+        });
+        
+        var dx = cx,
+            dy = cy,
+            dr = r;
+    
+        for (i = 0; i < len; i++) {
+            
+            paper.circle(dx, dy, dr).attr({ fill: opts.colors && opts.colors[i] || chartinst.colors[i] || "#3E66BC", stroke: "#fff", "stroke-width": 2 });
+            
+            var nx = dx,
+                ny = dy - dr + 20;
+        
+            if(i != 0) {
+                ny = dy - dr - 20;
+            }
+            
+            paper.text(nx, ny, Roo.util.Format.number(values[i], 0)).attr({ 
+                "font-size": "18",
+                "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                "font-weight": "bold",
+                fill : "#fff"
+            });
+            
+            paper.path(["M", dx, dy - dr, "l", opts.linewidth, 0]).attr({ stroke: "#fff", "stroke-width": 2 });
+            paper.text(dx + opts.linewidth + 10, dy - dr, opts.legend[values[i].origin]).attr({ 
+                "font-size": "18",
+                "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                "text-anchor": "start",
+                fill : "#0E1587"
+            });
+            
+            dy = dy + dr / 4 *3;
+            dr = Math.round(dr / 4);
+
+        }
+        
+        chart.cx = cx;
+        chart.cy = cy;
+        chart.r = r;
+        return chart;
+    };
+    
+    //inheritance
+    var F = function() {};
+    F.prototype = Raphael.g;
+    Piecircularchart.prototype = new F;
+    
+    //public
+    Raphael.fn.piecircularchart = function(width, height, cx, cy, r, values, opts) {
+        return new Piecircularchart(this, width, height, cx, cy, r, values, opts);
+    }
+    
+})();
diff --git a/g.pie.sector.js b/g.pie.sector.js
new file mode 100644 (file)
index 0000000..c0bb4d9
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * g.Raphael 0.5 - Charting library, based on Raphaël
+ *
+ * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
+ * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
+ */
+Raphael = typeof(Raphael) != 'undefined' ? Raphael :  (imports ? imports.seed.Raphael.Raphael : {});
+Roo = typeof(Roo) != 'undefined' ? Roo:  (imports ? imports.seed.Roo.Roo: {});
+//chartinst = typeof(chartinst) != 'undefined' ? chartinst:  (imports ? imports.chartinst.chartinst : {});
+
+
+(function () {
+
+    /**
+     * @param {Raphael} paper to draw on
+     * @param {int} cx - centre X
+     * @param {int} cy - centre Y
+     * @param {int} r - radius
+     * @param {Array} values
+     * @param {Object} opts options
+     *   cut : after this meany items - do not show a pie element?
+     *   
+     *   
+     * 
+     */
+
+    function Piesectorchart(paper, width, height, cx, cy, r, values, opts) {
+        
+        opts = opts || {};
+
+        var chartinst = this,
+            chart = paper.set(),
+            len = values.length,
+            angle = opts.start_angle || 90,
+            total = 0,
+            others = 0,
+            cut = opts.cut || 9,
+            defcut = true;
+        
+        opts.barwidth = opts.barwidth || 80;
+        
+        paper.rect(0, 0, width, height).attr({ stroke: "none", fill: (opts.background || "#F0F4F7") });
+        
+        paper.customAttributes.sector = function (cx, cy, startAngle, endAngle, color, R) {
+            
+            var rad = Math.PI / 180,
+                x1 = cx + r * Math.cos(-startAngle * rad),
+                x2 = cx + r * Math.cos(-endAngle * rad),
+                y1 = cy + r * Math.sin(-startAngle * rad),
+                y2 = cy + r * Math.sin(-endAngle * rad),
+                path;
+        
+            path = [["M", x1, y1], ["A", R, R, 0, +(Math.abs(endAngle - startAngle) > 180), 1, x2, y2]];
+
+            return {path: path, stroke: color};
+        };
+        
+        if (len == 1) {
+            total = values[0];
+            paper.circle(cx, cy, r + opts.barwidth / 2).attr({ fill: opts.colors && opts.colors[0] || chartinst.colors[0] || "#3E66BC" });
+            paper.circle(cx, cy, r - opts.barwidth / 2).attr({ fill: opts.background || "#F0F4F7" });
+            
+        } else {
+            
+            for (var i = 0; i < len; i++) {
+                total += values[i] * 1;
+                values[i] = {
+                    value: values[i],
+                    valueOf: function () { return this.value; }
+                };
+            }
+            
+            if (!opts.no_sort) {
+                values.sort(function (a, b) {
+                    return b.value - a.value;
+                });
+            }
+            
+            for (i = 0; i < len; i++) {
+                if (defcut && values[i] * 360 / total <= 1.5) {
+                    cut = i;
+                    defcut = false;
+                }
+
+                if (i > cut) {
+                    defcut = false;
+                    values[cut].value += values[i];
+                    values[cut].others = true;
+                }
+            }
+            
+            len = Math.min(cut + 1, values.length);
+            
+            for (i = 0; i < len; i++) {
+                
+                var p = paper.path().attr({
+                    "stroke": "#fff", 
+                    "stroke-width": opts.barwidth
+                }).attr({sector: [cx, cy, angle, angle -= 360 * values[i] / total, opts.colors && opts.colors[i] || chartinst.colors[i], r]});
+            
+            }
+            
+        }
+        
+        var ix = cx + r + opts.barwidth / 2 + 30,
+            iy = cy - r - 30;
+        
+        for (var i = 0; i < len; i++) {
+            
+            paper.circle(ix, iy, 6).attr({ fill: opts.colors && opts.colors[i] || chartinst.colors[i] || "#3E66BC" });
+            
+            var text = (values[i].others) ? opts.others : opts.legend[i] || values[i];
+            
+            if(text.indexOf('#%#') !== -1) {
+                text = text.replace('#%#', Math.round(values[i] / total * 100) + '%');
+            }
+            
+            paper.text(ix + 20, iy, text).attr({ 
+                "font-size": "18",
+                "font-family": "'Fontin Sans', Fontin-Sans, sans-serif",
+                "text-anchor": "start",
+                fill : "#0C014F"
+            });
+            
+            iy += 30;
+            
+        }
+
+        chart.cx = cx;
+        chart.cy = cy;
+        chart.r = r;
+        return chart;
+    };
+    
+    //inheritance
+    var F = function() {};
+    F.prototype = Raphael.g;
+    Piesectorchart.prototype = new F;
+    
+    //public
+    Raphael.fn.piesectorchart = function(width, height, cx, cy, r, values, opts) {
+        return new Piesectorchart(this, width, height, cx, cy, r, values, opts);
+    }
+    
+})();
index d64e06a..3f1f4dc 100644 (file)
@@ -15,8 +15,6 @@ var has = "hasOwnProperty";
     FakeDom(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"});
 }
 
-
-
 function tuneText (el, params) {
     if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) {
         return;
@@ -63,6 +61,91 @@ function tuneText (el, params) {
     dif && R.is(dif, "finite") && FakeDom(tspans[0], {dy: dif});
 }
 
+function addDashes(o, value, params) {
+    
+    var dasharray = {
+        // In Firefox 37.0.1 the value of "stroke-dasharray" attribute `0` make the stroke/border invisible.
+        // The actual issue is setting `none` as the value of `stroke-dasharray` attribute
+        // redraphael internally changes the "none" value to "0", thus the stroke/border becomes invisible
+        // To fix this issue now instead of setting the value as `0` for `stroke-dasharray` attribute
+        // now using `none` string as none is a w3c standard value for stroke-dasharray
+        "": ["none"],
+        "none": ["none"],
+        "-": [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]
+    };
+    
+    var $ = R._createNode = function(el, attr) {
+        if (attr) {
+            if (typeof el == "string") {
+                el = $(el);
+            }
+            for (var key in attr)
+                if (attr.hasOwnProperty(key)) {
+                    if (key.substring(0, 6) == "xlink:") {
+                        // setAttributeNS setAttribute won't works..
+//                        el.setAttributeNS("http://www.w3.org/1999/xlink", key.substring(6), String(attr[key]));
+                        el.attributes[key.substring(6)] =  String(attr[key]);
+                    } else {
+//                        el.setAttribute(key, String(attr[key]));
+                        el.attributes[key] =  String(attr[key]);
+                    }
+                }
+        } else {
+            el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el);
+        }
+        return el;
+    }
+    
+    var predefValue = dasharray[String(value).toLowerCase()],
+            calculatedValues,
+            width,
+            butt,
+            i,
+            l,
+            widthFactor;
+
+    value = predefValue || ((value !== undefined) && [].concat(value));
+    if (value) {
+
+        width = o.attrs["stroke-width"] || 1;
+        butt = {
+            round: width,
+            square: width,
+            butt: 0
+        }[params["stroke-linecap"] || o.attrs["stroke-linecap"]] || 0;
+        l = i = value.length;
+        widthFactor = predefValue ? width : 1;
+
+        if (value[0] == 'none') {
+            calculatedValues = value;
+        } else {
+            calculatedValues = [];
+            while (i--) {
+                calculatedValues[i] = (value[i] * widthFactor + ((i % 2) ? 1 : -1) * butt);
+                calculatedValues[i] <= 0 && (calculatedValues[i] = 0.01 + (width <= 1 ? butt : 0));
+                if (isNaN(calculatedValues[i])) {
+                    calculatedValues[i] = 0;
+                }
+            }
+        }
+
+        if (R.is(value, 'array')) {
+            $(o.node, {
+                "stroke-dasharray": calculatedValues.join(",")
+            });
+        }
+    }
+}
+
 
 setFillAndStroke = function (o, params) {
     //Roo.log(JSON.stringify(params));
index 0816c6a..facc7c5 100644 (file)
 importz = imports['seed/importz.js'].importz;
 Raphael = importz('Raphael');
 Roo = importz('Roo');
-       /**
-       * Escapes string for XML interpolation
-       * @param value string or number value to escape
-       * @returns string escaped
-       */
-       function escapeXML(s) {
-               if ( typeof s === 'number' ) return s.toString();
-
-               var replace = {
-            '&': 'amp',
-            '<': 'lt',
-            '>': 'gt',
-            '"': 'quot',
-            '\'': 'apos'
-        };
-
-               for ( var entity in replace ) {
-                       s = s.replace(new RegExp(entity, 'g'), '&' + replace[entity] + ';');
-               }
-
-               return s;
-       }
-
-       /**
-       * Generic map function
-       * @param iterable the array or object to be mapped
-       * @param callback the callback function(element, key)
-       * @returns array
-       */
-       function map(iterable, callback) {
-               var mapped = new Array;
-
-               for ( var i in iterable ) {
-                       if ( iterable.hasOwnProperty(i) ) {
-                               var value = callback.call(this, iterable[i], i);
-
-                               if ( value !== null ) mapped.push(value);
-                       }
-               }
-
-               return mapped;
-       }
-
-       /**
-       * Generic reduce function
-       * @param iterable array or object to be reduced
-       * @param callback the callback function(initial, element, i)
-       * @param initial the initial value
-       * @return the reduced value
-       */
-       function reduce(iterable, callback, initial) {
-               for ( var i in iterable ) {
-                       if ( iterable.hasOwnProperty(i) ) {
-                               initial = callback.call(this, initial, iterable[i], i);
-                       }
-               }
-
-               return initial;
-       }
-
-       /**
-       * Utility method for creating a tag
-       * @param name the tag name, e.g., 'text'
-       * @param attrs the attribute string, e.g., name1="val1" name2="val2"
-       * or attribute map, e.g., { name1 : 'val1', name2 : 'val2' }
-       * @param content the content string inside the tag
-       * @returns string of the tag
-       */
-       function tag(name, attrs, matrix, content) {
-               if ( typeof content === 'undefined' || content === null ) {
-                       content = '';
-               }
-
-               if ( typeof attrs === 'object' ) {
-                       attrs = map(attrs, function(element, name) {
-                               if ( name === 'transform') return;
-
-                               return name + '="' + escapeXML(element) + '"';
-                       }).join(' ');
-               }
-
-               return '<' + name + ( matrix ? ' transform="matrix(' + matrix.toString().replace(/^matrix\(|\)$/g, '') + ')" ' : ' ' ) + attrs + '>' +
-             content +
+
+/**
+ * Escapes string for XML interpolation
+ * @param value string or number value to escape
+ * @returns string escaped
+ */
+function escapeXML(s) {
+    if (typeof s === 'number')
+        return s.toString();
+
+    var replace = {
+        '&': 'amp',
+        '<': 'lt',
+        '>': 'gt',
+        '"': 'quot',
+        '\'': 'apos'
+    };
+
+    for (var entity in replace) {
+        s = s.replace(new RegExp(entity, 'g'), '&' + replace[entity] + ';');
+    }
+
+    return s;
+}
+
+/**
+ * Generic map function
+ * @param iterable the array or object to be mapped
+ * @param callback the callback function(element, key)
+ * @returns array
+ */
+function map(iterable, callback) {
+    var mapped = new Array;
+
+    for (var i in iterable) {
+        if (iterable.hasOwnProperty(i)) {
+            var value = callback.call(this, iterable[i], i);
+
+            if (value !== null)
+                mapped.push(value);
+        }
+    }
+
+    return mapped;
+}
+
+/**
+ * Generic reduce function
+ * @param iterable array or object to be reduced
+ * @param callback the callback function(initial, element, i)
+ * @param initial the initial value
+ * @return the reduced value
+ */
+function reduce(iterable, callback, initial) {
+    for (var i in iterable) {
+        if (iterable.hasOwnProperty(i)) {
+            initial = callback.call(this, initial, iterable[i], i);
+        }
+    }
+
+    return initial;
+}
+
+/**
+ * Utility method for creating a tag
+ * @param name the tag name, e.g., 'text'
+ * @param attrs the attribute string, e.g., name1="val1" name2="val2"
+ * or attribute map, e.g., { name1 : 'val1', name2 : 'val2' }
+ * @param content the content string inside the tag
+ * @returns string of the tag
+ */
+function tag(name, attrs, matrix, content) {
+    if (typeof content === 'undefined' || content === null) {
+        content = '';
+    }
+
+    if (typeof attrs === 'object') {
+        attrs = map(attrs, function (element, name) {
+            if (name === 'transform')
+                return;
+
+            return name + '="' + escapeXML(element) + '"';
+        }).join(' ');
+    }
+
+    return '<' + name + (matrix ? ' transform="matrix(' + matrix.toString().replace(/^matrix\(|\)$/g, '') + ')" ' : ' ') + attrs + '>' +
+            content +
             '</' + name + '>' + "\n";
-       }
-
-       /**
-       * @return object the style object
-       */
-       function extractStyle(node) {
-        //Roo.log(JSON.stringify(style));
-               return {
-                       font: {
-                               family: typeof node.attrs['font-family'] === 'undefined' ? null :node.attrs['font-family'],
-                               size:   typeof node.attrs['font-size'] === 'undefined' ? null : (node.attrs['font-size']),
-                anchor : typeof node.attrs['text-anchor'] === 'undefined' ? null : node.attrs['text-anchor'],
-                               }
-                       };
-       }
-
-       /**
-       * @param style object from style()
-       * @return string
-       */
-       function styleToString(style) {
-               // TODO figure out what is 'normal'
-        //Roo.log(JSON.stringify(style));
-        var r = [
-                'font-family:' + style.font.family,
-                'font-weight:normal',
-                'font-style:normal',
-                'font-stretch:normal',
-                'font-variant:normal'
-        ];
-        if (style.font.size !== null ) {
-                r.push('font-size: ' + style.font.size + 'px') 
+}
+
+/**
+ * @return object the style object
+ */
+function extractStyle(node) {
+    //Roo.log(JSON.stringify(style));
+    return {
+        font: {
+            family: typeof node.attrs['font-family'] === 'undefined' ? null : node.attrs['font-family'],
+            size: typeof node.attrs['font-size'] === 'undefined' ? null : (node.attrs['font-size']),
+            anchor: typeof node.attrs['text-anchor'] === 'undefined' ? null : node.attrs['text-anchor'],
         }
-        
-        return r.join(';')
-        
-       }
-
-       /**
-       * Computes tspan dy using font size. This formula was empircally determined
-       * using a best-fit line. Works well in both VML and SVG browsers.
-       * @param fontSize number
-       * @return number
-       */
-       function computeTSpanDy(fontSize, line, lines) {
-               if ( fontSize === null ) fontSize = 10;
-
-               //return fontSize * 4.5 / 13
-               return fontSize * 4.5 / 13 * ( line - .2 - lines / 2 ) * 3.5;
-       }
-
-       var serializer = {
-               'text': function(node) {
-                       style = extractStyle(node);
-            //Roo.log(JSON.stringify(node, null,4));
-                       var tags = new Array;
-
-                       map(node.attrs['text'].split('\n'), function(text, iterable, line) {
-                line = line || 0;
-                               tags.push(tag(
-                                       'text',
-                                       reduce(
-                                               node.attrs,
-                                               function(initial, value, name) {
-                                                       if ( name !== 'text' && name !== 'w' && name !== 'h' ) {
-                                                               if ( name === 'font-size') value = value + 'px';
-
-                                                               initial[name] = escapeXML(value.toString());
-                                                       }
-
-                                                       return initial;
-                                               },
-                                               {
-                                style: 'text-anchor: ' + (style.font.anchor ? (style.font.anchor  +';' ): 'middle;') + 
-                                    styleToString(style) + ';'
-                        }
-                                       ),
-                                       node.matrix,
-                                       tag('tspan',
-                            {
-                                dy: computeTSpanDy(style.font.size, line + 1, node.attrs['text'].split('\n').length)
-                            },
-                            null,
-                            escapeXML(text)
-                    )
-                               ));
-                       });
-
-                       return tags;
-               },
-               'path' : function(node) {
-                       var initial = ( node.matrix.a === 1 && node.matrix.d === 1 ) ? {} : { 'transform' : node.matrix.toString() };
-            
-            
-            
-                       return tag(
-                               'path',
-                               reduce(
-                                       node.attrs,
-                                       function(initial, value, name) {
-                                               if ( name === 'path' ) {
-                            name = 'd';
-                        }
+    };
+}
+
+/**
+ * @param style object from style()
+ * @return string
+ */
+function styleToString(style) {
+    // TODO figure out what is 'normal'
+    //Roo.log(JSON.stringify(style));
+    var r = [
+        'font-family:' + style.font.family,
+        'font-weight:normal',
+        'font-style:normal',
+        'font-stretch:normal',
+        'font-variant:normal'
+    ];
+    if (style.font.size !== null) {
+        r.push('font-size: ' + style.font.size + 'px')
+    }
+
+    return r.join(';')
+
+}
 
-                                               initial[name] = (typeof(value) == 'undefined') ? '' : value.toString();
+/**
+ * Computes tspan dy using font size. This formula was empircally determined
+ * using a best-fit line. Works well in both VML and SVG browsers.
+ * @param fontSize number
+ * @return number
+ */
+function computeTSpanDy(fontSize, line, lines) {
+    if (fontSize === null)
+        fontSize = 10;
 
-                                               return initial;
-                                       },
-                    {
-                            style:  'fill:' + Raphael.color(node.attrs.fill).hex + ';'
+    //return fontSize * 4.5 / 13
+    return fontSize * 4.5 / 13 * (line - .2 - lines / 2) * 4.5;
+}
+
+var serializer = {
+    'text': function (node) {
+        var style = extractStyle(node);
+            
+        var tags = new Array;
+
+        var content = [];
+
+        var textArray = node.attrs['text'].split('\n');
+
+        textArray.forEach((v,k) => {
+            content.push(tag('tspan',
+                {
+                    x: node.attrs.x,
+                    dy: computeTSpanDy(style.font.size, k + 1, textArray.length)
+                },
+                null,
+                escapeXML(v)
+            ))
+
+        });
+
+        tags.push(tag(
+            'text',
+            reduce(
+                node.attrs,
+                function (initial, value, name) {
+                    if (name !== 'text' && name !== 'w' && name !== 'h') {
+                        if (name === 'font-size')
+                            value = value + 'px';
+
+                        initial[name] = escapeXML(value.toString());
                     }
-                               ),
-                               node.matrix
-                               );
-               }
-               // Other serializers should go here
-       };
+
+                    return initial;
+                },
+                {
+                    style: 'text-anchor: ' + (style.font.anchor ? (style.font.anchor + ';') : 'middle;') +
+                            styleToString(style) + ';'
+                }
+            ),
+            node.matrix,
+            content.join("")
+        ));
+
+        return tags;
+    },
+    'path': function (node) {
+        var initial = (node.matrix.a === 1 && node.matrix.d === 1) ? {} : {'transform': node.matrix.toString()};
+
+
+
+        return tag(
+                'path',
+                reduce(
+                        node.attrs,
+                        function (initial, value, name) {
+                            if (name === 'path') {
+                                name = 'd';
+                            }
+
+                            initial[name] = (typeof (value) == 'undefined') ? '' : value.toString();
+
+                            return initial;
+                        },
+                        {
+                            style: 'fill:' + Raphael.color(node.attrs.fill).hex + ';'
+                        }
+                ),
+                node.matrix
+                );
+    }
+    // Other serializers should go here
+};
 
 function toSVG() {
-    var
-        paper   = this,
-         
-        svg     = '<svg style="overflow: hidden; position: relative;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="' + paper.width + '" version="1.1" height="' + paper.height + '">'
-        ;
-
-    
-    for ( var node = paper.bottom; node != null; node = node.next ) {
+    var paper = this,
+        svg = '<svg style="overflow: hidden; position: relative;" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="' + paper.width + '" version="1.1" height="' + paper.height + '">';
+
+
+    for (var node = paper.bottom; node != null; node = node.next) {
         //if ( node.node.style.display === 'none' ) continue;
 
         var attrs = '';
-
+        
         // Use serializer
-        if ( typeof serializer[node.type] === 'function' ) {
+        if (typeof serializer[node.type] === 'function') {
             svg += serializer[node.type](node);
 
             continue;
         }
 
-        switch ( node.type ) {
+        switch (node.type) {
             case 'image':
                 attrs += ' preserveAspectRatio="none"';
                 break;
         }
         //Roo.log(JSON.stringify(node, null,4));
-        
-        for ( i in node.attrs ) {
+
+        for (i in node.attrs) {
             var name = i;
-            
+
             var val = node.attrs[i].toString();
-            switch ( i ) {
+            switch (i) {
                 case 'src':
                     name = 'xlink:href';
 
@@ -251,27 +260,27 @@ function toSVG() {
                 case 'transform':
                     name = '';
                     break;
-                
+
                 case 'stroke':
                 case 'fill':
                     //s(JSON.stringify(node, null,4));
-                    val = typeof(node.node.attributes[i]) == 'undefined' ? val : node.node.attributes[i];
-                    
+                    val = typeof (node.node.attributes[i]) == 'undefined' ? val : node.node.attributes[i];
+
                     val = Raphael.color.getRGB(val).hex;
                     //Roo.log("fill: " + val);
                     break;
             }
 
-            if ( name ) {
+            if (name) {
                 attrs += ' ' + name + '="' + escapeXML(val) + '"';
             }
         }
 
-        svg += '<' + node.type + ' transform="matrix(' + node.matrix.toString().replace(/^matrix\(|\)$/g, '') + ')"' + attrs + '></' + node.type + '>' + "\n"; 
+        svg += '<' + node.type + ' transform="matrix(' + node.matrix.toString().replace(/^matrix\(|\)$/g, '') + ')"' + attrs + '></' + node.type + '>' + "\n";
     }
 
     svg += '</svg>';
+
     return svg;
 };
  
\ No newline at end of file