2 * o------------------------------------------------------------------------------o
3 * | This file is part of the RGraph package - you can learn more at: |
5 * | http://www.rgraph.net |
7 * | This package is licensed under the RGraph license. For all kinds of business |
8 * | purposes there is a small one-time licensing fee to pay and for non |
9 * | commercial purposes it is free to use. You can read the full license here: |
11 * | http://www.rgraph.net/LICENSE.txt |
12 * o------------------------------------------------------------------------------o
15 if (typeof(RGraph) == 'undefined') RGraph = {};
18 * The horizontal bar chart constructor. The horizontal bar is a minor variant
19 * on the bar chart. If you have big labels, this may be useful as there is usually
20 * more space available for them.
22 * @param object canvas The canvas object
23 * @param array data The chart data
25 RGraph.HBar = function (id, data)
27 // Get the canvas and context objects
29 this.canvas = document.getElementById(id);
30 this.context = this.canvas.getContext ? this.canvas.getContext("2d") : null;
31 this.canvas.__object__ = this;
39 * Compatibility with older browsers
41 RGraph.OldBrowserCompat(this.context);
45 this.stackedOrGrouped = false;
50 'chart.background.grid': true,
51 'chart.background.grid.color': '#ddd',
52 'chart.background.grid.width': 1,
53 'chart.background.grid.hsize': 25,
54 'chart.background.grid.vsize': 25,
55 'chart.background.barcolor1': 'white',
56 'chart.background.barcolor2': 'white',
57 'chart.background.grid.hlines': true,
58 'chart.background.grid.vlines': true,
59 'chart.background.grid.border': true,
60 'chart.background.grid.autofit':false,
61 'chart.background.grid.autofit.numhlines': 14,
62 'chart.background.grid.autofit.numvlines': 20,
64 'chart.title.background': null,
65 'chart.title.xaxis': '',
66 'chart.title.yaxis': '',
67 'chart.title.xaxis.pos': 0.25,
68 'chart.title.yaxis.pos': 0.5,
69 'chart.title.hpos': null,
70 'chart.title.vpos': null,
71 'chart.text.size': 10,
72 'chart.text.color': 'black',
73 'chart.text.font': 'Verdana',
74 'chart.colors': ['rgb(0,0,255)', '#0f0', '#00f', '#ff0', '#0ff', '#0f0'],
76 'chart.labels.above': false,
77 'chart.labels.above.decimals': 0,
78 'chart.contextmenu': null,
80 'chart.key.background': 'white',
81 'chart.key.position': 'graph',
82 'chart.key.shadow': false,
83 'chart.key.shadow.color': '#666',
84 'chart.key.shadow.blur': 3,
85 'chart.key.shadow.offsetx': 2,
86 'chart.key.shadow.offsety': 2,
87 'chart.key.position.gutter.boxed': true,
88 'chart.key.position.x': null,
89 'chart.key.position.y': null,
90 'chart.key.color.shape': 'square',
91 'chart.key.rounded': true,
92 'chart.units.pre': '',
93 'chart.units.post': '',
94 'chart.units.ingraph': false,
95 'chart.strokestyle': 'black',
97 'chart.axis.color': 'black',
98 'chart.shadow': false,
99 'chart.shadow.color': '#666',
100 'chart.shadow.blur': 3,
101 'chart.shadow.offsetx': 3,
102 'chart.shadow.offsety': 3,
104 'chart.grouping': 'grouped',
105 'chart.tooltips': null,
106 'chart.tooltips.effect': 'fade',
107 'chart.tooltips.css.class': 'RGraph_tooltip',
108 'chart.tooltips.highlight': true,
109 'chart.annotatable': false,
110 'chart.annotate.color': 'black',
111 'chart.zoom.factor': 1.5,
112 'chart.zoom.fade.in': true,
113 'chart.zoom.fade.out': true,
114 'chart.zoom.hdir': 'right',
115 'chart.zoom.vdir': 'down',
116 'chart.zoom.frames': 10,
117 'chart.zoom.delay': 50,
118 'chart.zoom.shadow': true,
119 'chart.zoom.mode': 'canvas',
120 'chart.zoom.thumbnail.width': 75,
121 'chart.zoom.thumbnail.height': 75,
122 'chart.zoom.background': true,
123 'chart.zoom.action': 'zoom',
124 'chart.resizable': false,
125 'chart.scale.point': '.',
126 'chart.scale.thousand': ',',
127 'chart.scale.decimals': null
132 alert('[HBAR] No canvas support');
136 // Check the canvasText library has been included
137 if (typeof(RGraph) == 'undefined') {
138 alert('[HBAR] Fatal error: The common library does not appear to have been included');
141 for (i=0; i<this.data.length; ++i) {
142 if (typeof(this.data[i]) == 'object') {
143 this.stackedOrGrouped = true;
152 * @param name string The name of the property to set
153 * @param value mixed The value of the property
155 RGraph.HBar.prototype.Set = function (name, value)
157 if (name == 'chart.labels.abovebar') {
158 name = 'chart.labels.above';
161 this.properties[name.toLowerCase()] = value;
168 * @param name string The name of the property to get
170 RGraph.HBar.prototype.Get = function (name)
172 if (name == 'chart.labels.abovebar') {
173 name = 'chart.labels.above';
176 return this.properties[name];
181 * The function you call to draw the bar chart
183 RGraph.HBar.prototype.Draw = function ()
186 * Fire the onbeforedraw event
188 RGraph.FireCustomEvent(this, 'onbeforedraw');
192 * Clear all of this canvases event handlers (the ones installed by RGraph)
194 RGraph.ClearEventListeners(this.id);
197 var gutter = this.Get('chart.gutter');
200 * Stop the coords array from growing uncontrollably
205 * Work out a few things. They need to be here because they depend on things you can change before you
206 * call Draw() but after you instantiate the object
208 this.graphwidth = this.canvas.width - ( (4 * gutter));
209 this.graphheight = this.canvas.height - (2 * gutter);
210 this.halfgrapharea = this.grapharea / 2;
211 this.halfTextHeight = this.Get('chart.text.size') / 2;
212 this.lgutter = 3 * gutter;
214 // Progressively Draw the chart
215 this.DrawBackground();
222 // Draw the key if necessary
223 if (this.Get('chart.key').length) {
224 RGraph.DrawKey(this, this.Get('chart.key'), this.Get('chart.colors'));
228 * Install the event handlers for tooltips
230 if (this.Get('chart.tooltips')) {
232 // Need to register this object for redrawing
233 RGraph.Register(this);
236 * Install the window onclick handler
238 window.onclick = function ()
246 * If the cursor is over a hotspot, change the cursor to a hand
248 //this.canvas.onmousemove = function (e)
249 var canvas_onmousemove_func = function (e)
251 e = RGraph.FixEventObject(e);
253 var canvas = document.getElementById(this.id);
254 var obj = canvas.__object__;
257 * Get the mouse X/Y coordinates
259 var mouseCoords = RGraph.getMouseXY(e);
262 * Loop through the bars determining if the mouse is over a bar
264 for (var i=0,len=obj.coords.length; i<len; i++) {
266 var mouseX = mouseCoords[0]; // In relation to the canvas
267 var mouseY = mouseCoords[1]; // In relation to the canvas
268 var left = obj.coords[i][0];
269 var top = obj.coords[i][1];
270 var width = obj.coords[i][2];
271 var height = obj.coords[i][3];
273 if ( mouseX >= (left)
274 && mouseX <= (left + width)
276 && mouseY <= (top + height)
277 && ( typeof(obj.Get('chart.tooltips')) == 'function'
278 || obj.Get('chart.tooltips')[i]
281 canvas.style.cursor = 'pointer';
285 canvas.style.cursor = 'default';
288 this.canvas.addEventListener('mousemove', canvas_onmousemove_func, false);
289 RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove_func);
293 * Install the onclick event handler for the tooltips
295 //this.canvas.onclick = function (e)
296 var canvas_onclick_func = function (e)
298 e = RGraph.FixEventObject(e);
300 //var canvas = document.getElementById(this.id);
301 var canvas = e.target;
302 var obj = canvas.__object__;
305 * Redraw the graph first, in effect resetting the graph to as it was when it was first drawn
306 * This "deselects" any already selected bar
311 * Get the mouse X/Y coordinates
313 var mouseCoords = RGraph.getMouseXY(e);
316 * Loop through the bars determining if the mouse is over a bar
318 for (var i=0,len=obj.coords.length; i<len; i++) {
320 var mouseX = mouseCoords[0]; // In relation to the canvas
321 var mouseY = mouseCoords[1]; // In relation to the canvas
322 var left = obj.coords[i][0];
323 var top = obj.coords[i][1];
324 var width = obj.coords[i][2];
325 var height = obj.coords[i][3];
328 if (mouseX >= left && mouseX <= (left + width) && mouseY >= top && mouseY <= (top + height) ) {
331 * Get the tooltip text
333 if (typeof(obj.Get('chart.tooltips')) == 'function') {
334 var text = obj.Get('chart.tooltips')(idx);
336 } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[idx]) == 'function') {
337 var text = obj.Get('chart.tooltips')[idx](idx);
339 } else if (typeof(obj.Get('chart.tooltips')) == 'object') {
340 var text = obj.Get('chart.tooltips')[idx];
347 * Show a tooltip if it's defined
349 if (String(text).length && text != null) {
351 obj.context.beginPath();
352 obj.context.strokeStyle = 'black';
353 obj.context.fillStyle = 'rgba(255,255,255,0.5)';
354 obj.context.strokeRect(left, top, width, height);
355 obj.context.fillRect(left, top, width, height);
357 obj.context.stroke();
360 RGraph.Tooltip(canvas, text, e.pageX, e.pageY, i);
366 * Stop the event bubbling
370 this.canvas.addEventListener('click', canvas_onclick_func, false);
371 RGraph.AddEventListener(this.id, 'click', canvas_onclick_func);
373 // This resets the bar graph
374 if (RGraph.Registry.Get('chart.tooltip')) {
375 RGraph.Registry.Get('chart.tooltip').style.display = 'none';
376 RGraph.Registry.Set('chart.tooltip', null)
381 * Setup the context menu if required
383 if (this.Get('chart.contextmenu')) {
384 RGraph.ShowContext(this);
389 * Draw "in graph" labels
391 RGraph.DrawInGraphLabels(this);
394 * If the canvas is annotatable, do install the event handlers
396 if (this.Get('chart.annotatable')) {
397 RGraph.Annotate(this);
401 * This bit shows the mini zoom window if requested
403 if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') {
404 RGraph.ShowZoomWindow(this);
409 * This function enables resizing
411 if (this.Get('chart.resizable')) {
412 RGraph.AllowResizing(this);
416 * Fire the RGraph ondraw event
418 RGraph.FireCustomEvent(this, 'ondraw');
422 * This draws the axes
424 RGraph.HBar.prototype.DrawAxes = function ()
426 var gutter = this.Get('chart.gutter');
427 var halfway = ((this.canvas.width - (4 * gutter)) / 2) + (3 * gutter);
429 this.context.beginPath();
430 this.context.lineWidth = 1;
431 this.context.strokeStyle = this.Get('chart.axis.color');
434 if (this.Get('chart.yaxispos') == 'center') {
435 this.context.moveTo(halfway, gutter);
436 this.context.lineTo(halfway, this.canvas.height - gutter);
438 this.context.moveTo(gutter * 3, gutter);
439 this.context.lineTo(gutter * 3, this.canvas.height - gutter);
443 this.context.moveTo(gutter * 3, this.canvas.height - gutter);
444 this.context.lineTo(this.canvas.width - gutter, this.canvas.height - gutter);
446 // Draw the Y tickmarks
447 var yTickGap = (this.canvas.height - (2 * gutter)) / this.data.length;
449 for (y=gutter; y<(this.canvas.height - gutter); y+=yTickGap) {
450 if (this.Get('chart.yaxispos') == 'center') {
451 this.context.moveTo(halfway + 3, y);
452 this.context.lineTo(halfway - 3, y);
454 this.context.moveTo(gutter * 3, y);
455 this.context.lineTo( (gutter * 3) - 3, y);
460 // Draw the X tickmarks
461 xTickGap = (this.canvas.width - (4 * gutter) ) / 10;
462 yStart = this.canvas.height - gutter;
463 yEnd = (this.canvas.height - gutter) + 3;
465 for (x=(this.canvas.width - gutter), i=0; this.Get('chart.yaxispos') == 'center' ? x>=(3 * gutter) : x>(3*gutter); x-=xTickGap) {
467 if (this.Get('chart.yaxispos') != 'center' || i != 5) {
468 this.context.moveTo(x, yStart);
469 this.context.lineTo(x, yEnd);
474 this.context.stroke();
479 * This function draws the background. The common function isn't used because the left gutter is
480 * three times as big.
482 * @param object obj The graph object
484 RGraph.HBar.prototype.DrawBackground = function ()
486 var gutter = this.Get('chart.gutter');
487 var size = this.Get('chart.text.size');
488 var font = this.Get('chart.text.font');
489 var canvas = this.canvas;
490 var context = this.context;
492 this.context.beginPath();
494 // Draw the horizontal bars
495 this.context.fillStyle = this.Get('chart.background.barcolor1');
496 for (var i=gutter; i < (canvas.height - gutter); i+=80) {
497 context.fillRect (gutter * 3, i, canvas.width - (gutter * 4), Math.min(40, canvas.height - gutter - i) );
500 this.context.fillStyle = this.Get('chart.background.barcolor2');
501 for (var i= (40 + gutter); i < (canvas.height - gutter); i+=80) {
502 context.fillRect (gutter * 3, i, canvas.width - (gutter * 4), i + 40 > (canvas.height - gutter) ? canvas.height - (gutter + i) : 40);
505 this.context.stroke();
507 // Draw the background grid
508 if (this.Get('chart.background.grid')) {
510 // If autofit is specified, use the .numhlines and .numvlines along with the width to work
511 // out the hsize and vsize
512 if (this.Get('chart.background.grid.autofit')) {
513 var vsize = (canvas.width - (4 * gutter)) / this.Get('chart.background.grid.autofit.numvlines');
514 var hsize = (canvas.height - (4 * gutter)) / this.Get('chart.background.grid.autofit.numhlines');
516 this.Set('chart.background.grid.vsize', vsize);
517 this.Set('chart.background.grid.hsize', hsize);
521 context.lineWidth = this.Get('chart.background.grid.width');
522 context.strokeStyle = this.Get('chart.background.grid.color');
524 // Draw the horizontal lines
525 if (this.Get('chart.background.grid.hlines')) {
526 for (y=gutter; y < (canvas.height - gutter); y+=this.Get('chart.background.grid.hsize')) {
527 context.moveTo(gutter * 3, y);
528 context.lineTo(canvas.width - gutter, y);
532 // Draw the vertical lines
533 if (this.Get('chart.background.grid.vlines')) {
534 for (x=gutter * 3; x <= (canvas.width - gutter); x+=this.Get('chart.background.grid.vsize')) {
535 context.moveTo(x, gutter);
536 context.lineTo(x, canvas.height - gutter);
540 if (this.Get('chart.background.grid.border')) {
541 // Make sure a rectangle, the same colour as the grid goes around the graph
542 context.strokeStyle = this.Get('chart.background.grid.color');
543 context.strokeRect(gutter * 3, gutter, canvas.width - (4 * gutter), canvas.height - (2 * gutter));
550 // Draw the title if one is set
551 if ( typeof(this.Get('chart.title')) == 'string') {
553 RGraph.DrawTitle(canvas,
554 this.Get('chart.title'),
556 (3 * gutter) + ((canvas.width - (4 * gutter)) / 2),
564 if (typeof(this.Get('chart.title.xaxis')) == 'string' && this.Get('chart.title.xaxis').length) {
566 RGraph.Text(context, font, size + 2, canvas.width / 2, canvas.height - (gutter * this.Get('chart.title.xaxis.pos')), this.Get('chart.title.xaxis'), 'center', 'center', false, false, false, true);
572 if (typeof(this.Get('chart.title.yaxis')) == 'string' && this.Get('chart.title.yaxis').length) {
574 RGraph.Text(context, font, size + 2, gutter * this.Get('chart.title.yaxis.pos'), canvas.height / 2, this.Get('chart.title.yaxis'), 'center', 'center', false, 270, false, true);
581 * This draws the labels for the graph
583 RGraph.HBar.prototype.DrawLabels = function ()
585 var gutter = this.Get('chart.gutter');
586 var context = this.context;
587 var canvas = this.canvas;
588 var units_pre = this.Get('chart.units.pre');
589 var units_post = this.Get('chart.units.post');
590 var text_size = this.Get('chart.text.size');
591 var font = this.Get('chart.text.font');
595 * Set the units to blank if they're to be used for ingraph labels only
597 if (this.Get('chart.units.ingraph')) {
604 * Draw the X axis labels
606 this.context.beginPath();
607 this.context.fillStyle = this.Get('chart.text.color');
609 //var interval = (this.canvas.width - (4 * gutter)) / (t ? 10 : 5);
611 if (this.Get('chart.yaxispos') == 'center') {
612 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (10/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[4], units_pre, units_post), 'center', 'center');
613 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (9/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', 'center');
614 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (8/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', 'center');
615 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (7/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', 'center');
616 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (6/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', 'center');
618 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (4/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, -1 * this.scale[0], units_pre, units_post), 'center', 'center');
619 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (3/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, -1 * this.scale[1], units_pre, units_post), 'center', 'center');
620 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (2/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, -1 * this.scale[2], units_pre, units_post), 'center', 'center');
621 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (1/10)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, -1 * this.scale[3], units_pre, units_post), 'center', 'center');
622 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (0)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, -1 * this.scale[4], units_pre, units_post), 'center', 'center');
626 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (5/5)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[4], units_pre, units_post), 'center', 'center');
627 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (4/5)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', 'center');
628 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (3/5)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', 'center');
629 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (2/5)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', 'center');
630 RGraph.Text(context, font, text_size, (gutter * 3) + (this.graphwidth * (1/5)), gutter + this.halfTextHeight + this.graphheight + 2, RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', 'center');
634 this.context.stroke();
639 if (typeof(this.Get('chart.labels')) == 'object') {
642 var font = this.Get('chart.text.font');
644 // Draw the X axis labels
645 this.context.fillStyle = this.Get('chart.text.color');
647 // How wide is each bar
648 var barHeight = (this.canvas.height - (2 * gutter) ) / this.Get('chart.labels').length;
650 // Reset the xTickGap
651 yTickGap = (this.canvas.height - (2 * gutter)) / this.Get('chart.labels').length
653 // Draw the X tickmarks
655 for (y=gutter + (yTickGap / 2); y<=this.canvas.height - gutter; y+=yTickGap) {
656 RGraph.Text(this.context, font,
657 this.Get('chart.text.size'),
658 (gutter * 3) - xOffset,
660 String(this.Get('chart.labels')[i++]),
669 * This function draws the actual bars
671 RGraph.HBar.prototype.Drawbars = function ()
673 this.context.lineWidth = 1;
674 this.context.strokeStyle = this.Get('chart.strokestyle');
675 this.context.fillStyle = this.Get('chart.colors')[0];
680 * Work out the max value
682 if (this.Get('chart.xmax')) {
684 (this.Get('chart.xmax') * 0.2).toFixed(this.Get('chart.scale.decimals')),
685 (this.Get('chart.xmax') * 0.4).toFixed(this.Get('chart.scale.decimals')),
686 (this.Get('chart.xmax') * 0.6).toFixed(this.Get('chart.scale.decimals')),
687 (this.Get('chart.xmax') * 0.8).toFixed(this.Get('chart.scale.decimals')),
688 (this.Get('chart.xmax')).toFixed(this.Get('chart.scale.decimals'))
690 this.max = this.scale[4];
692 var grouping = this.Get('chart.grouping');
694 for (i=0; i<this.data.length; ++i) {
695 if (typeof(this.data[i]) == 'object') {
696 var value = grouping == 'grouped' ? Number(RGraph.array_max(this.data[i], true)) : Number(RGraph.array_sum(this.data[i])) ;
698 var value = Number(this.data[i]);
701 this.max = Math.max(Math.abs(this.max), Math.abs(value));
704 this.scale = RGraph.getScale(this.max, this);
705 this.max = this.scale[4];
710 * The bars are drawn HERE
712 var gutter = this.Get('chart.gutter');
713 var graphwidth = (this.canvas.width - (4 * gutter));
714 var halfwidth = graphwidth / 2;
716 for (i=0; i<this.data.length; ++i) {
718 // Work out the width and height
719 var width = (this.data[i] / this.max) * graphwidth;
720 var height = this.graphheight / this.data.length;
722 var orig_height = height;
725 var y = gutter + (i * height);
726 var vmargin = this.Get('chart.vmargin');
729 // Account for negative lengths - Some browsers (eg Chrome) don't like a negative value
732 width = Math.abs(width);
736 * Turn on the shadow if need be
738 if (this.Get('chart.shadow')) {
739 this.context.shadowColor = this.Get('chart.shadow.color');
740 this.context.shadowBlur = this.Get('chart.shadow.blur');
741 this.context.shadowOffsetX = this.Get('chart.shadow.offsetx');
742 this.context.shadowOffsetY = this.Get('chart.shadow.offsety');
748 this.context.beginPath();
749 if (typeof(this.data[i]) == 'number') {
751 var barHeight = height - (2 * vmargin);
752 var barWidth = (this.data[i] / this.max) * this.graphwidth;
753 var barX = 3 * gutter;
755 // Account for Y axis pos
756 if (this.Get('chart.yaxispos') == 'center') {
761 // Set the fill color
762 this.context.strokeStyle = this.Get('chart.strokestyle');
763 this.context.fillStyle = this.Get('chart.colors')[0];
765 this.context.strokeRect(barX, gutter + (i * height) + this.Get('chart.vmargin'), barWidth, barHeight);
766 this.context.fillRect(barX, gutter + (i * height) + this.Get('chart.vmargin'), barWidth, barHeight);
768 this.coords.push([x, y + vmargin, width, height - (2 * vmargin), this.Get('chart.colors')[0], this.data[i]]);
773 } else if (typeof(this.data[i]) == 'object' && this.Get('chart.grouping') == 'stacked') {
775 var barHeight = height - (2 * vmargin);
777 for (j=0; j<this.data[i].length; ++j) {
779 // Set the fill/stroke colors
780 this.context.strokeStyle = this.Get('chart.strokestyle');
781 this.context.fillStyle = this.Get('chart.colors')[j];
783 var width = (this.data[i][j] / this.max) * this.graphwidth;
784 var totalWidth = (RGraph.array_sum(this.data[i]) / this.max) * this.graphwidth;
786 this.context.strokeRect(x, gutter + this.Get('chart.vmargin') + (this.graphheight / this.data.length) * i, width, height - (2 * vmargin) );
787 this.context.fillRect(x, gutter + this.Get('chart.vmargin') + (this.graphheight / this.data.length) * i, width, height - (2 * vmargin) );
790 * Store the coords for tooltips
793 this.coords.push([x, y + vmargin, width, height - (2 * vmargin), this.Get('chart.colors')[j], RGraph.array_sum(this.data[i])]);
799 * A grouped bar chart
801 } else if (typeof(this.data[i]) == 'object' && this.Get('chart.grouping') == 'grouped') {
803 for (j=0; j<this.data[i].length; ++j) {
806 * Turn on the shadow if need be
808 if (this.Get('chart.shadow')) {
809 RGraph.SetShadow(this, this.Get('chart.shadow.color'), this.Get('chart.shadow.offsetx'), this.Get('chart.shadow.offsety'), this.Get('chart.shadow.blur'));
812 // Set the fill/stroke colors
813 this.context.strokeStyle = this.Get('chart.strokestyle');
814 this.context.fillStyle = this.Get('chart.colors')[j];
816 var width = (this.data[i][j] / this.max) * (this.canvas.width - (4 * gutter) );
817 var individualBarHeight = (height - (2 * vmargin)) / this.data[i].length;
819 var startX = gutter * 3;
820 var startY = y + vmargin + (j * individualBarHeight);
822 // Account for the Y axis being in the middle
823 if (this.Get('chart.yaxispos') == 'center') {
833 this.context.strokeRect(startX, startY, width, individualBarHeight);
834 this.context.fillRect(startX, startY, width, individualBarHeight);
836 this.coords.push([startX, startY, width, individualBarHeight, this.Get('chart.colors')[j], this.data[i][j]]);
840 this.context.closePath();
844 this.context.stroke();
849 * Now the bars are stroke()ed, turn off the shadow
851 RGraph.NoShadow(this);
858 * This function goes over the bars after they been drawn, so that upwards shadows are underneath the bars
860 RGraph.HBar.prototype.RedrawBars = function ()
862 var coords = this.coords;
864 RGraph.NoShadow(this);
865 this.context.strokeStyle = this.Get('chart.strokestyle');
867 for (var i=0; i<coords.length; ++i) {
869 this.context.beginPath();
870 this.context.strokeStyle = this.Get('chart.strokestyle');
871 this.context.fillStyle = coords[i][4];
872 this.context.lineWidth = 1;
873 this.context.strokeRect(coords[i][0], coords[i][1], coords[i][2], coords[i][3]);
874 this.context.fillRect(coords[i][0], coords[i][1], coords[i][2], coords[i][3]);
876 this.context.stroke();
879 * Draw labels "above" the bar
881 if (this.Get('chart.labels.above')) {
883 this.context.fillStyle = this.Get('chart.text.color');
884 this.context.strokeStyle = 'black';
885 RGraph.NoShadow(this);
887 var border = (coords[i][0] + coords[i][2] + 7 + this.context.measureText(this.Get('chart.units.pre') + this.coords[i][5] + this.Get('chart.units.post')).width) > this.canvas.width ? true : false;
889 RGraph.Text(this.context,this.Get('chart.text.font'),this.Get('chart.text.size'),coords[i][0] + coords[i][2] + (border ? -5 : 5),coords[i][1] + (coords[i][3] / 2),RGraph.number_format(this, (this.coords[i][5]).toFixed(this.Get('chart.labels.above.decimals')), this.Get('chart.units.pre'), this.Get('chart.units.post')),'center',border ? 'right' : 'left',border,null,border ? 'rgba(255,255,255,0.9)' : null);