g.circular.js
[g.raphael] / g.circular.js
1 /*
2  * g.Raphael 0.5 - Charting library, based on RaphaĆ«l
3  *
4  * Copyright (c) 2009 Dmitry Baranovskiy (http://g.raphaeljs.com)
5  * Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license.
6  */
7 Raphael = typeof(Raphael) != 'undefined' ? Raphael :  (imports ? imports.seed.Raphael.Raphael : {});
8 Roo = typeof(Roo) != 'undefined' ? Roo:  (imports ? imports.seed.Roo.Roo: {});
9 //chartinst = typeof(chartinst) != 'undefined' ? chartinst:  (imports ? imports.chartinst.chartinst : {});
10  
11
12
13 (function () {
14
15     /**
16      * @param {Raphael} paper to draw on
17      * @param {int} cx - centre X
18      * @param {int} cy - centre Y
19      * @param {int} r - radius
20      * @param {Array} values
21      * @param {Object} opts options
22      *   cut : after this meany items - do not show a pie element?
23      *   
24      */
25
26     function Circularchart(paper, cx, cy, r, values, opts) {
27         
28         var chartinst = this;
29         
30         opts = opts || {};
31         
32         var colors = [
33             '#5f236c',
34             '#9336a7',
35             '#cc8cda',
36             '#6666b2',
37             '#9999cc',
38             '#66d6fb',
39             '#4795af',
40             '#93e2fc',
41             '#e0f6fe',
42             '#eeeeee'
43         ];
44         
45         paper.customAttributes.circularPath = function (cx, cy, value, maxvalue, maxangle, color, R) {
46             var alpha = maxangle / maxvalue * value,
47                 a = (90 - alpha) * Math.PI / 180,
48                 x = cx + R * Math.cos(a),
49                 y = cy - R * Math.sin(a),
50                 path;
51             
52             path = [["M", cx, cy - R], ["A", R, R, 0, +(alpha > 180), 1, x, y]];
53
54             return {path: path, stroke: color};
55         };
56         
57         if (!paper.raphael.is(values, "array")) {
58             values = [values];
59         }
60         
61         var chart = paper.set(),
62             sectors = [],
63             len = values.length,
64             maxangle = opts.maxangle || 270,
65             maxvalue = 0,
66             total = 0,
67             cut = opts.cut || 8;
68             
69         var barwidth = opts.barwidth || Math.min(Math.floor(r / cut), 12);
70         
71         var tempVal = [];
72         
73         for (var i = 0; i < len; i++){
74             
75             maxvalue = (maxvalue > values[i]) ? maxvalue : values[i];
76             
77             total += values[i];
78             
79             if(i <= cut){
80                 tempVal[i] = {
81                     value : values[i],
82                     order : i,
83                     others : false,
84                     valueOf: function () { return this.value; }
85                 };
86                 continue;
87             }
88             
89             tempVal[cut].value += values[i] * 1;
90             tempVal[cut].others = true;
91             
92         }
93         
94         values = tempVal;
95         len = values.length;
96                 
97         if (!opts.no_sort) {
98             values.sort(function (a, b) {
99                 return b.value - a.value;
100             });
101         }
102         
103         var rr = r;
104         
105         for (var i = 0; i < len; i++){
106             
107             var p = paper.path().attr({
108                 "stroke": "#fff", 
109                 "stroke-width": barwidth, 
110                 "stroke-linecap": "round", 
111                 "stroke-linejoin": "round"
112                 
113             }).attr({circularPath: [cx, cy, values[i], maxvalue, maxangle, colors[i] || chartinst.colors[i], rr]});
114             
115             var alpha = 90 * Math.PI / 180,
116             startX = cx + rr * Math.cos(alpha),
117             startY = cy - rr * Math.sin(alpha),
118             circleWidth = Math.max(Math.floor(barwidth / 2 - 1), 1);
119
120             paper.circle(startX, startY, circleWidth).attr({stroke: "none", fill: "#fff"});
121             
122             p.value = values[i];
123             sectors.push(p);
124             
125             rr -= barwidth;
126         }
127         
128         paper.text(cx - r + 20, cy + r + 30, (opts.totalmsg || 'Total:') + ' ' + total ).attr(opts.txtattr || chartinst.txtattr).attr({ fill: "#000", "text-anchor": "start"});
129         
130         var legend = function (labels, otherslabel, mark) {
131             var x = cx + r  + r / 3,
132                 y = cy - r,
133                 labels = labels || [];
134         
135             mark = paper[mark && mark.toLowerCase()] || "circle";
136             
137             for (var i = 0; i < len; i++) {
138                 var j = values[i].order,
139                     txt;
140
141                 if(values[i].others){
142                     continue;
143                 }
144                 
145                 paper[mark](x + 5, y, 5).attr({ fill: colors[i] || chartinst.colors[i], stroke: "none" })
146                 txt = paper.text(x + 20, y, labels[j] || values[i]).attr(opts.txtattr || chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"})
147                 
148                 y += txt.getBBox().height * 1.2;
149             }
150             
151             for (var i = 0; i < len; i++) {
152                 var j = values[i].order,
153                     txt;
154
155                 if(!values[i].others){
156                     continue;
157                 }
158                 
159                 paper[mark](x + 5, y, 5).attr({ fill: colors[i] || chartinst.colors[i], stroke: "none" })
160                 txt = paper.text(x + 20, y, otherslabel || 'Others').attr(opts.txtattr || chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"})
161                 
162                 y += txt.getBBox().height * 1.2;
163             }
164
165         };
166
167         if (opts.legend) {
168             legend(opts.legend, opts.legendothers, opts.legendmark);
169         }
170
171         chart.sectors = sectors;
172         chart.cx = cx;
173         chart.cy = cy;
174         chart.r = r;
175         return chart;
176     };
177     
178     //inheritance
179     var F = function() {};
180     F.prototype = Raphael.g;
181     Circularchart.prototype = new F;
182     
183     //public
184     Raphael.fn.circularchart = function(cx, cy, r, values, opts) {
185         return new Circularchart(this, cx, cy, r, values, opts);
186     }
187     
188 })();