source: Dev/branches/rest-dojo-ui/jQueryUI/client/RGraph/libraries/RGraph.scatter.js @ 312

Last change on this file since 312 was 312, checked in by jkraaijeveld, 13 years ago
File size: 57.8 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 scatter graph constructor
19    *
20    * @param object canvas The cxanvas object
21    * @param array  data   The chart data
22    */
23    RGraph.Scatter = function (id, data)
24    {
25        // Get the canvas and context objects
26        this.id                = id;
27        this.canvas            = document.getElementById(id);
28        this.canvas.__object__ = this;
29        this.context           = this.canvas.getContext ? this.canvas.getContext("2d") : null;
30        this.max               = 0;
31        this.coords            = [];
32        this.data              = [];
33        this.type              = 'scatter';
34        this.isRGraph          = true;
35
36
37        /**
38        * Compatibility with older browsers
39        */
40        RGraph.OldBrowserCompat(this.context);
41
42
43        // Various config properties
44        this.properties = {
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.width':  1,
49            'chart.background.grid.color':  '#ddd',
50            'chart.background.grid.hsize':  20,
51            'chart.background.grid.vsize':  20,
52            'chart.background.hbars':       null,
53            'chart.background.vbars':       null,
54            'chart.background.grid.vlines': true,
55            'chart.background.grid.hlines': true,
56            'chart.background.grid.border': true,
57            'chart.background.grid.autofit':false,
58            'chart.background.grid.autofit.numhlines': 7,
59            'chart.background.grid.autofit.numvlines': 20,
60            'chart.text.size':              10,
61            'chart.text.angle':             0,
62            'chart.text.color':             'black',
63            'chart.text.font':              'Verdana',
64            'chart.tooltips.effect':         'fade',
65            'chart.tooltips.hotspot':        3,
66            'chart.tooltips.css.class':      'RGraph_tooltip',
67            'chart.tooltips.highlight':      true,
68            'chart.tooltips.coords.adjust':  [0,0],
69            'chart.units.pre':              '',
70            'chart.units.post':             '',
71            'chart.tickmarks':              'cross',
72            'chart.ticksize':               5,
73            'chart.xticks':                 true,
74            'chart.xaxis':                  true,
75            'chart.gutter.left':            25,
76            'chart.gutter.right':           25,
77            'chart.gutter.top':             25,
78            'chart.gutter.bottom':          25,
79            'chart.xmax':                   0,
80            'chart.ymax':                   null,
81            'chart.ymin':                   null,
82            'chart.scale.decimals':         null,
83            'chart.scale.point':            '.',
84            'chart.scale.thousand':         ',',
85            'chart.title':                  '',
86            'chart.title.background':       null,
87            'chart.title.hpos':             null,
88            'chart.title.vpos':             null,
89            'chart.title.xaxis':            '',
90            'chart.title.yaxis':            '',
91            'chart.title.xaxis.pos':        0.25,
92            'chart.title.yaxis.pos':        0.25,
93            'chart.labels':                 [],
94            'chart.labels.ingraph':         null,
95            'chart.labels.above':           false,
96            'chart.labels.above.size':      8,
97            'chart.labels.above.decimals':  0,
98            'chart.ylabels':                true,
99            'chart.ylabels.count':          5,
100            'chart.ylabels.invert':         false,
101            'chart.contextmenu':            null,
102            'chart.defaultcolor':           'black',
103            'chart.xaxispos':               'bottom',
104            'chart.yaxispos':               'left',
105            'chart.noendxtick':             false,
106            'chart.crosshairs':             false,
107            'chart.crosshairs.color':       '#333',
108            'chart.crosshairs.linewidth':   1,
109            'chart.crosshairs.coords':      false,
110            'chart.crosshairs.coords.fixed':true,
111            'chart.crosshairs.coords.fadeout':false,
112            'chart.crosshairs.coords.labels.x': 'X',
113            'chart.crosshairs.coords.labels.y': 'Y',
114            'chart.annotatable':            false,
115            'chart.annotate.color':         'black',
116            'chart.line':                   false,
117            'chart.line.linewidth':         1,
118            'chart.line.colors':            ['green', 'red'],
119            'chart.line.shadow.color':      'rgba(0,0,0,0)',
120            'chart.line.shadow.blur':       2,
121            'chart.line.shadow.offsetx':    3,
122            'chart.line.shadow.offsety':    3,
123            'chart.line.stepped':           false,
124            'chart.noaxes':                 false,
125            'chart.key':                    [],
126            'chart.key.background':         'white',
127            'chart.key.position':           'graph',
128            'chart.key.halign':             'right',
129            'chart.key.shadow':             false,
130            'chart.key.shadow.color':       '#666',
131            'chart.key.shadow.blur':        3,
132            'chart.key.shadow.offsetx':     2,
133            'chart.key.shadow.offsety':     2,
134            'chart.key.position.gutter.boxed': true,
135            'chart.key.position.x':         null,
136            'chart.key.position.y':         null,
137            'chart.key.color.shape':        'square',
138            'chart.key.rounded':            true,
139            'chart.key.linewidth':          1,
140            'chart.axis.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.zoom.action':            'zoom',
154            'chart.boxplot.width':          8,
155            'chart.resizable':              false,
156            'chart.resize.handle.adjust':   [0,0],
157            'chart.resize.handle.background': null,
158            'chart.xmin':                   0,
159            'chart.labels.specific.align':  'left'
160        }
161
162        // Handle multiple datasets being given as one argument
163        if (arguments[1][0] && arguments[1][0][0] && typeof(arguments[1][0][0][0]) == 'number') {
164            // Store the data set(s)
165            for (var i=0; i<arguments[1].length; ++i) {
166                this.data[i] = arguments[1][i];
167            }
168
169        // Handle multiple data sets being supplied as seperate arguments
170        } else {
171            // Store the data set(s)
172            for (var i=1; i<arguments.length; ++i) {
173                this.data[i - 1] = arguments[i];
174            }
175        }
176
177        // Check for support
178        if (!this.canvas) {
179            alert('[SCATTER] No canvas support');
180            return;
181        }
182
183
184        /**
185        * Set the .getShape commonly named method
186        */
187        this.getShape = this.getPoint;
188    }
189
190
191    /**
192    * A simple setter
193    *
194    * @param string name  The name of the property to set
195    * @param string value The value of the property
196    */
197    RGraph.Scatter.prototype.Set = function (name, value)
198    {
199        /**
200        * This is here because the key expects a name of "chart.colors"
201        */
202        if (name == 'chart.line.colors') {
203            this.properties['chart.colors'] = value;
204        }
205       
206        /**
207        * Allow compatibility with older property names
208        */
209        if (name == 'chart.tooltip.hotspot') {
210            name = 'chart.tooltips.hotspot';
211        }
212       
213        /**
214        * chart.yaxispos should be left or right
215        */
216        if (name == 'chart.yaxispos' && value != 'left' && value != 'right') {
217            alert("[SCATTER] chart.yaxispos should be left or right. You've set it to: '" + value + "' Changing it to left");
218            value = 'left';
219        }
220       
221        /**
222        * Check for xaxispos
223        */
224        if (name == 'chart.xaxispos' ) {
225            if (value != 'bottom' && value != 'center') {
226                alert('[SCATTER] (' + this.id + ') chart.xaxispos should be center or bottom. Tried to set it to: ' + value + ' Changing it to center');
227                value = 'center';
228            }
229        }
230
231        this.properties[name.toLowerCase()] = value;
232    }
233
234
235    /**
236    * A simple getter
237    *
238    * @param string name  The name of the property to set
239    */
240    RGraph.Scatter.prototype.Get = function (name)
241    {
242        return this.properties[name];
243    }
244
245
246    /**
247    * The function you call to draw the line chart
248    */
249    RGraph.Scatter.prototype.Draw = function ()
250    {
251        // MUST be the first thing done!
252        if (typeof(this.Get('chart.background.image')) == 'string' && !this.__background_image__) {
253            RGraph.DrawBackgroundImage(this);
254            return;
255        }
256
257        /**
258        * Fire the onbeforedraw event
259        */
260        RGraph.FireCustomEvent(this, 'onbeforedraw');
261
262        /**
263        * Clear all of this canvases event handlers (the ones installed by RGraph)
264        */
265        RGraph.ClearEventListeners(this.id);
266       
267        /**
268        * This is new in May 2011 and facilitates indiviual gutter settings,
269        * eg chart.gutter.left
270        */
271        this.gutterLeft   = this.Get('chart.gutter.left');
272        this.gutterRight  = this.Get('chart.gutter.right');
273        this.gutterTop    = this.Get('chart.gutter.top');
274        this.gutterBottom = this.Get('chart.gutter.bottom');
275
276        // Go through all the data points and see if a tooltip has been given
277        this.Set('chart.tooltips', false);
278        this.hasTooltips = false;
279        var overHotspot  = false;
280
281        // Reset the coords array
282        this.coords = [];
283
284        if (!RGraph.isIE8()) {
285            for (var i=0; i<this.data.length; ++i) {
286                for (var j =0;j<this.data[i].length; ++j) {
287                    if (this.data[i][j] && this.data[i][j][3] && typeof(this.data[i][j][3]) == 'string' && this.data[i][j][3].length) {
288                        this.Set('chart.tooltips', [1]); // An array
289                        this.hasTooltips = true;
290                    }
291                }
292            }
293        }
294
295        // Reset the maximum value
296        this.max = 0;
297
298        // Work out the maximum Y value
299        if (this.Get('chart.ymax') && this.Get('chart.ymax') > 0) {
300
301            this.scale = [];
302            this.max   = this.Get('chart.ymax');
303            this.min   = this.Get('chart.ymin') ? this.Get('chart.ymin') : 0;
304
305            this.scale[0] = ((this.max - this.min) * (1/5)) + this.min;
306            this.scale[1] = ((this.max - this.min) * (2/5)) + this.min;
307            this.scale[2] = ((this.max - this.min) * (3/5)) + this.min;
308            this.scale[3] = ((this.max - this.min) * (4/5)) + this.min;
309            this.scale[4] = ((this.max - this.min) * (5/5)) + this.min;
310
311            var decimals = this.Get('chart.scale.decimals');
312
313            this.scale = [
314                          Number(this.scale[0]).toFixed(decimals),
315                          Number(this.scale[1]).toFixed(decimals),
316                          Number(this.scale[2]).toFixed(decimals),
317                          Number(this.scale[3]).toFixed(decimals),
318                          Number(this.scale[4]).toFixed(decimals)
319                         ];
320
321        } else {
322
323            var i = 0;
324            var j = 0;
325
326            for (i=0; i<this.data.length; ++i) {
327                for (j=0; j<this.data[i].length; ++j) {
328                    this.max = Math.max(this.max, typeof(this.data[i][j][1]) == 'object' ? RGraph.array_max(this.data[i][j][1]) : Math.abs(this.data[i][j][1]));
329                }
330            }
331
332            this.scale = RGraph.getScale(this.max, this);
333
334            this.max   = this.scale[4];
335            this.min   = this.Get('chart.ymin') ? this.Get('chart.ymin') : 0;
336
337            if (this.min) {
338                this.scale[0] = ((this.max - this.min) * (1/5)) + this.min;
339                this.scale[1] = ((this.max - this.min) * (2/5)) + this.min;
340                this.scale[2] = ((this.max - this.min) * (3/5)) + this.min;
341                this.scale[3] = ((this.max - this.min) * (4/5)) + this.min;
342                this.scale[4] = ((this.max - this.min) * (5/5)) + this.min;
343            }
344
345
346            if (typeof(this.Get('chart.scale.decimals')) == 'number') {
347                var decimals = this.Get('chart.scale.decimals');
348   
349                this.scale = [
350                              Number(this.scale[0]).toFixed(decimals),
351                              Number(this.scale[1]).toFixed(decimals),
352                              Number(this.scale[2]).toFixed(decimals),
353                              Number(this.scale[3]).toFixed(decimals),
354                              Number(this.scale[4]).toFixed(decimals)
355                             ];
356            }
357        }
358
359        this.grapharea = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom;
360
361        // Progressively Draw the chart
362        RGraph.background.Draw(this);
363
364        /**
365        * Draw any horizontal bars that have been specified
366        */
367        if (this.Get('chart.background.hbars') && this.Get('chart.background.hbars').length) {
368            RGraph.DrawBars(this);
369        }
370
371        /**
372        * Draw any vertical bars that have been specified
373        */
374        if (this.Get('chart.background.vbars') && this.Get('chart.background.vbars').length) {
375            this.DrawVBars();
376        }
377
378        if (!this.Get('chart.noaxes')) {
379            this.DrawAxes();
380        }
381
382        this.DrawLabels();
383
384        i = 0;
385        for(i=0; i<this.data.length; ++i) {
386            this.DrawMarks(i);
387
388            // Set the shadow
389            this.context.shadowColor   = this.Get('chart.line.shadow.color');
390            this.context.shadowOffsetX = this.Get('chart.line.shadow.offsetx');
391            this.context.shadowOffsetY = this.Get('chart.line.shadow.offsety');
392            this.context.shadowBlur    = this.Get('chart.line.shadow.blur');
393           
394            this.DrawLine(i);
395
396            // Turn the shadow off
397            RGraph.NoShadow(this);
398        }
399
400
401        if (this.Get('chart.line')) {
402            for (var i=0;i<this.data.length; ++i) {
403                this.DrawMarks(i); // Call this again so the tickmarks appear over the line
404            }
405        }
406
407
408
409        /**
410        * Setup the context menu if required
411        */
412        if (this.Get('chart.contextmenu')) {
413            RGraph.ShowContext(this);
414        }
415
416        /**
417        * Install the event handler for tooltips
418        */
419        if (this.hasTooltips) {
420
421            /**
422            * Register all charts
423            */
424            RGraph.Register(this);
425
426            var overHotspot = false;
427
428            var canvas_onmousemove_func = function (e)
429            {
430                e = RGraph.FixEventObject(e);
431
432                var canvas      = e.target;
433                var obj         = canvas.__object__;
434                var context     = obj.context;
435                var mouseCoords = RGraph.getMouseXY(e);
436                var point       = obj.getPoint(e);
437                var overHotspot = false;
438
439                if (point) {
440
441                    var __dataset__ = point[2];
442                    var __index__   = point[3];
443                    var __text__    = point[4];
444                    var overHotspot = true;
445
446                    if (point[4]) {
447                        canvas.style.cursor = 'pointer';
448
449                        if (
450                            !RGraph.Registry.Get('chart.tooltip') ||
451                            RGraph.Registry.Get('chart.tooltip').__text__ != __text__ ||
452                            RGraph.Registry.Get('chart.tooltip').__index__ != __index__ ||
453                            RGraph.Registry.Get('chart.tooltip').__dataset__ != __dataset__
454                           ) {
455
456                            if (obj.Get('chart.tooltips.highlight')) {
457                                RGraph.Redraw();
458                            }
459   
460                            /**
461                            * Get the tooltip text
462                            */
463                            if (typeof(__text__) == 'function') {
464                                var text = String(__text__(i));
465   
466                            } else {
467                                var text = String(__text__);
468                            }
469   
470                            RGraph.Tooltip(canvas, text, e.pageX, e.pageY, __index__);
471                           
472                            RGraph.Registry.Get('chart.tooltip').__index__ = __index__;
473                           
474                            if (RGraph.Registry.Get('chart.tooltip')) {
475                                RGraph.Registry.Get('chart.tooltip').__dataset__ = __dataset__;
476                            }
477                                   
478                            /**
479                            * Draw a circle around the mark
480                            */
481                            if (obj.Get('chart.tooltips.highlight')) {
482                                context.beginPath();
483                                context.fillStyle = 'rgba(255,255,255,0.5)';
484                                context.arc(point[0], point[1], 3, 0, 6.28, 0);
485                                context.fill();
486                            }
487                        }
488                    }
489                }
490
491                /**
492                * Reset the pointer
493                */
494                if (!overHotspot || !point[4]) {
495                    canvas.style.cursor = 'default';
496                }
497            }
498            this.canvas.addEventListener('mousemove', canvas_onmousemove_func, false);
499            RGraph.AddEventListener(this.id, 'mousemove', canvas_onmousemove_func);
500        }
501       
502       
503        /**
504        * Draw the key if necessary
505        */
506        if (this.Get('chart.key') && this.Get('chart.key').length) {
507            RGraph.DrawKey(this, this.Get('chart.key'), this.Get('chart.line.colors'));
508        }
509
510
511        /**
512        * Draw " above" labels if enabled
513        */
514        if (this.Get('chart.labels.above')) {
515            this.DrawAboveLabels();
516        }
517
518        /**
519        * Draw the "in graph" labels, using the member function, NOT the shared function in RGraph.common.core.js
520        */
521        this.DrawInGraphLabels(this);
522
523
524        /**
525        * Draw crosschairs
526        */
527        RGraph.DrawCrosshairs(this);
528
529       
530        /**
531        * If the canvas is annotatable, do install the event handlers
532        */
533        if (this.Get('chart.annotatable')) {
534            RGraph.Annotate(this);
535        }
536       
537        /**
538        * This bit shows the mini zoom window if requested
539        */
540        if (this.Get('chart.zoom.mode') == 'thumbnail' || this.Get('chart.zoom.mode') == 'area') {
541            RGraph.ShowZoomWindow(this);
542        }
543
544       
545        /**
546        * This function enables resizing
547        */
548        if (this.Get('chart.resizable')) {
549            RGraph.AllowResizing(this);
550        }
551       
552        /**
553        * Fire the RGraph ondraw event
554        */
555        RGraph.FireCustomEvent(this, 'ondraw');
556    }
557
558
559    /**
560    * Draws the axes of the scatter graph
561    */
562    RGraph.Scatter.prototype.DrawAxes = function ()
563    {
564        var canvas      = this.canvas;
565        var context     = this.context;
566        var graphHeight = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom;
567
568        context.beginPath();
569        context.strokeStyle = this.Get('chart.axis.color');
570        context.lineWidth   = 1;
571
572        // Draw the Y axis
573        if (this.Get('chart.yaxispos') == 'left') {
574            context.moveTo(this.gutterLeft, this.gutterTop);
575            context.lineTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom);
576        } else {
577            context.moveTo(RGraph.GetWidth(this) - this.gutterRight, this.gutterTop);
578            context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom);
579        }
580
581
582        // Draw the X axis
583        if (this.Get('chart.xaxis')) {
584            if (this.Get('chart.xaxispos') == 'center') {
585                context.moveTo(this.gutterLeft, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / 2));
586                context.lineTo(RGraph.GetWidth(this) - this.gutterRight, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / 2));
587            } else {
588                context.moveTo(this.gutterLeft, RGraph.GetHeight(this) - this.gutterBottom);
589                context.lineTo(RGraph.GetWidth(this) - this.gutterRight, RGraph.GetHeight(this) - this.gutterBottom);
590            }
591        }
592
593        /**
594        * Draw the Y tickmarks
595        */
596        for (y=this.gutterTop; y < RGraph.GetHeight(this) - this.gutterBottom + (this.Get('chart.xaxispos') == 'center' ? 1 : 0) ; y+=(graphHeight / 5) / 2) {
597
598            // This is here to accomodate the X axis being at the center
599            if (y == (this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / 2)) ) continue;
600
601            if (this.Get('chart.yaxispos') == 'left') {
602                context.moveTo(this.gutterLeft, y);
603                context.lineTo(this.gutterLeft - 3, y);
604            } else {
605                context.moveTo(RGraph.GetWidth(this) - this.gutterRight +3, y);
606                context.lineTo(RGraph.GetWidth(this) - this.gutterRight, y);
607            }
608        }
609
610
611        /**
612        * Draw the X tickmarks
613        */
614        if (this.Get('chart.xticks') && this.Get('chart.xaxis')) {
615
616            var x  = 0;
617            var y  =  (this.Get('chart.xaxispos') == 'center') ? this.gutterTop + (this.grapharea / 2): (this.canvas.height - this.gutterBottom);
618            this.xTickGap = (this.Get('chart.labels') && this.Get('chart.labels').length) ? ((this.canvas.width - this.gutterLeft - this.gutterRight ) / this.Get('chart.labels').length) : (this.canvas.width - this.gutterLeft - this.gutterRight) / 10;
619
620            for (x =  (this.gutterLeft + (this.Get('chart.yaxispos') == 'left' ? this.xTickGap : 0) );
621                 x <= (this.canvas.width - this.gutterRight - (this.Get('chart.yaxispos') == 'left' ? 0 : 1));
622                 x += this.xTickGap) {
623
624                if (this.Get('chart.yaxispos') == 'left' && this.Get('chart.noendxtick') == true && x == (RGraph.GetWidth(this) - this.gutterLeft) ) {
625                    continue;
626                } else if (this.Get('chart.yaxispos') == 'right' && this.Get('chart.noendxtick') == true && x == this.gutterLeft) {
627                    continue;
628                }
629
630                context.moveTo(x, y - (this.Get('chart.xaxispos') == 'center' ? 3 : 0));
631                context.lineTo(x, y + 3);
632            }
633        }
634
635        context.stroke();
636    }
637
638
639
640
641
642
643
644
645
646
647
648    /**
649    * Draws the labels on the scatter graph
650    */
651    RGraph.Scatter.prototype.DrawLabels = function ()
652    {
653        this.context.fillStyle = this.Get('chart.text.color');
654        var font       = this.Get('chart.text.font');
655        var xMin       = this.Get('chart.xmin');
656        var xMax       = this.Get('chart.xmax');
657        var yMax       = this.scale[4];
658        var yMin       = this.Get('chart.ymin');
659        var text_size  = this.Get('chart.text.size');
660        var units_pre  = this.Get('chart.units.pre');
661        var units_post = this.Get('chart.units.post');
662        var numYLabels = this.Get('chart.ylabels.count');
663        var invert     = this.Get('chart.ylabels.invert');
664        var context    = this.context;
665        var canvas     = this.canvas;
666
667        this.halfTextHeight = text_size / 2;
668
669           
670        this.halfGraphHeight = (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) / 2;
671
672        /**
673        * Draw the Y yaxis labels, be it at the top or center
674        */
675        if (this.Get('chart.ylabels')) {
676
677            var xPos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - 5 : RGraph.GetWidth(this) - this.gutterRight + 5;
678            var align = this.Get('chart.yaxispos') == 'right' ? 'left' : 'right';
679
680            if (this.Get('chart.xaxispos') == 'center') {
681
682
683                /**
684                * Specific Y labels
685                */
686                if (typeof(this.Get('chart.ylabels.specific')) == 'object') {
687               
688                    var labels = this.Get('chart.ylabels.specific');
689               
690                    for (var i=0; i<this.Get('chart.ylabels.specific').length; ++i) {
691                        var y = this.gutterTop + (i * (this.grapharea / (labels.length * 2) ) );
692                        RGraph.Text(context, font, text_size, xPos, y, labels[i], 'center', align);
693                    }
694                   
695                    var reversed_labels = RGraph.array_reverse(labels);
696               
697                    for (var i=0; i<reversed_labels.length; ++i) {
698                        var y = this.gutterTop + (this.grapharea / 2) + ((i+1) * (this.grapharea / (labels.length * 2) ) );
699                       
700                        RGraph.Text(context, font, text_size, xPos, y, reversed_labels[i], 'center', align);
701                    }
702               
703                    return;
704                }
705
706
707                if (numYLabels == 1 || numYLabels == 3 || numYLabels == 5) {
708                    // Draw the top halves labels
709                    RGraph.Text(context, font, text_size, xPos, this.gutterTop, RGraph.number_format(this, this.scale[4], units_pre, units_post), 'center', align);
710                   
711                   
712                    if (numYLabels >= 5) {
713                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (1/10) ), RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', align);
714                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (3/10) ), RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', align);
715                    }
716       
717                    if (numYLabels >= 3) {
718                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (2/10) ), RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', align);
719                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (4/10) ), RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', align);
720                    }
721                   
722                    // Draw the bottom halves labels
723                    if (numYLabels >= 3) {
724                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (1/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', align);
725                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (3/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', align);
726                    }
727       
728                    if (numYLabels == 5) {
729                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (2/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', align);
730                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (4/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', align);
731                    }
732       
733                    RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (5/10) ) + this.halfGraphHeight, '-' + RGraph.number_format(this, this.scale[4], units_pre, units_post), 'center', align);
734               
735                } else if (numYLabels == 10) {
736                    // 10 Y labels
737                    var interval = (this.grapharea / numYLabels) / 2;
738               
739                    for (var i=0; i<numYLabels; ++i) {
740                        RGraph.Text(context, font, text_size, xPos,this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (i/20) ),RGraph.number_format(this,
741                       
742                        (this.max - (this.max * (i/10))).toFixed(this.Get('chart.scale.decimals')),
743                       
744                        units_pre, units_post),'center', align);
745                        RGraph.Text(context, font, text_size, xPos,this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (i/20) ) + (this.grapharea / 2) + (this.grapharea / 20),'-' + RGraph.number_format(this, ((this.max * (i/10)) + (this.max * (1/10))).toFixed((this.Get('chart.scale.decimals'))), units_pre, units_post), 'center', align);
746                    }
747
748                } else {
749                    alert('[SCATTER SCALE] Number of Y labels can be 1/3/5/10 only');
750                }
751   
752            } else {
753               
754                var xPos  = this.Get('chart.yaxispos') == 'left' ? this.gutterLeft - 5 : RGraph.GetWidth(this) - this.gutterRight + 5;
755                var align = this.Get('chart.yaxispos') == 'right' ? 'left' : 'right';
756
757                /**
758                * Specific Y labels
759                */
760                if (typeof(this.Get('chart.ylabels.specific')) == 'object' && this.Get('chart.ylabels.specific')) {
761
762                    var labels = this.Get('chart.ylabels.specific');
763
764                    for (var i=0; i<this.Get('chart.ylabels.specific').length; ++i) {
765                        var y = this.gutterTop + (i * (this.grapharea / labels.length) );
766                       
767                        RGraph.Text(context, font, text_size, xPos, y, labels[i], 'center', align);
768                    }
769
770                    return;
771                }
772
773                if (numYLabels == 1 || numYLabels == 3 || numYLabels == 5) {
774                    if (invert) {
775                        RGraph.Text(context, font, text_size, xPos, this.gutterTop, RGraph.number_format(this, 0, units_pre, units_post), 'center', align);
776                        RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (5/5) ), RGraph.number_format(this, this.scale[4], units_pre, units_post), 'center', align);
777       
778                        if (numYLabels >= 5) {
779                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (2/5) ), RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', align);
780                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (4/5) ), RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', align);
781                        }
782       
783                        if (numYLabels >= 3) {
784                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (3/5) ), RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', align);
785                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (1/5) ), RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', align);
786                        }
787                    } else {
788                        RGraph.Text(context, font, text_size, xPos, this.gutterTop, RGraph.number_format(this, this.scale[4], units_pre, units_post), 'center', align);
789       
790                        if (numYLabels >= 5) {
791                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (1/5) ), RGraph.number_format(this, this.scale[3], units_pre, units_post), 'center', align);
792                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (3/5) ), RGraph.number_format(this, this.scale[1], units_pre, units_post), 'center', align);
793                        }
794       
795                        if (numYLabels >= 3) {
796                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (2/5) ), RGraph.number_format(this, this.scale[2], units_pre, units_post), 'center', align);
797                            RGraph.Text(context, font, text_size, xPos, this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * (4/5) ), RGraph.number_format(this, this.scale[0], units_pre, units_post), 'center', align);
798                        }
799                    }
800                } else if (numYLabels == 10) {
801                    var interval = (this.grapharea / numYLabels) / 2;
802                    if (invert) {
803                        for (var i=numYLabels; i>=0; --i) {
804                            RGraph.Text(context, font, text_size, xPos,this.gutterTop + ((RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom) * ((10-i)/10) ),
805                           
806                            RGraph.number_format(this,(this.max - (this.max * (i/10))).toFixed((this.Get('chart.scale.decimals'))), units_pre, units_post),
807                           
808                            'center', align);
809                        }
810                    } else {
811                        // 10 Y labels
812                        for (var i=0; i<numYLabels; ++i) {
813
814                            RGraph.Text(context, font, text_size, xPos,this.gutterTop + ((this.canvas.height - this.gutterTop - this.gutterBottom) * (i/10) ),
815
816                            RGraph.number_format(this,
817                                                 (this.max - ((this.max - this.min) * (i/10))).toFixed((this.Get('chart.scale.decimals'))),
818                                                 units_pre,
819                                                 units_post),
820                            'center', align);
821                        }
822                    }
823                } else {
824                    alert('[SCATTER SCALE] Number of Y labels can be 1/3/5/10 only');
825                }
826               
827                if (this.Get('chart.ymin')) {
828                    RGraph.Text(context, font, text_size, xPos, this.canvas.height - this.gutterBottom,RGraph.number_format(this, this.Get('chart.ymin').toFixed(this.Get('chart.scale.decimals')), units_pre, units_post),'center', align);
829                }
830            }
831        }
832
833
834
835
836
837
838        // Put the text on the X axis
839        var graphArea = RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight;
840        var xInterval = graphArea / this.Get('chart.labels').length;
841        var xPos      = this.gutterLeft;
842        var yPos      = (RGraph.GetHeight(this) - this.gutterBottom) + 15;
843        var labels    = this.Get('chart.labels');
844
845        /**
846        * Text angle
847        */
848        var angle  = 0;
849        var valign = null;
850        var halign = 'center';
851
852        if (this.Get('chart.text.angle') > 0) {
853            angle  = -1 * this.Get('chart.text.angle');
854            valign = 'center';
855            halign = 'right';
856            yPos -= 10;
857        }
858
859        for (i=0; i<labels.length; ++i) {
860           
861            if (typeof(labels[i]) == 'object') {
862           
863                if (this.Get('chart.labels.specific.align') == 'center') {
864                    var rightEdge = 0;
865
866                    if (labels[i+1] && labels[i+1][1]) {
867                        rightEdge = labels[i+1][1];
868                    } else {
869                        rightEdge = this.Get('chart.xmax');
870                    }
871                   
872                    var offset = (rightEdge - labels[i][1]) / 2;
873
874                } else {
875                    var offset = 0;
876                }
877           
878
879                RGraph.Text(context,
880                            font,
881                            this.Get('chart.text.size'),
882                            this.gutterLeft + (graphArea * ((labels[i][1] - xMin + offset) / (this.Get('chart.xmax') - xMin))) + 5,
883                            yPos,
884                            String(labels[i][0]),
885                            valign,
886                            angle != 0 ? 'right' : (this.Get('chart.labels.specific.align') == 'center' ? 'center' : 'left'),
887                            null,
888                            angle
889                           );
890               
891                /**
892                * Draw the gray indicator line
893                */
894                this.context.beginPath();
895                    this.context.strokeStyle = '#bbb';
896                    this.context.moveTo(this.gutterLeft + (graphArea * ((labels[i][1] - xMin)/ (this.Get('chart.xmax') - xMin))), RGraph.GetHeight(this) - this.gutterBottom);
897                    this.context.lineTo(this.gutterLeft + (graphArea * ((labels[i][1] - xMin)/ (this.Get('chart.xmax') - xMin))), RGraph.GetHeight(this) - this.gutterBottom + 20);
898                this.context.stroke();
899           
900            } else {
901                RGraph.Text(context, font, this.Get('chart.text.size'), xPos + (this.xTickGap / 2), yPos, String(labels[i]), valign, halign, null, angle);
902            }
903           
904            // Do this for the next time around
905            xPos += xInterval;
906        }
907
908        /**
909        * Draw the final indicator line
910        */
911        if (typeof(labels[0]) == 'object') {
912            this.context.beginPath();
913                this.context.strokeStyle = '#bbb';
914                this.context.moveTo(this.gutterLeft + graphArea, RGraph.GetHeight(this) - this.gutterBottom);
915                this.context.lineTo(this.gutterLeft + graphArea, RGraph.GetHeight(this) - this.gutterBottom + 20);
916            this.context.stroke();
917        }
918    }
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933    /**
934    * Draws the actual scatter graph marks
935    *
936    * @param i integer The dataset index
937    */
938    RGraph.Scatter.prototype.DrawMarks = function (i)
939    {
940        /**
941        *  Reset the coords array
942        */
943        this.coords[i] = [];
944
945        /**
946        * Plot the values
947        */
948        var xmax          = this.Get('chart.xmax');
949        var default_color = this.Get('chart.defaultcolor');
950
951        for (var j=0; j<this.data[i].length; ++j) {
952            /**
953            * This is here because tooltips are optional
954            */
955            var data_point = this.data[i];
956
957            var xCoord = data_point[j][0];
958            var yCoord = data_point[j][1];
959            var color  = data_point[j][2] ? data_point[j][2] : default_color;
960            var tooltip = (data_point[j] && data_point[j][3]) ? data_point[j][3] : null;
961
962           
963            this.DrawMark(
964                          i,
965                          xCoord,
966                          yCoord,
967                          xmax,
968                          this.scale[4],
969                          color,
970                          tooltip,
971                          this.coords[i],
972                          data_point
973                         );
974        }
975    }
976
977
978    /**
979    * Draws a single scatter mark
980    */
981    RGraph.Scatter.prototype.DrawMark = function (index, x, y, xMax, yMax, color, tooltip, coords, data)
982    {
983        /**
984        * Inverted Y scale handling
985        */
986        if (this.Get('chart.ylabels.invert')) {
987            if (typeof(y) == 'number') {
988                y = yMax - y;
989            }
990        }
991
992        var tickmarks = this.Get('chart.tickmarks');
993        var tickSize  = this.Get('chart.ticksize');
994        var xMin      = this.Get('chart.xmin');
995        var x = ((x - xMin) / (xMax - xMin)) * (RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight);
996        var originalX = x;
997        var originalY = y;
998       
999       
1000        /**
1001        * This allows chart.tickmarks to be an array
1002        */
1003
1004        if (tickmarks && typeof(tickmarks) == 'object') {
1005            tickmarks = tickmarks[index];
1006        }
1007
1008
1009        /**
1010        * This allows chart.ticksize to be an array
1011        */
1012        if (typeof(tickSize) == 'object') {
1013            var tickSize     = tickSize[index];
1014            var halfTickSize = tickSize / 2;
1015        } else {
1016            var halfTickSize = tickSize / 2;
1017        }
1018
1019
1020        /**
1021        * This bit is for boxplots only
1022        */
1023        if (   typeof(y) == 'object'
1024            && typeof(y[0]) == 'number'
1025            && typeof(y[1]) == 'number'
1026            && typeof(y[2]) == 'number'
1027            && typeof(y[3]) == 'number'
1028            && typeof(y[4]) == 'number'
1029           ) {
1030
1031            var yMin = this.Get('chart.ymin') ? this.Get('chart.ymin') : 0;
1032            this.Set('chart.boxplot', true);
1033            this.graphheight = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom;
1034           
1035            if (this.Get('chart.xaxispos') == 'center') {
1036                this.graphheight /= 2;
1037            }
1038
1039            var y0 = (this.graphheight) - ((y[4] - yMin) / (yMax - yMin)) * (this.graphheight);
1040            var y1 = (this.graphheight) - ((y[3] - yMin) / (yMax - yMin)) * (this.graphheight);
1041            var y2 = (this.graphheight) - ((y[2] - yMin) / (yMax - yMin)) * (this.graphheight);
1042            var y3 = (this.graphheight) - ((y[1] - yMin) / (yMax - yMin)) * (this.graphheight);
1043            var y4 = (this.graphheight) - ((y[0] - yMin) / (yMax - yMin)) * (this.graphheight);
1044           
1045            /**
1046            * Inverted labels
1047            */
1048            if (this.Get('chart.ylabels.invert')) {
1049                y0 = this.graphheight - y0;
1050                y1 = this.graphheight - y1;
1051                y2 = this.graphheight - y2;
1052                y3 = this.graphheight - y3;
1053                y4 = this.graphheight - y4;
1054            }
1055
1056            var col1  = y[5];
1057            var col2  = y[6];
1058
1059            // Override the boxWidth
1060            if (typeof(y[7]) == 'number') {
1061                var boxWidth = y[7];
1062            }
1063           
1064            var y = this.graphheight - y2;
1065
1066        } else {
1067            var yMin = this.Get('chart.ymin') ? this.Get('chart.ymin') : 0;
1068            var y = (( (y - yMin) / (yMax - yMin)) * (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom));
1069        }
1070
1071        /**
1072        * Account for the X axis being at the centre
1073        */
1074        if (this.Get('chart.xaxispos') == 'center') {
1075            y /= 2;
1076            y += this.halfGraphHeight;
1077        }
1078
1079        // This is so that points are on the graph, and not the gutter
1080        x += this.gutterLeft;
1081        y = RGraph.GetHeight(this) - this.gutterBottom - y;
1082
1083        this.context.beginPath();
1084       
1085        // Color
1086        this.context.strokeStyle = color;
1087
1088        /**
1089        * Boxplots
1090        */
1091        if (   this.Get('chart.boxplot')
1092            && typeof(y0) == 'number'
1093            && typeof(y1) == 'number'
1094            && typeof(y2) == 'number'
1095            && typeof(y3) == 'number'
1096            && typeof(y4) == 'number'
1097           ) {
1098
1099            var boxWidth = boxWidth ? boxWidth : this.Get('chart.boxplot.width');
1100            var halfBoxWidth = boxWidth / 2;
1101
1102            this.context.beginPath();
1103
1104            // Draw the upper coloured box if a value is specified
1105            if (col1) {
1106                this.context.fillStyle = col1;
1107                this.context.fillRect(x - halfBoxWidth, y1 + this.gutterTop, boxWidth, y2 - y1);
1108            }
1109
1110            // Draw the lower coloured box if a value is specified
1111            if (col2) {
1112                this.context.fillStyle = col2;
1113                this.context.fillRect(x - halfBoxWidth, y2 + this.gutterTop, boxWidth, y3 - y2);
1114            }
1115
1116            this.context.strokeRect(x - halfBoxWidth, y1 + this.gutterTop, boxWidth, y3 - y1);
1117            this.context.stroke();
1118
1119            // Now draw the whiskers
1120            this.context.beginPath();
1121            this.context.moveTo(x - halfBoxWidth, y0 + this.gutterTop);
1122            this.context.lineTo(x + halfBoxWidth, y0 + this.gutterTop);
1123
1124            this.context.moveTo(x, y0 + this.gutterTop);
1125            this.context.lineTo(x, y1 + this.gutterTop);
1126
1127            this.context.moveTo(x - halfBoxWidth, y4 + this.gutterTop);
1128            this.context.lineTo(x + halfBoxWidth, y4 + this.gutterTop);
1129
1130            this.context.moveTo(x, y4 + this.gutterTop);
1131            this.context.lineTo(x, y3 + this.gutterTop);
1132
1133            this.context.stroke();
1134        }
1135
1136
1137        /**
1138        * Draw the tickmark, but not for boxplots
1139        */
1140        if (!y0 && !y1 && !y2 && !y3 && !y4) {
1141           
1142            this.graphheight = RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom;
1143
1144
1145           
1146            if (tickmarks == 'circle') {
1147                this.context.arc(x, y, halfTickSize, 0, 6.28, 0);
1148                this.context.fillStyle = color;
1149                this.context.fill();
1150           
1151            } else if (tickmarks == 'plus') {
1152
1153                this.context.moveTo(x, y - halfTickSize);
1154                this.context.lineTo(x, y + halfTickSize);
1155                this.context.moveTo(x - halfTickSize, y);
1156                this.context.lineTo(x + halfTickSize, y);
1157                this.context.stroke();
1158           
1159            } else if (tickmarks == 'square') {
1160                this.context.strokeStyle = color;
1161                this.context.fillStyle = color;
1162                this.context.fillRect(
1163                                      x - halfTickSize,
1164                                      y - halfTickSize,
1165                                      tickSize,
1166                                      tickSize
1167                                     );
1168                //this.context.fill();
1169
1170            } else if (tickmarks == 'cross') {
1171
1172                this.context.moveTo(x - halfTickSize, y - halfTickSize);
1173                this.context.lineTo(x + halfTickSize, y + halfTickSize);
1174                this.context.moveTo(x + halfTickSize, y - halfTickSize);
1175                this.context.lineTo(x - halfTickSize, y + halfTickSize);
1176               
1177                this.context.stroke();
1178           
1179            /**
1180            * Diamond shape tickmarks
1181            */
1182            } else if (tickmarks == 'diamond') {
1183                this.context.fillStyle = this.context.strokeStyle;
1184
1185                this.context.moveTo(x, y - halfTickSize);
1186                this.context.lineTo(x + halfTickSize, y);
1187                this.context.lineTo(x, y + halfTickSize);
1188                this.context.lineTo(x - halfTickSize, y);
1189                this.context.lineTo(x, y - halfTickSize);
1190               
1191                this.context.fill();
1192                this.context.stroke();
1193
1194            /**
1195            * Custom tickmark style
1196            */
1197            } else if (typeof(tickmarks) == 'function') {
1198
1199                var graphWidth = RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight
1200                var xVal = ((x - this.gutterLeft) / graphWidth) * xMax;
1201                var yVal = ((this.graphheight - (y - this.gutterTop)) / this.graphheight) * yMax;
1202
1203                tickmarks(this, data, x, y, xVal, yVal, xMax, yMax, color)
1204
1205            /**
1206            * No tickmarks
1207            */
1208            } else if (tickmarks == null) {
1209   
1210            /**
1211            * Unknown tickmark type
1212            */
1213            } else {
1214                alert('[SCATTER] (' + this.id + ') Unknown tickmark style: ' + tickmarks );
1215            }
1216        }
1217
1218        /**
1219        * Add the tickmark to the coords array
1220        */
1221        coords.push([x, y, tooltip]);
1222    }
1223   
1224   
1225    /**
1226    * Draws an optional line connecting the tick marks.
1227    *
1228    * @param i The index of the dataset to use
1229    */
1230    RGraph.Scatter.prototype.DrawLine = function (i)
1231    {
1232        if (this.Get('chart.line') && this.coords[i].length >= 2) {
1233
1234            this.context.lineCap     = 'round';
1235            this.context.lineJoin    = 'round';
1236            this.context.lineWidth   = this.GetLineWidth(i);// i is the index of the set of coordinates
1237            this.context.strokeStyle = this.Get('chart.line.colors')[i];
1238            this.context.beginPath();
1239           
1240            var len = this.coords[i].length;
1241
1242            for (var j=0; j<this.coords[i].length; ++j) {
1243
1244                var xPos = this.coords[i][j][0];
1245                var yPos = this.coords[i][j][1];
1246
1247                if (j == 0) {
1248                    this.context.moveTo(xPos, yPos);
1249                } else {
1250               
1251                    // Stepped?
1252                    var stepped = this.Get('chart.line.stepped');
1253
1254                    if (   (typeof(stepped) == 'boolean' && stepped)
1255                        || (typeof(stepped) == 'object' && stepped[i])
1256                       ) {
1257                        this.context.lineTo(this.coords[i][j][0], this.coords[i][j - 1][1]);
1258                    }
1259
1260                    this.context.lineTo(xPos, yPos);
1261                }
1262            }
1263           
1264            this.context.stroke();
1265        }
1266       
1267        /**
1268        * Set the linewidth back to 1
1269        */
1270        this.context.lineWidth = 1;
1271    }
1272
1273
1274    /**
1275    * Returns the linewidth
1276    *
1277    * @param number i The index of the "line" (/set of coordinates)
1278    */
1279    RGraph.Scatter.prototype.GetLineWidth = function (i)
1280    {
1281        var linewidth = this.Get('chart.line.linewidth');
1282       
1283        if (typeof(linewidth) == 'number') {
1284            return linewidth;
1285       
1286        } else if (typeof(linewidth) == 'object') {
1287            if (linewidth[i]) {
1288                return linewidth[i];
1289            } else {
1290                return linewidth[0];
1291            }
1292
1293            alert('[SCATTER] Error! chart.linewidth should be a single number or an array of one or more numbers');
1294        }
1295    }
1296
1297
1298    /**
1299    * Draws vertical bars. Line chart doesn't use a horizontal scale, hence this function
1300    * is not common
1301    */
1302    RGraph.Scatter.prototype.DrawVBars = function ()
1303    {
1304        var canvas  = this.canvas;
1305        var context = this.context;
1306        var vbars = this.Get('chart.background.vbars');
1307        var graphWidth = RGraph.GetWidth(this) - this.gutterLeft - this.gutterRight;
1308       
1309        if (vbars) {
1310       
1311            var xmax = this.Get('chart.xmax');
1312
1313            for (var i=0; i<vbars.length; ++i) {
1314                var startX = ((vbars[i][0] / xmax) * graphWidth) + this.gutterLeft;
1315                var width  = (vbars[i][1] / xmax) * graphWidth;
1316
1317                context.beginPath();
1318                    context.fillStyle = vbars[i][2];
1319                    context.fillRect(startX, this.gutterTop, width, (RGraph.GetHeight(this) - this.gutterTop - this.gutterBottom));
1320                context.fill();
1321            }
1322        }
1323    }
1324
1325
1326
1327
1328
1329    /**
1330    * Draws in-graph labels.
1331    *
1332    * @param object obj The graph object
1333    */
1334    RGraph.Scatter.prototype.DrawInGraphLabels = function (obj)
1335    {
1336        var canvas  = obj.canvas;
1337        var context = obj.context;
1338        var labels  = obj.Get('chart.labels.ingraph');
1339        var labels_processed = [];
1340
1341        // Defaults
1342        var fgcolor   = 'black';
1343        var bgcolor   = 'white';
1344        var direction = 1;
1345
1346        if (!labels) {
1347            return;
1348        }
1349
1350        /**
1351        * Preprocess the labels array. Numbers are expanded
1352        */
1353        for (var i=0; i<labels.length; ++i) {
1354            if (typeof(labels[i]) == 'number') {
1355                for (var j=0; j<labels[i]; ++j) {
1356                    labels_processed.push(null);
1357                }
1358            } else if (typeof(labels[i]) == 'string' || typeof(labels[i]) == 'object') {
1359                labels_processed.push(labels[i]);
1360           
1361            } else {
1362                labels_processed.push('');
1363            }
1364        }
1365
1366        /**
1367        * Turn off any shadow
1368        */
1369        RGraph.NoShadow(obj);
1370
1371        if (labels_processed && labels_processed.length > 0) {
1372
1373            var i=0;
1374
1375            for (var set=0; set<obj.coords.length; ++set) {
1376                for (var point = 0; point<obj.coords[set].length; ++point) {
1377                    if (labels_processed[i]) {
1378                        var x = obj.coords[set][point][0];
1379                        var y = obj.coords[set][point][1];
1380                        var length = typeof(labels_processed[i][4]) == 'number' ? labels_processed[i][4] : 25;
1381                           
1382                        var text_x = x;
1383                        var text_y = y - 5 - length;
1384
1385                        context.moveTo(x, y - 5);
1386                        context.lineTo(x, y - 5 - length);
1387                       
1388                        context.stroke();
1389                        context.beginPath();
1390                       
1391                        // This draws the arrow
1392                        context.moveTo(x, y - 5);
1393                        context.lineTo(x - 3, y - 10);
1394                        context.lineTo(x + 3, y - 10);
1395                        context.closePath();
1396
1397
1398                        context.beginPath();
1399                           
1400                            // Fore ground color
1401                            context.fillStyle = (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][1]) == 'string') ? labels_processed[i][1] : 'black';
1402
1403                            RGraph.Text(context,
1404                                        obj.Get('chart.text.font'),
1405                                        obj.Get('chart.text.size'),
1406                                        text_x,
1407                                        text_y,
1408                                        (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][0]) == 'string') ? labels_processed[i][0] : labels_processed[i],
1409                                        'bottom',
1410                                        'center',
1411                                        true,
1412                                        null,
1413                                        (typeof(labels_processed[i]) == 'object' && typeof(labels_processed[i][2]) == 'string') ? labels_processed[i][2] : 'white');
1414                        context.fill();
1415                    }
1416                   
1417                    i++;
1418                }
1419            }
1420        }
1421    }
1422
1423
1424    /**
1425    * This function makes it much easier to get the (if any) point that is currently being hovered over.
1426    *
1427    * @param object e The event object
1428    */
1429    RGraph.Scatter.prototype.getPoint = function (e)
1430    {
1431        var canvas      = e.target;
1432        var obj         = canvas.__object__;
1433        var context     = obj.context;
1434        var context     = obj.context;
1435        var mouseXY     = RGraph.getMouseXY(e);
1436        var mouseX      = mouseXY[0];
1437        var mouseY      = mouseXY[1];
1438        var overHotspot = false;
1439        var offset = obj.Get('chart.tooltips.hotspot'); // This is how far the hotspot extends
1440
1441        for (var set=0; set<obj.coords.length; ++set) {
1442            for (var i=0; i<obj.coords[set].length; ++i) {
1443               
1444                var xCoord = obj.coords[set][i][0];
1445                var yCoord = obj.coords[set][i][1];
1446
1447                if (mouseX <= (xCoord + offset) &&
1448                    mouseX >= (xCoord - offset) &&
1449                    mouseY <= (yCoord + offset) &&
1450                    mouseY >= (yCoord - offset)) {
1451                   
1452                    return [xCoord, yCoord, set, i, obj.data[set][i][3]];
1453                }
1454            }
1455        }
1456    }
1457
1458
1459    /**
1460    * Draws the above line labels
1461    */
1462    RGraph.Scatter.prototype.DrawAboveLabels = function ()
1463    {
1464        var context    = this.context;
1465        var size       = this.Get('chart.labels.above.size');
1466        var font       = this.Get('chart.text.font');
1467        var units_pre  = this.Get('chart.units.pre');
1468        var units_post = this.Get('chart.units.post');
1469
1470
1471        for (var set=0; set<this.coords.length; ++set) {
1472            for (var point=0; point<this.coords[set].length; ++point) {
1473               
1474                var x_val = this.data[set][point][0];
1475                var y_val = this.data[set][point][1];
1476               
1477               
1478                var x_pos = this.coords[set][point][0];
1479                var y_pos = this.coords[set][point][1];
1480
1481                RGraph.Text(context,
1482                            font,
1483                            size,
1484                            x_pos,
1485                            y_pos - 5 - size,
1486                            x_val.toFixed(this.Get('chart.labels.above.decimals')) + ', ' + y_val.toFixed(this.Get('chart.labels.above.decimals')),
1487                            'center',
1488                            'center',
1489                            true,
1490                            null,
1491                            'rgba(255, 255, 255, 0.7)');
1492            }
1493        }
1494    }
Note: See TracBrowser for help on using the repository browser.