Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
    /**
2
    * o-------------------------------------------------------------------------------o
3
    * | This file is part of the RGraph package. RGraph is Free software, licensed    |
4
    * | under the MIT license - so it's free to use for all purposes. Extended        |
5
    * | support is available if required and donations are always welcome! You can    |
6
    * | read more here:                                                               |
7
    * |                         http://www.rgraph.net/support                         |
8
    * o-------------------------------------------------------------------------------o
9
    */
10
 
11
    if (typeof(RGraph) == 'undefined') RGraph = {};
12
 
13
    /**
14
    * The progress bar constructor
15
    *
16
    * @param int id    The ID of the canvas tag
17
    * @param int value The indicated value of the meter.
18
    * @param int max   The end value (the upper most) of the meter
19
    */
20
    RGraph.VProgress = function (id, value, max)
21
    {
22
        this.id                = id;
23
        this.max               = max;
24
        this.value             = value;
25
        this.canvas            = document.getElementById(typeof id === 'object' ? id.id : id);
26
        this.context           = this.canvas.getContext('2d');
27
        this.canvas.__object__ = this;
28
        this.type              = 'vprogress';
29
        this.coords            = [];
30
        this.isRGraph          = true;
31
        this.currentValue      = null;
32
        this.uid               = RGraph.CreateUID();
33
        this.canvas.uid        = this.canvas.uid ? this.canvas.uid : RGraph.CreateUID();
34
        this.colorsParsed      = false;
35
        this.coordsText        = [];
36
 
37
 
38
        /**
39
        * Compatibility with older browsers
40
        */
41
        RGraph.OldBrowserCompat(this.context);
42
 
43
        this.properties = {
44
            'chart.colors':             ['Gradient(white:#0c0)','Gradient(white:red)','Gradient(white:green)','yellow','pink','cyan','black','white','gray'],
45
            'chart.strokestyle.inner':  '#999',
46
            'chart.strokestyle.outer':  '#999',
47
            'chart.tickmarks':          true,
48
            'chart.tickmarks.zerostart':true,
49
            'chart.tickmarks.color':    '#999',
50
            'chart.tickmarks.inner':    false,
51
            'chart.gutter.left':        25,
52
            'chart.gutter.right':       25,
53
            'chart.gutter.top':         25,
54
            'chart.gutter.bottom':      25,
55
            'chart.numticks':           10,
56
            'chart.numticks.inner':     50,
57
            'chart.background.color':   '#eee',
58
            'chart.shadow':             false,
59
            'chart.shadow.color':       'rgba(0,0,0,0.5)',
60
            'chart.shadow.blur':        3,
61
            'chart.shadow.offsetx':     3,
62
            'chart.shadow.offsety':     3,
63
            'chart.title':              '',
64
            'chart.title.bold':         true,
65
            'chart.title.font':         null,
66
            'chart.title.size':         null,
67
            'chart.title.color':        'black',
68
 
69
            'chart.title.side':         null,
70
            'chart.title.side.font':    'Arial',
71
            'chart.title.side.size':    12,
72
            'chart.title.side.color':   'black',
73
            'chart.title.side.bold':    true,
74
 
75
            'chart.text.size':          10,
76
            'chart.text.color':         'black',
77
            'chart.text.font':          'Arial',
78
            'chart.contextmenu':        null,
79
            'chart.units.pre':          '',
80
            'chart.units.post':         '',
81
            'chart.tooltips':           null,
82
            'chart.tooltips.effect':    'fade',
83
            'chart.tooltips.css.class': 'RGraph_tooltip',
84
            'chart.tooltips.highlight': true,
85
            'chart.tooltips.event':         'onclick',
86
            'chart.highlight.stroke':   'rgba(0,0,0,0)',
87
            'chart.highlight.fill':     'rgba(255,255,255,0.7)',
88
            'chart.annotatable':        false,
89
            'chart.annotate.color':     'black',
90
            'chart.zoom.factor':        1.5,
91
            'chart.zoom.fade.in':       true,
92
            'chart.zoom.fade.out':      true,
93
            'chart.zoom.hdir':          'right',
94
            'chart.zoom.vdir':          'down',
95
            'chart.zoom.frames':        25,
96
            'chart.zoom.delay':         16.666,
97
            'chart.zoom.shadow':        true,
98
            'chart.zoom.background':    true,
99
            'chart.zoom.action':        'zoom',
100
            'chart.arrows':             false,
101
            'chart.margin':             0,
102
            'chart.resizable':              false,
103
            'chart.resize.handle.adjust':   [0,0],
104
            'chart.resize.handle.background': null,
105
            'chart.label.inner':        false,
106
            'chart.labels.count':       10,
107
            'chart.labels.position':    'right',
108
            'chart.adjustable':         false,
109
            'chart.min':                0,
110
            'chart.scale.decimals':     0,
111
            'chart.scale.thousand':     ',',
112
            'chart.scale.point':        '.',
113
            'chart.key':                null,
114
            'chart.key.background':     'white',
115
            'chart.key.position':       'graph',
116
            'chart.key.halign':             'right',
117
            'chart.key.shadow':         false,
118
            'chart.key.shadow.color':   '#666',
119
            'chart.key.shadow.blur':    3,
120
            'chart.key.shadow.offsetx': 2,
121
            'chart.key.shadow.offsety': 2,
122
            'chart.key.position.gutter.boxed': false,
123
            'chart.key.position.x':     null,
124
            'chart.key.position.y':     null,
125
            'chart.key.color.shape':    'square',
126
            'chart.key.rounded':        true,
127
            'chart.key.linewidth':      1,
128
            'chart.key.colors':         null,
129
            'chart.key.interactive':    false,
130
            'chart.key.interactive.highlight.chart.stroke': '#000',
131
            'chart.key.interactive.highlight.chart.fill': 'rgba(255,255,255,0.7)',
132
            'chart.key.interactive.highlight.label': 'rgba(255,0,0,0.2)',
133
            'chart.key.text.color':     'black',
134
            'chart.events.click':       null,
135
            'chart.events.mousemove':   null,
136
            'chart.border.inner':       true
137
        }
138
 
139
        /**
140
        * Allow for new style method of passing arguments to the constructor
141
        */
142
        if (arguments.length == 4) {
143
 
144
            this.min   = arguments[1];
145
            this.max   = arguments[2];
146
            this.value = arguments[3];
147
 
148
            this.properties['chart.min'] = arguments[1];
149
 
150
        } else if (arguments.length == 3) {
151
 
152
            this.min   = 0;
153
            this.max   = arguments[2];
154
            this.value = arguments[1];
155
 
156
            this.properties['chart.min'] = 0;
157
        }
158
 
159
        // Check for support
160
        if (!this.canvas) {
161
            alert('[PROGRESS] No canvas support');
162
            return;
163
        }
164
 
165
 
166
        /**
167
        * Create the dollar objects so that functions can be added to them
168
        */
169
        var linear_data = RGraph.array_linearize(value);
170
        for (var i=0; i<linear_data.length; ++i) {
171
            this['$' + i] = {};
172
        }
173
 
174
 
175
        /**
176
        * Translate half a pixel for antialiasing purposes - but only if it hasn't beeen
177
        * done already
178
        */
179
        if (!this.canvas.__rgraph_aa_translated__) {
180
            this.context.translate(0.5,0.5);
181
 
182
            this.canvas.__rgraph_aa_translated__ = true;
183
        }
184
 
185
 
186
 
187
 
188
        ///////////////////////////////// SHORT PROPERTIES /////////////////////////////////
189
 
190
 
191
 
192
 
193
        var RG   = RGraph;
194
        var ca   = this.canvas;
195
        var co   = ca.getContext('2d');
196
        var prop = this.properties;
197
        //var $jq  = jQuery;
198
 
199
 
200
 
201
 
202
        //////////////////////////////////// METHODS ///////////////////////////////////////
203
 
204
 
205
 
206
 
207
        /**
208
        * A generic setter
209
        *
210
        * @param string name  The name of the property to set
211
        * @param string value The value of the poperty
212
        */
213
        this.Set = function (name, value)
214
        {
215
            /**
216
            * This should be done first - prepend the propertyy name with "chart." if necessary
217
            */
218
            if (name.substr(0,6) != 'chart.') {
219
                name = 'chart.' + name;
220
            }
221
 
222
            /**
223
            * chart.strokestyle now sets both chart.strokestyle.inner and chart.strokestyle.outer
224
            */
225
            if (name == 'chart.strokestyle') {
226
                prop['chart.strokestyle.inner'] = value;
227
                prop['chart.strokestyle.outer'] = value;
228
 
229
                return;
230
            }
231
 
232
            prop[name.toLowerCase()] = value;
233
 
234
            return this;
235
        }
236
 
237
 
238
 
239
 
240
        /**
241
        * A generic getter
242
        *
243
        * @param string name  The name of the property to get
244
        */
245
        this.Get = function (name)
246
        {
247
            /**
248
            * This should be done first - prepend the property name with "chart." if necessary
249
            */
250
            if (name.substr(0,6) != 'chart.') {
251
                name = 'chart.' + name;
252
            }
253
 
254
            return prop[name.toLowerCase()];
255
        }
256
 
257
 
258
 
259
 
260
        /**
261
        * Draws the progress bar
262
        */
263
        this.Draw = function ()
264
        {
265
            /**
266
            * Fire the onbeforedraw event
267
            */
268
            RG.FireCustomEvent(this, 'onbeforedraw');
269
 
270
 
271
 
272
            /**
273
            * Parse the colors. This allows for simple gradient syntax
274
            */
275
            if (!this.colorsParsed) {
276
 
277
                this.parseColors();
278
 
279
 
280
                // Don't want to do this again
281
                this.colorsParsed = true;
282
            }
283
 
284
 
285
            /**
286
            * Set the current value
287
            */
288
            this.currentValue = this.value;
289
 
290
            /**
291
            * This is new in May 2011 and facilitates indiviual gutter settings,
292
            * eg chart.gutter.left
293
            */
294
            this.gutterLeft   = prop['chart.gutter.left'];
295
            this.gutterRight  = prop['chart.gutter.right'];
296
            this.gutterTop    = prop['chart.gutter.top'];
297
            this.gutterBottom = prop['chart.gutter.bottom'];
298
 
299
            // Figure out the width and height
300
            this.width  = ca.width - this.gutterLeft - this.gutterRight;
301
            this.height = ca.height - this.gutterTop - this.gutterBottom;
302
            this.coords = [];
303
 
304
            this.Drawbar();
305
            this.DrawTickMarks();
306
            this.DrawLabels();
307
            this.DrawTitles();
308
 
309
            co.stroke();
310
            co.fill();
311
 
312
 
313
            /**
314
            * Draw the bevel effect if requested
315
            */
316
            if (prop['chart.bevel']) {
317
                this.DrawBevel();
318
            }
319
 
320
 
321
 
322
            /**
323
            * Setup the context menu if required
324
            */
325
            if (prop['chart.contextmenu']) {
326
                RG.ShowContext(this);
327
            }
328
 
329
 
330
            /**
331
            * This installs the event listeners
332
            */
333
            RG.InstallEventListeners(this);
334
 
335
            // Draw a key if necessary
336
            if (prop['chart.key'] && prop['chart.key'].length) {
337
                RG.DrawKey(this, prop['chart.key'], prop['chart.colors']);
338
            }
339
 
340
 
341
 
342
            /**
343
            * This function enables resizing
344
            */
345
            if (prop['chart.resizable']) {
346
                RG.AllowResizing(this);
347
            }
348
 
349
            /**
350
            * Instead of using RGraph.common.adjusting.js, handle them here
351
            */
352
            this.AllowAdjusting();
353
 
354
            /**
355
            * Fire the RGraph ondraw event
356
            */
357
            RG.FireCustomEvent(this, 'ondraw');
358
 
359
            return this;
360
        }
361
 
362
 
363
 
364
 
365
        /**
366
        * Draw the bar itself
367
        */
368
        this.Drawbar = function ()
369
        {
370
            /**
371
            * First get the scale
372
            */
373
                this.scale2 = RGraph.getScale2(this, {
374
                                                    'max':this.max,
375
                                                    'min':this.min,
376
                                                    'strict':true,
377
                                                    'scale.thousand':prop['chart.scale.thousand'],
378
                                                    'scale.point':prop['chart.scale.point'],
379
                                                    'scale.decimals':prop['chart.scale.decimals'],
380
                                                    'ylabels.count':prop['chart.labels.count'],
381
                                                    'scale.round':prop['chart.scale.round'],
382
                                                    'units.pre': prop['chart.units.pre'],
383
                                                    'units.post': prop['chart.units.post']
384
                                                   });
385
 
386
 
387
            // Set a shadow if requested
388
            if (prop['chart.shadow']) {
389
                RG.SetShadow(this, prop['chart.shadow.color'], prop['chart.shadow.offsetx'], prop['chart.shadow.offsety'], prop['chart.shadow.blur']);
390
            }
391
 
392
            // Draw the shadow for MSIE
393
            if (ISOLD && prop['chart.shadow']) {
394
                co.fillStyle = prop['chart.shadow.color'];
395
                co.fillRect(this.gutterLeft + prop['chart.shadow.offsetx'], this.gutterTop + prop['chart.shadow.offsety'], this.width, this.height);
396
            }
397
 
398
            // Draw the outline
399
            co.fillStyle   = prop['chart.background.color'];
400
            co.strokeStyle = prop['chart.strokestyle.outer'];
401
            co.strokeRect(this.gutterLeft, this.gutterTop, this.width, this.height);
402
            co.fillRect(this.gutterLeft, this.gutterTop, this.width, this.height);
403
 
404
            // Turn off any shadow
405
            RG.NoShadow(this);
406
 
407
            co.strokeStyle = prop['chart.strokestyle.outer'];
408
            co.fillStyle   = prop['chart.colors'][0];
409
            var margin     = prop['chart.margin'];
410
            var barHeight  = (ca.height - this.gutterTop - this.gutterBottom) * (RG.array_sum(this.value) / this.max);
411
 
412
            // Draw the actual bar itself
413
            if (typeof(this.value) == 'number') {
414
 
415
                co.lineWidth   = 1;
416
                co.strokeStyle = prop['chart.strokestyle.inner'];
417
 
418
            } else if (typeof(this.value) == 'object') {
419
 
420
                co.beginPath();
421
                co.strokeStyle = prop['chart.strokestyle.inner'];
422
 
423
                var startPoint = ca.height - this.gutterBottom;
424
 
425
                for (var i=0; i<this.value.length; ++i) {
426
 
427
                    var segmentHeight = ( (this.value[i] - prop['chart.min']) / (this.max - prop['chart.min']) ) * (ca.height - this.gutterBottom - this.gutterTop);
428
 
429
                    co.fillStyle = prop['chart.colors'][i];
430
 
431
                    if (prop['chart.border.inner']) {
432
                        co.strokeRect(this.gutterLeft + margin, startPoint - segmentHeight, this.width - margin - margin, segmentHeight);
433
                    }
434
                    co.fillRect(this.gutterLeft + margin, startPoint - segmentHeight, this.width - margin - margin, segmentHeight);
435
 
436
 
437
 
438
                    // Store the coords
439
                    this.coords.push([this.gutterLeft + margin, startPoint - segmentHeight, this.width - margin - margin, segmentHeight]);
440
 
441
                    startPoint -= segmentHeight;
442
                }
443
 
444
 
445
                co.stroke();
446
                co.fill();
447
            }
448
 
449
            /**
450
            * Inner tickmarks
451
            */
452
            if (prop['chart.tickmarks.inner']) {
453
 
454
                var spacing = (ca.height - this.gutterTop - this.gutterBottom) / prop['chart.numticks.inner'];
455
 
456
                co.lineWidth   = 1;
457
                co.strokeStyle = prop['chart.strokestyle.outer'];
458
 
459
                co.beginPath();
460
 
461
                for (var y = this.gutterTop; y<ca.height - this.gutterBottom; y+=spacing) {
462
                    co.moveTo(this.gutterLeft, Math.round(y));
463
                    co.lineTo(this.gutterLeft + 3, Math.round(y));
464
 
465
                    co.moveTo(ca.width - this.gutterRight, Math.round(y));
466
                    co.lineTo(ca.width - this.gutterRight - 3, Math.round(y));
467
                }
468
 
469
                co.stroke();
470
            }
471
 
472
            co.beginPath();
473
            co.strokeStyle = prop['chart.strokestyle.inner'];
474
 
475
            if (typeof(this.value) == 'number') {
476
 
477
                if (prop['chart.border.inner']) {
478
                    co.strokeRect(this.gutterLeft + margin, this.gutterTop + this.height - barHeight, this.width - margin - margin, barHeight);
479
                }
480
                co.fillRect(this.gutterLeft + margin, this.gutterTop + this.height - barHeight, this.width - margin - margin, barHeight);
481
 
482
                // Store the coords
483
                this.coords.push([this.gutterLeft + margin, this.gutterTop + this.height - barHeight, this.width - margin - margin, barHeight]);
484
            }
485
 
486
 
487
            /**
488
            * Draw the arrows indicating the level if requested
489
            */
490
            if (prop['chart.arrows']) {
491
                var x = this.gutterLeft - 4;
492
                var y = ca.height - this.gutterBottom - barHeight;
493
 
494
                co.lineWidth = 1;
495
                co.fillStyle = 'black';
496
                co.strokeStyle = 'black';
497
 
498
                co.beginPath();
499
                    co.moveTo(x, y);
500
                    co.lineTo(x - 4, y - 2);
501
                    co.lineTo(x - 4, y + 2);
502
                co.closePath();
503
 
504
                co.stroke();
505
                co.fill();
506
 
507
                x +=  this.width + 8;
508
 
509
                co.beginPath();
510
                    co.moveTo(x, y);
511
                    co.lineTo(x + 4, y - 2);
512
                    co.lineTo(x + 4, y + 2);
513
                co.closePath();
514
 
515
                co.stroke();
516
                co.fill();
517
            }
518
 
519
 
520
 
521
 
522
            /**
523
            * Draw the "in-bar" label
524
            */
525
            if (prop['chart.label.inner']) {
526
                co.fillStyle = 'black';
527
                RG.Text2(this, {'font':prop['chart.text.font'],
528
                                'size':prop['chart.text.size'],
529
                                'x':((ca.width - this.gutterLeft - this.gutterRight) / 2) + this.gutterLeft,'y':this.coords[this.coords.length - 1][1] - 5,'text':RGraph.number_format(this, (typeof(this.value) == 'number' ? this.value : RG.array_sum(this.value)).toFixed(prop['chart.scale.decimals'])),
530
                                'valign':'bottom',
531
                                'halign':'center',
532
                                'bounding':true,
533
                                'boundingFill':'white',
534
                                'tag': 'label.inner'
535
                               });
536
            }
537
        }
538
 
539
 
540
 
541
 
542
        /**
543
        * The function that draws the tick marks.
544
        */
545
        this.DrawTickMarks = function ()
546
        {
547
            co.strokeStyle = prop['chart.tickmarks.color'];
548
 
549
            if (prop['chart.tickmarks']) {
550
                co.beginPath();
551
                    for (var i=0; prop['chart.tickmarks.zerostart'] ? i<=prop['chart.numticks'] : i<prop['chart.numticks']; i++) {
552
 
553
                        var startX = prop['chart.labels.position'] == 'left' ? this.gutterLeft : ca.width - prop['chart.gutter.right'];
554
                        var endX   = prop['chart.labels.position'] == 'left' ? startX - 4 : startX + 4;
555
                        var yPos   = (this.height * (i / prop['chart.numticks'])) + this.gutterTop
556
 
557
                        co.moveTo(startX, Math.round(yPos));
558
                        co.lineTo(endX, Math.round(yPos));
559
                    }
560
                co.stroke();
561
            }
562
        }
563
 
564
 
565
 
566
 
567
        /**
568
        * The function that draws the labels
569
        */
570
        this.DrawLabels = function ()
571
        {
572
            if (!RG.is_null(prop['chart.labels.specific'])) {
573
                return this.DrawSpecificLabels();
574
            }
575
 
576
            co.fillStyle = prop['chart.text.color'];
577
 
578
            var position   = prop['chart.labels.position'];
579
            var xAlignment = position == 'left' ? 'right' : 'left';
580
            var yAlignment = 'center';
581
            var count      = prop['chart.labels.count'];
582
            var units_pre  = prop['chart.units.pre'];
583
            var units_post = prop['chart.units.post'];
584
            var text_size  = prop['chart.text.size'];
585
            var text_font  = prop['chart.text.font'];
586
            var decimals   = prop['chart.scale.decimals'];
587
 
588
            if (prop['chart.tickmarks']) {
589
 
590
                for (var i=0; i<count ; ++i) {
591
                    RG.Text2(this, {'font':text_font,
592
                                    'size':text_size,
593
                                    'x':position == 'left' ? (this.gutterLeft - 7) : (ca.width - this.gutterRight + 7),
594
                                    'y':(((ca.height - this.gutterTop - this.gutterBottom) / count) * i) + this.gutterTop,
595
                                    'text':this.scale2.labels[this.scale2.labels.length - (i+1)],
596
                                    'valign':yAlignment,
597
                                    'halign':xAlignment,
598
                                    'tag': 'scale'
599
                                   });
600
                }
601
 
602
                /**
603
                * Show zero?
604
                */
605
                if (prop['chart.tickmarks.zerostart'] && prop['chart.min'] == 0) {
606
                    RG.Text2(this, {'font':text_font,
607
                                    'size':text_size,
608
                                    'x':position == 'left' ? (this.gutterLeft - 5) : (ca.width - this.gutterRight + 5),
609
                                    'y':ca.height - this.gutterBottom,'text':RG.number_format(this, prop['chart.min'].toFixed(decimals), units_pre, units_post),
610
                                    'valign':yAlignment,
611
                                    'halign':xAlignment,
612
                                    'tag': 'scale'
613
                                   });
614
                }
615
 
616
                /**
617
                * chart.ymin is set
618
                */
619
                if (prop['chart.min'] != 0) {
620
                    RG.Text2(this, {'font':text_font,
621
                                    'size':text_size,
622
                                    'x':position == 'left' ? (this.gutterLeft - 5) : (ca.width - this.gutterRight + 5),
623
                                    'y':ca.height - this.gutterBottom,
624
                                    'text':RG.number_format(this, prop['chart.min'].toFixed(decimals), units_pre, units_post),
625
                                    'valign':yAlignment,
626
                                    'halign':xAlignment,
627
                                    'tag': 'scale'
628
                                   });
629
                }
630
            }
631
        }
632
 
633
 
634
 
635
 
636
        /**
637
        * Draws titles
638
        */
639
        this.DrawTitles = function ()
640
        {
641
            var text_size  = prop['chart.text.size'];
642
            var text_font  = prop['chart.text.font'];
643
            var title_size = prop['chart.title.size'] ? prop['chart.title.size'] : text_size + 2;
644
 
645
            // Draw the title text
646
            if (prop['chart.title'].length > 0) {
647
 
648
                co.fillStyle = prop['chart.title.color'];
649
 
650
                RG.Text2(this, {'font':prop['chart.title.font'] ? prop['chart.title.font'] : text_font,
651
                                'size':title_size,
652
                                'x':this.gutterLeft + ((ca.width - this.gutterLeft - this.gutterRight) / 2),
653
                                'y':this.gutterTop - 5,
654
                                'text':prop['chart.title'],
655
                                'valign':'bottom',
656
                                'halign':'center',
657
                                'bold': prop['chart.title.bold'],
658
                                'tag': 'title'
659
                               });
660
            }
661
 
662
            // Draw side title
663
            if (typeof(prop['chart.title.side']) == 'string') {
664
 
665
                co.fillStyle = prop['chart.title.side.color'];
666
 
667
                RG.Text2(this, {'font':prop['chart.title.side.font'],
668
                                'size':prop['chart.title.side.size'],
669
                                'x':prop['chart.labels.position'] == 'right' ? this.gutterLeft - 10 : (ca.width - this.gutterRight) + 10,
670
                                'y':this.gutterTop + (this.height / 2),
671
                                'text': prop['chart.title.side'],
672
                                'valign':'bottom',
673
                                'halign':'center',
674
                                'angle': prop['chart.labels.position'] == 'right' ? 270 : 90,
675
                                'bold': prop['chart.title.side.bold'],
676
                                'tag': 'title.side'
677
                               });
678
            }
679
        }
680
 
681
 
682
 
683
 
684
        /**
685
        * Returns the focused bar
686
        *
687
        * @param event e The event object
688
        */
689
        this.getShape =
690
        this.getBar = function (e)
691
        {
692
            var mouseCoords = RG.getMouseXY(e)
693
 
694
            for (var i=0; i<this.coords.length; i++) {
695
 
696
                var mouseCoords = RG.getMouseXY(e);
697
                var mouseX = mouseCoords[0];
698
                var mouseY = mouseCoords[1];
699
                var left   = this.coords[i][0];
700
                var top    = this.coords[i][1];
701
                var width  = this.coords[i][2];
702
                var height = this.coords[i][3];
703
                var idx    = i;
704
 
705
                if (mouseX >= left && mouseX <= (left + width) && mouseY >= top && mouseY <= (top + height) ) {
706
 
707
                    var tooltip = RG.parseTooltipText(prop['chart.tooltips'], i);
708
 
709
                    return {0: this,   'object': this,
710
                            1: left,   'x':      left,
711
                            2: top,    'y':      top,
712
                            3: width,  'width':  width,
713
                            4: height, 'height': height,
714
                            5: i,      'index':  i,
715
                                       'tooltip': tooltip };
716
                }
717
            }
718
        }
719
 
720
 
721
 
722
 
723
        /**
724
        * This function returns the value that the mouse is positioned at, regardless of
725
        * the actual indicated value.
726
        *
727
        * @param object e The event object
728
        */
729
        this.getValue = function (e)
730
        {
731
            var mouseCoords = RG.getMouseXY(e);
732
            var mouseX      = mouseCoords[0];
733
            var mouseY      = mouseCoords[1];
734
 
735
            var value = (this.height - (mouseY - this.gutterTop)) / this.height;
736
                value *= this.max - prop['chart.min'];
737
                value += prop['chart.min'];
738
 
739
            // Bounds checking
740
            if (value > this.max) value = this.max;
741
            if (value < this.min) value = this.min;
742
 
743
            return value;
744
        }
745
 
746
 
747
 
748
 
749
        /**
750
        * Each object type has its own Highlight() function which highlights the appropriate shape
751
        *
752
        * @param object shape The shape to highlight
753
        */
754
        this.Highlight = function (shape)
755
        {
756
            // Add the new highlight
757
            RG.Highlight.Rect(this, shape);
758
        }
759
 
760
 
761
 
762
 
763
        /**
764
        * The getObjectByXY() worker method. Don't call this call:
765
        *
766
        * RGraph.ObjectRegistry.getObjectByXY(e)
767
        *
768
        * @param object e The event object
769
        */
770
        this.getObjectByXY = function (e)
771
        {
772
            var mouseXY = RG.getMouseXY(e);
773
 
774
            if (
775
                   mouseXY[0] > this.gutterLeft
776
                && mouseXY[0] < (ca.width - this.gutterRight)
777
                && mouseXY[1] >= this.gutterTop
778
                && mouseXY[1] <= (ca.height - this.gutterBottom)
779
                ) {
780
 
781
                return this;
782
            }
783
        }
784
 
785
 
786
 
787
 
788
        /**
789
        * This function allows the VProgress to be  adjustable.
790
        */
791
        this.AllowAdjusting = function () {return;}
792
 
793
 
794
 
795
 
796
        /**
797
        * This method handles the adjusting calculation for when the mouse is moved
798
        *
799
        * @param object e The event object
800
        */
801
        this.Adjusting_mousemove = function (e)
802
        {
803
            /**
804
            * Handle adjusting for the HProgress
805
            */
806
            if (prop['chart.adjustable'] && RG.Registry.Get('chart.adjusting') && RG.Registry.Get('chart.adjusting').uid == this.uid) {
807
 
808
                var mouseXY = RG.getMouseXY(e);
809
                var value   = this.getValue(e);
810
 
811
                if (typeof(value) == 'number') {
812
 
813
                    // Fire the onadjust event
814
                    RG.FireCustomEvent(this, 'onadjust');
815
 
816
                    this.value = Number(value.toFixed(prop['chart.scale.decimals']));
817
                    RG.Redraw();
818
                }
819
            }
820
        }
821
 
822
 
823
 
824
 
825
        /**
826
        * Draws chart.labels.specific
827
        */
828
        this.DrawSpecificLabels = function ()
829
        {
830
            var labels = prop['chart.labels.specific'];
831
 
832
            if (labels) {
833
 
834
                var font   = prop['chart.text.font'];
835
                var size   = prop['chart.text.size'];
836
                var halign = prop['chart.labels.position'] == 'right' ? 'left' : 'right';
837
                var step   = this.height / (labels.length - 1);
838
 
839
                co.beginPath();
840
 
841
                    co.fillStyle = prop['chart.text.color'];
842
 
843
                    for (var i=0; i<labels.length; ++i) {
844
 
845
                        RG.Text2(this,{'font':font,
846
                                       'size':size,
847
                                       'x': prop['chart.labels.position'] == 'right' ? ca.width - this.gutterRight + 7 : this.gutterLeft - 7,
848
                                       'y':(this.height + this.gutterTop) - (step * i),
849
                                       'text':labels[i],
850
                                       'valign':'center',
851
                                       'halign':halign,
852
                                        'tag': 'labels.specific'
853
                                      });
854
                    }
855
                co.fill();
856
            }
857
        }
858
 
859
 
860
 
861
 
862
        /**
863
        * This function positions a tooltip when it is displayed
864
        *
865
        * @param obj object    The chart object
866
        * @param int x         The X coordinate specified for the tooltip
867
        * @param int y         The Y coordinate specified for the tooltip
868
        * @param objec tooltip The tooltips DIV element
869
        */
870
        this.positionTooltip = function (obj, x, y, tooltip, idx)
871
        {
872
            var coordX     = obj.coords[tooltip.__index__][0];
873
            var coordY     = obj.coords[tooltip.__index__][1];
874
            var coordW     = obj.coords[tooltip.__index__][2];
875
            var coordH     = obj.coords[tooltip.__index__][3];
876
            var canvasXY   = RG.getCanvasXY(obj.canvas);
877
            var gutterLeft = obj.gutterLeft;
878
            var gutterTop  = obj.gutterTop;
879
            var width      = tooltip.offsetWidth;
880
            var height     = tooltip.offsetHeight;
881
 
882
            // Set the top position
883
            tooltip.style.left = 0;
884
            tooltip.style.top  = canvasXY[1] + coordY - height - 7 + 'px';
885
 
886
            // By default any overflow is hidden
887
            tooltip.style.overflow = '';
888
 
889
            // The arrow
890
            var img = new Image();
891
                img.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAAFCAYAAACjKgd3AAAARUlEQVQYV2NkQAN79+797+RkhC4M5+/bd47B2dmZEVkBCgcmgcsgbAaA9GA1BCSBbhAuA/AagmwQPgMIGgIzCD0M0AMMAEFVIAa6UQgcAAAAAElFTkSuQmCC';
892
                img.style.position = 'absolute';
893
                img.id = '__rgraph_tooltip_pointer__';
894
                img.style.top = (tooltip.offsetHeight - 2) + 'px';
895
            tooltip.appendChild(img);
896
 
897
            // Reposition the tooltip if at the edges:
898
 
899
            // LEFT edge
900
            if ((canvasXY[0] + coordX + (coordW / 2) - (width / 2)) < 10) {
901
                tooltip.style.left = (canvasXY[0] + coordX - (width * 0.1)) + (coordW / 2) + 'px';
902
                img.style.left = ((width * 0.1) - 8.5) + 'px';
903
 
904
            // RIGHT edge
905
            } else if ((canvasXY[0] + coordX + (coordW / 2) + (width / 2)) > document.body.offsetWidth) {
906
                tooltip.style.left = canvasXY[0] + coordX - (width * 0.9) + (coordW / 2) + 'px';
907
                img.style.left = ((width * 0.9) - 8.5) + 'px';
908
 
909
            // Default positioning - CENTERED
910
            } else {
911
                tooltip.style.left = (canvasXY[0] + coordX + (coordW / 2) - (width * 0.5)) + 'px';
912
                img.style.left = ((width * 0.5) - 8.5) + 'px';
913
            }
914
        }
915
 
916
 
917
 
918
 
919
        /**
920
        * This function returns the appropriate Y coordinate for the given Y value
921
        *
922
        * @param  int value The Y value you want the coordinate for
923
        * @returm int       The coordinate
924
        */
925
        this.getYCoord = function (value)
926
        {
927
            if (value > this.max || value < prop['chart.min']) {
928
                return null;
929
            }
930
 
931
            var barHeight = ca.height - prop['chart.gutter.top'] - prop['chart.gutter.bottom'];
932
            var coord = ((value - prop['chart.min']) / (this.max - prop['chart.min'])) * barHeight;
933
            coord = ca.height - coord - prop['chart.gutter.bottom'];
934
 
935
            return coord;
936
        }
937
 
938
 
939
 
940
 
941
        /**
942
        * This returns true/false as to whether the cursor is over the chart area.
943
        * The cursor does not necessarily have to be over the bar itself.
944
        */
945
        this.overChartArea = function  (e)
946
        {
947
            var mouseXY = RGraph.getMouseXY(e);
948
            var mouseX  = mouseXY[0];
949
            var mouseY  = mouseXY[1];
950
 
951
            if (   mouseX >= this.gutterLeft
952
                && mouseX <= (ca.width - this.gutterRight)
953
                && mouseY >= this.gutterTop
954
                && mouseY <= (ca.height - this.gutterBottom)
955
                ) {
956
 
957
                return true;
958
            }
959
 
960
            return false;
961
        }
962
 
963
 
964
 
965
 
966
        /**
967
        *
968
        */
969
        this.parseColors = function ()
970
        {
971
            var colors = prop['chart.colors'];
972
 
973
            for (var i=0; i<colors.length; ++i) {
974
                colors[i] = this.parseSingleColorForGradient(colors[i]);
975
            }
976
        }
977
 
978
 
979
 
980
 
981
        /**
982
        * This parses a single color value
983
        */
984
        this.parseSingleColorForGradient = function (color)
985
        {
986
            if (!color || typeof(color) != 'string') {
987
                return color;
988
            }
989
 
990
            if (color.match(/^gradient\((.*)\)$/i)) {
991
                var parts = RegExp.$1.split(':');
992
 
993
                // Create the gradient
994
                var grad = co.createLinearGradient(0, ca.height - prop['chart.gutter.bottom'], 0, prop['chart.gutter.top']);
995
 
996
                var diff = 1 / (parts.length - 1);
997
 
998
                grad.addColorStop(0, RG.trim(parts[0]));
999
 
1000
                for (var j=1; j<parts.length; ++j) {
1001
                    grad.addColorStop(j * diff, RG.trim(parts[j]));
1002
                }
1003
 
1004
                return grad ? grad : color;
1005
            }
1006
 
1007
            return grad ? grad : color;
1008
        }
1009
 
1010
 
1011
 
1012
 
1013
        /**
1014
        * Draws the bevel effect
1015
        */
1016
        this.DrawBevel = function ()
1017
        {
1018
            // In case of multiple segments - this adds up all the lengths
1019
            for (var i=0,len=0; i<this.coords.length; ++i) len += this.coords[i][3];
1020
 
1021
            co.save();
1022
                // Draw a path to clip to
1023
                co.beginPath();
1024
                    co.rect(this.coords[0][0], this.coords[this.coords.length - 1][1] - 1, this.coords[0][2], len);
1025
                    co.clip();
1026
 
1027
                // Now draw the rect with a shadow
1028
                co.beginPath();
1029
 
1030
                    co.shadowColor = 'black';
1031
                    co.shadowOffsetX = 0;
1032
                    co.shadowOffsetY = 0;
1033
                    co.shadowBlur    = 15;
1034
 
1035
                    co.lineWidth = 2;
1036
                    co.rect(this.coords[0][0] - 1, this.coords[this.coords.length - 1][1] - 1, this.coords[0][2] + 2, len + 2);
1037
 
1038
                co.stroke();
1039
 
1040
            co.restore();
1041
        }
1042
 
1043
 
1044
 
1045
 
1046
        /**
1047
        * This function handles highlighting an entire data-series for the interactive
1048
        * key
1049
        *
1050
        * @param int index The index of the data series to be highlighted
1051
        */
1052
        this.interactiveKeyHighlight = function (index)
1053
        {
1054
            var coords = this.coords[index];
1055
 
1056
            co.beginPath();
1057
 
1058
                co.strokeStyle = prop['chart.key.interactive.highlight.chart.stroke'];
1059
                co.lineWidth    = 2;
1060
                co.fillStyle   = prop['chart.key.interactive.highlight.chart.fill'];
1061
 
1062
                co.rect(coords[0], coords[1], coords[2], coords[3]);
1063
            co.fill();
1064
            co.stroke();
1065
 
1066
            // Reset the linewidth
1067
            co.lineWidth    = 1;
1068
        }
1069
 
1070
 
1071
 
1072
 
1073
        /**
1074
        * The chart is now always registered
1075
        */
1076
        RG.Register(this);
1077
    }