source: Dev/branches/jQueryUI/client/RGraph/libraries/RGraph.bar.js @ 249

Last change on this file since 249 was 249, checked in by hendrikvanantwerpen, 13 years ago

This one's for Subversion, because it's so close...

First widget (stripped down sequencer).
Seperated client and server code in two direcotry trees.

File size: 84.1 KB
Line 
1    /**
2    * o------------------------------------------------------------------------------o
3    * | This file is part of the RGraph package - you can learn more at:             |
4    * |                                                                              |
5    * |                          http://www.rgraph.net                               |
6    * |                                                                              |
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:  |
10    * |                                                                              |
11    * |                      http://www.rgraph.net/LICENSE.txt                       |
12    * o------------------------------------------------------------------------------o
13    */
14   
15    if (typeof(RGraph) == 'undefined') RGraph = {};
16
17    /**
18    * The bar chart constructor
19    *
20    * @param object canvas The canvas object
21    * @param array  data   The chart data
22    */
23    RGraph.Bar = function (id, data)
24    {
25        // Get the canvas and context objects
26        this.id                = id;
27        this.canvas            = document.getElementById(id);
28        this.context           = this.canvas.getContext ? this.canvas.getContext("2d") : null;
29        this.canvas.__object__ = this;
30        this.type              = 'bar';
31        this.max               = 0;
32        this.stackedOrGrouped  = false;
33        this.isRGraph          = true;
34
35        /**
36        * Compatibility with older browsers
37        */
38        RGraph.OldBrowserCompat(this.context);
39
40
41        // Various config type stuff
42        this.properties = {
43            'chart.width':                  null,
44            'chart.height':                 null,
45            'chart.background.barcolor1':   'rgba(0,0,0,0)',
46            'chart.background.barcolor2':   'rgba(0,0,0,0)',
47            'chart.background.grid':        true,
48            'chart.background.grid.color':  '#ddd',
49            'chart.background.grid.width':  1,
50            'chart.background.grid.hsize':  20,
51            'chart.background.grid.vsize':  20,
52            'chart.background.grid.vlines': true,
53            'chart.background.grid.hlines': true,
54            'chart.background.grid.border': true,
55            'chart.background.grid.autofit':false,
56            'chart.background.grid.autofit.numhlines': 7,
57            'chart.background.grid.autofit.numvlines': 20,
58            'chart.background.image':       null,
59            'chart.ytickgap':               20,
60            'chart.smallyticks':            3,
61            'chart.largeyticks':            5,
62            'chart.numyticks':              10,
63            'chart.hmargin':                5,
64            'chart.strokecolor':            '#666',
65            'chart.axis.color':             'black',
66            'chart.gutter.top':             25,
67            'chart.gutter.bottom':          25,
68            'chart.gutter.left':            25,
69            'chart.gutter.right':           25,
70            'chart.labels':                 null,
71            'chart.labels.ingraph':         null,
72            'chart.labels.above':           false,
73            'chart.labels.above.decimals':  0,
74            'chart.labels.above.size':      null,
75            'chart.labels.above.angle':     null,
76            'chart.ylabels':                true,
77            'chart.ylabels.count':          5,
78            'chart.ylabels.inside':         false,
79            'chart.xlabels.offset':         0,
80            'chart.xaxispos':               'bottom',
81            'chart.yaxispos':               'left',
82            'chart.text.color':             'black',
83            'chart.text.size':              10,
84            'chart.text.angle':             0,
85            'chart.text.font':              'Verdana',
86            'chart.ymax':                   null,
87            'chart.title':                  '',
88            'chart.title.background':       null,
89            'chart.title.hpos':             null,
90            'chart.title.vpos':             null,
91            'chart.title.xaxis':            '',
92            'chart.title.yaxis':            '',
93            'chart.title.xaxis.pos':        0.25,
94            'chart.title.yaxis.pos':        0.25,
95            'chart.colors':                 ['rgb(0,0,255)', '#0f0', '#00f', '#ff0', '#0ff', '#0f0'],
96            'chart.colors.sequential':      false,
97            'chart.colors.reverse':         false,
98            'chart.grouping':               'grouped',
99            'chart.variant':                'bar',
100            'chart.shadow':                 false,
101            'chart.shadow.color':           '#666',
102            'chart.shadow.offsetx':         3,
103            'chart.shadow.offsety':         3,
104            'chart.shadow.blur':            3,
105            'chart.tooltips':               null,
106            'chart.tooltips.effect':        'fade',
107            'chart.tooltips.css.class':     'RGraph_tooltip',
108            'chart.tooltips.event':         'onclick',
109            'chart.tooltips.highlight':     true,
110            'chart.highlight.stroke':       'black',
111            'chart.highlight.fill':         'rgba(255,255,255,0.5)',
112            'chart.background.hbars':       null,
113            'chart.key':                    [],
114            'chart.key.background':         'white',
115            'chart.key.position':           'graph',
116            'chart.key.shadow':             false,
117            'chart.key.shadow.color':       '#666',
118            'chart.key.shadow.blur':        3,
119            'chart.key.shadow.offsetx':     2,
120            'chart.key.shadow.offsety':     2,
121            'chart.key.position.gutter.boxed': true,
122            'chart.key.position.x':         null,
123            'chart.key.position.y':         null,
124            'chart.key.halign':             'right',
125            'chart.key.color.shape':        'square',
126            'chart.key.rounded':            true,
127            'chart.key.text.size':          10,
128            'chart.key.linewidth':          1,
129            'chart.contextmenu':            null,
130            'chart.line':                   null,
131            'chart.units.pre':              '',
132            'chart.units.post':             '',
133            'chart.scale.decimals':         0,
134            'chart.scale.point':            '.',
135            'chart.scale.thousand':         ',',
136            'chart.crosshairs':             false,
137            'chart.crosshairs.color':       '#333',
138            'chart.linewidth':              1,
139            'chart.annotatable':            false,
140            'chart.annotate.color':         'black',
141            'chart.zoom.factor':            1.5,
142            'chart.zoom.fade.in':           true,
143            'chart.zoom.fade.out':          true,
144            'chart.zoom.hdir':              'right',
145            'chart.zoom.vdir':              'down',
146            'chart.zoom.frames':            10,
147            'chart.zoom.delay':             50,
148            'chart.zoom.shadow':            true,
149            'chart.zoom.mode':              'canvas',
150            'chart.zoom.thumbnail.width':   75,
151            'chart.zoom.thumbnail.height':  75,
152            'chart.zoom.background':        true,
153            'chart.resizable':              false,
154            'chart.resize.handle.adjust':   [0,0],
155            'chart.resize.handle.background': null,
156            'chart.adjustable':             false,
157            'chart.noaxes':                 false,
158            'chart.noxaxis':                false,
159            'chart.noyaxis':                false
160        }
161
162        // Check for support
163        if (!this.canvas) {
164            alert('[BAR] No canvas support');
165            return;
166        }
167
168        /**
169        * Determine whether the chart will contain stacked or grouped bars
170        */
171        for (i=0; i<data.length; ++i) {
172            if (typeof(data[i]) == 'object') {
173                this.stackedOrGrouped = true;
174            }
175        }
176
177        // Store the data
178        this.data = data;
179       
180        // Used to store the coords of the bars
181        this.coords = [];
182
183        /**
184        * Set the .getShape commonly named method
185        */
186        this.getShape = this.getBar;
187    }
188
189
190    /**
191    * A setter
192    *
193    * @param name  string The name of the property to set
194    * @param value mixed  The value of the property
195    */
196    RGraph.Bar.prototype.Set = function (name, value)
197    {
198        name = name.toLowerCase();
199
200        if (name == 'chart.labels.abovebar') {
201            name = 'chart.labels.above';
202        }
203       
204        if (name == 'chart.strokestyle') {
205            name = 'chart.strokecolor';
206        }
207       
208        /**
209        * Check for xaxispos
210        */
211        if (name == 'chart.xaxispos' ) {
212            if (value != 'bottom' && value != 'center' && value != 'top') {
213                alert('[BAR] (' + this.id + ') chart.xaxispos should be top, center or bottom. Tried to set it to: ' + value + ' Changing it to center');
214                value = 'center';
215            }
216           
217            if (value == 'top') {
218                for (var i=0; i<this.data.length; ++i) {
219                    if (typeof(this.data[i]) == 'number' && this.data[i] > 0) {
220                        alert('[BAR] The data element with index ' + i + ' should be negative');
221                    }
222                }
223            }
224        }
225
226        this.properties[name] = value;
227    }
228
229
230    /**
231    * A getter
232    *
233    * @param name  string The name of the property to get
234    */
235    RGraph.Bar.prototype.Get = function (name)
236    {
237        if (name == 'chart.labels.abovebar') {
238            name = 'chart.labels.above';
239        }
240       
241        var value = this.properties[name];
242
243        return value;
244    }
245
246
247    /**
248    * The function you call to draw the bar chart
249    */
250    RGraph.Bar.prototype.Draw = function ()
251    {
252        // MUST be the first thing done!
253        if (typeof(this.Get('chart.background.image')) == 'string' && !this.__background_image__) {
254            RGraph.DrawBackgroundImage(this);
255            return;
256        }
257
258        /**
259        * Fire the onbeforedraw event
260        */
261        RGraph.FireCustomEvent(this, 'onbeforedraw');
262
263        /**
264        * Clear all of this canvases event handlers (the ones installed by RGraph)
265        */
266        RGraph.ClearEventListeners(this.id);
267       
268        /**
269        * This is new in May 2011 and facilitates indiviual gutter settings,
270        * eg chart.gutter.left
271        */
272        this.gutterLeft   = this.Get('chart.gutter.left');
273        this.gutterRight  = this.Get('chart.gutter.right');
274        this.gutterTop    = this.Get('chart.gutter.top');
275        this.gutterBottom = this.Get('chart.gutter.bottom');
276
277        /**
278        * Convert any null values to 0. Won't make any difference to the bar (as opposed to the line chart)
279        */
280        for (var i=0; i<this.data.length; ++i) {
281            if (this.data[i] == null) {
282                this.data[i] = 0;
283            }
284        }
285
286
287        // Cache this in a class variable as it's used rather a lot
288
289        /**
290        * Check for tooltips and alert the user that they're not supported with pyramid charts
291        */
292        if (   (this.Get('chart.variant') == 'pyramid' || this.Get('chart.variant') == 'dot')
293            && typeof(this.Get('chart.tooltips')) == 'object'
294            && this.Get('chart.tooltips')
295            && this.Get('chart.tooltips').length > 0) {
296
297            alert('[BAR] (' + this.id + ') Sorry, tooltips are not supported with dot or pyramid charts');
298        }
299
300        /**
301        * Stop the coords array from growing uncontrollably
302        */
303        this.coords = [];
304
305        /**
306        * Work out a few things. They need to be here because they depend on things you can change before you
307        * call Draw() but after you instantiate the object
308        */
309        this.max            = 0;
310        this.grapharea      = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom;
311        this.halfgrapharea  = this.grapharea / 2;
312        this.halfTextHeight = this.Get('chart.text.size') / 2;
313
314        // Progressively Draw the chart
315        RGraph.background.Draw(this);
316
317
318        //If it's a sketch chart variant, draw the axes first
319        if (this.Get('chart.variant') == 'sketch') {
320            this.DrawAxes();
321            this.Drawbars();
322        } else {
323            this.Drawbars();
324            this.DrawAxes();
325        }
326
327        this.DrawLabels();
328
329
330        // Draw the key if necessary
331        if (this.Get('chart.key').length) {
332            RGraph.DrawKey(this, this.Get('chart.key'), this.Get('chart.colors'));
333        }
334       
335       
336        /**
337        * Setup the context menu if required
338        */
339        if (this.Get('chart.contextmenu')) {
340            RGraph.ShowContext(this);
341        }
342
343
344        /**
345        * Is a line is defined, draw it
346        */
347        var line = this.Get('chart.line');
348
349        if (line) {
350       
351            line.__bar__ = this;
352           
353            // Check the X axis positions
354            if (this.Get('chart.xaxispos') != line.Get('chart.xaxispos')) {
355                alert("[BAR] Using different X axis positions when combining the Bar and Line is not advised");
356            }
357
358            line.Set('chart.gutter.left',   this.Get('chart.gutter.left'));
359            line.Set('chart.gutter.right',  this.Get('chart.gutter.right'));
360            line.Set('chart.gutter.top',    this.Get('chart.gutter.top'));
361            line.Set('chart.gutter.bottom', this.Get('chart.gutter.bottom'));
362
363            line.Set('chart.hmargin', (this.canvas.width - this.gutterLeft - this.gutterRight) / (line.original_data[0].length * 2));
364           
365            // If a BAR custom yMax is set, use that
366            if (this.Get('chart.ymax') && !line.Get('chart.ymax')) {
367                line.Set('chart.ymax', this.Get('chart.ymax'));
368           
369            } else if (line.Get('chart.ymax')) {
370                line.Set('chart.ymax', line.Get('chart.ymax'));
371            }
372
373            line.Draw();
374        }
375
376
377        /**
378        * Draw "in graph" labels
379        */
380        if (this.Get('chart.labels.ingraph')) {
381            RGraph.DrawInGraphLabels(this);
382        }
383       
384        /**
385        * Draw crosschairs
386        */
387        if (this.Get('chart.crosshairs')) {
388            RGraph.DrawCrosshairs(this);
389        }
390       
391        /**
392        * If the canvas is annotatable, do install the event handlers
393        */
394        if (this.Get('chart.annotatable')) {
395            RGraph.Annotate(this);
396        }
397       
398        /**
399        * This bit shows the mini zoom window if requested
400        */
401        if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') {
402            RGraph.ShowZoomWindow(this);
403        }
404
405       
406        /**
407        * This function enables resizing
408        */
409        if (this.Get('chart.resizable')) {
410            RGraph.AllowResizing(this);
411        }
412
413
414        /**
415        * This function enables adjusting
416        */
417        if (this.Get('chart.adjustable')) {
418            RGraph.AllowAdjusting(this);
419        }
420       
421        /**
422        * Fire the RGraph ondraw event
423        */
424        RGraph.FireCustomEvent(this, 'ondraw');
425    }
426
427   
428    /**
429    * Draws the charts axes
430    */
431    RGraph.Bar.prototype.DrawAxes = function ()
432    {
433        if (this.Get('chart.noaxes')) {
434            return;
435        }
436
437        var xaxispos = this.Get('chart.xaxispos');
438        var yaxispos = this.Get('chart.yaxispos');
439
440        this.context.beginPath();
441        this.context.strokeStyle = this.Get('chart.axis.color');
442        this.context.lineWidth   = 1;
443
444        // Draw the Y axis
445        if (this.Get('chart.noyaxis') == false) {
446            if (yaxispos == 'right') {
447                this.context.moveTo(RGraph.GetWidth(this) - this.gutterRight, this.gutterTop);
448                this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom);
449            } else {
450                this.context.moveTo(this.gutterLeft, this.gutterTop);
451                this.context.lineTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom);
452            }
453        }
454       
455        // Draw the X axis
456        if (this.Get('chart.noxaxis') == false) {
457            if (xaxispos == 'center') {
458                this.context.moveTo(this.gutterLeft, ((this.canvas.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop);
459                this.context.lineTo(this.canvas.width - this.gutterRight, ((this.canvas.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop);
460            } else if (xaxispos == 'top') {
461                this.context.moveTo(this.gutterLeft, this.gutterTop);
462                this.context.lineTo(this.canvas.width - this.gutterRight, this.gutterTop);
463            } else {
464                this.context.moveTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom);
465                this.context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom);
466            }
467        }
468
469        var numYTicks = this.Get('chart.numyticks');
470
471        // Draw the Y tickmarks
472        if (this.Get('chart.noyaxis') == false) {
473            var yTickGap = (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / numYTicks;
474            var xpos     = yaxispos == 'left' ? this.gutterLeft : RGraph.GetWidth(this) - this.gutterRight;
475   
476            for (y=this.gutterTop;
477                 xaxispos == 'center' ? y <= (RGraph.GetHeight(this) - this.gutterBottom) : y < (RGraph.GetHeight(this) - this.gutterBottom + (xaxispos == 'top' ? 1 : 0));
478                 y += yTickGap) {
479   
480                if (xaxispos == 'center' && y == (RGraph.GetHeight(this) / 2)) continue;
481               
482                // X axis at the top
483                if (xaxispos == 'top' && y == this.gutterTop) continue;
484               
485                this.context.moveTo(xpos, y);
486                this.context.lineTo(xpos + (yaxispos == 'left' ? -3 : 3), y);
487            }
488           
489            /**
490            * If the X axis is not being shown, draw an extra tick
491            */
492            if (this.Get('chart.noxaxis')) {
493                if (xaxispos == 'center') {
494                    this.context.moveTo(xpos + (yaxispos == 'left' ? -3 : 3), RGraph.GetHeight(this) / 2);
495                    this.context.lineTo(xpos, RGraph.GetHeight(this) / 2);
496                } else if (xaxispos == 'top') {
497                    this.context.moveTo(xpos + (yaxispos == 'left' ? -3 : 3), this.gutterTop);
498                    this.context.lineTo(xpos, this.gutterTop);
499                } else {
500                    this.context.moveTo(xpos + (yaxispos == 'left' ? -3 : 3), RGraph.GetHeight(this) - this.gutterBottom);
501                    this.context.lineTo(xpos, RGraph.GetHeight(this) - this.gutterBottom);
502                }
503            }
504        }
505
506
507        // Draw the X tickmarks
508        if (this.Get('chart.noxaxis') == false) {
509           
510            xTickGap = (RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight) / this.data.length;
511           
512            if (xaxispos == 'bottom') {
513                yStart   = this.canvas.height - this.gutterBottom;
514                yEnd     = (this.canvas.height - this.gutterBottom) + 3;
515            } else if (xaxispos == 'top') {
516                yStart = this.gutterTop - 3;
517                yEnd   = this.gutterTop;
518            } else if (xaxispos == 'center') {
519                yStart = ((this.canvas.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop + 3;
520                yEnd   = ((this.canvas.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop - 3;
521            }
522           
523            //////////////// X TICKS ////////////////
524           
525            var noEndXTick = this.Get('chart.noendxtick');
526
527            for (x=this.gutterLeft + (yaxispos == 'left' ? xTickGap : 0); x<this.canvas.width - this.gutterRight + (yaxispos == 'left' ? 5 : 0); x+=xTickGap) {
528
529                if (yaxispos == 'left' && !noEndXTick && x > this.gutterLeft) {
530                    this.context.moveTo(x, yStart);
531                    this.context.lineTo(x, yEnd);
532               
533                } else if (yaxispos == 'left' && noEndXTick && x > this.gutterLeft && x < (this.canvas.width - this.gutterRight) ) {
534                    this.context.moveTo(x, yStart);
535                    this.context.lineTo(x, yEnd);
536               
537                } else if (yaxispos == 'right' && x < (this.canvas.width - this.gutterRight) && !noEndXTick) {
538                    this.context.moveTo(x, yStart);
539                    this.context.lineTo(x, yEnd);
540               
541                } else if (yaxispos == 'right' && x < (this.canvas.width - this.gutterRight) && x > (this.gutterLeft) && noEndXTick) {
542                    this.context.moveTo(x, yStart);
543                    this.context.lineTo(x, yEnd);
544                }
545            }
546           
547            if (this.Get('chart.noyaxis')) {
548                this.context.moveTo(this.gutterLeft, yStart);
549                this.context.lineTo(this.gutterLeft, yEnd);
550            }
551   
552            //////////////// X TICKS ////////////////
553        }
554
555        /**
556        * If the Y axis is not being shown, draw an extra tick
557        */
558        if (this.Get('chart.noyaxis') && this.Get('chart.noxaxis') == false) {
559            if (xaxispos == 'center') {
560                this.context.moveTo(this.gutterLeft, (RGraph.GetHeight(this) / 2) - 3);
561                this.context.lineTo(this.gutterLeft, (RGraph.GetHeight(this) / 2) + 3);
562            } else {
563                this.context.moveTo(this.gutterLeft, this.canvas.height - this.gutterBottom);
564                this.context.lineTo(this.gutterLeft, this.canvas.height - this.gutterBottom + 3);
565            }
566        }
567
568        this.context.stroke();
569    }
570
571
572    /**
573    * Draws the bars
574    */
575    RGraph.Bar.prototype.Drawbars = function ()
576    {
577        this.context.lineWidth   = this.Get('chart.linewidth');
578        this.context.strokeStyle = this.Get('chart.strokecolor');
579        this.context.fillStyle   = this.Get('chart.colors')[0];
580        var prevX                = 0;
581        var prevY                = 0;
582        var decimals             = this.Get('chart.scale.decimals');
583
584        /**
585        * Work out the max value
586        */
587        if (this.Get('chart.ymax')) {
588            this.max = this.Get('chart.ymax');
589
590            this.scale = [
591                          (this.max * (1/5)).toFixed(decimals),
592                          (this.max * (2/5)).toFixed(decimals),
593                          (this.max * (3/5)).toFixed(decimals),
594                          (this.max * (4/5)).toFixed(decimals),
595                          this.max.toFixed(decimals)
596                         ];
597        } else {
598            for (i=0; i<this.data.length; ++i) {
599                if (typeof(this.data[i]) == 'object') {
600                    var value = this.Get('chart.grouping') == 'grouped' ? Number(RGraph.array_max(this.data[i], true)) : Number(RGraph.array_sum(this.data[i])) ;
601
602                } else {
603                    var value = Number(this.data[i]);
604                }
605
606                this.max = Math.max(Math.abs(this.max), Math.abs(value));
607            }
608
609            this.scale = RGraph.getScale(this.max, this);
610            this.max   = this.scale[4];
611
612            if (this.Get('chart.scale.decimals')) {
613                var decimals = this.Get('chart.scale.decimals');
614
615                this.scale[0] = Number(this.scale[0]).toFixed(decimals);
616                this.scale[1] = Number(this.scale[1]).toFixed(decimals);
617                this.scale[2] = Number(this.scale[2]).toFixed(decimals);
618                this.scale[3] = Number(this.scale[3]).toFixed(decimals);
619                this.scale[4] = Number(this.scale[4]).toFixed(decimals);
620            }
621        }
622
623        /**
624        * Draw horizontal bars here
625        */
626        if (this.Get('chart.background.hbars') && this.Get('chart.background.hbars').length > 0) {
627            RGraph.DrawBars(this);
628        }
629
630        var variant = this.Get('chart.variant');
631       
632        /**
633        * Draw the 3D axes is necessary
634        */
635        if (variant == '3d') {
636            RGraph.Draw3DAxes(this);
637        }
638
639        /**
640        * Get the variant once, and draw the bars, be they regular, stacked or grouped
641        */
642       
643        // Get these variables outside of the loop
644        var xaxispos      = this.Get('chart.xaxispos');
645        var width         = (RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight ) / this.data.length;
646        var orig_height   = height;
647        var hmargin       = this.Get('chart.hmargin');
648        var shadow        = this.Get('chart.shadow');
649        var shadowColor   = this.Get('chart.shadow.color');
650        var shadowBlur    = this.Get('chart.shadow.blur');
651        var shadowOffsetX = this.Get('chart.shadow.offsetx');
652        var shadowOffsetY = this.Get('chart.shadow.offsety');
653        var strokeStyle   = this.Get('chart.strokecolor');
654        var colors        = this.Get('chart.colors');
655
656        for (i=0; i<this.data.length; ++i) {
657
658            // Work out the height
659            //The width is up outside the loop
660            var height = (RGraph.array_sum(this.data[i]) / this.max) * (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom);
661
662            // Half the height if the Y axis is at the center
663            if (xaxispos == 'center') {
664                height /= 2;
665            }
666
667            var x = (i * width) + this.gutterLeft;
668            var y = xaxispos == 'center' ? ((this.canvas.height - this.gutterTop - this.gutterBottom) / 2) + this.gutterTop - height : RGraph.GetHeight(this) - height - this.gutterBottom;
669           
670            // xaxispos is top
671            if (xaxispos == 'top') {
672                y = this.gutterTop + Math.abs(height);
673            }
674           
675
676            // Account for negative lengths - Some browsers (eg Chrome) don't like a negative value
677            if (height < 0) {
678                y += height;
679                height = Math.abs(height);
680            }
681
682            /**
683            * Turn on the shadow if need be
684            */
685            if (shadow) {
686                this.context.shadowColor   = shadowColor;
687                this.context.shadowBlur    = shadowBlur;
688                this.context.shadowOffsetX = shadowOffsetX;
689                this.context.shadowOffsetY = shadowOffsetY;
690            }
691
692            /**
693            * Draw the bar
694            */
695            this.context.beginPath();
696                if (typeof(this.data[i]) == 'number') {
697                   
698                    var barWidth = width - (2 * hmargin);
699
700                    // Set the fill color
701                    this.context.strokeStyle = strokeStyle;
702                    this.context.fillStyle = colors[0];
703                   
704                    /**
705                    * Sequential colors
706                    */
707                    if (this.Get('chart.colors.sequential')) {
708                        this.context.fillStyle = colors[i];
709                    }
710
711                    if (variant == 'sketch') {
712
713                        this.context.lineCap = 'round';
714                       
715                        var sketchOffset = 3;
716
717                        this.context.beginPath();
718
719                        this.context.strokeStyle = colors[0];
720
721                        /**
722                        * Sequential colors
723                        */
724                        if (this.Get('chart.colors.sequential')) {
725                            this.context.strokeStyle = colors[i];
726                        }
727
728                        // Left side
729                        this.context.moveTo(x + hmargin + 2, y + height - 2);
730                        this.context.lineTo(x + hmargin , y - 2);
731
732                        // The top
733                        this.context.moveTo(x + hmargin - 3, y + -2 + (this.data[i] < 0 ? height : 0));
734                        this.context.bezierCurveTo(x + ((hmargin + width) * 0.33),y + 5 + (this.data[i] < 0 ? height - 10: 0),x + ((hmargin + width) * 0.66),y + 5 + (this.data[i] < 0 ? height - 10 : 0),x + hmargin + width + -1, y + 0 + (this.data[i] < 0 ? height : 0));
735
736
737                        // The right side
738                        this.context.moveTo(x + hmargin + width - 2, y + -2);
739                        this.context.lineTo(x + hmargin + width - 3, y + height - 3);
740
741                        for (var r=0.2; r<=0.8; r+=0.2) {
742                            this.context.moveTo(x + hmargin + width + (r > 0.4 ? -1 : 3) - (r * width),y - 1);
743                            this.context.lineTo(x + hmargin + width - (r > 0.4 ? 1 : -1) - (r * width), y + height + (r == 0.2 ? 1 : -2));
744                        }
745
746                        this.context.stroke();
747
748                    // Regular bar
749                    } else if (variant == 'bar' || variant == '3d' || variant == 'glass' || variant == 'bevel') {
750                   
751                        if (RGraph.isIE8() && shadow) {
752                            this.DrawIEShadow([x + hmargin, y, barWidth, height]);
753                        }
754                       
755                        if (variant == 'glass') {
756                            RGraph.filledCurvyRect(this.context, x + hmargin, y, barWidth, height, 3, this.data[i] > 0, this.data[i] > 0, this.data[i] < 0, this.data[i] < 0);
757                            RGraph.strokedCurvyRect(this.context, x + hmargin, y, barWidth, height, 3, this.data[i] > 0, this.data[i] > 0, this.data[i] < 0, this.data[i] < 0);
758                        } else {
759                            this.context.strokeRect(x + hmargin, y, barWidth, height);
760                            this.context.fillRect(x + hmargin, y, barWidth, height);
761                        }
762
763                       
764                        // This bit draws the text labels that appear above the bars if requested
765                        if (this.Get('chart.labels.above')) {
766
767                            // Turn off any shadow
768                            if (shadow) {
769                                RGraph.NoShadow(this);
770                            }
771
772                            var yPos = y - 3;
773
774                            // Account for negative bars
775                            if (this.data[i] < 0) {
776                                yPos += height + 6 + (this.Get('chart.text.size') - 4);
777                            }
778
779                            // Account for chart.xaxispos=top
780                            if (this.Get('chart.xaxispos') == 'top') {
781                                yPos = this.gutterTop + height + 6 + (typeof(this.Get('chart.labels.above.size')) == 'number' ? this.Get('chart.labels.above.size') : this.Get('chart.text.size') - 4);
782                            }
783
784                            this.context.fillStyle = this.Get('chart.text.color');
785
786                            RGraph.Text(this.context,
787                                        this.Get('chart.text.font'),
788                                        typeof(this.Get('chart.labels.above.size')) == 'number' ? this.Get('chart.labels.above.size') : this.Get('chart.text.size') - 3,
789                                        x + hmargin + (barWidth / 2),
790                                        yPos,
791                                        RGraph.number_format(this, Number(this.data[i]).toFixed(this.Get('chart.labels.above.decimals')),this.Get('chart.units.pre'),this.Get('chart.units.post')),
792                                        this.Get('chart.labels.above.angle') ? 'bottom' : null,
793                                        this.Get('chart.labels.above.angle') ? (this.Get('chart.labels.above.angle') > 0 && (this.Get('chart.xaxispos') != 'top') ? 'right' : 'left') : 'center',
794                                        null,
795                                        this.Get('chart.labels.above.angle')
796                                       );
797                        }
798
799                        // 3D effect
800                        if (variant == '3d') {
801
802                            var prevStrokeStyle = this.context.strokeStyle;
803                            var prevFillStyle   = this.context.fillStyle;
804
805                            // Draw the top
806                            this.context.beginPath();
807                                this.context.moveTo(x + hmargin, y);
808                                this.context.lineTo(x + hmargin + 10, y - 5);
809                                this.context.lineTo(x + hmargin + 10 + barWidth, y - 5);
810                                this.context.lineTo(x + hmargin + barWidth, y);
811                            this.context.closePath();
812
813                            this.context.stroke();
814                            this.context.fill();
815
816                            // Draw the right hand side
817                            this.context.beginPath();
818                                this.context.moveTo(x + hmargin + barWidth, y);
819                                this.context.lineTo(x + hmargin + barWidth + 10, y - 5);
820                                this.context.lineTo(x + hmargin + barWidth + 10, y + height - 5);
821                                this.context.lineTo(x + hmargin + barWidth, y + height);
822                            this.context.closePath();
823   
824                            this.context.stroke();                       
825                            this.context.fill();
826
827                            // Draw the darker top section
828                            this.context.beginPath();
829                                this.context.fillStyle = 'rgba(255,255,255,0.3)';
830                                this.context.moveTo(x + hmargin, y);
831                                this.context.lineTo(x + hmargin + 10, y - 5);
832                                this.context.lineTo(x + hmargin + 10 + barWidth, y - 5);
833                                this.context.lineTo(x + hmargin + barWidth, y);
834                                this.context.lineTo(x + hmargin, y);
835                            this.context.closePath();
836   
837                            this.context.stroke();
838                            this.context.fill();
839
840                            // Draw the darker right side section
841                            this.context.beginPath();
842                                this.context.fillStyle = 'rgba(0,0,0,0.4)';
843                                this.context.moveTo(x + hmargin + barWidth, y);
844                                this.context.lineTo(x + hmargin + barWidth + 10, y - 5);
845                                this.context.lineTo(x + hmargin + barWidth + 10, y - 5 + height);
846                                this.context.lineTo(x + hmargin + barWidth, y + height);
847                                this.context.lineTo(x + hmargin + barWidth, y);
848                            this.context.closePath();
849
850                            this.context.stroke();
851                            this.context.fill();
852
853                            this.context.strokeStyle = prevStrokeStyle;
854                            this.context.fillStyle   = prevFillStyle;
855                       
856                        // Glass variant
857                        } else if (variant == 'glass') {
858 
859                            var grad = this.context.createLinearGradient(
860                                                                         x + hmargin,
861                                                                         y,
862                                                                         x + hmargin + (barWidth / 2),
863                                                                         y
864                                                                        );
865                            grad.addColorStop(0, 'rgba(255,255,255,0.9)');
866                            grad.addColorStop(1, 'rgba(255,255,255,0.5)');
867
868                            this.context.beginPath();
869                            this.context.fillStyle = grad;
870                            this.context.fillRect(x + hmargin + 2,y + (this.data[i] > 0 ? 2 : 0),(barWidth / 2) - 2,height - 2);
871                            this.context.fill();
872                        }
873
874                    // Dot chart
875                    } else if (variant == 'dot') {
876
877                        this.context.beginPath();
878                        this.context.moveTo(x + (width / 2), y);
879                        this.context.lineTo(x + (width / 2), y + height);
880                        this.context.stroke();
881                       
882                        this.context.beginPath();
883                        this.context.fillStyle = this.Get('chart.colors')[i];
884                        this.context.arc(x + (width / 2), y + (this.data[i] > 0 ? 0 : height), 2, 0, 6.28, 0);
885                       
886                        // Set the colour for the dots
887                        this.context.fillStyle = this.Get('chart.colors')[0];
888
889                        /**
890                        * Sequential colors
891                        */
892                        if (this.Get('chart.colors.sequential')) {
893                            this.context.fillStyle = colors[i];
894                        }
895
896                        this.context.stroke();
897                        this.context.fill();
898                   
899                    // Pyramid chart
900                    } else if (variant == 'pyramid') {
901
902                        this.context.beginPath();
903                            var startY = (this.Get('chart.xaxispos') == 'center' ? (RGraph.GetHeight(this) / 2) : (RGraph.GetHeight(this) - this.gutterBottom));
904                       
905                            this.context.moveTo(x + hmargin, startY);
906                            this.context.lineTo(
907                                                x + hmargin + (barWidth / 2),
908                                                y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0)
909                                               );
910                            this.context.lineTo(x + hmargin + barWidth, startY);
911                       
912                        this.context.closePath();
913                       
914                        this.context.stroke();
915                        this.context.fill();
916                   
917                    // Arrow chart
918                    } else if (variant == 'arrow') {
919                       
920                        var startY = (this.Get('chart.xaxispos') == 'center' ? (RGraph.GetHeight(this) / 2) : (RGraph.GetHeight(this) - this.gutterBottom));
921
922                        this.context.lineWidth = this.Get('chart.linewidth') ? this.Get('chart.linewidth') : 1;
923                        this.context.lineCap = 'round';
924
925                        this.context.beginPath();
926
927                            this.context.moveTo(x + hmargin + (barWidth / 2), startY);
928                            this.context.lineTo(x + hmargin + (barWidth / 2), y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0));
929                            this.context.arc(x + hmargin + (barWidth / 2),
930                                             y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0),
931                                             5,
932                                             this.data[i] > 0 ? 0.78 : 5.6,
933                                             this.data[i] > 0 ? 0.79 : 5.48,
934                                             this.data[i] < 0);
935
936                            this.context.moveTo(x + hmargin + (barWidth / 2), y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0));
937                            this.context.arc(x + hmargin + (barWidth / 2),
938                                             y + (this.Get('chart.xaxispos') == 'center' && (this.data[i] < 0) ? height : 0),
939                                             5,
940                                             this.data[i] > 0 ? 2.355 : 4,
941                                             this.data[i] > 0 ? 2.4 : 3.925,
942                                             this.data[i] < 0);
943
944                        this.context.stroke();
945                       
946                        this.context.lineWidth = 1;
947
948                    // Unknown variant type
949                    } else {
950                        alert('[BAR] Warning! Unknown chart.variant: ' + variant);
951                    }
952
953                    this.coords.push([x + hmargin, y, width - (2 * hmargin), height]);
954
955
956                /**
957                * Stacked bar
958                */
959                } else if (typeof(this.data[i]) == 'object' && this.Get('chart.grouping') == 'stacked') {
960                   
961                    var barWidth     = width - (2 * hmargin);
962                    var redrawCoords = [];// Necessary to draw if the shadow is enabled
963                    var startY       = 0;
964
965                    for (j=0; j<this.data[i].length; ++j) {
966
967                        // Stacked bar chart and X axis pos in the middle - poitless since negative values are not permitted
968                        if (xaxispos == 'center') {
969                            alert("[BAR] It's fruitless having the X axis position at the center on a stacked bar chart.");
970                            return;
971                        }
972
973                        // Negative values not permitted for the stacked chart
974                        if (this.data[i][j] < 0) {
975                            alert('[BAR] Negative values are not permitted with a stacked bar chart. Try a grouped one instead.');
976                            return;
977                        }
978
979                        /**
980                        * Set the fill and stroke colors
981                        */
982                            this.context.strokeStyle = strokeStyle
983                            this.context.fillStyle = colors[j];
984   
985                            if (this.Get('chart.colors.reverse')) {
986                                this.context.fillStyle = colors[this.data[i].length - j - 1];
987                            }
988
989                        var height = (this.data[i][j] / this.max) * (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom );
990
991                        // If the X axis pos is in the center, we need to half the  height
992                        if (xaxispos == 'center') {
993                            height /= 2;
994                        }
995
996                        var totalHeight = (RGraph.array_sum(this.data[i]) / this.max) * (RGraph.GetHeight(this) - hmargin - this.gutterTop - this.gutterBottom);
997
998                        /**
999                        * Store the coords for tooltips
1000                        */
1001                        this.coords.push([x + hmargin, y, width - (2 * hmargin), height]);
1002
1003                        // MSIE shadow
1004                        if (document.all && shadow) {
1005                            this.DrawIEShadow([x + hmargin, y, width - (2 * hmargin), height + 1]);
1006                        }
1007
1008                        this.context.strokeRect(x + hmargin, y, width - (2 * hmargin), height);
1009                        this.context.fillRect(x + hmargin, y, width - (2 * hmargin), height);
1010
1011                       
1012                        if (j == 0) {
1013                            var startY = y;
1014                            var startX = x;
1015                        }
1016
1017                        /**
1018                        * Store the redraw coords if the shadow is enabled
1019                        */
1020                        if (shadow) {
1021                            redrawCoords.push([x + hmargin, y, width - (2 * hmargin), height, colors[j]]);
1022                        }
1023
1024                        /**
1025                        * Stacked 3D effect
1026                        */
1027                        if (variant == '3d') {
1028
1029                            var prevFillStyle = this.context.fillStyle;
1030                            var prevStrokeStyle = this.context.strokeStyle;
1031
1032   
1033                            // Draw the top side
1034                            if (j == 0) {
1035                                this.context.beginPath();
1036                                    this.context.moveTo(startX + hmargin, y);
1037                                    this.context.lineTo(startX + 10 + hmargin, y - 5);
1038                                    this.context.lineTo(startX + 10 + barWidth + hmargin, y - 5);
1039                                    this.context.lineTo(startX + barWidth + hmargin, y);
1040                                this.context.closePath();
1041                               
1042                                this.context.fill();
1043                                this.context.stroke();
1044                            }
1045
1046                            // Draw the side section
1047                            this.context.beginPath();
1048                                this.context.moveTo(startX + barWidth + hmargin, y);
1049                                this.context.lineTo(startX + barWidth + hmargin + 10, y - 5);
1050                                this.context.lineTo(startX + barWidth + + hmargin + 10, y - 5 + height);
1051                                this.context.lineTo(startX + barWidth + hmargin , y + height);
1052                            this.context.closePath();
1053                           
1054                            this.context.fill();
1055                            this.context.stroke();
1056
1057                            // Draw the darker top side
1058                            if (j == 0) {
1059                                this.context.fillStyle = 'rgba(255,255,255,0.3)';
1060                                this.context.beginPath();
1061                                    this.context.moveTo(startX + hmargin, y);
1062                                    this.context.lineTo(startX + 10 + hmargin, y - 5);
1063                                    this.context.lineTo(startX + 10 + barWidth + hmargin, y - 5);
1064                                    this.context.lineTo(startX + barWidth + hmargin, y);
1065                                this.context.closePath();
1066                               
1067                                this.context.fill();
1068                                this.context.stroke();
1069                            }
1070
1071                            // Draw the darker side section
1072                            this.context.fillStyle = 'rgba(0,0,0,0.4)';
1073                            this.context.beginPath();
1074                                this.context.moveTo(startX + barWidth + hmargin, y);
1075                                this.context.lineTo(startX + barWidth + hmargin + 10, y - 5);
1076                                this.context.lineTo(startX + barWidth + + hmargin + 10, y - 5 + height);
1077                                this.context.lineTo(startX + barWidth + hmargin , y + height);
1078                            this.context.closePath();
1079                           
1080                            this.context.fill();
1081                            this.context.stroke();
1082
1083                            this.context.strokeStyle = prevStrokeStyle;
1084                            this.context.fillStyle = prevFillStyle;
1085                        }
1086
1087                        y += height;
1088                    }
1089
1090                    // This bit draws the text labels that appear above the bars if requested
1091                    if (this.Get('chart.labels.above')) {
1092
1093                        // Turn off any shadow
1094                        RGraph.NoShadow(this);
1095
1096                        this.context.fillStyle = this.Get('chart.text.color');
1097                        RGraph.Text(this.context,this.Get('chart.text.font'),typeof(this.Get('chart.labels.above.size')) == 'number' ? this.Get('chart.labels.above.size') : this.Get('chart.text.size') - 3,startX + (barWidth / 2) + this.Get('chart.hmargin'),startY - (this.Get('chart.shadow') && this.Get('chart.shadow.offsety') < 0 ? 7 : 4),String(this.Get('chart.units.pre') + RGraph.array_sum(this.data[i]).toFixed(this.Get('chart.labels.above.decimals')) + this.Get('chart.units.post')),this.Get('chart.labels.above.angle') ? 'bottom' : null,this.Get('chart.labels.above.angle') ? (this.Get('chart.labels.above.angle') > 0 ? 'right' : 'left') : 'center',null,this.Get('chart.labels.above.angle'));
1098                     
1099                        // Turn any shadow back on
1100                        if (shadow) {
1101                            this.context.shadowColor   = shadowColor;
1102                            this.context.shadowBlur    = shadowBlur;
1103                            this.context.shadowOffsetX = shadowOffsetX;
1104                            this.context.shadowOffsetY = shadowOffsetY;
1105                        }
1106                    }
1107                   
1108
1109                    /**
1110                    * Redraw the bars if the shadow is enabled due to hem being drawn from the bottom up, and the
1111                    * shadow spilling over to higher up bars
1112                    */
1113                    if (shadow) {
1114
1115                        RGraph.NoShadow(this);
1116
1117                        for (k=0; k<redrawCoords.length; ++k) {
1118                            this.context.strokeStyle = strokeStyle;
1119                            this.context.fillStyle = redrawCoords[k][4];
1120                            this.context.strokeRect(redrawCoords[k][0], redrawCoords[k][1], redrawCoords[k][2], redrawCoords[k][3]);
1121                            this.context.fillRect(redrawCoords[k][0], redrawCoords[k][1], redrawCoords[k][2], redrawCoords[k][3]);
1122
1123                            this.context.stroke();
1124                            this.context.fill();
1125                        }
1126                       
1127                        // Reset the redraw coords to be empty
1128                        redrawCoords = [];
1129                    }
1130                /**
1131                * Grouped bar
1132                */
1133                } else if (typeof(this.data[i]) == 'object' && this.Get('chart.grouping') == 'grouped') {
1134
1135                    var redrawCoords = [];
1136                    this.context.lineWidth = this.Get('chart.linewidth');
1137
1138                    for (j=0; j<this.data[i].length; ++j) {
1139                        // Set the fill and stroke colors
1140                        this.context.strokeStyle = strokeStyle;
1141                        this.context.fillStyle   = colors[j];
1142
1143                        var individualBarWidth = (width - (2 * hmargin)) / this.data[i].length;
1144                        var height = (this.data[i][j] / this.max) * (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom );
1145
1146                        // If the X axis pos is in the center, we need to half the  height
1147                        if (xaxispos == 'center') {
1148                            height /= 2;
1149                        }
1150
1151                        var startX = x + hmargin + (j * individualBarWidth);
1152
1153                        /**
1154                        * Determine the start positioning for the bar
1155                        */
1156                        if (xaxispos == 'top') {
1157                            var startY = this.Get('chart.gutter.top');
1158                            var height = Math.abs(height);
1159
1160                        } else if (xaxispos == 'center') {
1161                            var startY = this.gutterTop + (this.grapharea / 2) - height;
1162                           
1163                        } else {
1164                            var startY = this.canvas.height - this.gutterBottom - height;
1165                            var height = Math.abs(height);
1166                        }
1167
1168                        /**
1169                        * Draw MSIE shadow
1170                        */
1171                        if (RGraph.isIE8() && shadow) {
1172                            this.DrawIEShadow([startX, startY, individualBarWidth, height]);
1173                        }
1174
1175                        this.context.strokeRect(startX, startY, individualBarWidth, height);
1176                        this.context.fillRect(startX, startY, individualBarWidth, height);
1177                        y += height;
1178
1179                        // This bit draws the text labels that appear above the bars if requested
1180                        if (this.Get('chart.labels.above')) {
1181                       
1182                            this.context.strokeStyle = 'rgba(0,0,0,0)';
1183
1184                            // Turn off any shadow
1185                            if (shadow) {
1186                                RGraph.NoShadow(this);
1187                            }
1188
1189                            var yPos = y - 3;
1190
1191                            // Account for negative bars
1192                            if (this.data[i][j] < 0) {
1193                                yPos += height + 6 + (this.Get('chart.text.size') - 4);
1194                            }
1195
1196                            this.context.fillStyle = this.Get('chart.text.color');
1197                            RGraph.Text(this.context,this.Get('chart.text.font'),typeof(this.Get('chart.labels.above.size')) == 'number' ? this.Get('chart.labels.above.size') : this.Get('chart.text.size') - 3,startX + (individualBarWidth / 2),startY - 2,RGraph.number_format(this, this.data[i][j].toFixed(this.Get('chart.labels.above.decimals'))),null,this.Get('chart.labels.above.angle') ? (this.Get('chart.labels.above.angle') > 0 ? 'right' : 'left') : 'center', null, this.Get('chart.labels.above.angle'));
1198                         
1199                            // Turn any shadow back on
1200                            if (shadow) {
1201                                this.context.shadowColor   = shadowColor;
1202                                this.context.shadowBlur    = shadowBlur;
1203                                this.context.shadowOffsetX = shadowOffsetX;
1204                                this.context.shadowOffsetY = shadowOffsetY;
1205                            }
1206                        }
1207
1208                        /**
1209                        * Grouped 3D effect
1210                        */
1211                        if (variant == '3d') {
1212                            var prevFillStyle = this.context.fillStyle;
1213                            var prevStrokeStyle = this.context.strokeStyle;
1214                           
1215                            // Draw the top side
1216                            this.context.beginPath();
1217                                this.context.moveTo(startX, startY);
1218                                this.context.lineTo(startX + 10, startY - 5);
1219                                this.context.lineTo(startX + 10 + individualBarWidth, startY - 5);
1220                                this.context.lineTo(startX + individualBarWidth, startY);
1221                            this.context.closePath();
1222                           
1223                            this.context.fill();
1224                            this.context.stroke();
1225                           
1226                            // Draw the side section
1227                            this.context.beginPath();
1228                                this.context.moveTo(startX + individualBarWidth, startY);
1229                                this.context.lineTo(startX + individualBarWidth + 10, startY - 5);
1230                                this.context.lineTo(startX + individualBarWidth + 10, startY - 5 + height);
1231                                this.context.lineTo(startX + individualBarWidth , startY + height);
1232                            this.context.closePath();
1233                           
1234                            this.context.fill();
1235                            this.context.stroke();
1236
1237
1238                            // Draw the darker top side
1239                            this.context.fillStyle = 'rgba(255,255,255,0.3)';
1240                            this.context.beginPath();
1241                                this.context.moveTo(startX, startY);
1242                                this.context.lineTo(startX + 10, startY - 5);
1243                                this.context.lineTo(startX + 10 + individualBarWidth, startY - 5);
1244                                this.context.lineTo(startX + individualBarWidth, startY);
1245                            this.context.closePath();
1246                           
1247                            this.context.fill();
1248                            this.context.stroke();
1249                           
1250                            // Draw the darker side section
1251                            this.context.fillStyle = 'rgba(0,0,0,0.4)';
1252                            this.context.beginPath();
1253                                this.context.moveTo(startX + individualBarWidth, startY);
1254                                this.context.lineTo(startX + individualBarWidth + 10, startY - 5);
1255                                this.context.lineTo(startX + individualBarWidth + 10, startY - 5 + height);
1256                                this.context.lineTo(startX + individualBarWidth , startY + height);
1257                            this.context.closePath();
1258                           
1259                            this.context.fill();
1260                            this.context.stroke();
1261
1262                            this.context.strokeStyle = prevStrokeStyle;
1263                            this.context.fillStyle   = prevFillStyle;
1264                        }
1265
1266                        this.coords.push([startX, startY, individualBarWidth, height]);
1267
1268                        // Facilitate shadows going to the left
1269                        if (this.Get('chart.shadow')) {
1270                            redrawCoords.push([startX, startY, individualBarWidth, height]);
1271                        }
1272                    }
1273                   
1274                    /**
1275                    * Redraw the bar if shadows are going to the left
1276                    */
1277                    if (redrawCoords.length) {
1278
1279                        RGraph.NoShadow(this);
1280                       
1281                        this.context.lineWidth = this.Get('chart.linewidth');
1282
1283                        this.context.beginPath();
1284                            for (var j=0; j<redrawCoords.length; ++j) {
1285
1286                                this.context.fillStyle   = this.Get('chart.colors')[j];
1287                                this.context.strokeStyle = this.Get('chart.strokecolor');
1288
1289                                this.context.fillRect(redrawCoords[j][0], redrawCoords[j][1], redrawCoords[j][2], redrawCoords[j][3]);
1290                                this.context.strokeRect(redrawCoords[j][0], redrawCoords[j][1], redrawCoords[j][2], redrawCoords[j][3]);
1291                            }
1292                        this.context.fill();
1293                        this.context.stroke();
1294
1295                        redrawCoords = [];
1296                    }
1297                }
1298
1299            this.context.closePath();
1300        }
1301
1302        /**
1303        * Turn off any shadow
1304        */
1305        RGraph.NoShadow(this);
1306
1307
1308        /**
1309        * Install the onclick event handler
1310        */
1311        if (this.Get('chart.tooltips')) {
1312       
1313            // Need to register this object for redrawing
1314            RGraph.Register(this);
1315
1316            /**
1317            * Install the window onclick handler
1318            */
1319            var window_onclick_func = function (){RGraph.Redraw();};
1320            window.addEventListener('click', window_onclick_func, false);
1321            RGraph.AddEventListener('window_' + this.id, 'click', window_onclick_func);
1322
1323
1324
1325            /**
1326            * If the cursor is over a hotspot, change the cursor to a hand. Bar chart tooltips can now
1327            * be based around the onmousemove event
1328            */
1329            canvas_onmousemove = function (e)
1330            {
1331                e = RGraph.FixEventObject(e);
1332
1333                var canvas    = document.getElementById(e.target.id);
1334                var obj       = canvas.__object__;
1335                var barCoords = obj.getBar(e);
1336
1337                /**
1338                * If there are bar coords AND the bar has height
1339                */
1340
1341                if (barCoords && barCoords[4] > 0) {
1342
1343                    /**
1344                    * Get the tooltip text
1345                    */
1346                    if (typeof(obj.Get('chart.tooltips')) == 'function') {
1347                        var text = String(obj.Get('chart.tooltips')(barCoords[5]));
1348                   
1349                    } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'function') {
1350                        var text = String(obj.Get('chart.tooltips')[barCoords[5]](barCoords[5]));
1351                   
1352                    } else if (typeof(obj.Get('chart.tooltips')) == 'object' && (typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'string' || typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'number')) {
1353                        var text = String(obj.Get('chart.tooltips')[barCoords[5]]);
1354               
1355                    } else {
1356                        var text = null;
1357                    }
1358
1359                    if (text) {
1360                        canvas.style.cursor = 'pointer';
1361                    } else {
1362                        canvas.style.cursor = 'default';
1363                    }
1364                   
1365                    /**
1366                    * Hide the currently displayed tooltip if the index is the same
1367                    */
1368                    if (   RGraph.Registry.Get('chart.tooltip')
1369                        && RGraph.Registry.Get('chart.tooltip').__canvas__.id != obj.id
1370                        && obj.Get('chart.tooltips.event') == 'onmousemove') {
1371
1372                        RGraph.Redraw();
1373                        RGraph.HideTooltip();
1374                    }
1375
1376                    /**
1377                    * This facilitates the tooltips using the onmousemove event
1378                    */
1379
1380                    if (   obj.Get('chart.tooltips.event') == 'onmousemove'
1381                        && (
1382                               (RGraph.Registry.Get('chart.tooltip') && RGraph.Registry.Get('chart.tooltip').__index__ != barCoords[5])
1383                            || !RGraph.Registry.Get('chart.tooltip')
1384                           )
1385                        && text) {
1386                        /**
1387                        * Show a tooltip if it's defined
1388                        */
1389                        RGraph.Redraw(obj);
1390
1391                        if (obj.Get('chart.tooltips.highlight')) {
1392                            obj.context.beginPath();
1393                            obj.context.strokeStyle = obj.Get('chart.highlight.stroke');
1394                            obj.context.fillStyle   = obj.Get('chart.highlight.fill');
1395                            obj.context.strokeRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]);
1396                            obj.context.fillRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]);
1397                   
1398                            obj.context.stroke();
1399                            obj.context.fill();
1400                        }
1401
1402                        RGraph.Tooltip(canvas, text, e.pageX, e.pageY, barCoords[5]);
1403                    }
1404                } else {
1405                    canvas.style.cursor = 'default';
1406                }
1407            }
1408            RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove);
1409            this.canvas.addEventListener('mousemove', canvas_onmousemove, false);
1410
1411
1412            /**
1413            * Install the onclick event handler for the tooltips
1414            */
1415            if (this.Get('chart.tooltips.event') == 'onclick') {
1416
1417                canvas_onclick = function (e)
1418                {
1419                    var e = RGraph.FixEventObject(e);
1420   
1421                    // If the button pressed isn't the left, we're not interested
1422                    if (e.button != 0) return;
1423   
1424                    e = RGraph.FixEventObject(e);
1425   
1426                    var canvas    = document.getElementById(this.id);
1427                    var obj       = canvas.__object__;
1428                    var barCoords = obj.getBar(e);
1429
1430                    /**
1431                    * Redraw the graph first, in effect resetting the graph to as it was when it was first drawn
1432                    * This "deselects" any already selected bar
1433                    */
1434                    RGraph.Redraw();
1435
1436                    /**
1437                    * Loop through the bars determining if the mouse is over a bar
1438                    */
1439                    if (barCoords) {
1440
1441                        /**
1442                        * Get the tooltip text
1443                        */
1444                        if (typeof(obj.Get('chart.tooltips')) == 'function') {
1445                            var text = String(obj.Get('chart.tooltips')(barCoords[5]));
1446                       
1447                        } else if (typeof(obj.Get('chart.tooltips')) == 'object' && typeof(obj.Get('chart.tooltips')[barCoords[5]]) == 'function') {
1448                            var text = String(obj.Get('chart.tooltips')[barCoords[5]](barCoords[5]));
1449                       
1450                        } else if (typeof(obj.Get('chart.tooltips')) == 'object') {
1451                            var text = String(obj.Get('chart.tooltips')[barCoords[5]]);
1452
1453                        } else {
1454                            var text = null;
1455                        }
1456
1457                        /**
1458                        * Show a tooltip if it's defined
1459                        */
1460                        if (text && text != 'undefined') {
1461
1462                            if (obj.Get('chart.tooltips.highlight')) {
1463                                // [TODO] Allow customisation of the highlight colors
1464                                obj.context.beginPath();
1465                                obj.context.strokeStyle = obj.Get('chart.highlight.stroke');
1466                                obj.context.fillStyle   = obj.Get('chart.highlight.fill');
1467                                obj.context.strokeRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]);
1468                                obj.context.fillRect(barCoords[1], barCoords[2], barCoords[3], barCoords[4]);
1469           
1470                                obj.context.stroke();
1471                                obj.context.fill();
1472                            }
1473
1474                            RGraph.Tooltip(canvas, text, e.pageX, e.pageY, barCoords[5]);
1475                        }
1476                    }
1477   
1478                    /**
1479                    * Stop the event bubbling
1480                    */
1481                    e.stopPropagation();
1482                }
1483                RGraph.AddEventListener(this.id, 'click', canvas_onclick);
1484                this.canvas.addEventListener('click', canvas_onclick, false);
1485            }
1486
1487
1488            // This resets the bar graph
1489            // 8th August 2010 : Is this redundant
1490            //if (typeof(obj) != 'undefined' && obj == RGraph.Registry.Get('chart.tooltip')) {
1491            //    obj.style.display = 'none';
1492            //    RGraph.Registry.Set('chart.tooltip', null)
1493            //}
1494        }
1495    }
1496
1497    /**
1498    * Draws the labels for the graph
1499    */
1500    RGraph.Bar.prototype.DrawLabels = function ()
1501    {
1502        var context    = this.context;
1503        var text_angle = this.Get('chart.text.angle');
1504        var text_size  = this.Get('chart.text.size');
1505        var labels     = this.Get('chart.labels');
1506
1507
1508        // Draw the Y axis labels:
1509        if (this.Get('chart.ylabels')) {
1510            this.Drawlabels_top();
1511            this.Drawlabels_center();
1512            this.Drawlabels_bottom();
1513        }
1514
1515        /**
1516        * The X axis labels
1517        */
1518        if (typeof(labels) == 'object' && labels) {
1519
1520            var yOffset = 13 + Number(this.Get('chart.xlabels.offset'));
1521
1522            /**
1523            * Text angle
1524            */
1525            var angle  = 0;
1526            var halign = 'center';
1527
1528            if (text_angle > 0) {
1529                angle  = -1 * text_angle;
1530                halign   = 'right';
1531                yOffset -= 5;
1532               
1533                if (this.Get('chart.xaxispos') == 'top') {
1534                    halign   = 'left';
1535                    yOffset += 5;
1536                }
1537            }
1538
1539            // Draw the X axis labels
1540            context.fillStyle = this.Get('chart.text.color');
1541           
1542            // How wide is each bar
1543            var barWidth = (RGraph.GetWidth(this) - this.gutterRight - this.gutterLeft) / labels.length;
1544           
1545            // Reset the xTickGap
1546            xTickGap = (RGraph.GetWidth(this) - this.gutterRight - this.gutterLeft) / labels.length
1547
1548            // Draw the X tickmarks
1549            var i=0;
1550            var font = this.Get('chart.text.font');
1551
1552            for (x=this.gutterLeft + (xTickGap / 2); x<=RGraph.GetWidth(this) - this.gutterRight; x+=xTickGap) {
1553                RGraph.Text(context, font,
1554                                      text_size,
1555                                      x + (this.Get('chart.text.angle') == 90 ? 0 : 0),
1556                                      this.Get('chart.xaxispos') == 'top' ? this.gutterTop - yOffset + text_size  - 1: (RGraph.GetHeight(this) - this.gutterBottom) + yOffset,
1557                                      String(labels[i++]),
1558                                      (this.Get('chart.text.angle') == 90 ? 'center' : null),
1559                                      halign,
1560                                      null,
1561                                      angle);
1562            }
1563        }
1564    }
1565
1566    /**
1567    * Draws the X axis at the top
1568    */
1569    RGraph.Bar.prototype.Drawlabels_top = function ()
1570    {
1571        this.context.beginPath();
1572        this.context.fillStyle = this.Get('chart.text.color');
1573        this.context.strokeStyle = 'black';
1574
1575        if (this.Get('chart.xaxispos') == 'top') {
1576
1577            var context    = this.context;
1578            var interval   = (this.grapharea * (1/5) );
1579            var text_size  = this.Get('chart.text.size');
1580            var units_pre  = this.Get('chart.units.pre');
1581            var units_post = this.Get('chart.units.post');
1582            var align      = this.Get('chart.yaxispos') == 'left' ? 'right' : 'left';
1583            var font       = this.Get('chart.text.font');
1584            var numYLabels = this.Get('chart.ylabels.count');
1585
1586            if (this.Get('chart.ylabels.inside') == true) {
1587                var xpos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft + 5 : RGraph.GetWidth(this) - this.gutterRight - 5;
1588                var align = this.Get('chart.yaxispos') == 'left' ? 'left' : 'right';
1589                var boxed = true;
1590            } else {
1591                var xpos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - 5 : this.canvas.width - this.gutterRight + 5;
1592                var boxed = false;
1593            }
1594           
1595            /**
1596            * Draw specific Y labels here so that the local variables can be reused
1597            */
1598            if (typeof(this.Get('chart.ylabels.specific')) == 'object' && this.Get('chart.ylabels.specific')) {
1599               
1600                var labels = RGraph.array_reverse(this.Get('chart.ylabels.specific'));
1601                var grapharea = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom;
1602
1603                for (var i=0; i<labels.length; ++i) {
1604                   
1605                    var y = this.gutterTop + (grapharea * (i / labels.length)) + (grapharea / labels.length);
1606                   
1607                    RGraph.Text(context, font, text_size, xpos, y, labels[i], 'center', align, boxed);
1608                }
1609
1610                return;
1611            }
1612
1613            // 1(ish) label
1614            if (numYLabels == 3 || numYLabels == 5) {
1615                RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight + interval, '-' + RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, boxed);
1616   
1617                // 5 labels
1618                if (numYLabels == 5) {
1619                    RGraph.Text(context, font, text_size, xpos, (1*interval) + this.gutterTop + this.halfTextHeight + interval, '-' + RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, boxed);
1620                    RGraph.Text(context, font, text_size, xpos, (3*interval) + this.gutterTop + this.halfTextHeight + interval, '-' + RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, boxed);
1621                }
1622               
1623                // 3 labels
1624                if (numYLabels == 3 || numYLabels == 5) {
1625                    RGraph.Text(context, font, text_size, xpos, (2*interval) + this.gutterTop + this.halfTextHeight + interval, '-' + RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, boxed);
1626                    RGraph.Text(context, font, text_size, xpos, (4*interval) + this.gutterTop + this.halfTextHeight + interval, '-' + RGraph.number_format(this, this.scale[4], units_pre, units_post), null, align, boxed);
1627                }
1628            }
1629           
1630            // 10 Y labels
1631            if (numYLabels == 10) {
1632
1633                interval = (this.grapharea / numYLabels );
1634
1635                for (var i=10; i>0; --i) {
1636                    RGraph.Text(context, font, text_size, xpos,this.gutterTop + ((this.grapharea / numYLabels) * i),'-' + RGraph.number_format(this,((this.scale[4] / numYLabels) * i).toFixed((this.Get('chart.scale.decimals'))), units_pre, units_post), 'center', align, boxed);
1637                }
1638            }
1639        }
1640       
1641        this.context.fill();
1642        this.context.stroke();
1643    }
1644
1645    /**
1646    * Draws the X axis in the middle
1647    */
1648    RGraph.Bar.prototype.Drawlabels_center = function ()
1649    {
1650        var font       = this.Get('chart.text.font');
1651        var numYLabels = this.Get('chart.ylabels.count');
1652
1653        this.context.fillStyle = this.Get('chart.text.color');
1654
1655        if (this.Get('chart.xaxispos') == 'center') {
1656
1657            /**
1658            * Draw the top labels
1659            */
1660            var interval   = (this.grapharea * (1/10) );
1661            var text_size  = this.Get('chart.text.size');
1662            var units_pre  = this.Get('chart.units.pre');
1663            var units_post = this.Get('chart.units.post');
1664            var context = this.context;
1665            var align   = '';
1666            var xpos    = 0;
1667            var boxed   = false;
1668
1669            this.context.fillStyle = this.Get('chart.text.color');
1670            this.context.strokeStyle = 'black';
1671
1672            if (this.Get('chart.ylabels.inside') == true) {
1673                var xpos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft + 5 : RGraph.GetWidth(this) - this.gutterRight - 5;
1674                var align = this.Get('chart.yaxispos') == 'left' ? 'left' : 'right';
1675                var boxed = true;
1676            } else {
1677                var xpos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - 5 : RGraph.GetWidth(this) - this.gutterRight + 5;
1678                var align = this.Get('chart.yaxispos') == 'left' ? 'right' : 'left';
1679                var boxed = false;
1680            }
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693            /**
1694            * Draw specific Y labels here so that the local variables can be reused
1695            */
1696            if (typeof(this.Get('chart.ylabels.specific')) == 'object' && this.Get('chart.ylabels.specific')) {
1697
1698                var labels = this.Get('chart.ylabels.specific');
1699                var grapharea = this.canvas.height - this.gutterTop - this.gutterBottom;
1700
1701                // Draw the top halves labels
1702                for (var i=0; i<labels.length; ++i) {
1703
1704                    var y = this.gutterTop + ((grapharea / 2) / labels.length) * i;
1705                   
1706                    RGraph.Text(context, font, text_size, xpos, y, String(labels[i]), 'center', align, boxed);
1707                }
1708
1709                // Draw the bottom halves labels
1710                for (var i=labels.length-1; i>=0; --i) {
1711                    var y = this.gutterTop  + (grapharea * ( (i+1) / (labels.length * 2) )) + (grapharea / 2);
1712
1713                    RGraph.Text(context, font, text_size, xpos, y, labels[labels.length - i - 1], 'center', align, boxed);
1714                }
1715
1716                return;
1717            }
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730            if (numYLabels == 3 || numYLabels == 5) {
1731                RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[4], units_pre, units_post), null, align, boxed);
1732   
1733                if (numYLabels == 5) {
1734                    RGraph.Text(context, font, text_size, xpos, (1*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, boxed);
1735                    RGraph.Text(context, font, text_size, xpos, (3*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, boxed);
1736                }
1737               
1738                if (numYLabels == 3 || numYLabels == 5) {
1739                    RGraph.Text(context, font, text_size, xpos, (4*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, boxed);
1740                    RGraph.Text(context, font, text_size, xpos, (2*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, boxed);
1741                }
1742            } else if (numYLabels == 10) {
1743                // 10Y labels
1744                interval = (this.grapharea / numYLabels) / 2;
1745           
1746                for (var i=0; i<numYLabels; ++i) {
1747                    RGraph.Text(context, font, text_size, xpos,this.gutterTop + ((this.grapharea / (numYLabels * 2)) * i),RGraph.number_format(this, ((this.scale[4] / numYLabels) * (numYLabels - i)).toFixed((this.Get('chart.scale.decimals'))), units_pre, units_post), 'center', align, boxed);
1748                }
1749            }
1750            ///////////////////////////////////////////////////////////////////////////////////
1751
1752            /**
1753            * Draw the bottom (X axis) labels
1754            */
1755            var interval = (this.grapharea) / 10;
1756
1757            if (numYLabels == 3 || numYLabels == 5) {
1758                if (numYLabels == 3 || numYLabels == 5) {
1759                    RGraph.Text(context, font, text_size, xpos, (this.grapharea + this.gutterTop + this.halfTextHeight) - (4 * interval), '-' + RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, boxed);
1760                    RGraph.Text(context, font, text_size, xpos, (this.grapharea + this.gutterTop + this.halfTextHeight) - (2 * interval), '-' + RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, boxed);
1761                }
1762   
1763                if (numYLabels == 5) {
1764                    RGraph.Text(context, font, text_size, xpos, (this.grapharea + this.gutterTop + this.halfTextHeight) - (3 * interval), '-' + RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, boxed);
1765                    RGraph.Text(context, font, text_size, xpos, (this.grapharea + this.gutterTop + this.halfTextHeight) - interval, '-' + RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, boxed);
1766                }
1767   
1768                RGraph.Text(context, font, text_size, xpos,  this.grapharea + this.gutterTop + this.halfTextHeight, '-' + RGraph.number_format(this, this.scale[4], units_pre, units_post), null, align, boxed);
1769
1770            } else if (numYLabels == 10) {
1771
1772                // Arbitrary number of Y labels
1773                interval = (this.grapharea / numYLabels) / 2;
1774           
1775                for (var i=0; i<numYLabels; ++i) {
1776                    RGraph.Text(context, font, text_size, xpos,this.gutterTop + (this.grapharea / 2) + ((this.grapharea / (numYLabels * 2)) * i) + (this.grapharea / (numYLabels * 2)),RGraph.number_format(this, ((this.scale[4] / numYLabels) * (i+1)).toFixed((this.Get('chart.scale.decimals'))), '-' + units_pre, units_post),'center', align, boxed);
1777                }
1778            }
1779
1780
1781
1782        }
1783    }
1784
1785    /**
1786    * Draws the X axdis at the bottom (the default)
1787    */
1788    RGraph.Bar.prototype.Drawlabels_bottom = function ()
1789    {
1790        this.context.beginPath();
1791        this.context.fillStyle = this.Get('chart.text.color');
1792        this.context.strokeStyle = 'black';
1793
1794        if (this.Get('chart.xaxispos') != 'center' && this.Get('chart.xaxispos') != 'top') {
1795           
1796            var interval   = (this.grapharea * (1/5) );
1797            var text_size  = this.Get('chart.text.size');
1798            var units_pre  = this.Get('chart.units.pre');
1799            var units_post = this.Get('chart.units.post');
1800            var context    = this.context;
1801            var align      = this.Get('chart.yaxispos') == 'left' ? 'right' : 'left';
1802            var font       = this.Get('chart.text.font');
1803            var numYLabels = this.Get('chart.ylabels.count');
1804
1805            if (this.Get('chart.ylabels.inside') == true) {
1806                var xpos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft + 5 : RGraph.GetWidth(this) - this.gutterRight - 5;
1807                var align = this.Get('chart.yaxispos') == 'left' ? 'left' : 'right';
1808                var boxed = true;
1809            } else {
1810                var xpos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - 5 : RGraph.GetWidth(this) - this.gutterRight + 5;
1811                var boxed = false;
1812            }
1813           
1814            /**
1815            * Draw specific Y labels here so that the local variables can be reused
1816            */
1817            if (this.Get('chart.ylabels.specific') && typeof(this.Get('chart.ylabels.specific')) == 'object') {
1818               
1819                var labels = this.Get('chart.ylabels.specific');
1820                var grapharea = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom;
1821
1822                for (var i=0; i<labels.length; ++i) {
1823                    var y = this.gutterTop + (grapharea * (i / labels.length));
1824                   
1825                    RGraph.Text(context, font, text_size, xpos, y, labels[i], 'center', align, boxed);
1826                }
1827
1828                return;
1829            }
1830
1831            // 1 label
1832            if (numYLabels == 3 || numYLabels == 5) {
1833                RGraph.Text(context, font, text_size, xpos, this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[4], units_pre, units_post), null, align, boxed);
1834   
1835                // 5 labels
1836                if (numYLabels == 5) {
1837                    RGraph.Text(context, font, text_size, xpos, (1*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[3], units_pre, units_post), null, align, boxed);
1838                    RGraph.Text(context, font, text_size, xpos, (3*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[1], units_pre, units_post), null, align, boxed);
1839                }
1840               
1841                // 3 labels
1842                if (numYLabels == 3 || numYLabels == 5) {
1843                    RGraph.Text(context, font, text_size, xpos, (2*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[2], units_pre, units_post), null, align, boxed);
1844                    RGraph.Text(context, font, text_size, xpos, (4*interval) + this.gutterTop + this.halfTextHeight, RGraph.number_format(this, this.scale[0], units_pre, units_post), null, align, boxed);
1845                }
1846            }
1847           
1848            // 10 Y labels
1849            if (numYLabels == 10) {
1850
1851                interval   = (this.grapharea / numYLabels );
1852
1853                for (var i=0; i<numYLabels; ++i) {
1854                    RGraph.Text(context, font, text_size, xpos, this.gutterTop + ((this.grapharea / numYLabels) * i), RGraph.number_format(this,((this.scale[4] / numYLabels) * (numYLabels - i)).toFixed((this.Get('chart.scale.decimals'))), units_pre, units_post), 'center', align, boxed);
1855                }
1856            }
1857        }
1858       
1859        this.context.fill();
1860        this.context.stroke();
1861    }
1862
1863
1864    /**
1865    * This function is used by MSIE only to manually draw the shadow
1866    *
1867    * @param array coords The coords for the bar
1868    */
1869    RGraph.Bar.prototype.DrawIEShadow = function (coords)
1870    {
1871        var prevFillStyle = this.context.fillStyle;
1872        var offsetx       = this.Get('chart.shadow.offsetx');
1873        var offsety       = this.Get('chart.shadow.offsety');
1874       
1875        this.context.lineWidth = this.Get('chart.linewidth');
1876        this.context.fillStyle = this.Get('chart.shadow.color');
1877        this.context.beginPath();
1878       
1879        // Draw shadow here
1880        this.context.fillRect(coords[0] + offsetx, coords[1] + offsety, coords[2], coords[3]);
1881
1882        this.context.fill();
1883       
1884        // Change the fillstyle back to what it was
1885        this.context.fillStyle = prevFillStyle;
1886    }
1887
1888
1889    /**
1890    * Not used by the class during creating the graph, but is used by event handlers
1891    * to get the coordinates (if any) of the selected bar
1892    */
1893    RGraph.Bar.prototype.getBar = function (e)
1894    {
1895        var canvas      = e.target;
1896        var obj         = e.target.__object__;
1897        var mouseCoords = RGraph.getMouseXY(e);
1898
1899        /**
1900        * Loop through the bars determining if the mouse is over a bar
1901        */
1902        for (var i=0; i<obj.coords.length; i++) {
1903
1904            var mouseX = mouseCoords[0];
1905            var mouseY = mouseCoords[1];
1906
1907            var left   = obj.coords[i][0];
1908            var top    = obj.coords[i][1];
1909            var width  = obj.coords[i][2];
1910            var height = obj.coords[i][3];
1911
1912            if (   mouseX >= left
1913                && mouseX <= left + width
1914                && mouseY >= top
1915                && mouseY <= top + height) {
1916               
1917                return [obj, left, top, width, height, i];
1918            }
1919        }
1920       
1921        return null;
1922    }
Note: See TracBrowser for help on using the repository browser.