g.bar.js
[g.raphael] / g.bar.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 (function () {
8     var mmin = Math.min,
9         mmax = Math.max;
10
11     function finger(x, y, width, height, dir, ending, isPath, paper) {
12         var path,
13             ends = { round: 'round', sharp: 'sharp', soft: 'soft', square: 'square' };
14
15         // dir 0 for horizontal and 1 for vertical
16         if ((dir && !height) || (!dir && !width)) {
17             return isPath ? "" : paper.path();
18         }
19
20         ending = ends[ending] || "square";
21         height = Math.round(height);
22         width = Math.round(width);
23         x = Math.round(x);
24         y = Math.round(y);
25
26         switch (ending) {
27             case "round":
28                 if (!dir) {
29                     var r = ~~(height / 2);
30
31                     if (width < r) {
32                         r = width;
33                         path = [
34                             "M", x + .5, y + .5 - ~~(height / 2),
35                             "l", 0, 0,
36                             "a", r, ~~(height / 2), 0, 0, 1, 0, height,
37                             "l", 0, 0,
38                             "z"
39                         ];
40                     } else {
41                         path = [
42                             "M", x + .5, y + .5 - r,
43                             "l", width - r, 0,
44                             "a", r, r, 0, 1, 1, 0, height,
45                             "l", r - width, 0,
46                             "z"
47                         ];
48                     }
49                 } else {
50                     r = ~~(width / 2);
51
52                     if (height < r) {
53                         r = height;
54                         path = [
55                             "M", x - ~~(width / 2), y,
56                             "l", 0, 0,
57                             "a", ~~(width / 2), r, 0, 0, 1, width, 0,
58                             "l", 0, 0,
59                             "z"
60                         ];
61                     } else {
62                         path = [
63                             "M", x - r, y,
64                             "l", 0, r - height,
65                             "a", r, r, 0, 1, 1, width, 0,
66                             "l", 0, height - r,
67                             "z"
68                         ];
69                     }
70                 }
71                 break;
72             case "sharp":
73                 if (!dir) {
74                     var half = ~~(height / 2);
75
76                     path = [
77                         "M", x, y + half,
78                         "l", 0, -height, mmax(width - half, 0), 0, mmin(half, width), half, -mmin(half, width), half + (half * 2 < height),
79                         "z"
80                     ];
81                 } else {
82                     half = ~~(width / 2);
83                     path = [
84                         "M", x + half, y,
85                         "l", -width, 0, 0, -mmax(height - half, 0), half, -mmin(half, height), half, mmin(half, height), half,
86                         "z"
87                     ];
88                 }
89                 break;
90             case "square":
91                 if (!dir) {
92                     path = [
93                         "M", x, y + ~~(height / 2),
94                         "l", 0, -height, width, 0, 0, height,
95                         "z"
96                     ];
97                 } else {
98                     path = [
99                         "M", x + ~~(width / 2), y,
100                         "l", 1 - width, 0, 0, -height, width - 1, 0,
101                         "z"
102                     ];
103                 }
104                 break;
105             case "soft":
106                 if (!dir) {
107                     r = mmin(width, Math.round(height / 5));
108                     path = [
109                         "M", x + .5, y + .5 - ~~(height / 2),
110                         "l", width - r, 0,
111                         "a", r, r, 0, 0, 1, r, r,
112                         "l", 0, height - r * 2,
113                         "a", r, r, 0, 0, 1, -r, r,
114                         "l", r - width, 0,
115                         "z"
116                     ];
117                 } else {
118                     r = mmin(Math.round(width / 5), height);
119                     path = [
120                         "M", x - ~~(width / 2), y,
121                         "l", 0, r - height,
122                         "a", r, r, 0, 0, 1, r, -r,
123                         "l", width - 2 * r, 0,
124                         "a", r, r, 0, 0, 1, r, r,
125                         "l", 0, height - r,
126                         "z"
127                     ];
128                 }
129         }
130
131         if (isPath) {
132             return path.join(",");
133         } else {
134             return paper.path(path);
135         }
136     }
137
138     /*
139      * Vertical Barchart
140      * @param {Raphael} paper  The paper to render the graph on
141      * @param {int} x    left coord
142      * @param {int} y   right coord
143      * @param {int} width  width of graph
144      * @param {int} height heigt of graph
145      * @param {Array} values - single = [1,2,3] or multiple [ [1,2,3] , [1,2,3]]
146      * @param {Object} opts  - options
147      *    type :  {String} square | ???
148      *    gutter: {Number} percentage width default 20%
149      *    vgutter : {Number}  vertical gutter?
150      *    colors : {Array} list of colours - default chartinst.colors
151      *    xvalues : {Array} not sure - this looks like can be single or multi dimensional array 
152      *    yvalues : {Array} not sure - this looks like can be single or multi dimensional array
153      *    ymin :
154      *    axis: {String} eg. "top right bottom left" - which sides to show an axis eg. "0 0 1 1"
155      *    axisxstep
156      *    axisystep
157      *    axisxlabels: {Array} - note - first element appears left of first bar..
158      *    stacked
159      *    to
160      *    stretch
161      *    labels : {Array} labels to go above the chart..
162      *    
163      */
164     function VBarchart(paper, x, y, width, height, values, opts) {
165         opts = opts || {};
166         opts.xvalues 
167         
168         var chartinst = this,
169             type = opts.type || "square",
170             gutter = parseFloat(opts.gutter || "20%"),
171             chart = paper.set(),
172             bars = paper.set(),
173 //            covers = paper.set(),
174 //            covers2 = paper.set(),
175             total = Math.max.apply(Math, values),
176             stacktotal = [],
177             multi = 0,
178             colors = opts.colors || chartinst.colors,
179             len = values.length + 2,
180             sum = 0;
181             
182         opts.xvalues = opts.xvalues|| [];
183         if (!paper.raphael.is(opts.xvalues[0], "array")) {
184             opts.xvalues = [opts.xvalues];
185         }
186         opts.yvalues = opts.yvalues|| [];
187         if (!paper.raphael.is(opts.yvalues[0], "array")) {
188             opts.yvalues = [opts.yvalues];
189         }
190         
191         
192         var allx = Array.prototype.concat.apply([], opts.xvalues),
193             ally = Array.prototype.concat.apply([], opts.yvalues),
194             xdim = chartinst.snapEnds(
195                 Math.min.apply(Math, allx),
196                 Math.max.apply(Math, allx),
197                 opts.xvalues[0].length - 1
198             ),
199             minx = xdim.from,
200             maxx = xdim.to,
201             ydim = chartinst.snapEnds(
202                     Math.min.apply(Math, ally),
203                     Math.max.apply(Math, ally),
204                     opts.yvalues[0].length - 1
205             ),
206             miny = typeof(opts.ymin) == 'undefined' ? ydim.from : opts.ymin,
207             maxy = ydim.to,
208             kx = (width - gutter * 2) / ((maxx - minx) || 1),
209             ky = (height - gutter * 2) / ((maxy - miny) || 1);
210             
211        
212         
213         if (Raphael.is(values[0], "array") && values.length > 1) {
214             total = [];
215             multi = len;
216             len = 0;
217
218             for (var i = values.length; i--;) {
219                 bars.push(paper.set());
220                 total.push(Math.max.apply(Math, values[i]));
221                 len = Math.max(len, values[i].length);
222             }
223
224             for (var i = values.length; i--;) {
225                 if (values[i].length < len) {
226                     for (var j = len; j--;) {
227                         values[i].push(0);
228                     }
229                 }
230             }
231
232             total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
233         }
234         
235         for (var i = 0; i < len; i++) {
236             sum += values[i];
237             values[i] = { value: values[i], order: i, valueOf: function () { return this.value; } };
238         }
239         
240         total = (opts.to) || total;
241         Roo.log([width, len, gutter]);
242         var barwidth = width / (len * (90 + gutter) + gutter) * 100,
243             barhgutter = barwidth * (gutter) / 100,
244             barvgutter = opts.vgutter == null ? 20 : opts.vgutter,
245             stack = [],
246             X = x + barhgutter,
247             Y = (height - 2 * barvgutter) / total;
248         Roo.log([barwidth, X, barhgutter]);
249         if (!opts.stretch) {
250             barhgutter = Math.round(barhgutter);
251             barwidth = Math.floor(barwidth);
252         }
253         
254         
255          var axis = paper.set();
256         
257         if (opts.axis) {
258             
259             // Roo.log(opts.axis);
260             
261             // Value - "top right bottom left". If
262             var ax = (opts.axis + "").split(/[,\s]+/);
263             
264             // top axis
265             +ax[0] && axis.push(
266                     chartinst.axis(
267                         x + gutter,
268                         y + gutter,
269                         width - 2 * gutter,
270                         minx,
271                         maxx,
272                         opts.axisxstep || Math.floor((width - 2 * gutter) / 20),
273                         2,
274                         paper));
275             // right axis
276             +ax[1] && axis.push(
277                     chartinst.axis(
278                         x + width - gutter,
279                         y + height - gutter,
280                         height - 2 * gutter,
281                         miny, maxy,
282                         opts.axisystep || Math.floor((height - 2 * gutter) / 20),
283                         3,
284                         paper
285                     ));
286             // bottom axis
287             opts.axisxlabels = opts.axisxlabels || [];
288             // add elements at beginning and end of array...
289             opts.axisxlabels.unshift('');
290             opts.axisxlabels.push('');
291             opts.axisxstep  = opts.axisxstep  || (opts.axisxlabels ? opts.axisxlabels.length  -1    : false ) || len;
292             Roo.log(opts.axisxlabels);
293             
294             +ax[2] && axis.push(
295                 // bottom
296                 // x, y, length, from, to, steps, orientation, labels, type, dashsize, paper
297                 chartinst.axis(
298                     x + gutter ,
299                     y + height - gutter,
300                     width - gutter, // total width
301                     minx ,  // from
302                     maxx, //to
303                     opts.axisxstep ,
304                     0, // orientation
305                     opts.axisxlabels || false, // labels
306                     "-", // type
307                     5, // dash size
308                     paper
309                 ));
310             // left axis
311             +ax[3] && axis.push(
312                     chartinst.axis(
313                         x + gutter,
314                         y + height - gutter,
315                         height - 2 * gutter,
316                         miny,
317                         maxy ,
318 //                        opts.axisystep || Math.floor((height - 2 * gutter) / 20),
319                         10,
320                         1,
321                         paper
322             ));
323         }
324         
325         
326         !opts.stacked && (barwidth /= multi || 1);
327         
328         for (var i = 0; i < len; i++) {
329             stack = [];
330             if(i == 0){
331                 X += barwidth;
332             }
333             Roo.log( {X : X});
334             for (var j = 0; j < (multi || 1); j++) {
335                 var h = Math.round((multi ? values[j][i] : values[i]) * Y),
336                     top = y + height - barvgutter - h,
337                     bar = finger(Math.round(X + barwidth / 2), top + h, barwidth, h, true, type, null, paper).attr({ stroke: "none", fill: colors[multi ? j : i] });
338                     
339 //                    bar = finger(x, Y + barwidth / 2, Math.round(8 * X), barwidth - 1, false, type, null, paper).attr({stroke: "none", fill: colors[multi ? j : i]});
340                 
341                 
342                 if (multi && bars[j]) { // bars[j] did not appear to exist?
343                     bars[j].push(bar);
344                 } else {
345                     bars.push(bar);
346                 }
347                 
348                 bar.y = top;
349                 bar.x = Math.round(X + barwidth / 2);
350                 bar.w = barwidth;
351                 bar.h = h;
352                 bar.value = multi ? values[j][i] : values[i];
353                 
354                 if(!isNaN(bar.y) && opts.labels && opts.labels[i]){
355                     bar.labels = paper.set();
356                     var qtyLbl = paper.text(
357                             bar.x - 10,
358                             (bar.y - 10),
359                             opts.labels[i])
360                             .attr({
361                                 fill : '#000',
362                                 'text-anchor' : 'start',
363                                 font : '10px Arial'
364                             });
365
366                     bar.labels.push(qtyLbl);
367                 }
368                 
369                 if (!opts.stacked) {
370                     X += barwidth;
371                 } else {
372                     stack.push(bar);
373                 }
374             }
375
376             //X += barhgutter + 25; -- why add 25??
377             X += barhgutter;
378         }
379         X = x + barhgutter;
380         
381         
382         /*
383          * create the legend for Vbarchart
384          * 
385          */
386         
387 //        var legend = function (labels, otherslabel, mark, dir) {
388 //            var h = Y + 10;
389 //            
390 //            labels = labels || [];
391 ////            dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "south"; 
392 //            dir = "east"; // default set to east, do not support other position first...
393 //            mark = paper[mark && mark.toLowerCase()] || "circle";
394 //            chart.labels = paper.set();
395 //            
396 //            for (var i = 0; i < len; i++) {
397 //                var txt;
398 //                
399 //                values[i].others && (labels[i] = otherslabel || "Others");
400 //                
401 //                labels[i] = chartinst.labelise(labels[i], values[i], sum);
402 //                chart.labels.push(paper.set());
403 //                chart.labels[i].push(paper[mark](x + 5, h, 5).attr({ stroke: "none", fill: colors[i] }));
404 //                chart.labels[i].push(txt = paper.text(x + 20, h, labels[i] || values[i]).attr(chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"}));
405 //                covers[i].label = chart.labels[i];
406 //                h += txt.getBBox().height * 1.2;
407 //            }
408 //            
409 //            var tr = {
410 //                    east: [width + 15, - Y +30]
411 ////                    west: [-bb.width - 2 * r - 20, -bb.height / 2],
412 ////                    north: [-r - bb.width / 2, -r - bb.height - 10],
413 ////                    south: [ x - 5, 10]
414 //                }[dir];
415 //                
416 //            chart.labels.translate.apply(chart.labels, tr);
417 //            chart.push(chart.labels);
418 //        };
419 //
420 //        if (opts.legend) {
421 //            legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);
422 //        }
423         
424         
425         
426 //        chart.hover = function (fin, fout) {
427 //            covers2.hide();
428 //            covers.show();
429 //            covers.mouseover(fin).mouseout(fout);
430 //            return this;
431 //        };
432 //
433 //        chart.hoverColumn = function (fin, fout) {
434 //            covers.hide();
435 //            covers2.show();
436 //            fout = fout || function () {};
437 //            covers2.mouseover(fin).mouseout(fout);
438 //            return this;
439 //        };
440 //
441 //        chart.click = function (f) {
442 //            covers2.hide();
443 //            covers.show();
444 //            covers.click(f);
445 //            return this;
446 //        };
447
448 //        chart.each = function (f) {
449 //            if (!Raphael.is(f, "function")) {
450 //                return this;
451 //            }
452 //            for (var i = covers.length; i--;) {
453 //                f.call(covers[i]);
454 //            }
455 //            return this;
456 //        };
457 //
458 //        chart.eachColumn = function (f) {
459 //            if (!Raphael.is(f, "function")) {
460 //                return this;
461 //            }
462 //            for (var i = covers2.length; i--;) {
463 //                f.call(covers2[i]);
464 //            }
465 //            return this;
466 //        };
467 //
468 //        chart.clickColumn = function (f) {
469 //            covers.hide();
470 //            covers2.show();
471 //            covers2.click(f);
472 //            return this;
473 //        };
474         
475 //        chart.push(bars, covers, covers2);
476         chart.bars = bars;
477 //        chart.covers = covers;
478         return chart;
479     };
480
481     /**
482      * Horizontal Barchart
483      */
484     function HBarchart(paper, x, y, width, height, values, opts) {
485         opts = opts || {};
486         
487         var chartinst = this,
488             type = opts.type || "square",
489             gutter = parseFloat(opts.gutter || "20%"),
490             chart = paper.set(),
491             bars = paper.set(),
492             covers = paper.set(),
493             covers2 = paper.set(),
494             total = Math.max.apply(Math, values),
495             stacktotal = [],
496             multi = 0,
497             colors = opts.colors || chartinst.colors,
498             len = values.length,
499             others = 0,
500             sum = 0;
501             
502         if (Raphael.is(values[0], "array")) {
503             total = [];
504             multi = len;
505             len = 0;
506
507             for (var i = values.length; i--;) {
508                 bars.push(paper.set());
509                 total.push(Math.max.apply(Math, values[i]));
510                 len = Math.max(len, values[i].length);
511             }
512
513             if (opts.stacked) {
514                 for (var i = len; i--;) {
515                     var tot = 0;
516                     for (var j = values.length; j--;) {
517                         tot +=+ values[j][i] || 0;
518                     }
519                     stacktotal.push(tot);
520                 }
521             }
522
523             for (var i = values.length; i--;) {
524                 if (values[i].length < len) {
525                     for (var j = len; j--;) {
526                         values[i].push(0);
527                     }
528                 }
529             }
530
531             total = Math.max.apply(Math, opts.stacked ? stacktotal : total);
532         }
533         
534         for (var i = 0; i < len; i++) {
535             sum += values[i];
536             values[i] = { value: values[i], order: i, valueOf: function () { return this.value; } };
537         }
538         
539         if(opts.cut){
540            for (i = 0; i < len; i++) {
541                 if (i > opts.cut) {
542                     values[opts.cut].value += values[i];
543                     values[opts.cut].others = true;
544                     others = values[opts.cut].value;
545                 }
546             }
547             
548             len = Math.min(opts.cut + 1, values.length);
549             
550             others && values.splice(len) && (values[opts.cut].others = true);
551         }
552         
553         total = (opts.to) || Math.max.apply(Math, values);
554
555         var barheight = Math.floor(height / (len * (100 + gutter) + gutter) * 100),
556             bargutter = Math.floor(barheight * gutter / 100),
557             stack = [],
558             Y = y + bargutter,
559             X = (width - 1) / total;
560
561         !opts.stacked && (barheight /= multi || 1);
562     
563         for (var i = 0; i < len; i++) {
564             stack = [];
565
566             for (var j = 0; j < (multi || 1); j++) {
567                 var val = multi ? values[j][i] : values[i],
568                     bar = finger(x, Y + barheight / 2, Math.round(val * X), barheight - 1, false, type, null, paper).attr({stroke: "none", fill: colors[multi ? j : i]});
569
570                 if (multi) {
571                     bars[j].push(bar);
572                 } else {
573                     bars.push(bar);
574                 }
575
576                 bar.x = x + Math.round(val * X);
577                 bar.y = Y + barheight / 2;
578                 bar.w = Math.round(val * X);
579                 bar.h = barheight;
580                 bar.value = +val;
581
582                 if (!opts.stacked) {
583                     Y += barheight;
584                 } else {
585                     stack.push(bar);
586                 }
587             }
588             
589             if (opts.stacked) {
590                 var cvr = paper.rect(x, stack[0].y - stack[0].h / 2, width, barheight).attr(chartinst.shim);
591
592                 covers2.push(cvr);
593                 cvr.bars = paper.set();
594
595                 var size = 0;
596
597                 for (var s = stack.length; s--;) {
598                     stack[s].toFront();
599                 }
600
601                 for (var s = 0, ss = stack.length; s < ss; s++) {
602                     var bar = stack[s],
603                         cover,
604                         val = Math.round((size + bar.value) * X),
605                         path = finger(x, bar.y, val, barheight - 1, false, type, 1, paper);
606
607                     cvr.bars.push(bar);
608                     size && bar.attr({ path: path });
609                     bar.w = val;
610                     bar.x = x + val;
611                     covers.push(cover = paper.rect(x + size * X, bar.y - bar.h / 2, bar.value * X, barheight).attr(chartinst.shim));
612                     cover.bar = bar;
613                     size += bar.value;
614                 }
615
616                 Y += barheight;
617             }
618
619             Y += bargutter;
620         }
621
622         covers2.toFront();
623         Y = y + bargutter;
624
625         if (!opts.stacked) {
626             for (var i = 0; i < len; i++) {
627                 for (var j = 0; j < (multi || 1); j++) {
628                     var cover = paper.rect(x, Y, width, barheight).attr(chartinst.shim);
629
630                     covers.push(cover);
631                     cover.bar = multi ? bars[j][i] : bars[i];
632                     cover.value = cover.bar.value;
633                     Y += barheight;
634                 }
635
636                 Y += bargutter;
637             }
638         }
639
640         chart.label = function (labels, isRight) {
641             labels = labels || [];
642             this.labels = paper.set();
643             var txtattr =  { };
644             for (var i = 0; i < len; i++) {
645                 for (var j = 0; j < (multi || 1); j++) {
646                     //var  label = paper.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total),
647                     var  label = Raphael.g.labelise(multi ? labels[j] && labels[j][i] : labels[i], multi ? values[j][i] : values[i], total),
648                         X = isRight ?
649                                 bars[i * (multi || 1) + j].x + 5 : // - barheight / 2 + 3 :
650                                 x + 5,
651                         A = !isRight ? "end" : "start",
652                         L;
653
654                     this.labels.push(L = paper.text(X, bars[i * (multi || 1) + j].y, label).attr(txtattr).attr({ "text-anchor": A }).insertBefore(covers[0]));
655
656                     if (L.getBBox().x < x + 5) {
657                         L.attr({x: x + 5, "text-anchor": "start"});
658                     } else {
659                         bars[i * (multi || 1) + j].label = L;
660                     }
661                 }
662             }
663
664             return this;
665         };
666         
667         var axis = paper.set();
668         
669         if (opts.axis) {    
670             // Roo.log(opts.axis);
671             
672             // Value - "top right bottom left". If
673             var ax = (opts.axis + "").split(/[,\s]+/);
674             
675             // top axis
676             +ax[0] && axis.push(// not in used at the moment
677                     chartinst.axis(
678                         x + gutter,
679                         y + gutter,
680                         width - 2 * gutter,
681                         0,
682                         0,
683                         opts.axisxstep || Math.floor((width - 2 * gutter) / 20),
684                         2,
685                         paper));
686             // right axis
687             +ax[1] && axis.push(// not in used at the moment
688                     chartinst.axis(
689                         x + width - gutter,
690                         y + height - gutter,
691                         height - 2 * gutter,
692                         0,
693                         0,
694                         opts.axisystep || Math.floor((height - 2 * gutter) / 20),
695                         3,
696                         paper
697                     ));
698             // bottom axis
699             +ax[2] && axis.push(// not in used at the moment
700                 // bottom
701                 // x, y, length, from, to, steps, orientation, labels, type, dashsize, paper
702                 chartinst.axis(
703                     x + gutter,
704                     y + height - gutter,
705 //                    width - 2 * gutter,
706 //                    20,
707 //                    50,
708                     width - 20, // total width
709                     0,
710                     0,
711 //                    20,
712 //                    50,
713                     opts.axisxstep || Math.floor((width - 2 * gutter) / 20), // data length
714                     0,
715                     opts.axisxlabels || false,
716                     "-",
717                     5,
718                     paper
719                 ));
720             // left axis
721             +ax[3] && axis.push(// just hardcode this
722                 chartinst.axis(
723                     19, // x pos 
724                     240, // y pos
725                     220,// length
726                     0, // from
727                     0, // to
728                     0,// steps
729                     1,// orientation
730                     false, // labels
731                     "-",// type
732 //                        opts.axisystep || Math.floor((height - 2 * gutter) / 20),
733                     100,// dashsize
734                     paper
735             ));
736         }
737         
738         
739
740         chart.hover = function (fin, fout) {
741             covers2.hide();
742             covers.show();
743             fout = fout || function () {};
744             covers.mouseover(fin).mouseout(fout);
745             return this;
746         };
747
748         chart.hoverColumn = function (fin, fout) {
749             covers.hide();
750             covers2.show();
751             fout = fout || function () {};
752             covers2.mouseover(fin).mouseout(fout);
753             return this;
754         };
755
756         chart.each = function (f) {
757             if (!Raphael.is(f, "function")) {
758                 return this;
759             }
760             for (var i = covers.length; i--;) {
761                 f.call(covers[i]);
762             }
763             return this;
764         };
765
766         chart.eachColumn = function (f) {
767             if (!Raphael.is(f, "function")) {
768                 return this;
769             }
770             for (var i = covers2.length; i--;) {
771                 f.call(covers2[i]);
772             }
773             return this;
774         };
775
776         chart.click = function (f) {
777             covers2.hide();
778             covers.show();
779             covers.click(f);
780             return this;
781         };
782
783         chart.clickColumn = function (f) {
784             covers.hide();
785             covers2.show();
786             covers2.click(f);
787             return this;
788         };
789         
790         /*
791          * create the legend for Hbarchart
792          * 
793          */
794         
795         var legend = function (labels, otherslabel, mark, dir) {
796             var h = Y + 10;
797             
798             labels = labels || [];
799 //            dir = (dir && dir.toLowerCase && dir.toLowerCase()) || "south"; 
800             dir = "east"; // default set to east, do not support other position first...
801             mark = paper[mark && mark.toLowerCase()] || "circle";
802             chart.labels = paper.set();
803             
804             for (var i = 0; i < len; i++) {
805                 var txt;
806                 
807                 values[i].others && (labels[i] = otherslabel || "Others");
808 //                Roo.log(values[i]);
809                 labels[i] = chartinst.labelise(labels[i], values[i], sum);
810                 chart.labels.push(paper.set());
811                 chart.labels[i].push(paper[mark](x + 5, h, 5).attr({ stroke: "none", fill: colors[i] }));
812                 chart.labels[i].push(txt = paper.text(x + 20, h, labels[i] || values[i]).attr(chartinst.txtattr).attr({ fill: opts.legendcolor || "#000", "text-anchor": "start"}));
813                 covers[i].label = chart.labels[i];
814                 h += txt.getBBox().height * 1.2;
815             }
816 //            Roo.log(labels)
817             var tr = {
818                     east: [width + 25, - Y +30]
819 //                    west: [-bb.width - 2 * r - 20, -bb.height / 2],
820 //                    north: [-r - bb.width / 2, -r - bb.height - 10],
821 //                    south: [ x - 5, 10]
822                 }[dir];
823                 
824             chart.labels.translate.apply(chart.labels, tr);
825             chart.push(chart.labels);
826         };
827
828         if (opts.legend) {
829             legend(opts.legend, opts.legendothers, opts.legendmark, opts.legendpos);
830         }
831         
832         chart.push(bars, covers, covers2);
833         chart.bars = bars;
834         chart.covers = covers;
835         return chart;
836     };
837     
838     //inheritance
839     var F = function() {};
840     F.prototype = Raphael.g;
841     HBarchart.prototype = VBarchart.prototype = new F;
842     
843     Raphael.fn.hbarchart = function(x, y, width, height, values, opts) {
844         return new HBarchart(this, x, y, width, height, values, opts);
845     };
846     
847     Raphael.fn.barchart = function(x, y, width, height, values, opts) {
848         return new VBarchart(this, x, y, width, height, values, opts);
849     };
850 })();