fix #7522 - merge insights into main branch
authorAlan <alan@roojs.com>
Tue, 9 May 2023 07:47:56 +0000 (15:47 +0800)
committerAlan <alan@roojs.com>
Tue, 9 May 2023 07:47:56 +0000 (15:47 +0800)
g.bar.horizontal.js [new file with mode: 0644]

diff --git a/g.bar.horizontal.js b/g.bar.horizontal.js
new file mode 100644 (file)
index 0000000..6b82ca4
--- /dev/null
@@ -0,0 +1,219 @@
+/*!
+ * 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.
+ */
+imports = typeof(imports) == 'undefined' ? false : imports;
+Raphael = typeof(Raphael) != 'undefined' ? Raphael :  (imports ? imports.seed.Raphael.Raphael : {});
+Roo = typeof(Roo) != 'undefined' ? Roo:  (imports ? imports.seed.Roo.Roo: {});
+
+(function () {
+
+    /**
+     * Create a horizontal chart
+     * support left axis with labels and bottom axis with interval
+     * 
+     * @param {Raphael} paper to draw on
+     * @param {int} width - width of the chart
+     * @param {int} height - height of the chart
+     * @param {Array} values
+     * @param {Object} opts options
+     *   background (string) : background color
+     *   colors (array) : colors of the bars
+     *   labelfont (string) : font family of bar labels
+     *   labelfontsize (number) : font size of bar labels
+     *   labelfontweight (string) (number) : font weight of bar labels
+     *   labelfontcolors (array) : font colors of bar labels
+     *   gutter (string) (number) : height of gutters in terms of percentage of bar height (e.g. '20%' : height raito of a bar to a gutter is 10 to 2)
+     *   axis (string) : composed of 4 '0' / '1' separated by space (indicated whether top / right / bottom / left axis should be shown) 
+     *   (e.g. '0 0 1 1' indicates that the bottom and the left axis should be shown)
+     *   leftaxiswidth (number) : width of left axis area
+     *   leftaxislabels (array) : labels in left axis area
+     *   leftaxisfontsize (number) : font size of labels in left axis
+     *   bottomaxisheight (number) : height of bottom axis area
+     *   bottomaxisstep (number) : number of steps in bottom axis
+     *   bottomaxisfontsize (number) : font size of labels in bottom axis
+     *   axisfont (string) : font family of labels in axes
+     *   axisfontweight (string) (number) : font weight of labels in axes
+     *   axisfontcolor (string) : font color of labels in axes
+     */
+
+    function MHBarchart(paper, width, height, values, opts) {
+        opts = opts || {};
+
+        var chartinst = this,
+            chart = paper.set(),
+            len = values.length,
+            max = values.length == 0 ? 0 : Math.max(...values),
+            background = opts.background || '#FFFFFF',
+            colors = opts.colors || chartinst.colors,
+            labelFont = opts.labelfont || 'Work Sans',
+            labelFontSize = opts.labelfontsize || 12,
+            labelFontWeight = opts.labelfontweight || 'bold',
+            labelFontColors = opts.labelfontcolors || [],
+            gutter = parseFloat(opts.gutter || "40%"),
+            axis = opts.axis || "0 0 0 0",
+            ax = (axis + "").split(/[,\s]+/),
+            leftAxisWidth = 0,
+            leftAxisLabels = opts.leftaxislabels || [];
+            leftAxisFontSize = opts.leftaxisfontsize || 16,
+            bottomAxisHeight = 0,
+            bottomAxisStep = opts.bottomaxisstep || 10;
+            bottomAxisFontSize = opts.bottomaxisfontsize || 16,
+            axisFont = opts.axisfont || 'Work Sans',
+            axisFontWeight = opts.axisfontweight || 'normal',
+            axisFontColor = opts.axisfontcolor || '#323232';
+
+        // bottom axis
+        if(+ax[2]) {
+            bottomAxisHeight = opts.bottomaxisheight || 30;
+            max = Math.ceil(max / bottomAxisStep) * bottomAxisStep;
+        }
+        // left axis
+        if(+ax[3]) {
+            leftAxisWidth = opts.leftaxiswidth || 240;
+        }
+
+        if(labelFontColors.length < len) {
+            for(var i = labelFontColors.length; i < len; i++) {
+                labelFontColors.push('#FFFFFF');
+            }
+        }
+
+        // background
+        paper.rect(0, 0, width, height).attr({ stroke: "none", fill: background });
+
+        var barWidth = (width - leftAxisWidth); // maximum width of bar
+        var barHeight = (height - bottomAxisHeight) / (len * (100 + gutter) + gutter) * 100;
+        var barGutter = barHeight * (gutter / 100);
+
+        // bottom axis
+        if(+ax[2]) {
+            chartinst.bottomAxis(
+                paper,
+                leftAxisWidth,
+                height - bottomAxisHeight,
+                width - leftAxisWidth,
+                max,
+                bottomAxisStep,
+                bottomAxisHeight,
+                axisFont,
+                bottomAxisFontSize,
+                axisFontWeight,
+                axisFontColor
+            )
+        }
+
+        // left axis
+        if(+ax[3]) {
+            chartinst.leftAxis(
+                paper,
+                leftAxisWidth,
+                0,
+                height - bottomAxisHeight,
+                leftAxisLabels,
+                barHeight,
+                barGutter,
+                axisFont,
+                leftAxisFontSize,
+                axisFontWeight,
+                axisFontColor
+            )
+        }
+
+        // bars
+        var unit = barWidth / max;
+        
+        values.forEach(function(v,k) {
+            if(v == 0) {
+                return;
+            }
+            
+            paper.rect(leftAxisWidth, barGutter + (k * (barHeight + barGutter)), v * unit, barHeight).attr({ stroke: "none", fill: colors[k] });
+
+            // bar label
+            // 16 pixels away from right of left axis
+            // align bar label in the center
+            paper.text(leftAxisWidth + 16, barGutter + (k * (barHeight + barGutter)) + barHeight / 2, Roo.util.Format.number(v, 0)).attr({ 
+                "font-size": labelFontSize,
+                "font-family": labelFont,
+                "font-weight": labelFontWeight,
+                "text-anchor": 'start',
+                fill : labelFontColors[k]
+            });
+
+        });
+
+        return chart;
+        
+    }
+
+    //inheritance
+    var F = function() {};
+    F.prototype = Raphael.g;
+    MHBarchart.prototype = new F;
+    
+    Raphael.fn.mhbarchart = function(width, height, values, opts) {
+        return new MHBarchart(this, width, height, values, opts);
+    };
+
+    MHBarchart.prototype.bottomAxis = function (paper, x, y, length, max, steps, axisHeight, axisFont, axisFontSize, axisFontWeight, axisFontColor)
+    {
+        var path = ["M", x, y, "l", length, 0],
+            text = paper.set(),
+            d = Math.ceil(max / steps),
+            dl = length / steps;
+
+        for(var i = 0; i < steps; i++) {
+            paper.text(x + i * dl, y + axisHeight / 2, i * d).attr({ 
+                "font-size": axisFontSize,
+                "font-family": axisFont,
+                "font-weight": axisFontWeight,
+                "text-anchor": 'middle',
+                fill : axisFontColor
+            });
+
+            // bottom axis interval
+            paper.path(["M", x + i * dl , y, "l", 0, -1 * y]).attr({ stroke: '#9E9E9E', "stroke-width": 1 });
+        }
+        
+        var res = paper.path(path).attr({ stroke: '#000', "stroke-width": 0 }); // default no axis
+
+        res.text = text;
+        res.all = paper.set([res, text]);
+        res.remove = function () {
+            this.text.remove();
+            this.constructor.prototype.remove.call(this);
+        };
+
+        return res;
+    }
+
+    MHBarchart.prototype.leftAxis = function (paper, x, y, length, labels, barHeight, barGutter, axisFont, axisFontSize, axisFontWeight, axisFontColor)
+    {
+        var path = ["M", x, y, "l", 0, length],
+            text = paper.set();
+        
+        labels.forEach(function(v,k)  {
+            paper.text(0, barGutter + (k * (barHeight + barGutter)) + barHeight / 2, v).attr({ 
+                "font-size": axisFontSize,
+                "font-family": axisFont,
+                "font-weight": axisFontWeight,
+                "text-anchor": 'start',
+                fill : axisFontColor
+            });
+        });
+        
+        var res = paper.path(path).attr({ stroke: '#000', "stroke-width": 0 }); // default no axis
+
+        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