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         if(opts.colors){
46             colors = opts.colors;
47         }
48         
49         paper.customAttributes.circularPath = function (cx, cy, value, maxvalue, maxangle, color, R) {
50             var alpha = maxangle / maxvalue * value,
51                 a = (90 - alpha) * Math.PI / 180,
52                 x = cx + R * Math.cos(a),
53                 y = cy - R * Math.sin(a),
54                 path;
55             if (total == value) {
56                 path = [["M", cx, cy - R], ["A", R, R, 0, 1, 1, cx - 1, cy - R]];
57             } else {
58                 path = [["M", cx, cy - R], ["A", R, R, 0, +(alpha > 180), 1, x, y]];
59             }
60
61             return {path: path, stroke: color};
62         };
63         
64         if (!paper.raphael.is(values, "array")) {
65             values = [values];
66         }
67         
68         var chart = paper.set(),
69             sectors = [],
70             len = values.length,
71             maxangle = opts.maxangle || 270,
72             maxvalue = 0,
73             total = 0,
74             cut = opts.cut || 10;
75             
76         var barwidth = Math.min(Math.floor(r / cut), 12);
77         
78         for (var i = 0; i < len; i++){
79             
80             maxvalue = (maxvalue > values[i]) ? maxvalue : values[i];
81             
82             total += values[i];
83             
84             if(i <= cut){
85                 values[i] = {
86                     value : values[i],
87                     order : i,
88                     others : false,
89                     valueOf: function () { return this.value; }
90                 };
91                 continue;
92             }
93             
94             values[cut].value += values[i];
95             values[cut].others = true;
96             
97             values.splice(i, 1);
98             
99         }
100         
101         len = values.length;
102                 
103         if (!opts.no_sort) {
104             values.sort(function (a, b) {
105                 return b.value - a.value;
106             });
107         }
108         
109         var rr = r;
110         
111         for (var i = 0; i < len; i++){
112             
113             var p = paper.path().attr({
114                 "stroke": "#fff", 
115                 "stroke-width": barwidth, 
116                 "stroke-linecap": "round", 
117                 "stroke-linejoin": "round"
118                 
119             }).attr({circularPath: [cx, cy, values[i], maxvalue, maxangle, colors[i] || chartinst.colors[i], rr]});
120             
121             var alpha = 90 * Math.PI / 180,
122             startX = cx + rr * Math.cos(alpha),
123             startY = cy - rr * Math.sin(alpha),
124             circleWidth = Math.max(Math.floor(barwidth / 2 - 1), 1);
125
126             paper.circle(startX, startY, circleWidth).attr({stroke: "none", fill: "#fff"});
127             
128             p.value = values[i];
129             sectors.push(p);
130             
131             rr -= barwidth;
132         }
133         
134         paper.text(cx - r + 20, cy + r + 30, (opts.totalmsg || 'Total:') + ' ' + total ).attr(opts.txtattr || chartinst.txtattr).attr({ fill: "#000", "text-anchor": "start"});
135         
136         var legend = function (labels, otherslabel, mark, dir) {
137             var x = cx + r  + r / 3,
138                 y = cy,
139                 labels = labels || [];
140         
141             dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "east";
142             mark = paper[mark && mark.toLowerCase()] || "circle";
143             chart.labels = paper.set();
144
145 //            for (var i = 0; i < len; i++) {
146 //                var j = values[i].order,
147 //                    txt;
148 //
149 //                var l = values[i].others ? (otherslabel || "Others") : labels[j];
150 //                
151 //                chart.labels.push(paper.set());
152 //                chart.labels[i].push(paper[mark](x + 5, y, 5).attr({ fill: colors[i] || chartinst.colors[i], stroke: "none" }));
153 //                chart.labels[i].push(
154 //                    txt = paper.text(x + 20, y, l || values[i]).attr(opts.txtattr || chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"}));
155 //                
156 //                y += txt.getBBox().height * 1.2;
157 //            }
158             
159             for (var i = 0; i < len; i++) {
160                 var j = values[i].order,
161                     txt;
162
163                 if(values[i].others){
164                     continue;
165                 }
166                 
167                 chart.labels.push(paper.set());
168                 chart.labels[i].push(paper[mark](x + 5, y, 5).attr({ fill: colors[i] || chartinst.colors[i], stroke: "none" }));
169                 chart.labels[i].push(
170                     txt = paper.text(x + 20, y, labels[j] || values[i]).attr(opts.txtattr || chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"}));
171                 
172                 y += txt.getBBox().height * 1.2;
173             }
174             
175 //            for (var i = 0; i < len; i++) {
176 //                var j = values[i].order,
177 //                    txt;
178 //
179 //                if(!values[i].others){
180 //                    continue;
181 //                }
182 //                
183 //                chart.labels.push(paper.set());
184 //                chart.labels[len - 1].push(paper[mark](x + 5, y, 5).attr({ fill: colors[i] || chartinst.colors[i], stroke: "none" }));
185 //                chart.labels[len - 1].push(
186 //                    txt = paper.text(x + 20, y, otherslabel || 'Others').attr(opts.txtattr || chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"}));
187 //                
188 //                y += txt.getBBox().height * 1.2;
189 //            }
190
191             var bb = chart.labels.getBBox(),
192                 tr = {
193                     east: [0, -bb.height / 2],
194                     west: [-bb.width - 2 * r - 20, -bb.height / 2],
195                     north: [-r - bb.width / 2, -r - bb.height - 10],
196                     south: [-r - bb.width / 2, r + 10]
197                 }[dir];
198
199             chart.labels.translate.apply(chart.labels, tr);
200             chart.push(chart.labels);
201         };
202
203         if (opts.legend) {
204             legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);
205         }
206
207         chart.sectors = sectors;
208         chart.cx = cx;
209         chart.cy = cy;
210         chart.r = r;
211         return chart;
212     };
213     
214     //inheritance
215     var F = function() {};
216     F.prototype = Raphael.g;
217     Circularchart.prototype = new F;
218     
219     //public
220     Raphael.fn.circularchart = function(cx, cy, r, values, opts) {
221         return new Circularchart(this, cx, cy, r, values, opts);
222     }
223     
224 })();