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